From owner-svn-src-all@FreeBSD.ORG Fri Jan 6 19:27:51 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A2DE9106564A; Fri, 6 Jan 2012 19:27:51 +0000 (UTC) (envelope-from yongari@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 8A7BA8FC0A; Fri, 6 Jan 2012 19:27:51 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q06JRpQc004154; Fri, 6 Jan 2012 19:27:51 GMT (envelope-from yongari@svn.freebsd.org) Received: (from yongari@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q06JRpmY004150; Fri, 6 Jan 2012 19:27:51 GMT (envelope-from yongari@svn.freebsd.org) Message-Id: <201201061927.q06JRpmY004150@svn.freebsd.org> From: Pyun YongHyeon Date: Fri, 6 Jan 2012 19:27:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r229722 - stable/7/sys/dev/et X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 06 Jan 2012 19:27:51 -0000 Author: yongari Date: Fri Jan 6 19:27:51 2012 New Revision: 229722 URL: http://svn.freebsd.org/changeset/base/229722 Log: MFC r228326-228327,228331-228332: r228326: Controller does not require TX start command for every frame. So send a single TX command after setting up all TX frames. This removes unnecessary register accesses and bus_dmamap_sync(9) calls. et(4) uses TX interrupt moderation so it's possible to have TX buffers that were already transmitted but waiting for TX completion interrupt. If the number of available TX descriptor is less then 1/3 of total TX descriptor, try reclaiming first to get enough free TX descriptors before setting up TX descriptors. After r228325, et_txeof() no longer tries to send frames after reclaiming TX buffers. That change was made to give more chance to transmit frames in main interrupt handler since we can still send frames in interrupt handler with RX interrupt. So right before exiting interrupt hander, after enabling interrupt, try to send more frames. This gives slightly better performance numbers. While I'm here reduce number of spare TX descriptors from 8 to 4. Controller does not require reserved TX descriptors, it was just to reduce TX overhead. After r228325, driver has much lower TX overhead so it does not make sense to reserve 8 TX descriptors. r228327: Remove et_enable_intrs(), et_disable_intrs() functions and manipulation of interrupt register access is done through CSR_WRITE_4 macro. Also add disabling interrupt into et_reset() because we want interrupt disabled state after controller reset. While I'm here slightly change interrupt handler to be more readable one. r228331: Rework link state tracking and TX/RX MAC configuration. o Do not report link status if driver is not running. o TX/RX MAC configuration should be done with resolved speed, duplex and flow control after establishing a link so it can't be done in driver initialization routine. Move the configuration to miibus_statchg callback which will be called whenever any link state change is detected. At this moment, flow-control is not enabled yet mainly because I was not able to set correct flow control parameters to generate TX pause frames. o Now TX/RX MAC is enabled only when a valid link is detected. Rearragnge hardware initialization routine a bit to leave enabling MAC to miibus_statchg callback. In order to that, TX/RX DMA engine is enabled in et_init_locked(). o Introduce ET_FLAG_LINK flag to track current link state. o Introduce ET_FLAG_FASTETHER flag to mark whether controller is fast ethernet. This flag is checked in miibus_statchg callback to know whether PHY established a valid link. o In et_stop(), TX/RX MAC is explicitly disabled instead of relying on et_reset(). And move et_reset() from et_stop() to controller initialization. Controler reset is not required here and it would also clear critial registers(i.e station address, RX filter configuration, WOL etc) that are required to make WOL work. o Switching to current media is done in et_init_locked() after setting IFF_DRV_RUNNING flag. This should ensure reliable auto-negotiation/manual link establishment. o In et_start_locked(), check whether driver got a valid link before trying to send frames. o Remove checking a link in et_tick() as this is done by miibus_statchg callback. r228332: Implement hardware MAC statistics counter. Counters could be queried with dev.et.%d.stats sysctl node where %d is an instance of device. Modified: stable/7/sys/dev/et/if_et.c stable/7/sys/dev/et/if_etreg.h stable/7/sys/dev/et/if_etvar.h Directory Properties: stable/7/sys/ (props changed) stable/7/sys/cddl/contrib/opensolaris/ (props changed) stable/7/sys/contrib/dev/acpica/ (props changed) stable/7/sys/contrib/pf/ (props changed) Modified: stable/7/sys/dev/et/if_et.c ============================================================================== --- stable/7/sys/dev/et/if_et.c Fri Jan 6 19:26:31 2012 (r229721) +++ stable/7/sys/dev/et/if_et.c Fri Jan 6 19:27:51 2012 (r229722) @@ -110,8 +110,6 @@ static int et_sysctl_rx_intr_npkts(SYSCT static int et_sysctl_rx_intr_delay(SYSCTL_HANDLER_ARGS); static void et_intr(void *); -static void et_enable_intrs(struct et_softc *, uint32_t); -static void et_disable_intrs(struct et_softc *); static void et_rxeof(struct et_softc *); static void et_txeof(struct et_softc *); @@ -144,13 +142,12 @@ static int et_start_rxdma(struct et_soft static int et_start_txdma(struct et_softc *); static int et_stop_rxdma(struct et_softc *); static int et_stop_txdma(struct et_softc *); -static int et_enable_txrx(struct et_softc *, int); static void et_reset(struct et_softc *); static int et_bus_config(struct et_softc *); static void et_get_eaddr(device_t, uint8_t[]); static void et_setmulti(struct et_softc *); static void et_tick(void *); -static void et_setmedia(struct et_softc *); +static void et_stats_update(struct et_softc *); static const struct et_dev { uint16_t vid; @@ -302,6 +299,9 @@ et_attach(device_t dev) goto fail; } + if (pci_get_device(dev) == PCI_PRODUCT_LUCENT_ET1310_FAST) + sc->sc_flags |= ET_FLAG_FASTETHER; + error = et_bus_config(sc); if (error) goto fail; @@ -313,8 +313,6 @@ et_attach(device_t dev) et_reset(sc); - et_disable_intrs(sc); - error = et_dma_alloc(sc); if (error) goto fail; @@ -495,7 +493,89 @@ et_miibus_writereg(device_t dev, int phy static void et_miibus_statchg(device_t dev) { - et_setmedia(device_get_softc(dev)); + struct et_softc *sc; + struct mii_data *mii; + struct ifnet *ifp; + uint32_t cfg1, cfg2, ctrl; + int i; + + sc = device_get_softc(dev); + + mii = device_get_softc(sc->sc_miibus); + ifp = sc->ifp; + if (mii == NULL || ifp == NULL || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + + sc->sc_flags &= ~ET_FLAG_LINK; + if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == + (IFM_ACTIVE | IFM_AVALID)) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_10_T: + case IFM_100_TX: + sc->sc_flags |= ET_FLAG_LINK; + break; + case IFM_1000_T: + if ((sc->sc_flags & ET_FLAG_FASTETHER) == 0) + sc->sc_flags |= ET_FLAG_LINK; + break; + } + } + + /* XXX Stop TX/RX MAC? */ + if ((sc->sc_flags & ET_FLAG_LINK) == 0) + return; + + /* Program MACs with resolved speed/duplex/flow-control. */ + ctrl = CSR_READ_4(sc, ET_MAC_CTRL); + ctrl &= ~(ET_MAC_CTRL_GHDX | ET_MAC_CTRL_MODE_MII); + cfg1 = CSR_READ_4(sc, ET_MAC_CFG1); + cfg1 &= ~(ET_MAC_CFG1_TXFLOW | ET_MAC_CFG1_RXFLOW | + ET_MAC_CFG1_LOOPBACK); + cfg2 = CSR_READ_4(sc, ET_MAC_CFG2); + cfg2 &= ~(ET_MAC_CFG2_MODE_MII | ET_MAC_CFG2_MODE_GMII | + ET_MAC_CFG2_FDX | ET_MAC_CFG2_BIGFRM); + cfg2 |= ET_MAC_CFG2_LENCHK | ET_MAC_CFG2_CRC | ET_MAC_CFG2_PADCRC | + ((7 << ET_MAC_CFG2_PREAMBLE_LEN_SHIFT) & + ET_MAC_CFG2_PREAMBLE_LEN_MASK); + + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) + cfg2 |= ET_MAC_CFG2_MODE_GMII; + else { + cfg2 |= ET_MAC_CFG2_MODE_MII; + ctrl |= ET_MAC_CTRL_MODE_MII; + } + + if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { + cfg2 |= ET_MAC_CFG2_FDX; +#ifdef notyet + if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) + cfg1 |= ET_MAC_CFG1_TXFLOW; + if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) + cfg1 |= ET_MAC_CFG1_RXFLOW; +#endif + } else + ctrl |= ET_MAC_CTRL_GHDX; + + CSR_WRITE_4(sc, ET_MAC_CTRL, ctrl); + CSR_WRITE_4(sc, ET_MAC_CFG2, cfg2); + cfg1 |= ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN; + CSR_WRITE_4(sc, ET_MAC_CFG1, cfg1); + +#define NRETRY 50 + + for (i = 0; i < NRETRY; ++i) { + cfg1 = CSR_READ_4(sc, ET_MAC_CFG1); + if ((cfg1 & (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) == + (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) + break; + DELAY(100); + } + if (i == NRETRY) + if_printf(ifp, "can't enable RX/TX\n"); + sc->sc_flags |= ET_FLAG_TXRX_ENABLED; + +#undef NRETRY } static int @@ -526,10 +606,17 @@ et_ifmedia_upd(struct ifnet *ifp) static void et_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { - struct et_softc *sc = ifp->if_softc; - struct mii_data *mii = device_get_softc(sc->sc_miibus); + struct et_softc *sc; + struct mii_data *mii; + sc = ifp->if_softc; ET_LOCK(sc); + if ((ifp->if_flags & IFF_UP) == 0) { + ET_UNLOCK(sc); + return; + } + + mii = device_get_softc(sc->sc_miibus); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; @@ -544,17 +631,20 @@ et_stop(struct et_softc *sc) ET_LOCK_ASSERT(sc); callout_stop(&sc->sc_tick); + /* Disable interrupts. */ + CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); + + CSR_WRITE_4(sc, ET_MAC_CFG1, CSR_READ_4(sc, ET_MAC_CFG1) & ~( + ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN)); + DELAY(100); et_stop_rxdma(sc); et_stop_txdma(sc); - - et_disable_intrs(sc); + et_stats_update(sc); et_free_tx_ring(sc); et_free_rx_ring(sc); - et_reset(sc); - sc->sc_tx = 0; sc->sc_tx_intr = 0; sc->sc_flags &= ~ET_FLAG_TXRX_ENABLED; @@ -674,20 +764,10 @@ et_reset(struct et_softc *sc) ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC); CSR_WRITE_4(sc, ET_MAC_CFG1, 0); -} - -static void -et_disable_intrs(struct et_softc *sc) -{ + /* Disable interrupts. */ CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); } -static void -et_enable_intrs(struct et_softc *sc, uint32_t intrs) -{ - CSR_WRITE_4(sc, ET_INTR_MASK, ~intrs); -} - struct et_dmamap_arg { bus_addr_t et_busaddr; }; @@ -1087,12 +1167,12 @@ et_intr(void *xsc) return; } - et_disable_intrs(sc); + /* Disable further interrupts. */ + CSR_WRITE_4(sc, ET_INTR_MASK, 0xffffffff); intrs = CSR_READ_4(sc, ET_INTR_STATUS); - intrs &= ET_INTRS; - if (intrs == 0) /* Not interested */ - goto back; + if ((intrs & ET_INTRS) == 0) + goto done; if (intrs & ET_INTR_RXEOF) et_rxeof(sc); @@ -1100,8 +1180,12 @@ et_intr(void *xsc) et_txeof(sc); if (intrs & ET_INTR_TIMER) CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); -back: - et_enable_intrs(sc, ET_INTRS); +done: + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + CSR_WRITE_4(sc, ET_INTR_MASK, ~ET_INTRS); + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + et_start_locked(ifp); + } ET_UNLOCK(sc); } @@ -1118,6 +1202,7 @@ et_init_locked(struct et_softc *sc) return; et_stop(sc); + et_reset(sc); et_init_tx_ring(sc); error = et_init_rx_ring(sc); @@ -1126,21 +1211,33 @@ et_init_locked(struct et_softc *sc) error = et_chip_init(sc); if (error) - goto back; + goto fail; - error = et_enable_txrx(sc, 1); + /* + * Start TX/RX DMA engine + */ + error = et_start_rxdma(sc); if (error) - goto back; + return; - et_enable_intrs(sc, ET_INTRS); + error = et_start_txdma(sc); + if (error) + return; - callout_reset(&sc->sc_tick, hz, et_tick, sc); + /* Enable interrupts. */ + CSR_WRITE_4(sc, ET_INTR_MASK, ~ET_INTRS); CSR_WRITE_4(sc, ET_TIMER, sc->sc_timer); ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; -back: + + sc->sc_flags &= ~ET_FLAG_LINK; + et_ifmedia_upd_locked(ifp); + + callout_reset(&sc->sc_tick, hz, et_tick, sc); + +fail: if (error) et_stop(sc); } @@ -1244,19 +1341,32 @@ et_start_locked(struct ifnet *ifp) { struct et_softc *sc; struct mbuf *m_head = NULL; + struct et_txdesc_ring *tx_ring; struct et_txbuf_data *tbd; + uint32_t tx_ready_pos; int enq; sc = ifp->if_softc; ET_LOCK_ASSERT(sc); - if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) - return; - - if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING || + (sc->sc_flags & (ET_FLAG_LINK | ET_FLAG_TXRX_ENABLED)) != + (ET_FLAG_LINK | ET_FLAG_TXRX_ENABLED)) return; + /* + * Driver does not request TX completion interrupt for every + * queued frames to prevent generating excessive interrupts. + * This means driver may wait for TX completion interrupt even + * though some frames were sucessfully transmitted. Reclaiming + * transmitted frames will ensure driver see all available + * descriptors. + */ tbd = &sc->sc_tx_data; + if (tbd->tbd_used > (ET_TX_NDESC * 2) / 3) + et_txeof(sc); + for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) { if (tbd->tbd_used + ET_NSEG_SPARE >= ET_TX_NDESC) { ifp->if_drv_flags |= IFF_DRV_OACTIVE; @@ -1281,8 +1391,17 @@ et_start_locked(struct ifnet *ifp) ETHER_BPF_MTAP(ifp, m_head); } - if (enq > 0) + if (enq > 0) { + tx_ring = &sc->sc_tx_ring; + bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, + BUS_DMASYNC_PREWRITE); + tx_ready_pos = tx_ring->tr_ready_index & + ET_TX_READY_POS_INDEX_MASK; + if (tx_ring->tr_ready_wrap) + tx_ready_pos |= ET_TX_READY_POS_WRAP; + CSR_WRITE_4(sc, ET_TX_READY_POS, tx_ready_pos); sc->watchdog_timer = 5; + } } static void @@ -1861,56 +1980,6 @@ et_start_txdma(struct et_softc *sc) return (0); } -static int -et_enable_txrx(struct et_softc *sc, int media_upd) -{ - struct ifnet *ifp = sc->ifp; - uint32_t val; - int i, error; - - val = CSR_READ_4(sc, ET_MAC_CFG1); - val |= ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN; - val &= ~(ET_MAC_CFG1_TXFLOW | ET_MAC_CFG1_RXFLOW | - ET_MAC_CFG1_LOOPBACK); - CSR_WRITE_4(sc, ET_MAC_CFG1, val); - - if (media_upd) - et_ifmedia_upd_locked(ifp); - else - et_setmedia(sc); - -#define NRETRY 50 - - for (i = 0; i < NRETRY; ++i) { - val = CSR_READ_4(sc, ET_MAC_CFG1); - if ((val & (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) == - (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) - break; - - DELAY(100); - } - if (i == NRETRY) { - if_printf(ifp, "can't enable RX/TX\n"); - return (0); - } - sc->sc_flags |= ET_FLAG_TXRX_ENABLED; - -#undef NRETRY - - /* - * Start TX/RX DMA engine - */ - error = et_start_rxdma(sc); - if (error) - return (error); - - error = et_start_txdma(sc); - if (error) - return (error); - - return (0); -} - static void et_rxeof(struct et_softc *sc) { @@ -1986,7 +2055,6 @@ et_rxeof(struct et_softc *sc) m = rbd->rbd_buf[buf_idx].rb_mbuf; if ((rxst_info1 & ET_RXST_INFO1_OK) == 0){ /* Discard errored frame. */ - ifp->if_ierrors++; rbd->rbd_discard(rbd, buf_idx); } else if (rbd->rbd_newbuf(rbd, buf_idx) != 0) { /* No available mbufs, discard it. */ @@ -2000,7 +2068,6 @@ et_rxeof(struct et_softc *sc) } else { m->m_pkthdr.len = m->m_len = buflen; m->m_pkthdr.rcvif = ifp; - ifp->if_ipackets++; ET_UNLOCK(sc); ifp->if_input(ifp, m); ET_LOCK(sc); @@ -2040,7 +2107,7 @@ et_encap(struct et_softc *sc, struct mbu struct mbuf *m; bus_dma_segment_t segs[ET_NSEG_MAX]; bus_dmamap_t map; - uint32_t csum_flags, last_td_ctrl2, tx_ready_pos; + uint32_t csum_flags, last_td_ctrl2; int error, i, idx, first_idx, last_idx, nsegs; tx_ring = &sc->sc_tx_ring; @@ -2125,12 +2192,6 @@ et_encap(struct et_softc *sc, struct mbu tbd->tbd_used += nsegs; MPASS(tbd->tbd_used <= ET_TX_NDESC); - bus_dmamap_sync(tx_ring->tr_dtag, tx_ring->tr_dmap, - BUS_DMASYNC_PREWRITE); - tx_ready_pos = tx_ring->tr_ready_index & ET_TX_READY_POS_INDEX_MASK; - if (tx_ring->tr_ready_wrap) - tx_ready_pos |= ET_TX_READY_POS_WRAP; - CSR_WRITE_4(sc, ET_TX_READY_POS, tx_ready_pos); return (0); } @@ -2172,7 +2233,6 @@ et_txeof(struct et_softc *sc) bus_dmamap_unload(sc->sc_tx_tag, tb->tb_dmap); m_freem(tb->tb_mbuf); tb->tb_mbuf = NULL; - ifp->if_opackets++; } if (++tbd->tbd_start_index == ET_TX_NDESC) { @@ -2189,6 +2249,7 @@ et_txeof(struct et_softc *sc) if (tbd->tbd_used + ET_NSEG_SPARE < ET_TX_NDESC) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } + static void et_tick(void *xsc) { @@ -2201,13 +2262,7 @@ et_tick(void *xsc) mii = device_get_softc(sc->sc_miibus); mii_tick(mii); - if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0 && - (mii->mii_media_status & IFM_ACTIVE) && - IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { - if_printf(ifp, "Link up, enable TX/RX\n"); - if (et_enable_txrx(sc, 0) == 0) - et_start_locked(ifp); - } + et_stats_update(sc); if (et_watchdog(sc) == EJUSTRETURN) return; callout_reset(&sc->sc_tick, hz, et_tick, sc); @@ -2320,6 +2375,11 @@ et_newbuf_hdr(struct et_rxbuf_data *rbd, return (0); } +#define ET_SYSCTL_STAT_ADD32(c, h, n, p, d) \ + SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) +#define ET_SYSCTL_STAT_ADD64(c, h, n, p, d) \ + SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) + /* * Create sysctl tree */ @@ -2327,7 +2387,9 @@ static void et_add_sysctls(struct et_softc * sc) { struct sysctl_ctx_list *ctx; - struct sysctl_oid_list *children; + struct sysctl_oid_list *children, *parent; + struct sysctl_oid *tree; + struct et_hw_stats *stats; ctx = device_get_sysctl_ctx(sc->dev); children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); @@ -2343,8 +2405,116 @@ et_add_sysctls(struct et_softc * sc) "TX IM, # segments per TX interrupt"); SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "timer", CTLFLAG_RW, &sc->sc_timer, 0, "TX timer"); + + tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, + NULL, "ET statistics"); + parent = SYSCTL_CHILDREN(tree); + + /* TX/RX statistics. */ + stats = &sc->sc_stats; + ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_64", &stats->pkts_64, + "0 to 64 bytes frames"); + ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_65_127", &stats->pkts_65, + "65 to 127 bytes frames"); + ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_128_255", &stats->pkts_128, + "128 to 255 bytes frames"); + ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_256_511", &stats->pkts_256, + "256 to 511 bytes frames"); + ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_512_1023", &stats->pkts_512, + "512 to 1023 bytes frames"); + ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_1024_1518", &stats->pkts_1024, + "1024 to 1518 bytes frames"); + ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_1519_1522", &stats->pkts_1519, + "1519 to 1522 bytes frames"); + + /* RX statistics. */ + tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, + NULL, "RX MAC statistics"); + children = SYSCTL_CHILDREN(tree); + ET_SYSCTL_STAT_ADD64(ctx, children, "bytes", + &stats->rx_bytes, "Good bytes"); + ET_SYSCTL_STAT_ADD64(ctx, children, "frames", + &stats->rx_frames, "Good frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "crc_errs", + &stats->rx_crcerrs, "CRC errors"); + ET_SYSCTL_STAT_ADD64(ctx, children, "mcast_frames", + &stats->rx_mcast, "Multicast frames"); + ET_SYSCTL_STAT_ADD64(ctx, children, "bcast_frames", + &stats->rx_bcast, "Broadcast frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "control", + &stats->rx_control, "Control frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "pause", + &stats->rx_pause, "Pause frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "unknown_control", + &stats->rx_unknown_control, "Unknown control frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "align_errs", + &stats->rx_alignerrs, "Alignment errors"); + ET_SYSCTL_STAT_ADD32(ctx, children, "len_errs", + &stats->rx_lenerrs, "Frames with length mismatched"); + ET_SYSCTL_STAT_ADD32(ctx, children, "code_errs", + &stats->rx_codeerrs, "Frames with code error"); + ET_SYSCTL_STAT_ADD32(ctx, children, "cs_errs", + &stats->rx_cserrs, "Frames with carrier sense error"); + ET_SYSCTL_STAT_ADD32(ctx, children, "runts", + &stats->rx_runts, "Too short frames"); + ET_SYSCTL_STAT_ADD64(ctx, children, "oversize", + &stats->rx_oversize, "Oversized frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "fragments", + &stats->rx_fragments, "Fragmented frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "jabbers", + &stats->rx_jabbers, "Frames with jabber error"); + ET_SYSCTL_STAT_ADD32(ctx, children, "drop", + &stats->rx_drop, "Dropped frames"); + + /* TX statistics. */ + tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, + NULL, "TX MAC statistics"); + children = SYSCTL_CHILDREN(tree); + ET_SYSCTL_STAT_ADD64(ctx, children, "bytes", + &stats->tx_bytes, "Good bytes"); + ET_SYSCTL_STAT_ADD64(ctx, children, "frames", + &stats->tx_frames, "Good frames"); + ET_SYSCTL_STAT_ADD64(ctx, children, "mcast_frames", + &stats->tx_mcast, "Multicast frames"); + ET_SYSCTL_STAT_ADD64(ctx, children, "bcast_frames", + &stats->tx_bcast, "Broadcast frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "pause", + &stats->tx_pause, "Pause frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "deferred", + &stats->tx_deferred, "Deferred frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "excess_deferred", + &stats->tx_excess_deferred, "Excessively deferred frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "single_colls", + &stats->tx_single_colls, "Single collisions"); + ET_SYSCTL_STAT_ADD32(ctx, children, "multi_colls", + &stats->tx_multi_colls, "Multiple collisions"); + ET_SYSCTL_STAT_ADD32(ctx, children, "late_colls", + &stats->tx_late_colls, "Late collisions"); + ET_SYSCTL_STAT_ADD32(ctx, children, "excess_colls", + &stats->tx_excess_colls, "Excess collisions"); + ET_SYSCTL_STAT_ADD32(ctx, children, "total_colls", + &stats->tx_total_colls, "Total collisions"); + ET_SYSCTL_STAT_ADD32(ctx, children, "pause_honored", + &stats->tx_pause_honored, "Honored pause frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "drop", + &stats->tx_drop, "Dropped frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "jabbers", + &stats->tx_jabbers, "Frames with jabber errors"); + ET_SYSCTL_STAT_ADD32(ctx, children, "crc_errs", + &stats->tx_crcerrs, "Frames with CRC errors"); + ET_SYSCTL_STAT_ADD32(ctx, children, "control", + &stats->tx_control, "Control frames"); + ET_SYSCTL_STAT_ADD64(ctx, children, "oversize", + &stats->tx_oversize, "Oversized frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "undersize", + &stats->tx_undersize, "Undersized frames"); + ET_SYSCTL_STAT_ADD32(ctx, children, "fragments", + &stats->tx_fragments, "Fragmented frames"); } +#undef ET_SYSCTL_STAT_ADD32 +#undef ET_SYSCTL_STAT_ADD64 + static int et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS) { @@ -2396,35 +2566,70 @@ back: } static void -et_setmedia(struct et_softc *sc) +et_stats_update(struct et_softc *sc) { - struct mii_data *mii = device_get_softc(sc->sc_miibus); - uint32_t cfg2, ctrl; - - cfg2 = CSR_READ_4(sc, ET_MAC_CFG2); - cfg2 &= ~(ET_MAC_CFG2_MODE_MII | ET_MAC_CFG2_MODE_GMII | - ET_MAC_CFG2_FDX | ET_MAC_CFG2_BIGFRM); - cfg2 |= ET_MAC_CFG2_LENCHK | ET_MAC_CFG2_CRC | ET_MAC_CFG2_PADCRC | - ((7 << ET_MAC_CFG2_PREAMBLE_LEN_SHIFT) & - ET_MAC_CFG2_PREAMBLE_LEN_MASK); - - ctrl = CSR_READ_4(sc, ET_MAC_CTRL); - ctrl &= ~(ET_MAC_CTRL_GHDX | ET_MAC_CTRL_MODE_MII); - - if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { - cfg2 |= ET_MAC_CFG2_MODE_GMII; - } else { - cfg2 |= ET_MAC_CFG2_MODE_MII; - ctrl |= ET_MAC_CTRL_MODE_MII; - } + struct ifnet *ifp; + struct et_hw_stats *stats; - if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) - cfg2 |= ET_MAC_CFG2_FDX; - else - ctrl |= ET_MAC_CTRL_GHDX; + stats = &sc->sc_stats; + stats->pkts_64 += CSR_READ_4(sc, ET_STAT_PKTS_64); + stats->pkts_65 += CSR_READ_4(sc, ET_STAT_PKTS_65_127); + stats->pkts_128 += CSR_READ_4(sc, ET_STAT_PKTS_128_255); + stats->pkts_256 += CSR_READ_4(sc, ET_STAT_PKTS_256_511); + stats->pkts_512 += CSR_READ_4(sc, ET_STAT_PKTS_512_1023); + stats->pkts_1024 += CSR_READ_4(sc, ET_STAT_PKTS_1024_1518); + stats->pkts_1519 += CSR_READ_4(sc, ET_STAT_PKTS_1519_1522); + + stats->rx_bytes += CSR_READ_4(sc, ET_STAT_RX_BYTES); + stats->rx_frames += CSR_READ_4(sc, ET_STAT_RX_FRAMES); + stats->rx_crcerrs += CSR_READ_4(sc, ET_STAT_RX_CRC_ERR); + stats->rx_mcast += CSR_READ_4(sc, ET_STAT_RX_MCAST); + stats->rx_bcast += CSR_READ_4(sc, ET_STAT_RX_BCAST); + stats->rx_control += CSR_READ_4(sc, ET_STAT_RX_CTL); + stats->rx_pause += CSR_READ_4(sc, ET_STAT_RX_PAUSE); + stats->rx_unknown_control += CSR_READ_4(sc, ET_STAT_RX_UNKNOWN_CTL); + stats->rx_alignerrs += CSR_READ_4(sc, ET_STAT_RX_ALIGN_ERR); + stats->rx_lenerrs += CSR_READ_4(sc, ET_STAT_RX_LEN_ERR); + stats->rx_codeerrs += CSR_READ_4(sc, ET_STAT_RX_CODE_ERR); + stats->rx_cserrs += CSR_READ_4(sc, ET_STAT_RX_CS_ERR); + stats->rx_runts += CSR_READ_4(sc, ET_STAT_RX_RUNT); + stats->rx_oversize += CSR_READ_4(sc, ET_STAT_RX_OVERSIZE); + stats->rx_fragments += CSR_READ_4(sc, ET_STAT_RX_FRAG); + stats->rx_jabbers += CSR_READ_4(sc, ET_STAT_RX_JABBER); + stats->rx_drop += CSR_READ_4(sc, ET_STAT_RX_DROP); + + stats->tx_bytes += CSR_READ_4(sc, ET_STAT_TX_BYTES); + stats->tx_frames += CSR_READ_4(sc, ET_STAT_TX_FRAMES); + stats->tx_mcast += CSR_READ_4(sc, ET_STAT_TX_MCAST); + stats->tx_bcast += CSR_READ_4(sc, ET_STAT_TX_BCAST); + stats->tx_pause += CSR_READ_4(sc, ET_STAT_TX_PAUSE); + stats->tx_deferred += CSR_READ_4(sc, ET_STAT_TX_DEFER); + stats->tx_excess_deferred += CSR_READ_4(sc, ET_STAT_TX_EXCESS_DEFER); + stats->tx_single_colls += CSR_READ_4(sc, ET_STAT_TX_SINGLE_COL); + stats->tx_multi_colls += CSR_READ_4(sc, ET_STAT_TX_MULTI_COL); + stats->tx_late_colls += CSR_READ_4(sc, ET_STAT_TX_LATE_COL); + stats->tx_excess_colls += CSR_READ_4(sc, ET_STAT_TX_EXCESS_COL); + stats->tx_total_colls += CSR_READ_4(sc, ET_STAT_TX_TOTAL_COL); + stats->tx_pause_honored += CSR_READ_4(sc, ET_STAT_TX_PAUSE_HONOR); + stats->tx_drop += CSR_READ_4(sc, ET_STAT_TX_DROP); + stats->tx_jabbers += CSR_READ_4(sc, ET_STAT_TX_JABBER); + stats->tx_crcerrs += CSR_READ_4(sc, ET_STAT_TX_CRC_ERR); + stats->tx_control += CSR_READ_4(sc, ET_STAT_TX_CTL); + stats->tx_oversize += CSR_READ_4(sc, ET_STAT_TX_OVERSIZE); + stats->tx_undersize += CSR_READ_4(sc, ET_STAT_TX_UNDERSIZE); + stats->tx_fragments += CSR_READ_4(sc, ET_STAT_TX_FRAG); - CSR_WRITE_4(sc, ET_MAC_CTRL, ctrl); - CSR_WRITE_4(sc, ET_MAC_CFG2, cfg2); + /* Update ifnet counters. */ + ifp = sc->ifp; + ifp->if_opackets = (u_long)stats->tx_frames; + ifp->if_collisions = stats->tx_total_colls; + ifp->if_oerrors = stats->tx_drop + stats->tx_jabbers + + stats->tx_crcerrs + stats->tx_excess_deferred + + stats->tx_late_colls; + ifp->if_ipackets = (u_long)stats->rx_frames; + ifp->if_ierrors = stats->rx_crcerrs + stats->rx_alignerrs + + stats->rx_lenerrs + stats->rx_codeerrs + stats->rx_cserrs + + stats->rx_runts + stats->rx_jabbers + stats->rx_drop; } static int Modified: stable/7/sys/dev/et/if_etreg.h ============================================================================== --- stable/7/sys/dev/et/if_etreg.h Fri Jan 6 19:26:31 2012 (r229721) +++ stable/7/sys/dev/et/if_etreg.h Fri Jan 6 19:27:51 2012 (r229722) @@ -318,6 +318,52 @@ #define ET_MAC_ADDR1 0x5040 #define ET_MAC_ADDR2 0x5044 +/* MAC statistics counters. */ +#define ET_STAT_PKTS_64 0x6080 +#define ET_STAT_PKTS_65_127 0x6084 +#define ET_STAT_PKTS_128_255 0x6088 +#define ET_STAT_PKTS_256_511 0x608C +#define ET_STAT_PKTS_512_1023 0x6090 +#define ET_STAT_PKTS_1024_1518 0x6094 +#define ET_STAT_PKTS_1519_1522 0x6098 +#define ET_STAT_RX_BYTES 0x609C +#define ET_STAT_RX_FRAMES 0x60A0 +#define ET_STAT_RX_CRC_ERR 0x60A4 +#define ET_STAT_RX_MCAST 0x60A8 +#define ET_STAT_RX_BCAST 0x60AC +#define ET_STAT_RX_CTL 0x60B0 +#define ET_STAT_RX_PAUSE 0x60B4 +#define ET_STAT_RX_UNKNOWN_CTL 0x60B8 +#define ET_STAT_RX_ALIGN_ERR 0x60BC +#define ET_STAT_RX_LEN_ERR 0x60C0 +#define ET_STAT_RX_CODE_ERR 0x60C4 +#define ET_STAT_RX_CS_ERR 0x60C8 +#define ET_STAT_RX_RUNT 0x60CC +#define ET_STAT_RX_OVERSIZE 0x60D0 +#define ET_STAT_RX_FRAG 0x60D4 +#define ET_STAT_RX_JABBER 0x60D8 +#define ET_STAT_RX_DROP 0x60DC +#define ET_STAT_TX_BYTES 0x60E0 +#define ET_STAT_TX_FRAMES 0x60E4 +#define ET_STAT_TX_MCAST 0x60E8 +#define ET_STAT_TX_BCAST 0x60EC +#define ET_STAT_TX_PAUSE 0x60F0 +#define ET_STAT_TX_DEFER 0x60F4 +#define ET_STAT_TX_EXCESS_DEFER 0x60F8 +#define ET_STAT_TX_SINGLE_COL 0x60FC +#define ET_STAT_TX_MULTI_COL 0x6100 +#define ET_STAT_TX_LATE_COL 0x6104 +#define ET_STAT_TX_EXCESS_COL 0x6108 +#define ET_STAT_TX_TOTAL_COL 0x610C +#define ET_STAT_TX_PAUSE_HONOR 0x6110 +#define ET_STAT_TX_DROP 0x6114 +#define ET_STAT_TX_JABBER 0x6118 +#define ET_STAT_TX_CRC_ERR 0x611C +#define ET_STAT_TX_CTL 0x6120 +#define ET_STAT_TX_OVERSIZE 0x6124 +#define ET_STAT_TX_UNDERSIZE 0x6128 +#define ET_STAT_TX_FRAG 0x612C + #define ET_MMC_CTRL 0x7000 #define ET_MMC_CTRL_ENABLE 0x00000001 #define ET_MMC_CTRL_ARB_DISABLE 0x00000002 Modified: stable/7/sys/dev/et/if_etvar.h ============================================================================== --- stable/7/sys/dev/et/if_etvar.h Fri Jan 6 19:26:31 2012 (r229721) +++ stable/7/sys/dev/et/if_etvar.h Fri Jan 6 19:27:51 2012 (r229722) @@ -41,7 +41,7 @@ #define ET_RING_ALIGN 4096 #define ET_STATUS_ALIGN 8 #define ET_NSEG_MAX 32 /* XXX no limit actually */ -#define ET_NSEG_SPARE 8 +#define ET_NSEG_SPARE 4 #define ET_TX_NDESC 512 #define ET_RX_NDESC 512 @@ -231,6 +231,56 @@ struct et_rxbuf_data { void (*rbd_discard)(struct et_rxbuf_data *, int); }; +struct et_hw_stats { + /* RX/TX stats. */ + uint64_t pkts_64; + uint64_t pkts_65; + uint64_t pkts_128; + uint64_t pkts_256; + uint64_t pkts_512; + uint64_t pkts_1024; + uint64_t pkts_1519; + /* RX stats. */ + uint64_t rx_bytes; + uint64_t rx_frames; + uint32_t rx_crcerrs; + uint64_t rx_mcast; + uint64_t rx_bcast; + uint32_t rx_control; + uint32_t rx_pause; + uint32_t rx_unknown_control; + uint32_t rx_alignerrs; + uint32_t rx_lenerrs; + uint32_t rx_codeerrs; + uint32_t rx_cserrs; + uint32_t rx_runts; + uint64_t rx_oversize; + uint32_t rx_fragments; + uint32_t rx_jabbers; + uint32_t rx_drop; + /* TX stats. */ + uint64_t tx_bytes; + uint64_t tx_frames; + uint64_t tx_mcast; + uint64_t tx_bcast; + uint32_t tx_pause; + uint32_t tx_deferred; + uint32_t tx_excess_deferred; + uint32_t tx_single_colls; + uint32_t tx_multi_colls; + uint32_t tx_late_colls; + uint32_t tx_excess_colls; + uint32_t tx_total_colls; + uint32_t tx_pause_honored; + uint32_t tx_drop; + uint32_t tx_jabbers; + uint32_t tx_crcerrs; + uint32_t tx_control; + uint64_t tx_oversize; + uint32_t tx_undersize; + uint32_t tx_fragments; +}; + struct et_softc { struct ifnet *ifp; device_t dev; @@ -271,6 +321,7 @@ struct et_softc { struct et_rxbuf_data sc_rx_data[ET_RX_NRING]; struct et_txbuf_data sc_tx_data; + struct et_hw_stats sc_stats; uint32_t sc_tx; uint32_t sc_tx_intr; @@ -289,7 +340,9 @@ struct et_softc { #define ET_FLAG_PCIE 0x0001 #define ET_FLAG_MSI 0x0002 +#define ET_FLAG_FASTETHER 0x0004 #define ET_FLAG_TXRX_ENABLED 0x0100 #define ET_FLAG_JUMBO 0x0200 +#define ET_FLAG_LINK 0x8000 #endif /* !_IF_ETVAR_H */