svn commit: r214844 - in head/sys: dev/re pci

Pyun YongHyeon yongari at FreeBSD.org
Fri Nov 5 19:28:01 UTC 2010


Author: yongari
Date: Fri Nov  5 19:28:00 2010
New Revision: 214844
URL: http://svn.freebsd.org/changeset/base/214844

Log:
  Add simple MAC statistics counter reading support. Unfortunately
  useful counters like rl_missed_pkts is 16 bits quantity which is
  too small to hold meaningful information happened in a second. This
  means driver should frequently read these counters in order not to
  lose accuracy and that approach is too inefficient in driver's
  view. Moreover it seems there is no way to trigger an interrupt to
  detect counter near-full or wraparound event as well as lacking
  clearing the MAC counters. Another limitation of reading the
  counters from RealTek controllers is lack of interrupt firing at
  the end of DMA cycle of MAC counter read request such that driver
  have to poll the end of the DMA which is a time consuming process
  as well as inefficient. The more severe issue of the MAC counter
  read request is it takes too long to complete the DMA. All these
  limitation made maintaining MAC counters in driver impractical. For
  now, just provide simple sysctl interface to trigger reading the
  MAC counters. These counters could be used to track down driver
  issues. Users can read MAC counters maintained in controller with
  the following command.
  #sysctl dev.re.0.stats=1
  
  While I'm here add check for validity of dma map and allocated
  memory before unloading/freeing them.
  
  Tested by:	rmacklem

Modified:
  head/sys/dev/re/if_re.c
  head/sys/pci/if_rlreg.h

Modified: head/sys/dev/re/if_re.c
==============================================================================
--- head/sys/dev/re/if_re.c	Fri Nov  5 19:12:48 2010	(r214843)
+++ head/sys/dev/re/if_re.c	Fri Nov  5 19:28:00 2010	(r214844)
@@ -123,6 +123,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/socket.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
+#include <sys/sysctl.h>
 #include <sys/taskqueue.h>
 
 #include <net/if.h>
@@ -281,6 +282,9 @@ static void re_clrwol		(struct rl_softc 
 static int re_diag		(struct rl_softc *);
 #endif
 
+static void re_add_sysctls	(struct rl_softc *);
+static int re_sysctl_stats	(SYSCTL_HANDLER_ARGS);
+
 static device_method_t re_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		re_probe),
@@ -1084,6 +1088,35 @@ re_allocmem(device_t dev, struct rl_soft
 		}
 	}
 
+	/* Create DMA map for statistics. */
+	error = bus_dma_tag_create(sc->rl_parent_tag, RL_DUMP_ALIGN, 0,
+	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+	    sizeof(struct rl_stats), 1, sizeof(struct rl_stats), 0, NULL, NULL,
+	    &sc->rl_ldata.rl_stag);
+	if (error) {
+		device_printf(dev, "could not create statistics DMA tag\n");
+		return (error);
+	}
+	/* Allocate DMA'able memory for statistics. */
+	error = bus_dmamem_alloc(sc->rl_ldata.rl_stag,
+	    (void **)&sc->rl_ldata.rl_stats,
+	    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
+	    &sc->rl_ldata.rl_smap);
+	if (error) {
+		device_printf(dev,
+		    "could not allocate statistics DMA memory\n");
+		return (error);
+	}
+	/* Load the map for statistics. */
+	sc->rl_ldata.rl_stats_addr = 0;
+	error = bus_dmamap_load(sc->rl_ldata.rl_stag, sc->rl_ldata.rl_smap,
+	    sc->rl_ldata.rl_stats, sizeof(struct rl_stats), re_dma_map_addr,
+	     &sc->rl_ldata.rl_stats_addr, BUS_DMA_NOWAIT);
+	if (error != 0 || sc->rl_ldata.rl_stats_addr == 0) {
+		device_printf(dev, "could not load statistics DMA memory\n");
+		return (ENOMEM);
+	}
+
 	return (0);
 }
 
@@ -1374,6 +1407,7 @@ re_attach(device_t dev)
 	error = re_allocmem(dev, sc);
 	if (error)
 		goto fail;
