summaryrefslogtreecommitdiffstats
path: root/sys/dev/fxp/if_fxp.c
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/if_fxp.c
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/if_fxp.c')
-rw-r--r--sys/dev/fxp/if_fxp.c287
1 files changed, 209 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)
{
OpenPOWER on IntegriCloud