svn commit: r208200 - stable/7/sys/dev/fxp

Pyun YongHyeon yongari at FreeBSD.org
Mon May 17 16:59:36 UTC 2010


Author: yongari
Date: Mon May 17 16:59:36 2010
New Revision: 208200
URL: http://svn.freebsd.org/changeset/base/208200

Log:
  MFC r207832:
    Export hardware MAC statistics through sysctl node. Previously
    fxp(4) already used to extract most hardware MAC statistics but it
    didn't show them. With this change, all MAC statistics counters
    are exported. Because there are a couple of new counters for 82558
    and 82559, enable extended MAC statistics functionality to get
    these counters. Accoring to public data sheet, 82559 MAC statistics
    return 24 DWORD counters(3 counters are unknown at this moment) so
    increase MAC counter structure to meet the MAC statistics block size.
    The completion of MAC counter dump is now checked against
    FXP_STATS_DR_COMPLETE status code which is appended at the end of
    status block. Previously fxp(4) ignored the status of the
    FXP_SCB_COMMAND_CU_DUMPRESET command. fxp(4) does not wait for the
    completion of pending command before issuing
    FXP_SCB_COMMAND_CU_DUMPRESET. Instead it skips the command and try
    it next time. This scheme may show better performance but there is
    chance to loose updated counters after stopping controller. So make
    sure to update MAC statistics in fxp_stop().
    While I'm here move sysctl node creation to fxp_sysctl_node().
  
    Tested by:	Larry Baird < lab <> gta dot com >

Modified:
  stable/7/sys/dev/fxp/if_fxp.c
  stable/7/sys/dev/fxp/if_fxpreg.h
  stable/7/sys/dev/fxp/if_fxpvar.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/fxp/if_fxp.c
==============================================================================
--- stable/7/sys/dev/fxp/if_fxp.c	Mon May 17 16:57:55 2010	(r208199)
+++ stable/7/sys/dev/fxp/if_fxp.c	Mon May 17 16:59:36 2010	(r208200)
@@ -262,6 +262,8 @@ static int		fxp_miibus_readreg(device_t 
 static void		fxp_miibus_writereg(device_t dev, int phy, int reg,
 			    int value);
 static void		fxp_load_ucode(struct fxp_softc *sc);
+static void		fxp_update_stats(struct fxp_softc *sc);
+static void		fxp_sysctl_node(struct fxp_softc *sc);
 static int		sysctl_int_range(SYSCTL_HANDLER_ARGS,
 			    int low, int high);
 static int		sysctl_hw_fxp_bundle_max(SYSCTL_HANDLER_ARGS);
@@ -538,39 +540,7 @@ fxp_attach(device_t dev)
 	    && (data & FXP_PHY_SERIAL_ONLY))
 		sc->flags |= FXP_FLAG_SERIAL_MEDIA;
 