+	re_add_sysctls(sc);
 
 	ifp = sc->rl_ifp = if_alloc(IFT_ETHER);
 	if (ifp == NULL) {
@@ -1603,22 +1637,26 @@ re_detach(device_t dev)
 	/* Unload and free the RX DMA ring memory and map */
 
 	if (sc->rl_ldata.rl_rx_list_tag) {
-		bus_dmamap_unload(sc->rl_ldata.rl_rx_list_tag,
-		    sc->rl_ldata.rl_rx_list_map);
-		bus_dmamem_free(sc->rl_ldata.rl_rx_list_tag,
-		    sc->rl_ldata.rl_rx_list,
-		    sc->rl_ldata.rl_rx_list_map);
+		if (sc->rl_ldata.rl_rx_list_map)
+			bus_dmamap_unload(sc->rl_ldata.rl_rx_list_tag,
+			    sc->rl_ldata.rl_rx_list_map);
+		if (sc->rl_ldata.rl_rx_list_map && sc->rl_ldata.rl_rx_list)
+			bus_dmamem_free(sc->rl_ldata.rl_rx_list_tag,
+			    sc->rl_ldata.rl_rx_list,
+			    sc->rl_ldata.rl_rx_list_map);
 		bus_dma_tag_destroy(sc->rl_ldata.rl_rx_list_tag);
 	}
 
 	/* Unload and free the TX DMA ring memory and map */
 
 	if (sc->rl_ldata.rl_tx_list_tag) {
-		bus_dmamap_unload(sc->rl_ldata.rl_tx_list_tag,
-		    sc->rl_ldata.rl_tx_list_map);
-		bus_dmamem_free(sc->rl_ldata.rl_tx_list_tag,
-		    sc->rl_ldata.rl_tx_list,
-		    sc->rl_ldata.rl_tx_list_map);
+		if (sc->rl_ldata.rl_tx_list_map)
+			bus_dmamap_unload(sc->rl_ldata.rl_tx_list_tag,
+			    sc->rl_ldata.rl_tx_list_map);
+		if (sc->rl_ldata.rl_tx_list_map && sc->rl_ldata.rl_tx_list)
+			bus_dmamem_free(sc->rl_ldata.rl_tx_list_tag,
+			    sc->rl_ldata.rl_tx_list,
+			    sc->rl_ldata.rl_tx_list_map);
 		bus_dma_tag_destroy(sc->rl_ldata.rl_tx_list_tag);
 	}
 
@@ -1643,11 +1681,12 @@ re_detach(device_t dev)
 	/* Unload and free the stats buffer and map */
 
 	if (sc->rl_ldata.rl_stag) {
-		bus_dmamap_unload(sc->rl_ldata.rl_stag,
-		    sc->rl_ldata.rl_rx_list_map);
-		bus_dmamem_free(sc->rl_ldata.rl_stag,
-		    sc->rl_ldata.rl_stats,
-		    sc->rl_ldata.rl_smap);
+		if (sc->rl_ldata.rl_smap)
+			bus_dmamap_unload(sc->rl_ldata.rl_stag,
+			    sc->rl_ldata.rl_smap);
+		if (sc->rl_ldata.rl_smap && sc->rl_ldata.rl_stats)
+			bus_dmamem_free(sc->rl_ldata.rl_stag,
+			    sc->rl_ldata.rl_stats, sc->rl_ldata.rl_smap);
 		bus_dma_tag_destroy(sc->rl_ldata.rl_stag);
 	}
 
@@ -3185,3 +3224,88 @@ re_clrwol(struct rl_softc *sc)
 	v &= ~RL_CFG5_WOL_LANWAKE;
 	CSR_WRITE_1(sc, RL_CFG5, v);
 }
