--- //depot/vendor/freebsd_6/src/sys/dev/bge/if_bge.c 2008/09/18 16:32:10 +++ //depot/yahoo/ybsd_6/src/sys/dev/bge/if_bge.c 2008/09/22 14:24:23 @@ -80,6 +81,7 @@ #include #include #include +#include #include #include @@ -340,7 +342,10 @@ static void bge_stats_update_regs(struct bge_softc *); static int bge_encap(struct bge_softc *, struct mbuf **, uint32_t *); +static void bge_handle_rxtx(void *, int); +static void bge_handle_link(void *, int); static void bge_intr(void *); +static void bge_intr_fast(void *); static void bge_start_locked(struct ifnet *); static void bge_start(struct ifnet *); static int bge_ioctl(struct ifnet *, u_long, caddr_t); @@ -410,6 +415,7 @@ static int bge_sysctl_mem_read(SYSCTL_HANDLER_ARGS); #endif static void bge_add_sysctls(struct bge_softc *); +static int bge_sysctl_stats(SYSCTL_HANDLER_ARGS); static device_method_t bge_methods[] = { /* Device interface */ @@ -854,10 +860,10 @@ static int bge_newbuf_std(struct bge_softc *sc, int i, struct mbuf *m) { + bus_dma_segment_t segs[1]; struct mbuf *m_new = NULL; struct bge_rx_bd *r; - struct bge_dmamap_arg ctx; - int error; + int error, nsegs = 0; if (m == NULL) { m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); @@ -874,22 +880,19 @@ m_adj(m_new, ETHER_ALIGN); sc->bge_cdata.bge_rx_std_chain[i] = m_new; r = &sc->bge_ldata.bge_rx_std_ring[i]; - ctx.bge_maxsegs = 1; - ctx.sc = sc; - error = bus_dmamap_load(sc->bge_cdata.bge_mtag, - sc->bge_cdata.bge_rx_std_dmamap[i], mtod(m_new, void *), - m_new->m_len, bge_dma_map_addr, &ctx, BUS_DMA_NOWAIT); - if (error || ctx.bge_maxsegs == 0) { + error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_mtag, + sc->bge_cdata.bge_rx_std_dmamap[i], m_new, segs, &nsegs, 0); + if (error || nsegs != 1) { if (m == NULL) { sc->bge_cdata.bge_rx_std_chain[i] = NULL; m_freem(m_new); } return (ENOMEM); } - r->bge_addr.bge_addr_lo = BGE_ADDR_LO(ctx.bge_busaddr); - r->bge_addr.bge_addr_hi = BGE_ADDR_HI(ctx.bge_busaddr); + r->bge_addr.bge_addr_lo = BGE_ADDR_LO(segs[0].ds_addr); + r->bge_addr.bge_addr_hi = BGE_ADDR_HI(segs[0].ds_addr); r->bge_flags = BGE_RXBDFLAG_END; - r->bge_len = m_new->m_len; + r->bge_len = segs[0].ds_len; r->bge_idx = i; bus_dmamap_sync(sc->bge_cdata.bge_mtag, @@ -2702,6 +2705,15 @@ /* * Hookup IRQ last. */ + TASK_INIT(&sc->rxtx_task, 0, bge_handle_rxtx, sc); + TASK_INIT(&sc->link_task, 0, bge_handle_link, sc); + sc->tq = taskqueue_create_fast("bge_taskq", M_NOWAIT, + taskqueue_thread_enqueue, &sc->tq); + taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq", + device_get_nameunit(dev)); + error = bus_setup_intr(dev, sc->bge_irq, INTR_TYPE_NET | INTR_FAST, + bge_intr_fast, sc, &sc->bge_intrhand); + if (error) { #if __FreeBSD_version > 700030 error = bus_setup_intr(dev, sc->bge_irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, bge_intr, sc, &sc->bge_intrhand); @@ -2709,6 +2721,7 @@ error = bus_setup_intr(dev, sc->bge_irq, INTR_TYPE_NET | INTR_MPSAFE, bge_intr, sc, &sc->bge_intrhand); #endif + } if (error) { bge_detach(dev); @@ -2770,6 +2783,17 @@ if (sc->bge_intrhand != NULL) bus_teardown_intr(dev, sc->bge_irq, sc->bge_intrhand); + if (sc->tq != NULL) { + /* XXX These block and drain calls are probably redundant now + * with bge_stop(). + */ + taskqueue_block(sc->tq); + taskqueue_drain(sc->tq, &sc->rxtx_task); + taskqueue_drain(sc->tq, &sc->link_task); + taskqueue_free(sc->tq); + sc->tq = NULL; + } + if (sc->bge_irq != NULL) bus_release_resource(dev, SYS_RES_IRQ, sc->bge_flags & BGE_FLAG_MSI ? 1 : 0, sc->bge_irq); @@ -3003,13 +3027,13 @@ bge_rxeof(struct bge_softc *sc) { struct ifnet *ifp; + struct bge_status_block *sts; + uint32_t crc, frame_crc; int stdcnt = 0, jumbocnt = 0; - BGE_LOCK_ASSERT(sc); - /* Nothing to do. */ - if (sc->bge_rx_saved_considx == - sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx) + sts = sc->bge_ldata.bge_status_block; + if (sc->bge_rx_saved_considx == sts->bge_idx[0].bge_rx_prod_idx) return; ifp = sc->bge_ifp; @@ -3022,8 +3046,7 @@ bus_dmamap_sync(sc->bge_cdata.bge_rx_jumbo_ring_tag, sc->bge_cdata.bge_rx_jumbo_ring_map, BUS_DMASYNC_POSTREAD); - while(sc->bge_rx_saved_considx != - sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx) { + while(sc->bge_rx_saved_considx != sts->bge_idx[0].bge_rx_prod_idx) { struct bge_rx_bd *cur_rx; uint32_t rxidx; struct mbuf *m = NULL; @@ -3060,13 +3083,21 @@ sc->bge_cdata.bge_rx_jumbo_chain[rxidx] = NULL; jumbocnt++; if (cur_rx->bge_flags & BGE_RXBDFLAG_ERROR) { - ifp->if_ierrors++; - bge_newbuf_jumbo(sc, sc->bge_jumbo, m); - continue; + atomic_add_long(&sc->bge_rxbdflag_errors, 1); + crc = crc32(m->m_data, + cur_rx->bge_len - ETHER_CRC_LEN); + bcopy(&m->m_data[cur_rx->bge_len - + ETHER_CRC_LEN], &frame_crc, ETHER_CRC_LEN); + if (crc != frame_crc) { + atomic_add_long(&ifp->if_ierrors, 1); + bge_newbuf_jumbo(sc, sc->bge_jumbo, m); + continue; + } } if (bge_newbuf_jumbo(sc, sc->bge_jumbo, NULL) == ENOBUFS) { - ifp->if_ierrors++; + atomic_add_long(&ifp->if_ierrors, 1); + atomic_add_long(&sc->bge_rxenobufs, 1); bge_newbuf_jumbo(sc, sc->bge_jumbo, m); continue; } @@ -3081,13 +3112,21 @@ sc->bge_cdata.bge_rx_std_chain[rxidx] = NULL; stdcnt++; if (cur_rx->bge_flags & BGE_RXBDFLAG_ERROR) { - ifp->if_ierrors++; - bge_newbuf_std(sc, sc->bge_std, m); - continue; + atomic_add_long(&sc->bge_rxbdflag_errors, 1); + crc = crc32(m->m_data, + cur_rx->bge_len - ETHER_CRC_LEN); + bcopy(&m->m_data[cur_rx->bge_len - + ETHER_CRC_LEN], &frame_crc, ETHER_CRC_LEN); + if (crc != frame_crc) { + atomic_add_long(&ifp->if_ierrors, 1); + bge_newbuf_std(sc, sc->bge_std, m); + continue; + } } if (bge_newbuf_std(sc, sc->bge_std, NULL) == ENOBUFS) { - ifp->if_ierrors++; + atomic_add_long(&ifp->if_ierrors, 1); + atomic_add_long(&sc->bge_rxenobufs, 1); bge_newbuf_std(sc, sc->bge_std, m); continue; } @@ -3138,9 +3177,7 @@ #endif } - BGE_UNLOCK(sc); (*ifp->if_input)(ifp, m); - BGE_LOCK(sc); } if (stdcnt > 0) @@ -3161,8 +3198,13 @@ * This register wraps very quickly under heavy packet drops. * If you need correct statistics, you can enable this check. */ - if (BGE_IS_5705_PLUS(sc)) - ifp->if_ierrors += CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_DROPS); + if (BGE_IS_5705_PLUS(sc)) { + int drops; + + drops = CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_DROPS); + atomic_add_long(&ifp->if_ierrors, drops); + atomic_add_long(&sc->bge_rxifacedrops, drops); + } #endif } @@ -3258,6 +3300,85 @@ #endif /* DEVICE_POLLING */ static void +bge_handle_link(void *context, int pending) +{ + struct bge_softc *sc = context; + + BGE_LOCK(sc); + bge_link_upd(sc); + BGE_UNLOCK(sc); + + /* + * Checking the queues is cheap and ensures that the interrupt is + * only reenabled in one spot, helping to avoid missed interrupts. + */ + taskqueue_enqueue(sc->tq, &sc->rxtx_task); +} + +static void +bge_handle_rxtx(void *context, int pending) +{ + struct bge_softc *sc = context; + struct ifnet *ifp; + + NET_LOCK_GIANT(); + ifp = sc->bge_ifp; + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + bge_rxeof(sc); + + BGE_LOCK(sc); + bge_txeof(sc); + + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + bge_start_locked(ifp); + BGE_UNLOCK(sc); + } + + CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0); + NET_UNLOCK_GIANT(); +} + +static void +bge_intr_fast(void *xsc) +{ + struct bge_softc *sc; + struct bge_status_block *sts; + uint32_t statusword; + int work = 0; + + sc = xsc; + sts = sc->bge_ldata.bge_status_block; + + CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 1); + statusword = CSR_READ_4(sc, BGE_MAC_STS) & BGE_MACSTAT_LINK_CHANGED; + + if ((sc->bge_asicrev == BGE_ASICREV_BCM5700 && + sc->bge_chipid != BGE_CHIPID_BCM5700_B2) || + statusword || sc->bge_link_evt) { + taskqueue_enqueue(sc->tq, &sc->link_task); + work = 1; + } + + /* Make sure the descriptor ring indexes are coherent. */ + bus_dmamap_sync(sc->bge_cdata.bge_status_tag, + sc->bge_cdata.bge_status_map, BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->bge_cdata.bge_status_tag, + sc->bge_cdata.bge_status_map, BUS_DMASYNC_PREREAD); + + if ((sc->bge_rx_saved_considx != sts->bge_idx[0].bge_rx_prod_idx) || + (sc->bge_tx_saved_considx != sts->bge_idx[0].bge_tx_cons_idx)) { + taskqueue_enqueue(sc->tq, &sc->rxtx_task); + work = 1; + } + + if (work == 0) + CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0); + + return; +} + +static void bge_intr(void *xsc) { struct bge_softc *sc; @@ -3317,7 +3438,9 @@ if (ifp->if_drv_flags & IFF_DRV_RUNNING) { /* Check RX return ring producer/consumer. */ + BGE_UNLOCK(sc); bge_rxeof(sc); + BGE_LOCK(sc); /* Check TX ring producer/consumer. */ bge_txeof(sc); @@ -3368,6 +3491,12 @@ bge_stats_update(sc); if ((sc->bge_flags & BGE_FLAG_TBI) == 0) { + if (sc->bge_link == 0 && + (CSR_READ_4(sc, BGE_MI_STS) & BGE_MISTS_LINK)) { + sc->bge_link_evt++; + sc->bge_missed_link++; + BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_INTR_SET); + } mii = device_get_softc(sc->bge_miibus); /* * Do not touch PHY if we have link up. This could break @@ -3402,13 +3531,16 @@ bge_stats_update_regs(struct bge_softc *sc) { struct ifnet *ifp; + int drops; ifp = sc->bge_ifp; ifp->if_collisions += CSR_READ_4(sc, BGE_MAC_STATS + offsetof(struct bge_mac_stats_regs, etherStatsCollisions)); - ifp->if_ierrors += CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_DROPS); + drops = CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_DROPS); + atomic_add_long(&ifp->if_ierrors, drops); + atomic_add_long(&sc->bge_rxifacedrops, drops); } static void @@ -3430,7 +3562,8 @@ sc->bge_tx_collisions = cnt; cnt = READ_STAT(sc, stats, ifInDiscards.bge_addr_lo); - ifp->if_ierrors += (uint32_t)(cnt - sc->bge_rx_discards); + atomic_add_long(&ifp->if_ierrors, + (uint32_t)(cnt - sc->bge_rx_discards)); sc->bge_rx_discards = cnt; cnt = READ_STAT(sc, stats, txstats.ifOutDiscards.bge_addr_lo); @@ -3821,6 +3954,7 @@ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; callout_reset(&sc->bge_stat_ch, hz, bge_tick, sc); + taskqueue_unblock(sc->tq); } static void @@ -3912,6 +4046,22 @@ } mii_mediachg(mii); + /* + * Force an interrupt so that we will call bge_link_upd + * if needed and clear any pending link state attention. + * Without this we are not getting any further interrupts + * for link state changes and thus will not UP the link and + * not be able to send in bge_start_locked. The only + * way to get things working was to receive a packet and + * get an RX intr. + * bge_tick should help for fiber cards and we might not + * need to do this here if BGE_FLAG_TBI is set but as + * we poll for fiber anyway it should not harm. + * This might be a problem with certain revisions only + * but I cannot say. + */ + BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_INTR_SET); + return (0); } @@ -3998,6 +4148,10 @@ } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { bge_stop(sc); + /* Reenable the tq so that link events can + * get processed. + */ + taskqueue_unblock(sc->tq); } } sc->bge_if_flags = ifp->if_flags; @@ -4032,6 +4186,9 @@ error = ether_poll_register(bge_poll, ifp); if (error) return (error); + taskqueue_block(sc->tq); + taskqueue_drain(sc->tq, &sc->rxtx_task); + taskqueue_drain(sc->tq, &sc->link_task); BGE_LOCK(sc); BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR); @@ -4046,6 +4203,7 @@ BGE_PCIMISCCTL_MASK_PCI_INTR); bge_writembx(sc, BGE_MBX_IRQ0_LO, 0); ifp->if_capenable &= ~IFCAP_POLLING; + taskqueue_unblock(sc->tq); BGE_UNLOCK(sc); } } @@ -4111,6 +4269,13 @@ callout_stop(&sc->bge_stat_ch); + taskqueue_block(sc->tq); + /* XXX Can this lock fumbling be handled better? */ + BGE_UNLOCK(sc); + taskqueue_drain(sc->tq, &sc->rxtx_task); + taskqueue_drain(sc->tq, &sc->link_task); + BGE_LOCK(sc); + /* * Disable all of the receiver blocks. */ @@ -4251,6 +4416,7 @@ sc = device_get_softc(dev); BGE_LOCK(sc); + taskqueue_unblock(sc->tq); ifp = sc->bge_ifp; if (ifp->if_flags & IFF_UP) { bge_init_locked(sc); @@ -4377,15 +4543,24 @@ BGE_MACSTAT_LINK_CHANGED); } +#define BGE_SYSCTL_STAT(sc, ctx, desc, parent, node, oid) \ + SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, oid, CTLTYPE_UINT|CTLFLAG_RD, \ + sc, offsetof(struct bge_stats, node), bge_sysctl_stats, "IU", \ + desc) + static void bge_add_sysctls(struct bge_softc *sc) { struct sysctl_ctx_list *ctx; - struct sysctl_oid_list *children; + struct sysctl_oid_list *children, *schildren; + struct sysctl_oid *tree; ctx = device_get_sysctl_ctx(sc->bge_dev); children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->bge_dev)); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, "missed_link", CTLFLAG_RD, + &sc->bge_missed_link, 0, "Missed Link Events"); + #ifdef BGE_REGISTER_DEBUG SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "debug_info", CTLTYPE_INT | CTLFLAG_RW, sc, 0, bge_sysctl_debug_info, "I", @@ -4399,16 +4574,153 @@ CTLTYPE_INT | CTLFLAG_RW, sc, 0, bge_sysctl_mem_read, "I", "Memory Read"); - SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, "stat_IfHcInOctets", - CTLFLAG_RD, - &sc->bge_ldata.bge_stats->rxstats.ifHCInOctets.bge_addr_lo, - "Bytes received"); +#endif + + tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, + NULL, "BGE Statistics"); + schildren = children = SYSCTL_CHILDREN(tree); + BGE_SYSCTL_STAT(sc, ctx, "Frames Dropped Due To Filters", + children, COSFramesDroppedDueToFilters, + "FramesDroppedDueToFilters"); + BGE_SYSCTL_STAT(sc, ctx, "NIC DMA Write Queue Full", + children, nicDmaWriteQueueFull, "DmaWriteQueueFull"); + BGE_SYSCTL_STAT(sc, ctx, "NIC DMA Write High Priority Queue Full", + children, nicDmaWriteHighPriQueueFull, "DmaWriteHighPriQueueFull"); + BGE_SYSCTL_STAT(sc, ctx, "NIC No More RX Buffer Descriptors", + children, nicNoMoreRxBDs, "NoMoreRxBDs"); + BGE_SYSCTL_STAT(sc, ctx, "Discarded Input Frames", + children, ifInDiscards, "InputDiscards"); + BGE_SYSCTL_STAT(sc, ctx, "Input Errors", + children, ifInErrors, "InputErrors"); + BGE_SYSCTL_STAT(sc, ctx, "NIC Recv Threshold Hit", + children, nicRecvThresholdHit, "RecvThresholdHit"); + BGE_SYSCTL_STAT(sc, ctx, "NIC DMA Read Queue Full", + children, nicDmaReadQueueFull, "DmaReadQueueFull"); + BGE_SYSCTL_STAT(sc, ctx, "NIC DMA Read High Priority Queue Full", + children, nicDmaReadHighPriQueueFull, "DmaReadHighPriQueueFull"); + BGE_SYSCTL_STAT(sc, ctx, "NIC Send Data Complete Queue Full", + children, nicSendDataCompQueueFull, "SendDataCompQueueFull"); + BGE_SYSCTL_STAT(sc, ctx, "NIC Ring Set Send Producer Index", + children, nicRingSetSendProdIndex, "RingSetSendProdIndex"); + BGE_SYSCTL_STAT(sc, ctx, "NIC Ring Status Update", + children, nicRingStatusUpdate, "RingStatusUpdate"); + BGE_SYSCTL_STAT(sc, ctx, "NIC Interrupts", + children, nicInterrupts, "Interrupts"); + BGE_SYSCTL_STAT(sc, ctx, "NIC Avoided Interrupts", + children, nicAvoidedInterrupts, "AvoidedInterrupts"); + BGE_SYSCTL_STAT(sc, ctx, "NIC Send Threshold Hit", + children, nicSendThresholdHit, "SendThresholdHit"); + + tree = SYSCTL_ADD_NODE(ctx, schildren, OID_AUTO, "rxerrors", + CTLFLAG_RD, NULL, "BGE RX stats"); + children = SYSCTL_CHILDREN(tree); + SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, "bdflag_errors", + CTLFLAG_RD, &sc->bge_rxbdflag_errors,"RX Buffer Descriptor errors"); + SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, "enobufs", + CTLFLAG_RD, &sc->bge_rxenobufs, "RX ENOBUFS"); + SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, "iface_drops", + CTLFLAG_RD, &sc->bge_rxifacedrops, "RX interface packet drops"); + SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, "discards", + CTLFLAG_RD, &sc->bge_rx_discards, "RX interface packet discards"); + + tree = SYSCTL_ADD_NODE(ctx, schildren, OID_AUTO, "rx", CTLFLAG_RD, + NULL, "BGE RX Statistics"); + children = SYSCTL_CHILDREN(tree); + BGE_SYSCTL_STAT(sc, ctx, "Inbound Octets", + children, rxstats.ifHCInOctets, "Octets"); + BGE_SYSCTL_STAT(sc, ctx, "Fragments", + children, rxstats.etherStatsFragments, "Fragments"); + BGE_SYSCTL_STAT(sc, ctx, "Inbound Unicast Packets", + children, rxstats.ifHCInUcastPkts, "UcastPkts"); + BGE_SYSCTL_STAT(sc, ctx, "Inbound Multicast Packets", + children, rxstats.ifHCInMulticastPkts, "MulticastPkts"); + BGE_SYSCTL_STAT(sc, ctx, "FCS Errors", + children, rxstats.dot3StatsFCSErrors, "FCSErrors"); + BGE_SYSCTL_STAT(sc, ctx, "Alignment Errors", + children, rxstats.dot3StatsAlignmentErrors, "AlignmentErrors"); + BGE_SYSCTL_STAT(sc, ctx, "XON Pause Frames Received", + children, rxstats.xonPauseFramesReceived, "xonPauseFramesReceived"); + BGE_SYSCTL_STAT(sc, ctx, "XOFF Pause Frames Received", + children, rxstats.xoffPauseFramesReceived, + "xoffPauseFramesReceived"); + BGE_SYSCTL_STAT(sc, ctx, "MAC Control Frames Received", + children, rxstats.macControlFramesReceived, + "ControlFramesReceived"); + BGE_SYSCTL_STAT(sc, ctx, "XOFF State Entered", + children, rxstats.xoffStateEntered, "xoffStateEntered"); + BGE_SYSCTL_STAT(sc, ctx, "Frames Too Long", + children, rxstats.dot3StatsFramesTooLong, "FramesTooLong"); + BGE_SYSCTL_STAT(sc, ctx, "Jabbers", + children, rxstats.etherStatsJabbers, "Jabbers"); + BGE_SYSCTL_STAT(sc, ctx, "Undersized Packets", + children, rxstats.etherStatsUndersizePkts, "UndersizePkts"); + BGE_SYSCTL_STAT(sc, ctx, "Inbound Range Length Errors", + children, rxstats.inRangeLengthError, "inRangeLengthError"); + BGE_SYSCTL_STAT(sc, ctx, "Outbound Range Length Errors", + children, rxstats.outRangeLengthError, "outRangeLengthError"); + + tree = SYSCTL_ADD_NODE(ctx, schildren, OID_AUTO, "tx", CTLFLAG_RD, + NULL, "BGE TX Statistics"); + children = SYSCTL_CHILDREN(tree); + BGE_SYSCTL_STAT(sc, ctx, "Outbound Octets", + children, txstats.ifHCOutOctets, "Octets"); + BGE_SYSCTL_STAT(sc, ctx, "TX Collisions", + children, txstats.etherStatsCollisions, "Collisions"); + BGE_SYSCTL_STAT(sc, ctx, "XON Sent", + children, txstats.outXonSent, "XonSent"); + BGE_SYSCTL_STAT(sc, ctx, "XOFF Sent", + children, txstats.outXoffSent, "XoffSent"); + BGE_SYSCTL_STAT(sc, ctx, "Flow Control Done", + children, txstats.flowControlDone, "flowControlDone"); + BGE_SYSCTL_STAT(sc, ctx, "Internal MAC TX errors", + children, txstats.dot3StatsInternalMacTransmitErrors, + "InternalMacTransmitErrors"); + BGE_SYSCTL_STAT(sc, ctx, "Single Collision Frames", + children, txstats.dot3StatsSingleCollisionFrames, + "SingleCollisionFrames"); + BGE_SYSCTL_STAT(sc, ctx, "Multiple Collision Frames", + children, txstats.dot3StatsMultipleCollisionFrames, + "MultipleCollisionFrames"); + BGE_SYSCTL_STAT(sc, ctx, "Deferred Transmissions", + children, txstats.dot3StatsDeferredTransmissions, + "DeferredTransmissions"); + BGE_SYSCTL_STAT(sc, ctx, "Excessive Collisions", + children, txstats.dot3StatsExcessiveCollisions, + "ExcessiveCollisions"); + BGE_SYSCTL_STAT(sc, ctx, "Late Collisions", + children, txstats.dot3StatsLateCollisions, + "LateCollisions"); + BGE_SYSCTL_STAT(sc, ctx, "Outbound Unicast Packets", + children, txstats.ifHCOutUcastPkts, "UcastPkts"); + BGE_SYSCTL_STAT(sc, ctx, "Outbound Multicast Packets", + children, txstats.ifHCOutMulticastPkts, "MulticastPkts"); + BGE_SYSCTL_STAT(sc, ctx, "Outbound Broadcast Packets", + children, txstats.ifHCOutBroadcastPkts, "BroadcastPkts"); + BGE_SYSCTL_STAT(sc, ctx, "Carrier Sense Errors", + children, txstats.dot3StatsCarrierSenseErrors, + "CarrierSenseErrors"); + BGE_SYSCTL_STAT(sc, ctx, "Outbound Discards", + children, txstats.ifOutDiscards, "Discards"); + BGE_SYSCTL_STAT(sc, ctx, "Outbound Errors", + children, txstats.ifOutErrors, "Errors"); +} + +static int +bge_sysctl_stats(SYSCTL_HANDLER_ARGS) +{ + struct bge_softc *sc; + uint32_t result; + int base, offset; - SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, "stat_IfHcOutOctets", - CTLFLAG_RD, - &sc->bge_ldata.bge_stats->txstats.ifHCOutOctets.bge_addr_lo, - "Bytes received"); -#endif + sc = (struct bge_softc *)arg1; + offset = arg2; + if (BGE_IS_5705_PLUS(sc)) + base = BGE_MAC_STATS; + else + base = BGE_MEMWIN_START + BGE_STATS_BLOCK; + result = CSR_READ_4(sc, base + offset + offsetof(bge_hostaddr, + bge_addr_lo)); + return (sysctl_handle_int(oidp, &result, sizeof(result), req)); } #ifdef BGE_REGISTER_DEBUG --- //depot/vendor/freebsd_6/src/sys/dev/bge/if_bgereg.h 2008/06/26 21:28:53 +++ //depot/yahoo/ybsd_6/src/sys/dev/bge/if_bgereg.h 2008/07/30 14:54:10 @@ -2007,10 +2008,11 @@ #define BGE_RXERRFLAG_COLL_DETECT 0x0002 #define BGE_RXERRFLAG_LINK_LOST 0x0004 #define BGE_RXERRFLAG_PHY_DECODE_ERR 0x0008 -#define BGE_RXERRFLAG_MAC_ABORT 0x0010 -#define BGE_RXERRFLAG_RUNT 0x0020 -#define BGE_RXERRFLAG_TRUNC_NO_RSRCS 0x0040 -#define BGE_RXERRFLAG_GIANT 0x0080 +#define BGE_RXERRFLAG_ODD_NIBBLE 0x0010 +#define BGE_RXERRFLAG_MAC_ABORT 0x0020 +#define BGE_RXERRFLAG_RUNT 0x0040 +#define BGE_RXERRFLAG_TRUNC_NO_RSRCS 0x0080 +#define BGE_RXERRFLAG_GIANT 0x0100 struct bge_sts_idx { #if BYTE_ORDER == LITTLE_ENDIAN @@ -2519,6 +2521,9 @@ struct ifnet *bge_ifp; /* interface info */ device_t bge_dev; struct mtx bge_mtx; + struct task link_task; + struct task rxtx_task; + struct taskqueue *tq; device_t bge_miibus; bus_space_handle_t bge_bhandle; bus_space_tag_t bge_btag; @@ -2572,9 +2577,13 @@ int bge_link_evt; /* pending link event */ int bge_timer; struct callout bge_stat_ch; - uint32_t bge_rx_discards; + u_long bge_rxbdflag_errors; + u_long bge_rxenobufs; + u_long bge_rxifacedrops; + u_long bge_rx_discards; uint32_t bge_tx_discards; uint32_t bge_tx_collisions; + int bge_missed_link; #ifdef DEVICE_POLLING int rxcycles; #endif /* DEVICE_POLLING */