-	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "int_delay", CTLTYPE_INT | CTLFLAG_RW,
-	    &sc->tunable_int_delay, 0, sysctl_hw_fxp_int_delay, "I",
-	    "FXP driver receive interrupt microcode bundling delay");
-	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "bundle_max", CTLTYPE_INT | CTLFLAG_RW,
-	    &sc->tunable_bundle_max, 0, sysctl_hw_fxp_bundle_max, "I",
-	    "FXP driver receive interrupt microcode bundle size limit");
-	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "rnr", CTLFLAG_RD, &sc->rnr, 0,
-	    "FXP RNR events");
-	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "noflow", CTLFLAG_RW, &sc->tunable_noflow, 0,
-	    "FXP flow control disabled");
-
-	/*
-	 * Pull in device tunables.
-	 */
-	sc->tunable_int_delay = TUNABLE_INT_DELAY;
-	sc->tunable_bundle_max = TUNABLE_BUNDLE_MAX;
-	sc->tunable_noflow = 1;
-	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
-	    "int_delay", &sc->tunable_int_delay);
-	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
-	    "bundle_max", &sc->tunable_bundle_max);
-	(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
-	    "noflow", &sc->tunable_noflow);
-	sc->rnr = 0;
-
+	fxp_sysctl_node(sc);
 	/*
 	 * Enable workarounds for certain chip revision deficiencies.
 	 *
@@ -2014,6 +1984,81 @@ fxp_intr_body(struct fxp_softc *sc, stru
 	}
 }
 
+static void
+fxp_update_stats(struct fxp_softc *sc)
+{
+	struct ifnet *ifp = sc->ifp;
+	struct fxp_stats *sp = sc->fxp_stats;
+	struct fxp_hwstats *hsp;
+	uint32_t *status;
+
+	FXP_LOCK_ASSERT(sc, MA_OWNED);
+
+	bus_dmamap_sync(sc->fxp_stag, sc->fxp_smap,
+	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+	/* Update statistical counters. */
+	if (sc->revision >= FXP_REV_82559_A0)
+		status = &sp->completion_status;
+	else if (sc->revision >= FXP_REV_82558_A4)
+		status = (uint32_t *)&sp->tx_tco;
+	else
+		status = &sp->tx_pause;
+	if (*status == htole32(FXP_STATS_DR_COMPLETE)) {
+		hsp = &sc->fxp_hwstats;
+		hsp->tx_good += le32toh(sp->tx_good);
+		hsp->tx_maxcols += le32toh(sp->tx_maxcols);
+		hsp->tx_latecols += le32toh(sp->tx_latecols);
+		hsp->tx_underruns += le32toh(sp->tx_underruns);
+		hsp->tx_lostcrs += le32toh(sp->tx_lostcrs);
+		hsp->tx_deffered += le32toh(sp->tx_deffered);
+		hsp->tx_single_collisions += le32toh(sp->tx_single_collisions);
+		hsp->tx_multiple_collisions +=
+		    le32toh(sp->tx_multiple_collisions);
+		hsp->tx_total_collisions += le32toh(sp->tx_total_collisions);
+		hsp->rx_good += le32toh(sp->rx_good);
+		hsp->rx_crc_errors += le32toh(sp->rx_crc_errors);
+		hsp->rx_alignment_errors += le32toh(sp->rx_alignment_errors);
+		hsp->rx_rnr_errors += le32toh(sp->rx_rnr_errors);
+		hsp->rx_overrun_errors += le32toh(sp->rx_overrun_errors);
+		hsp->rx_cdt_errors += le32toh(sp->rx_cdt_errors);
+		hsp->rx_shortframes += le32toh(sp->rx_shortframes);
+		hsp->tx_pause += le32toh(sp->tx_pause);
+		hsp->rx_pause += le32toh(sp->rx_pause);
+		hsp->rx_controls += le32toh(sp->rx_controls);
+		hsp->tx_tco += le16toh(sp->tx_tco);
+		hsp->rx_tco += le16toh(sp->rx_tco);
+
+		ifp->if_opackets += le32toh(sp->tx_good);
+		ifp->if_collisions += le32toh(sp->tx_total_collisions);
+		if (sp->rx_good) {
+			ifp->if_ipackets += le32toh(sp->rx_good);
+			sc->rx_idle_secs = 0;
+		} else if (sc->flags & FXP_FLAG_RXBUG) {
+			/*
+			 * Receiver's been idle for another second.
+			 */
+			sc->rx_idle_secs++;
+		}
+		ifp->if_ierrors += 
+		    le32toh(sp->rx_crc_errors) +
+		    le32toh(sp->rx_alignment_errors) +
+		    le32toh(sp->rx_rnr_errors) +
+		    le32toh(sp->rx_overrun_errors);
+		/*
+		 * If any transmit underruns occured, bump up the transmit
+		 * threshold by another 512 bytes (64 * 8).
+		 */
+		if (sp->tx_underruns) {
+			ifp->if_oerrors += le32toh(sp->tx_underruns);
+			if (tx_threshold < 192)
+				tx_threshold += 64;
+		}
+		*status = 0;
+		bus_dmamap_sync(sc->fxp_stag, sc->fxp_smap,
+		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+	}
+}
+
 /*
  * Update packet in/out/collision statistics. The i82557 doesn't
  * allow you to access these counters without doing a fairly
@@ -2030,35 +2075,11 @@ fxp_tick(void *xsc)
 {
 	struct fxp_softc *sc = xsc;
 	struct ifnet *ifp = sc->ifp;
-	struct fxp_stats *sp = sc->fxp_stats;
 
 	FXP_LOCK_ASSERT(sc, MA_OWNED);
-	bus_dmamap_sync(sc->fxp_stag, sc->fxp_smap, BUS_DMASYNC_POSTREAD);
-	ifp->if_opackets += le32toh(sp->tx_good);
-	ifp->if_collisions += le32toh(sp->tx_total_collisions);
-	if (sp->rx_good) {
-		ifp->if_ipackets += le32toh(sp->rx_good);
-		sc->rx_idle_secs = 0;
-	} else if (sc->flags & FXP_FLAG_RXBUG) {
-		/*
-		 * Receiver's been idle for another second.
-		 */
-		sc->rx_idle_secs++;
-	}
-	ifp->if_ierrors +=
-	    le32toh(sp->rx_crc_errors) +
-	    le32toh(sp->rx_alignment_errors) +
-	    le32toh(sp->rx_rnr_errors) +
-	    le32toh(sp->rx_overrun_errors);
-	/*
-	 * If any transmit underruns occured, bump up the transmit
-	 * threshold by another 512 bytes (64 * 8).
-	 */
-	if (sp->tx_underruns) {
-		ifp->if_oerrors += le32toh(sp->tx_underruns);
-		if (tx_threshold < 192)
-			tx_threshold += 64;
-	}
+
+	/* Update statistical counters. */
+	fxp_update_stats(sc);
 
 	/*
 	 * Release any xmit buffers that have completed DMA. This isn't
@@ -2093,24 +2114,7 @@ fxp_tick(void *xsc)
 		/*
 		 * Start another stats dump.
 		 */
