Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 13 Nov 2010 01:11:13 +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-7@freebsd.org
Subject:   svn commit: r215223 - in stable/7/sys: dev/re pci
Message-ID:  <201011130111.oAD1BDVk030277@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Sat Nov 13 01:11:13 2010
New Revision: 215223
URL: http://svn.freebsd.org/changeset/base/215223

Log:
  MFC r214844:
    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:
  stable/7/sys/dev/re/if_re.c
  stable/7/sys/pci/if_rlreg.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/re/if_re.c
==============================================================================
--- stable/7/sys/dev/re/if_re.c	Sat Nov 13 01:09:44 2010	(r215222)
+++ stable/7/sys/dev/re/if_re.c	Sat Nov 13 01:11:13 2010	(r215223)
@@ -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),
@@ -1085,6 +1089,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);
 }
 
@@ -1375,6 +1408,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) {
@@ -1604,22 +1638,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);
 	}
 
@@ -1644,11 +1682,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);
 	}
 
@@ -3179,3 +3218,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: stable/7/sys/pci/if_rlreg.h
==============================================================================
--- stable/7/sys/pci/if_rlreg.h	Sat Nov 13 01:09:44 2010	(r215222)
+++ stable/7/sys/pci/if_rlreg.h	Sat Nov 13 01:11:13 2010	(r215223)
@@ -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))



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