+
+static void
+re_add_sysctls(struct rl_softc *sc)
+{
+	struct sysctl_ctx_list	*ctx;
+	struct sysctl_oid_list	*children;
+
+	ctx = device_get_sysctl_ctx(sc->rl_dev);
+	children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->rl_dev));
+
+	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "stats",
+	    CTLTYPE_INT | CTLFLAG_RW, sc, 0, re_sysctl_stats, "I",
+	    "Statistics Information");
+}
+
+static int
+re_sysctl_stats(SYSCTL_HANDLER_ARGS)
+{
+	struct rl_softc		*sc;
+	struct rl_stats		*stats;
+	int			error, i, result;
+
+	result = -1;
+	error = sysctl_handle_int(oidp, &result, 0, req);
+	if (error || req->newptr == NULL)
+		return (error);
+
+	if (result == 1) {
+		sc = (struct rl_softc *)arg1;
+		RL_LOCK(sc);
+		bus_dmamap_sync(sc->rl_ldata.rl_stag,
+		    sc->rl_ldata.rl_smap, BUS_DMASYNC_PREREAD);
+		CSR_WRITE_4(sc, RL_DUMPSTATS_HI,
+		    RL_ADDR_HI(sc->rl_ldata.rl_stats_addr));
+		CSR_WRITE_4(sc, RL_DUMPSTATS_LO,
+		    RL_ADDR_LO(sc->rl_ldata.rl_stats_addr));
+		CSR_WRITE_4(sc, RL_DUMPSTATS_LO,
+		    RL_ADDR_LO(sc->rl_ldata.rl_stats_addr |
+		    RL_DUMPSTATS_START));
+		for (i = RL_TIMEOUT; i > 0; i--) {
+			if ((CSR_READ_4(sc, RL_DUMPSTATS_LO) &
+			    RL_DUMPSTATS_START) == 0)
+				break;
+			DELAY(1000);
+		}
+		bus_dmamap_sync(sc->rl_ldata.rl_stag,
+		    sc->rl_ldata.rl_smap, BUS_DMASYNC_POSTREAD);
+		RL_UNLOCK(sc);
+		if (i == 0) {
+			device_printf(sc->rl_dev,
+			    "DUMP statistics request timedout\n");
+			return (ETIMEDOUT);
+		}
+		stats = sc->rl_ldata.rl_stats;
+		printf("%s statistics:\n", device_get_nameunit(sc->rl_dev));
+		printf("Tx frames : %ju\n",
+		    (uintmax_t)le64toh(stats->rl_tx_pkts));
+		printf("Rx frames : %ju\n",
+		    (uintmax_t)le64toh(stats->rl_rx_pkts));
+		printf("Tx errors : %ju\n",
+		    (uintmax_t)le64toh(stats->rl_tx_errs));
+		printf("Rx errors : %u\n",
+		    le32toh(stats->rl_rx_errs));
+		printf("Rx missed frames : %u\n",
+		    (uint32_t)le16toh(stats->rl_missed_pkts));
+		printf("Rx frame alignment errs : %u\n",
+		    (uint32_t)le16toh(stats->rl_rx_framealign_errs));
+		printf("Tx single collisions : %u\n",
+		    le32toh(stats->rl_tx_onecoll));
+		printf("Tx multiple collisions : %u\n",
+		    le32toh(stats->rl_tx_multicolls));
+		printf("Rx unicast frames : %ju\n",
+		    (uintmax_t)le64toh(stats->rl_rx_ucasts));
+		printf("Rx broadcast frames : %ju\n",
+		    (uintmax_t)le64toh(stats->rl_rx_bcasts));
+		printf("Rx multicast frames : %u\n",
+		    le32toh(stats->rl_rx_mcasts));
+		printf("Tx aborts : %u\n",
+		    (uint32_t)le16toh(stats->rl_tx_aborts));
+		printf("Tx underruns : %u\n",
+		    (uint32_t)le16toh(stats->rl_rx_underruns));
+	}
+
+	return (error);
+}

Modified: head/sys/pci/if_rlreg.h
==============================================================================
--- head/sys/pci/if_rlreg.h	Fri Nov  5 19:12:48 2010	(r214843)
+++ head/sys/pci/if_rlreg.h	Fri Nov  5 19:28:00 2010	(r214844)
@@ -723,19 +723,16 @@ struct rl_desc {
  * Statistics counter structure (8139C+ and 8169 only)
  */
 struct rl_stats {
-	uint32_t		rl_tx_pkts_lo;
-	uint32_t		rl_tx_pkts_hi;
-	uint32_t		rl_tx_errs_lo;
-	uint32_t		rl_tx_errs_hi;
-	uint32_t		rl_tx_errs;
+	uint64_t		rl_tx_pkts;
+	uint64_t		rl_rx_pkts;
+	uint64_t		rl_tx_errs;
+	uint32_t		rl_rx_errs;
 	uint16_t		rl_missed_pkts;
 	uint16_t		rl_rx_framealign_errs;
 	uint32_t		rl_tx_onecoll;
 	uint32_t		rl_tx_multicolls;
-	uint32_t		rl_rx_ucasts_hi;
-	uint32_t		rl_rx_ucasts_lo;
-	uint32_t		rl_rx_bcasts_lo;
-	uint32_t		rl_rx_bcasts_hi;
+	uint64_t		rl_rx_ucasts;
+	uint64_t		rl_rx_bcasts;
 	uint32_t		rl_rx_mcasts;
 	uint16_t		rl_tx_aborts;
 	uint16_t		rl_rx_underruns;
@@ -769,6 +766,7 @@ struct rl_stats {
 #define	RL_NTXSEGS		32
 
 #define RL_RING_ALIGN		256
+#define RL_DUMP_ALIGN		64
 #define RL_IFQ_MAXLEN		512
 #define RL_TX_DESC_NXT(sc,x)	((x + 1) & ((sc)->rl_ldata.rl_tx_desc_cnt - 1))
 #define RL_TX_DESC_PRV(sc,x)	((x - 1) & ((sc)->rl_ldata.rl_tx_desc_cnt - 1))


More information about the svn-src-head mailing list