-		bus_dmamap_sync(sc->fxp_stag, sc->fxp_smap,
-		    BUS_DMASYNC_PREREAD);
 		fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_DUMPRESET);
-	} else {
-		/*
-		 * A previous command is still waiting to be accepted.
-		 * Just zero our copy of the stats and wait for the
-		 * next timer event to update them.
-		 */
-		sp->tx_good = 0;
-		sp->tx_underruns = 0;
-		sp->tx_total_collisions = 0;
-
-		sp->rx_good = 0;
-		sp->rx_crc_errors = 0;
-		sp->rx_alignment_errors = 0;
-		sp->rx_rnr_errors = 0;
-		sp->rx_overrun_errors = 0;
 	}
 	if (sc->miibus != NULL)
 		mii_tick(device_get_softc(sc->miibus));
@@ -2154,6 +2158,8 @@ fxp_stop(struct fxp_softc *sc)
 	/* Disable interrupts. */
 	CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE);
 
+	fxp_update_stats(sc);
+
 	/*
 	 * Release any xmit buffers.
 	 */
@@ -2256,7 +2262,9 @@ fxp_init_body(struct fxp_softc *sc)
 	 * Initialize base of dump-stats buffer.
 	 */
 	fxp_scb_wait(sc);
-	bus_dmamap_sync(sc->fxp_stag, sc->fxp_smap, BUS_DMASYNC_PREREAD);
+	bzero(sc->fxp_stats, sizeof(struct fxp_stats));
+	bus_dmamap_sync(sc->fxp_stag, sc->fxp_smap,
+	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, sc->stats_addr);
 	fxp_scb_cmd(sc, FXP_SCB_COMMAND_CU_DUMP_ADR);
 
@@ -2377,6 +2385,22 @@ fxp_init_body(struct fxp_softc *sc)
 		cbp->pri_fc_loc =	1;	/* FC pri location (byte31) */
 	}
 
+	/* Enable 82558 and 82559 extended statistics functionality. */
+	if (sc->revision >= FXP_REV_82558_A4) {
+		if (sc->revision >= FXP_REV_82559_A0) {
+			/*
+			 * Extend configuration table size to 32
+			 * to include TCO configuration.
+			 */
+			cbp->byte_count = 32;
+			cbp->ext_stats_dis = 1;
+			/* Enable TCO stats. */
+			cbp->tno_int_or_tco_en = 1;
+			cbp->gamla_rx = 1;
+		} else
+			cbp->ext_stats_dis = 0;
+	}
+
 	/*
 	 * Start the config command/DMA.
 	 */
