summaryrefslogtreecommitdiffstats
path: root/sys/dev/et
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2011-12-07 21:46:09 +0000
committeryongari <yongari@FreeBSD.org>2011-12-07 21:46:09 +0000
commitc557fccc885517cacf953a1d5df3392a97b66285 (patch)
tree9d822bc2461b592878ec70006dfde0895aa98b66 /sys/dev/et
parent3185636e8556df8d59e8fb523b111b4df478144e (diff)
downloadFreeBSD-src-c557fccc885517cacf953a1d5df3392a97b66285.zip
FreeBSD-src-c557fccc885517cacf953a1d5df3392a97b66285.tar.gz
Implement hardware MAC statistics counter. Counters could be
queried with dev.et.%d.stats sysctl node where %d is an instance of device.
Diffstat (limited to 'sys/dev/et')
-rw-r--r--sys/dev/et/if_et.c190
-rw-r--r--sys/dev/et/if_etreg.h46
-rw-r--r--sys/dev/et/if_etvar.h51
3 files changed, 283 insertions, 4 deletions
diff --git a/sys/dev/et/if_et.c b/sys/dev/et/if_et.c
index fd124af..176d858 100644
--- a/sys/dev/et/if_et.c
+++ b/sys/dev/et/if_et.c
@@ -146,6 +146,7 @@ static int et_bus_config(struct et_softc *);
static void et_get_eaddr(device_t, uint8_t[]);
static void et_setmulti(struct et_softc *);
static void et_tick(void *);
+static void et_stats_update(struct et_softc *);
static const struct et_dev {
uint16_t vid;
@@ -635,6 +636,7 @@ et_stop(struct et_softc *sc)
et_stop_rxdma(sc);
et_stop_txdma(sc);
+ et_stats_update(sc);
et_free_tx_ring(sc);
et_free_rx_ring(sc);
@@ -2049,7 +2051,6 @@ et_rxeof(struct et_softc *sc)
m = rbd->rbd_buf[buf_idx].rb_mbuf;
if ((rxst_info1 & ET_RXST_INFO1_OK) == 0){
/* Discard errored frame. */
- ifp->if_ierrors++;
rbd->rbd_discard(rbd, buf_idx);
} else if (rbd->rbd_newbuf(rbd, buf_idx) != 0) {
/* No available mbufs, discard it. */
@@ -2063,7 +2064,6 @@ et_rxeof(struct et_softc *sc)
} else {
m->m_pkthdr.len = m->m_len = buflen;
m->m_pkthdr.rcvif = ifp;
- ifp->if_ipackets++;
ET_UNLOCK(sc);
ifp->if_input(ifp, m);
ET_LOCK(sc);
@@ -2229,7 +2229,6 @@ et_txeof(struct et_softc *sc)
bus_dmamap_unload(sc->sc_tx_tag, tb->tb_dmap);
m_freem(tb->tb_mbuf);
tb->tb_mbuf = NULL;
- ifp->if_opackets++;
}
if (++tbd->tbd_start_index == ET_TX_NDESC) {
@@ -2259,6 +2258,7 @@ et_tick(void *xsc)
mii = device_get_softc(sc->sc_miibus);
mii_tick(mii);
+ et_stats_update(sc);
if (et_watchdog(sc) == EJUSTRETURN)
return;
callout_reset(&sc->sc_tick, hz, et_tick, sc);
@@ -2371,6 +2371,11 @@ et_newbuf_hdr(struct et_rxbuf_data *rbd, int buf_idx)
return (0);
}
+#define ET_SYSCTL_STAT_ADD32(c, h, n, p, d) \
+ SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
+#define ET_SYSCTL_STAT_ADD64(c, h, n, p, d) \
+ SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d)
+
/*
* Create sysctl tree
*/
@@ -2378,7 +2383,9 @@ static void
et_add_sysctls(struct et_softc * sc)
{
struct sysctl_ctx_list *ctx;
- struct sysctl_oid_list *children;
+ struct sysctl_oid_list *children, *parent;
+ struct sysctl_oid *tree;
+ struct et_hw_stats *stats;
ctx = device_get_sysctl_ctx(sc->dev);
children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
@@ -2394,8 +2401,116 @@ et_add_sysctls(struct et_softc * sc)
"TX IM, # segments per TX interrupt");
SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "timer",
CTLFLAG_RW, &sc->sc_timer, 0, "TX timer");
+
+ tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD,
+ NULL, "ET statistics");
+ parent = SYSCTL_CHILDREN(tree);
+
+ /* TX/RX statistics. */
+ stats = &sc->sc_stats;
+ ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_64", &stats->pkts_64,
+ "0 to 64 bytes frames");
+ ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_65_127", &stats->pkts_65,
+ "65 to 127 bytes frames");
+ ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_128_255", &stats->pkts_128,
+ "128 to 255 bytes frames");
+ ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_256_511", &stats->pkts_256,
+ "256 to 511 bytes frames");
+ ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_512_1023", &stats->pkts_512,
+ "512 to 1023 bytes frames");
+ ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_1024_1518", &stats->pkts_1024,
+ "1024 to 1518 bytes frames");
+ ET_SYSCTL_STAT_ADD64(ctx, parent, "frames_1519_1522", &stats->pkts_1519,
+ "1519 to 1522 bytes frames");
+
+ /* RX statistics. */
+ tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD,
+ NULL, "RX MAC statistics");
+ children = SYSCTL_CHILDREN(tree);
+ ET_SYSCTL_STAT_ADD64(ctx, children, "bytes",
+ &stats->rx_bytes, "Good bytes");
+ ET_SYSCTL_STAT_ADD64(ctx, children, "frames",
+ &stats->rx_frames, "Good frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "crc_errs",
+ &stats->rx_crcerrs, "CRC errors");
+ ET_SYSCTL_STAT_ADD64(ctx, children, "mcast_frames",
+ &stats->rx_mcast, "Multicast frames");
+ ET_SYSCTL_STAT_ADD64(ctx, children, "bcast_frames",
+ &stats->rx_bcast, "Broadcast frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "control",
+ &stats->rx_control, "Control frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "pause",
+ &stats->rx_pause, "Pause frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "unknown_control",
+ &stats->rx_unknown_control, "Unknown control frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "align_errs",
+ &stats->rx_alignerrs, "Alignment errors");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "len_errs",
+ &stats->rx_lenerrs, "Frames with length mismatched");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "code_errs",
+ &stats->rx_codeerrs, "Frames with code error");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "cs_errs",
+ &stats->rx_cserrs, "Frames with carrier sense error");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "runts",
+ &stats->rx_runts, "Too short frames");
+ ET_SYSCTL_STAT_ADD64(ctx, children, "oversize",
+ &stats->rx_oversize, "Oversized frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "fragments",
+ &stats->rx_fragments, "Fragmented frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "jabbers",
+ &stats->rx_jabbers, "Frames with jabber error");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "drop",
+ &stats->rx_drop, "Dropped frames");
+
+ /* TX statistics. */
+ tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD,
+ NULL, "TX MAC statistics");
+ children = SYSCTL_CHILDREN(tree);
+ ET_SYSCTL_STAT_ADD64(ctx, children, "bytes",
+ &stats->tx_bytes, "Good bytes");
+ ET_SYSCTL_STAT_ADD64(ctx, children, "frames",
+ &stats->tx_frames, "Good frames");
+ ET_SYSCTL_STAT_ADD64(ctx, children, "mcast_frames",
+ &stats->tx_mcast, "Multicast frames");
+ ET_SYSCTL_STAT_ADD64(ctx, children, "bcast_frames",
+ &stats->tx_bcast, "Broadcast frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "pause",
+ &stats->tx_pause, "Pause frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "deferred",
+ &stats->tx_deferred, "Deferred frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "excess_deferred",
+ &stats->tx_excess_deferred, "Excessively deferred frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "single_colls",
+ &stats->tx_single_colls, "Single collisions");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "multi_colls",
+ &stats->tx_multi_colls, "Multiple collisions");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "late_colls",
+ &stats->tx_late_colls, "Late collisions");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "excess_colls",
+ &stats->tx_excess_colls, "Excess collisions");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "total_colls",
+ &stats->tx_total_colls, "Total collisions");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "pause_honored",
+ &stats->tx_pause_honored, "Honored pause frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "drop",
+ &stats->tx_drop, "Dropped frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "jabbers",
+ &stats->tx_jabbers, "Frames with jabber errors");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "crc_errs",
+ &stats->tx_crcerrs, "Frames with CRC errors");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "control",
+ &stats->tx_control, "Control frames");
+ ET_SYSCTL_STAT_ADD64(ctx, children, "oversize",
+ &stats->tx_oversize, "Oversized frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "undersize",
+ &stats->tx_undersize, "Undersized frames");
+ ET_SYSCTL_STAT_ADD32(ctx, children, "fragments",
+ &stats->tx_fragments, "Fragmented frames");
}
+#undef ET_SYSCTL_STAT_ADD32
+#undef ET_SYSCTL_STAT_ADD64
+
static int
et_sysctl_rx_intr_npkts(SYSCTL_HANDLER_ARGS)
{
@@ -2446,6 +2561,73 @@ back:
return (error);
}
+static void
+et_stats_update(struct et_softc *sc)
+{
+ struct ifnet *ifp;
+ struct et_hw_stats *stats;
+
+ stats = &sc->sc_stats;
+ stats->pkts_64 += CSR_READ_4(sc, ET_STAT_PKTS_64);
+ stats->pkts_65 += CSR_READ_4(sc, ET_STAT_PKTS_65_127);
+ stats->pkts_128 += CSR_READ_4(sc, ET_STAT_PKTS_128_255);
+ stats->pkts_256 += CSR_READ_4(sc, ET_STAT_PKTS_256_511);
+ stats->pkts_512 += CSR_READ_4(sc, ET_STAT_PKTS_512_1023);
+ stats->pkts_1024 += CSR_READ_4(sc, ET_STAT_PKTS_1024_1518);
+ stats->pkts_1519 += CSR_READ_4(sc, ET_STAT_PKTS_1519_1522);
+
+ stats->rx_bytes += CSR_READ_4(sc, ET_STAT_RX_BYTES);
+ stats->rx_frames += CSR_READ_4(sc, ET_STAT_RX_FRAMES);
+ stats->rx_crcerrs += CSR_READ_4(sc, ET_STAT_RX_CRC_ERR);
+ stats->rx_mcast += CSR_READ_4(sc, ET_STAT_RX_MCAST);
+ stats->rx_bcast += CSR_READ_4(sc, ET_STAT_RX_BCAST);
+ stats->rx_control += CSR_READ_4(sc, ET_STAT_RX_CTL);
+ stats->rx_pause += CSR_READ_4(sc, ET_STAT_RX_PAUSE);
+ stats->rx_unknown_control += CSR_READ_4(sc, ET_STAT_RX_UNKNOWN_CTL);
+ stats->rx_alignerrs += CSR_READ_4(sc, ET_STAT_RX_ALIGN_ERR);
+ stats->rx_lenerrs += CSR_READ_4(sc, ET_STAT_RX_LEN_ERR);
+ stats->rx_codeerrs += CSR_READ_4(sc, ET_STAT_RX_CODE_ERR);
+ stats->rx_cserrs += CSR_READ_4(sc, ET_STAT_RX_CS_ERR);
+ stats->rx_runts += CSR_READ_4(sc, ET_STAT_RX_RUNT);
+ stats->rx_oversize += CSR_READ_4(sc, ET_STAT_RX_OVERSIZE);
+ stats->rx_fragments += CSR_READ_4(sc, ET_STAT_RX_FRAG);
+ stats->rx_jabbers += CSR_READ_4(sc, ET_STAT_RX_JABBER);
+ stats->rx_drop += CSR_READ_4(sc, ET_STAT_RX_DROP);
+
+ stats->tx_bytes += CSR_READ_4(sc, ET_STAT_TX_BYTES);
+ stats->tx_frames += CSR_READ_4(sc, ET_STAT_TX_FRAMES);
+ stats->tx_mcast += CSR_READ_4(sc, ET_STAT_TX_MCAST);
+ stats->tx_bcast += CSR_READ_4(sc, ET_STAT_TX_BCAST);
+ stats->tx_pause += CSR_READ_4(sc, ET_STAT_TX_PAUSE);
+ stats->tx_deferred += CSR_READ_4(sc, ET_STAT_TX_DEFER);
+ stats->tx_excess_deferred += CSR_READ_4(sc, ET_STAT_TX_EXCESS_DEFER);
+ stats->tx_single_colls += CSR_READ_4(sc, ET_STAT_TX_SINGLE_COL);
+ stats->tx_multi_colls += CSR_READ_4(sc, ET_STAT_TX_MULTI_COL);
+ stats->tx_late_colls += CSR_READ_4(sc, ET_STAT_TX_LATE_COL);
+ stats->tx_excess_colls += CSR_READ_4(sc, ET_STAT_TX_EXCESS_COL);
+ stats->tx_total_colls += CSR_READ_4(sc, ET_STAT_TX_TOTAL_COL);
+ stats->tx_pause_honored += CSR_READ_4(sc, ET_STAT_TX_PAUSE_HONOR);
+ stats->tx_drop += CSR_READ_4(sc, ET_STAT_TX_DROP);
+ stats->tx_jabbers += CSR_READ_4(sc, ET_STAT_TX_JABBER);
+ stats->tx_crcerrs += CSR_READ_4(sc, ET_STAT_TX_CRC_ERR);
+ stats->tx_control += CSR_READ_4(sc, ET_STAT_TX_CTL);
+ stats->tx_oversize += CSR_READ_4(sc, ET_STAT_TX_OVERSIZE);
+ stats->tx_undersize += CSR_READ_4(sc, ET_STAT_TX_UNDERSIZE);
+ stats->tx_fragments += CSR_READ_4(sc, ET_STAT_TX_FRAG);
+
+ /* Update ifnet counters. */
+ ifp = sc->ifp;
+ ifp->if_opackets = (u_long)stats->tx_frames;
+ ifp->if_collisions = stats->tx_total_colls;
+ ifp->if_oerrors = stats->tx_drop + stats->tx_jabbers +
+ stats->tx_crcerrs + stats->tx_excess_deferred +
+ stats->tx_late_colls;
+ ifp->if_ipackets = (u_long)stats->rx_frames;
+ ifp->if_ierrors = stats->rx_crcerrs + stats->rx_alignerrs +
+ stats->rx_lenerrs + stats->rx_codeerrs + stats->rx_cserrs +
+ stats->rx_runts + stats->rx_jabbers + stats->rx_drop;
+}
+
static int
et_suspend(device_t dev)
{
diff --git a/sys/dev/et/if_etreg.h b/sys/dev/et/if_etreg.h
index a8612c7..33be44e 100644
--- a/sys/dev/et/if_etreg.h
+++ b/sys/dev/et/if_etreg.h
@@ -318,6 +318,52 @@
#define ET_MAC_ADDR1 0x5040
#define ET_MAC_ADDR2 0x5044
+/* MAC statistics counters. */
+#define ET_STAT_PKTS_64 0x6080
+#define ET_STAT_PKTS_65_127 0x6084
+#define ET_STAT_PKTS_128_255 0x6088
+#define ET_STAT_PKTS_256_511 0x608C
+#define ET_STAT_PKTS_512_1023 0x6090
+#define ET_STAT_PKTS_1024_1518 0x6094
+#define ET_STAT_PKTS_1519_1522 0x6098
+#define ET_STAT_RX_BYTES 0x609C
+#define ET_STAT_RX_FRAMES 0x60A0
+#define ET_STAT_RX_CRC_ERR 0x60A4
+#define ET_STAT_RX_MCAST 0x60A8
+#define ET_STAT_RX_BCAST 0x60AC
+#define ET_STAT_RX_CTL 0x60B0
+#define ET_STAT_RX_PAUSE 0x60B4
+#define ET_STAT_RX_UNKNOWN_CTL 0x60B8
+#define ET_STAT_RX_ALIGN_ERR 0x60BC
+#define ET_STAT_RX_LEN_ERR 0x60C0
+#define ET_STAT_RX_CODE_ERR 0x60C4
+#define ET_STAT_RX_CS_ERR 0x60C8
+#define ET_STAT_RX_RUNT 0x60CC
+#define ET_STAT_RX_OVERSIZE 0x60D0
+#define ET_STAT_RX_FRAG 0x60D4
+#define ET_STAT_RX_JABBER 0x60D8
+#define ET_STAT_RX_DROP 0x60DC
+#define ET_STAT_TX_BYTES 0x60E0
+#define ET_STAT_TX_FRAMES 0x60E4
+#define ET_STAT_TX_MCAST 0x60E8
+#define ET_STAT_TX_BCAST 0x60EC
+#define ET_STAT_TX_PAUSE 0x60F0
+#define ET_STAT_TX_DEFER 0x60F4
+#define ET_STAT_TX_EXCESS_DEFER 0x60F8
+#define ET_STAT_TX_SINGLE_COL 0x60FC
+#define ET_STAT_TX_MULTI_COL 0x6100
+#define ET_STAT_TX_LATE_COL 0x6104
+#define ET_STAT_TX_EXCESS_COL 0x6108
+#define ET_STAT_TX_TOTAL_COL 0x610C
+#define ET_STAT_TX_PAUSE_HONOR 0x6110
+#define ET_STAT_TX_DROP 0x6114
+#define ET_STAT_TX_JABBER 0x6118
+#define ET_STAT_TX_CRC_ERR 0x611C
+#define ET_STAT_TX_CTL 0x6120
+#define ET_STAT_TX_OVERSIZE 0x6124
+#define ET_STAT_TX_UNDERSIZE 0x6128
+#define ET_STAT_TX_FRAG 0x612C
+
#define ET_MMC_CTRL 0x7000
#define ET_MMC_CTRL_ENABLE 0x00000001
#define ET_MMC_CTRL_ARB_DISABLE 0x00000002
diff --git a/sys/dev/et/if_etvar.h b/sys/dev/et/if_etvar.h
index b3591f83..dee3ee5 100644
--- a/sys/dev/et/if_etvar.h
+++ b/sys/dev/et/if_etvar.h
@@ -231,6 +231,56 @@ struct et_rxbuf_data {
void (*rbd_discard)(struct et_rxbuf_data *, int);
};
+struct et_hw_stats {
+ /* RX/TX stats. */
+ uint64_t pkts_64;
+ uint64_t pkts_65;
+ uint64_t pkts_128;
+ uint64_t pkts_256;
+ uint64_t pkts_512;
+ uint64_t pkts_1024;
+ uint64_t pkts_1519;
+ /* RX stats. */
+ uint64_t rx_bytes;
+ uint64_t rx_frames;
+ uint32_t rx_crcerrs;
+ uint64_t rx_mcast;
+ uint64_t rx_bcast;
+ uint32_t rx_control;
+ uint32_t rx_pause;
+ uint32_t rx_unknown_control;
+ uint32_t rx_alignerrs;
+ uint32_t rx_lenerrs;
+ uint32_t rx_codeerrs;
+ uint32_t rx_cserrs;
+ uint32_t rx_runts;
+ uint64_t rx_oversize;
+ uint32_t rx_fragments;
+ uint32_t rx_jabbers;
+ uint32_t rx_drop;
+ /* TX stats. */
+ uint64_t tx_bytes;
+ uint64_t tx_frames;
+ uint64_t tx_mcast;
+ uint64_t tx_bcast;
+ uint32_t tx_pause;
+ uint32_t tx_deferred;
+ uint32_t tx_excess_deferred;
+ uint32_t tx_single_colls;
+ uint32_t tx_multi_colls;
+ uint32_t tx_late_colls;
+ uint32_t tx_excess_colls;
+ uint32_t tx_total_colls;
+ uint32_t tx_pause_honored;
+ uint32_t tx_drop;
+ uint32_t tx_jabbers;
+ uint32_t tx_crcerrs;
+ uint32_t tx_control;
+ uint64_t tx_oversize;
+ uint32_t tx_undersize;
+ uint32_t tx_fragments;
+};
+
struct et_softc {
struct ifnet *ifp;
device_t dev;
@@ -271,6 +321,7 @@ struct et_softc {
struct et_rxbuf_data sc_rx_data[ET_RX_NRING];
struct et_txbuf_data sc_tx_data;
+ struct et_hw_stats sc_stats;
uint32_t sc_tx;
uint32_t sc_tx_intr;
OpenPOWER on IntegriCloud