Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 6 Jan 2012 19:26:31 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r229721 - stable/8/sys/dev/et
Message-ID:  <201201061926.q06JQVsU004066@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Fri Jan  6 19:26:31 2012
New Revision: 229721
URL: http://svn.freebsd.org/changeset/base/229721

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/8/sys/dev/et/if_et.c
  stable/8/sys/dev/et/if_etreg.h
  stable/8/sys/dev/et/if_etvar.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/dev/et/if_et.c
==============================================================================
--- stable/8/sys/dev/et/if_et.c	Fri Jan  6 19:24:33 2012	(r229720)
+++ stable/8/sys/dev/et/if_et.c	Fri Jan  6 19:26:31 2012	(r229721)
@@ -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/8/sys/dev/et/if_etreg.h
==============================================================================
--- stable/8/sys/dev/et/if_etreg.h	Fri Jan  6 19:24:33 2012	(r229720)
+++ stable/8/sys/dev/et/if_etreg.h	Fri Jan  6 19:26:31 2012	(r229721)
@@ -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/8/sys/dev/et/if_etvar.h
==============================================================================
--- stable/8/sys/dev/et/if_etvar.h	Fri Jan  6 19:24:33 2012	(r229720)
+++ stable/8/sys/dev/et/if_etvar.h	Fri Jan  6 19:26:31 2012	(r229721)
@@ -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 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201061926.q06JQVsU004066>