@@ -2997,6 +3021,113 @@ fxp_load_ucode(struct fxp_softc *sc)
 	sc->flags |= FXP_FLAG_UCODE;
 }
 
+#define FXP_SYSCTL_STAT_ADD(c, h, n, p, d)	\
+	SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
+
+static void
+fxp_sysctl_node(struct fxp_softc *sc)
+{
+	struct sysctl_ctx_list *ctx;
+	struct sysctl_oid_list *child, *parent;
+	struct sysctl_oid *tree;
+	struct fxp_hwstats *hsp;
+
+	ctx = device_get_sysctl_ctx(sc->dev);
+	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
+
+	SYSCTL_ADD_PROC(ctx, child,
+	    OID_AUTO, "int_delay", CTLTYPE_INT | CTLFLAG_RW,
+	    &sc->tunable_int_delay, 0, sysctl_hw_fxp_int_delay, "I",
+	    "FXP driver receive interrupt microcode bundling delay");
+	SYSCTL_ADD_PROC(ctx, child,
+	    OID_AUTO, "bundle_max", CTLTYPE_INT | CTLFLAG_RW,
+	    &sc->tunable_bundle_max, 0, sysctl_hw_fxp_bundle_max, "I",
+	    "FXP driver receive interrupt microcode bundle size limit");
+	SYSCTL_ADD_INT(ctx, child,OID_AUTO, "rnr", CTLFLAG_RD, &sc->rnr, 0,
+	    "FXP RNR events");
+	SYSCTL_ADD_INT(ctx, child,
+	    OID_AUTO, "noflow", CTLFLAG_RW, &sc->tunable_noflow, 0,
+	    "FXP flow control disabled");
+
+	/*
+	 * Pull in device tunables.
+	 */
+	sc->tunable_int_delay = TUNABLE_INT_DELAY;
+	sc->tunable_bundle_max = TUNABLE_BUNDLE_MAX;
+	sc->tunable_noflow = 1;
+	(void) resource_int_value(device_get_name(sc->dev),
+	    device_get_unit(sc->dev), "int_delay", &sc->tunable_int_delay);
+	(void) resource_int_value(device_get_name(sc->dev),
+	    device_get_unit(sc->dev), "bundle_max", &sc->tunable_bundle_max);
+	(void) resource_int_value(device_get_name(sc->dev),
+	    device_get_unit(sc->dev), "noflow", &sc->tunable_noflow);
+	sc->rnr = 0;
+
+	hsp = &sc->fxp_hwstats;
+	tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
+	    NULL, "FXP statistics");
+	parent = SYSCTL_CHILDREN(tree);
+
+	/* Rx MAC statistics. */
+	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD,
+	    NULL, "Rx MAC statistics");
+	child = SYSCTL_CHILDREN(tree);
+	FXP_SYSCTL_STAT_ADD(ctx, child, "good_frames",
+	    &hsp->rx_good, "Good frames");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "crc_errors",
+	    &hsp->rx_crc_errors, "CRC errors");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "alignment_errors",
+	    &hsp->rx_alignment_errors, "Alignment errors");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "rnr_errors",
+	    &hsp->rx_rnr_errors, "RNR errors");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "overrun_errors",
+	    &hsp->rx_overrun_errors, "Overrun errors");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "cdt_errors",
+	    &hsp->rx_cdt_errors, "Collision detect errors");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "shortframes",
+	    &hsp->rx_shortframes, "Short frame errors");
+	if (sc->revision >= FXP_REV_82558_A4) {
+		FXP_SYSCTL_STAT_ADD(ctx, child, "pause",
+		    &hsp->rx_pause, "Pause frames");
+		FXP_SYSCTL_STAT_ADD(ctx, child, "controls",
+		    &hsp->rx_controls, "Unsupported control frames");
+	}
+	if (sc->revision >= FXP_REV_82559_A0)
+		FXP_SYSCTL_STAT_ADD(ctx, child, "tco",
+		    &hsp->rx_tco, "TCO frames");
+
+	/* Tx MAC statistics. */
+	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD,
+	    NULL, "Tx MAC statistics");
+	child = SYSCTL_CHILDREN(tree);
+	FXP_SYSCTL_STAT_ADD(ctx, child, "good_frames",
+	    &hsp->tx_good, "Good frames");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "maxcols",
+	    &hsp->tx_maxcols, "Maximum collisions errors");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "latecols",
+	    &hsp->tx_latecols, "Late collisions errors");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "underruns",
+	    &hsp->tx_underruns, "Underrun errors");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "lostcrs",
+	    &hsp->tx_lostcrs, "Lost carrier sense");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "deffered",
+	    &hsp->tx_deffered, "Deferred");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "single_collisions",
+	    &hsp->tx_single_collisions, "Single collisions");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "multiple_collisions",
+	    &hsp->tx_multiple_collisions, "Multiple collisions");
+	FXP_SYSCTL_STAT_ADD(ctx, child, "total_collisions",
+	    &hsp->tx_total_collisions, "Total collisions");
+	if (sc->revision >= FXP_REV_82558_A4)
+		FXP_SYSCTL_STAT_ADD(ctx, child, "pause",
+		    &hsp->tx_pause, "Pause frames");
+	if (sc->revision >= FXP_REV_82559_A0)
+		FXP_SYSCTL_STAT_ADD(ctx, child, "tco",
+		    &hsp->tx_tco, "TCO frames");
+}
+
+#undef FXP_SYSCTL_STAT_ADD
+
 static int
 sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
 {

Modified: stable/7/sys/dev/fxp/if_fxpreg.h
==============================================================================
--- stable/7/sys/dev/fxp/if_fxpreg.h	Mon May 17 16:57:55 2010	(r208199)
+++ stable/7/sys/dev/fxp/if_fxpreg.h	Mon May 17 16:59:36 2010	(r208200)
@@ -418,7 +418,15 @@ struct fxp_stats {
 	uint32_t rx_overrun_errors;
 	uint32_t rx_cdt_errors;
 	uint32_t rx_shortframes;
+	uint32_t tx_pause;
+	uint32_t rx_pause;
+	uint32_t rx_controls;
+	uint16_t tx_tco;
+	uint16_t rx_tco;
 	uint32_t completion_status;
+	uint32_t reserved0;
+	uint32_t reserved1;
+	uint32_t reserved2;
 };
 #define FXP_STATS_DUMP_COMPLETE	0xa005
 #define FXP_STATS_DR_COMPLETE	0xa007

Modified: stable/7/sys/dev/fxp/if_fxpvar.h
==============================================================================
--- stable/7/sys/dev/fxp/if_fxpvar.h	Mon May 17 16:57:55 2010	(r208199)
+++ stable/7/sys/dev/fxp/if_fxpvar.h	Mon May 17 16:59:36 2010	(r208200)
@@ -149,6 +149,30 @@ struct fxp_ident {
 	char 		*name;
 };
 
+struct fxp_hwstats {
+	uint32_t tx_good;
+	uint32_t tx_maxcols;
+	uint32_t tx_latecols;
+	uint32_t tx_underruns;
+	uint32_t tx_lostcrs;
+	uint32_t tx_deffered;
+	uint32_t tx_single_collisions;
+	uint32_t tx_multiple_collisions;
+	uint32_t tx_total_collisions;
+	uint32_t tx_pause;
+	uint32_t tx_tco;
+	uint32_t rx_good;
+	uint32_t rx_crc_errors;
+	uint32_t rx_alignment_errors;
+	uint32_t rx_rnr_errors;
+	uint32_t rx_overrun_errors;
+	uint32_t rx_cdt_errors;
+	uint32_t rx_shortframes;
+	uint32_t rx_pause;
+	uint32_t rx_controls;
+	uint32_t rx_tco;
+};
+
 /*
  * NOTE: Elements are ordered for optimal cacheline behavior, and NOT
  *	 for functional grouping.
@@ -175,6 +199,7 @@ struct fxp_softc {
 	int tx_queued;			/* # of active TxCB's */
 	struct fxp_stats *fxp_stats;	/* Pointer to interface stats */
 	uint32_t stats_addr;		/* DMA address of the stats structure */
+	struct fxp_hwstats fxp_hwstats;
 	int rx_idle_secs;		/* # of seconds RX has been idle */
 	struct callout stat_ch;		/* stat callout */
 	int watchdog_timer;		/* seconds until chip reset */


More information about the svn-src-all mailing list