summaryrefslogtreecommitdiffstats
path: root/sys/dev/fxp
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2010-05-09 22:16:15 +0000
committeryongari <yongari@FreeBSD.org>2010-05-09 22:16:15 +0000
commit3e09decd1986826f54af1a47be97bb87c1220783 (patch)
tree37186e7204715c4fe42c5d9a9db3cf8d50f2b3ae /sys/dev/fxp
parent48c5cd85a64eb9c45f373bdcba6b8287284a13ef (diff)
downloadFreeBSD-src-3e09decd1986826f54af1a47be97bb87c1220783.zip
FreeBSD-src-3e09decd1986826f54af1a47be97bb87c1220783.tar.gz
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 >
Diffstat (limited to 'sys/dev/fxp')
-rw-r--r--sys/dev/fxp/if_fxp.c287
-rw-r--r--sys/dev/fxp/if_fxpreg.h8
-rw-r--r--sys/dev/fxp/if_fxpvar.h25
3 files changed, 242 insertions, 78 deletions
diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c
index 9c0b44a..5cc8547 100644
--- a/sys/dev/fxp/if_fxp.c
+++ b/sys/dev/fxp/if_fxp.c
@@ -262,6 +262,8 @@ static int fxp_miibus_readreg(device_t dev, int phy, int reg);
static int 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);
@@ -537,39 +539,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.
*
@@ -2020,6 +1990,81 @@ fxp_intr_body(struct fxp_softc *sc, struct ifnet *ifp, uint8_t statack,
return (rx_npkts);
}
+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
@@ -2036,35 +2081,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
@@ -2099,24 +2120,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));
@@ -2160,6 +2164,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.
*/
@@ -2262,7 +2268,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);
@@ -2383,6 +2391,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.
*/
@@ -3004,6 +3028,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)
{
diff --git a/sys/dev/fxp/if_fxpreg.h b/sys/dev/fxp/if_fxpreg.h
index 9831bd2..d46b49a 100644
--- a/sys/dev/fxp/if_fxpreg.h
+++ b/sys/dev/fxp/if_fxpreg.h
@@ -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
diff --git a/sys/dev/fxp/if_fxpvar.h b/sys/dev/fxp/if_fxpvar.h
index 96b2418..de44636 100644
--- a/sys/dev/fxp/if_fxpvar.h
+++ b/sys/dev/fxp/if_fxpvar.h
@@ -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 */
OpenPOWER on IntegriCloud