summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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