this is a first pass at converting the stats gathering in em(4) to
kstat instead of a disabled printf.
there are some semantic differences. the most obvious is that hardware
counters are not fed into the stacks counters on struct ifnet. i also
don't collect ring based counters (yet).
they look like this:
em0:0:em-stats:0
rx crc errs: 0 packets
rx align errs: 0 packets
rx align errs: 0 packets
rx errs: 0 packets
rx missed: 0 packets
tx single coll: 0 packets
tx excess coll: 0 packets
tx multi coll: 0 packets
tx late coll: 0 packets
tx coll: 0
tx defers: 0
tx no CRS: 0 packets
seq errs: 0
carr ext errs: 0 packets
rx len errs: 0 packets
rx xon: 0 packets
tx xon: 0 packets
rx xoff: 0 packets
tx xoff: 0 packets
FC unsupported: 0 packets
rx 64B: 6 packets
rx 65-127B: 223 packets
rx 128-255B: 15 packets
rx 256-511B: 7 packets
rx 512-1023B: 2 packets
rx 1024-maxB: 1234584 packets
rx good: 1234837 packets
rx bcast: 19 packets
rx mcast: 0 packets
tx good: 630873 packets
rx good: 1874122399 bytes
tx good: 44180108 bytes
rx no buffers: 0 packets
rx undersize: 0 packets
rx fragments: 0 packets
rx oversize: 0 packets
rx jabbers: 0 packets
rx mgmt: 0 packets
rx mgmt drops: 0 packets
tx mgmt: 0 packets
rx total: 1874146525 bytes
tx total: 44180108 bytes
rx total: 1235017 packets
tx total: 630873 packets
tx 64B: 113 packets
tx 65-127B: 630681 packets
tx 128-255B: 47 packets
tx 256-511B: 29 packets
tx 512-1023B: 2 packets
tx 1024-maxB: 1 packets
tx mcast: 0 packets
tx bcast: 10 packets
unfortunately em(4) covers a lot of chips of different vintages, so if
anyone has a super old one they can try this diff on with kstat enabled
in their kernel config, that would be appreciated.
Index: if_em.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em.c,v
retrieving revision 1.354
diff -u -p -r1.354 if_em.c
--- if_em.c 22 Jun 2020 02:31:32 -0000 1.354
+++ if_em.c 7 Jul 2020 08:48:37 -0000
@@ -270,9 +270,6 @@ void em_receive_checksum(struct em_softc
u_int em_transmit_checksum_setup(struct em_queue *, struct mbuf *, u_int,
u_int32_t *, u_int32_t *);
void em_iff(struct em_softc *);
-#ifdef EM_DEBUG
-void em_print_hw_stats(struct em_softc *);
-#endif
void em_update_link_status(struct em_softc *);
int em_get_buf(struct em_queue *, int);
void em_enable_hw_vlans(struct em_softc *);
@@ -302,6 +299,12 @@ void em_enable_queue_intr_msix(struct em
#define em_allocate_msix(_sc) (-1)
#endif
+#if NKSTAT > 0
+void em_kstat_attach(struct em_softc *);
+int em_kstat_read(struct kstat *);
+void em_tbi_adjust_stats(struct em_softc *, uint32_t, uint8_t *);
+#endif
+
/*********************************************************************
* OpenBSD Device Interface Entry Points
*********************************************************************/
@@ -561,8 +564,8 @@ em_attach(struct device *parent, struct
/* Initialize statistics */
em_clear_hw_cntrs(&sc->hw);
-#ifndef SMALL_KERNEL
- em_update_stats_counters(sc);
+#if NKSTAT > 0
+ em_kstat_attach(sc);
#endif
sc->hw.get_link_status = 1;
if (!defer)
@@ -1467,26 +1470,21 @@ em_iff(struct em_softc *sc)
void
em_local_timer(void *arg)
{
- struct ifnet *ifp;
struct em_softc *sc = arg;
int s;
- ifp = &sc->sc_ac.ac_if;
+ timeout_add_sec(&sc->timer_handle, 1);
s = splnet();
-
-#ifndef SMALL_KERNEL
- em_update_stats_counters(sc);
-#ifdef EM_DEBUG
- if (ifp->if_flags & IFF_DEBUG && ifp->if_flags & IFF_RUNNING)
- em_print_hw_stats(sc);
-#endif
-#endif
em_smartspeed(sc);
-
- timeout_add_sec(&sc->timer_handle, 1);
-
splx(s);
+
+#if NKSTAT > 0
+ if (sc->kstat != NULL && mtx_enter_try(&sc->kstat_mtx)) {
+ em_kstat_read(sc->kstat);
+ mtx_leave(&sc->kstat_mtx);
+ }
+#endif
}
void
@@ -2934,8 +2932,8 @@ em_rxeof(struct em_queue *que)
last_byte = *(mtod(m, caddr_t) + desc_len - 1);
if (TBI_ACCEPT(&sc->hw, status, desc->errors,
pkt_len, last_byte)) {
-#ifndef SMALL_KERNEL
- em_tbi_adjust_stats(&sc->hw, &sc->stats,
+#if NKSTAT > 0
+ em_tbi_adjust_stats(sc,
pkt_len, sc->hw.mac_addr);
#endif
if (len > 0)
@@ -3396,228 +3394,365 @@ em_allocate_legacy(struct em_softc *sc)
return (0);
}
+#if NKSTAT > 0
+/* this is used to look up the array of kstats quickly */
+enum em_stat {
+ em_stat_crcerrs,
+ em_stat_algnerrc,
+ em_stat_symerrs,
+ em_stat_rxerrc,
+ em_stat_mpc,
+ em_stat_scc,
+ em_stat_ecol,
+ em_stat_mcc,
+ em_stat_latecol,
+ em_stat_colc,
+ em_stat_dc,
+ em_stat_tncrs,
+ em_stat_sec,
+ em_stat_cexterr,
+ em_stat_rlec,
+ em_stat_xonrxc,
+ em_stat_xontxc,
+ em_stat_xoffrxc,
+ em_stat_xofftxc,
+ em_stat_fcruc,
+ em_stat_prc64,
+ em_stat_prc127,
+ em_stat_prc255,
+ em_stat_prc511,
+ em_stat_prc1023,
+ em_stat_prc1522,
+ em_stat_gprc,
+ em_stat_bprc,
+ em_stat_mprc,
+ em_stat_gptc,
+ em_stat_gorc,
+ em_stat_gotc,
+ em_stat_rnbc,
+ em_stat_ruc,
+ em_stat_rfc,
+ em_stat_roc,
+ em_stat_rjc,
+ em_stat_mgtprc,
+ em_stat_mgtpdc,
+ em_stat_mgtptc,
+ em_stat_tor,
+ em_stat_tot,
+ em_stat_tpr,
+ em_stat_tpt,
+ em_stat_ptc64,
+ em_stat_ptc127,
+ em_stat_ptc255,
+ em_stat_ptc511,
+ em_stat_ptc1023,
+ em_stat_ptc1522,
+ em_stat_mptc,
+ em_stat_bptc,
+#if 0
+ em_stat_tsctc,
+ em_stat_tsctf,
+#endif
+
+ em_stat_count,
+};
+
+struct em_counter {
+ const char *name;
+ enum kstat_kv_unit unit;
+ uint32_t reg;
+};
+
+static const struct em_counter em_counters[em_stat_count] = {
+ [em_stat_crcerrs] =
+ { "rx crc errs", KSTAT_KV_U_PACKETS, E1000_CRCERRS },
+ [em_stat_algnerrc] = /* >= em_82543 */
+ { "rx align errs", KSTAT_KV_U_PACKETS, 0 },
+ [em_stat_symerrs] = /* >= em_82543 */
+ { "rx align errs", KSTAT_KV_U_PACKETS, 0 },
+ [em_stat_rxerrc] =
+ { "rx errs", KSTAT_KV_U_PACKETS, E1000_RXERRC },
+ [em_stat_mpc] =
+ { "rx missed", KSTAT_KV_U_PACKETS, E1000_MPC },
+ [em_stat_scc] =
+ { "tx single coll", KSTAT_KV_U_PACKETS, E1000_SCC },
+ [em_stat_ecol] =
+ { "tx excess coll", KSTAT_KV_U_PACKETS, E1000_ECOL },
+ [em_stat_mcc] =
+ { "tx multi coll", KSTAT_KV_U_PACKETS, E1000_MCC },
+ [em_stat_latecol] =
+ { "tx late coll", KSTAT_KV_U_PACKETS, E1000_LATECOL },
+ [em_stat_colc] =
+ { "tx coll", KSTAT_KV_U_NONE, E1000_COLC },
+ [em_stat_dc] =
+ { "tx defers", KSTAT_KV_U_NONE, E1000_DC },
+ [em_stat_tncrs] = /* >= em_82543 */
+ { "tx no CRS", KSTAT_KV_U_PACKETS, 0 },
+ [em_stat_sec] =
+ { "seq errs", KSTAT_KV_U_NONE, E1000_SEC },
+ [em_stat_cexterr] = /* >= em_82543 */
+ { "carr ext errs", KSTAT_KV_U_PACKETS, 0 },
+ [em_stat_rlec] =
+ { "rx len errs", KSTAT_KV_U_PACKETS, E1000_RLEC },
+ [em_stat_xonrxc] =
+ { "rx xon", KSTAT_KV_U_PACKETS, E1000_XONRXC },
+ [em_stat_xontxc] =
+ { "tx xon", KSTAT_KV_U_PACKETS, E1000_XONTXC },
+ [em_stat_xoffrxc] =
+ { "rx xoff", KSTAT_KV_U_PACKETS, E1000_XOFFRXC },
+ [em_stat_xofftxc] =
+ { "tx xoff", KSTAT_KV_U_PACKETS, E1000_XOFFTXC },
+ [em_stat_fcruc] =
+ { "FC unsupported", KSTAT_KV_U_PACKETS, E1000_FCRUC },
+ [em_stat_prc64] =
+ { "rx 64B", KSTAT_KV_U_PACKETS, E1000_PRC64 },
+ [em_stat_prc127] =
+ { "rx 65-127B", KSTAT_KV_U_PACKETS, E1000_PRC127 },
+ [em_stat_prc255] =
+ { "rx 128-255B", KSTAT_KV_U_PACKETS, E1000_PRC255 },
+ [em_stat_prc511] =
+ { "rx 256-511B", KSTAT_KV_U_PACKETS, E1000_PRC511 },
+ [em_stat_prc1023] =
+ { "rx 512-1023B", KSTAT_KV_U_PACKETS, E1000_PRC1023 },
+ [em_stat_prc1522] =
+ { "rx 1024-maxB", KSTAT_KV_U_PACKETS, E1000_PRC1522 },
+ [em_stat_gprc] =
+ { "rx good", KSTAT_KV_U_PACKETS, E1000_GPRC },
+ [em_stat_bprc] =
+ { "rx bcast", KSTAT_KV_U_PACKETS, E1000_BPRC },
+ [em_stat_mprc] =
+ { "rx mcast", KSTAT_KV_U_PACKETS, E1000_MPRC },
+ [em_stat_gptc] =
+ { "tx good", KSTAT_KV_U_PACKETS, E1000_GPTC },
+ [em_stat_gorc] = /* 64bit */
+ { "rx good", KSTAT_KV_U_BYTES, 0 },
+ [em_stat_gotc] = /* 64bit */
+ { "tx good", KSTAT_KV_U_BYTES, 0 },
+ [em_stat_rnbc] =
+ { "rx no buffers", KSTAT_KV_U_PACKETS, E1000_RNBC },
+ [em_stat_ruc] =
+ { "rx undersize", KSTAT_KV_U_PACKETS, E1000_RUC },
+ [em_stat_rfc] =
+ { "rx fragments", KSTAT_KV_U_PACKETS, E1000_RFC },
+ [em_stat_roc] =
+ { "rx oversize", KSTAT_KV_U_PACKETS, E1000_ROC },
+ [em_stat_rjc] =
+ { "rx jabbers", KSTAT_KV_U_PACKETS, E1000_RJC },
+ [em_stat_mgtprc] =
+ { "rx mgmt", KSTAT_KV_U_PACKETS, E1000_MGTPRC },
+ [em_stat_mgtpdc] =
+ { "rx mgmt drops", KSTAT_KV_U_PACKETS, E1000_MGTPDC },
+ [em_stat_mgtptc] =
+ { "tx mgmt", KSTAT_KV_U_PACKETS, E1000_MGTPTC },
+ [em_stat_tor] = /* 64bit */
+ { "rx total", KSTAT_KV_U_BYTES, 0 },
+ [em_stat_tot] = /* 64bit */
+ { "tx total", KSTAT_KV_U_BYTES, 0 },
+ [em_stat_tpr] =
+ { "rx total", KSTAT_KV_U_PACKETS, E1000_TPR },
+ [em_stat_tpt] =
+ { "tx total", KSTAT_KV_U_PACKETS, E1000_TPT },
+ [em_stat_ptc64] =
+ { "tx 64B", KSTAT_KV_U_PACKETS, E1000_PTC64 },
+ [em_stat_ptc127] =
+ { "tx 65-127B", KSTAT_KV_U_PACKETS, E1000_PTC127 },
+ [em_stat_ptc255] =
+ { "tx 128-255B", KSTAT_KV_U_PACKETS, E1000_PTC255 },
+ [em_stat_ptc511] =
+ { "tx 256-511B", KSTAT_KV_U_PACKETS, E1000_PTC511 },
+ [em_stat_ptc1023] =
+ { "tx 512-1023B", KSTAT_KV_U_PACKETS, E1000_PTC1023 },
+ [em_stat_ptc1522] =
+ { "tx 1024-maxB", KSTAT_KV_U_PACKETS, E1000_PTC1522 },
+ [em_stat_mptc] =
+ { "tx mcast", KSTAT_KV_U_PACKETS, E1000_MPTC },
+ [em_stat_bptc] =
+ { "tx bcast", KSTAT_KV_U_PACKETS, E1000_BPTC },
+};
-#ifndef SMALL_KERNEL
/**********************************************************************
*
* Update the board statistics counters.
*
**********************************************************************/
-void
-em_update_stats_counters(struct em_softc *sc)
+int
+em_kstat_read(struct kstat *ks)
{
- struct em_queue *que = sc->queues; /* Use only first queue. */
- struct ifnet *ifp = &sc->sc_ac.ac_if;
- uint64_t colc, rxerrc, crcerrs, algnerrc;
- uint64_t ruc, roc, mpc, cexterr;
- uint64_t ecol, latecol;
-
- crcerrs = E1000_READ_REG(&sc->hw, CRCERRS);
- sc->stats.crcerrs += crcerrs;
- mpc = E1000_READ_REG(&sc->hw, MPC);
- sc->stats.mpc += mpc;
- ecol = E1000_READ_REG(&sc->hw, ECOL);
- sc->stats.ecol += ecol;
-
- latecol = E1000_READ_REG(&sc->hw, LATECOL);
- sc->stats.latecol += latecol;
- colc = E1000_READ_REG(&sc->hw, COLC);
- sc->stats.colc += colc;
-
- ruc = E1000_READ_REG(&sc->hw, RUC);
- sc->stats.ruc += ruc;
- roc = E1000_READ_REG(&sc->hw, ROC);
- sc->stats.roc += roc;
+ struct em_softc *sc = ks->ks_softc;
+ struct em_hw *hw = &sc->hw;
+ struct kstat_kv *kvs = ks->ks_data;
+ uint32_t lo, hi;
+ unsigned int i;
+
+ for (i = 0; i < nitems(em_counters); i++) {
+ const struct em_counter *c = &em_counters[i];
+ if (c->reg == 0)
+ continue;
- algnerrc = rxerrc = cexterr = 0;
- if (sc->hw.mac_type >= em_82543) {
- algnerrc = E1000_READ_REG(&sc->hw, ALGNERRC);
- rxerrc = E1000_READ_REG(&sc->hw, RXERRC);
- cexterr = E1000_READ_REG(&sc->hw, CEXTERR);
- }
- sc->stats.algnerrc += algnerrc;
- sc->stats.rxerrc += rxerrc;
- sc->stats.cexterr += cexterr;
+ kstat_kv_u64(&kvs[i]) += EM_READ_REG(hw,
+ E1000_REG_TR(hw, c->reg)); /* wtf */
+ }
-#ifdef EM_DEBUG
- if (sc->hw.media_type == em_media_type_copper ||
- (E1000_READ_REG(&sc->hw, STATUS) & E1000_STATUS_LU)) {
- sc->stats.symerrs += E1000_READ_REG(&sc->hw, SYMERRS);
- sc->stats.sec += E1000_READ_REG(&sc->hw, SEC);
- }
- sc->stats.scc += E1000_READ_REG(&sc->hw, SCC);
-
- sc->stats.mcc += E1000_READ_REG(&sc->hw, MCC);
- sc->stats.dc += E1000_READ_REG(&sc->hw, DC);
- sc->stats.rlec += E1000_READ_REG(&sc->hw, RLEC);
- sc->stats.xonrxc += E1000_READ_REG(&sc->hw, XONRXC);
- sc->stats.xontxc += E1000_READ_REG(&sc->hw, XONTXC);
- sc->stats.xoffrxc += E1000_READ_REG(&sc->hw, XOFFRXC);
- sc->stats.xofftxc += E1000_READ_REG(&sc->hw, XOFFTXC);
- sc->stats.fcruc += E1000_READ_REG(&sc->hw, FCRUC);
- sc->stats.prc64 += E1000_READ_REG(&sc->hw, PRC64);
- sc->stats.prc127 += E1000_READ_REG(&sc->hw, PRC127);
- sc->stats.prc255 += E1000_READ_REG(&sc->hw, PRC255);
- sc->stats.prc511 += E1000_READ_REG(&sc->hw, PRC511);
- sc->stats.prc1023 += E1000_READ_REG(&sc->hw, PRC1023);
- sc->stats.prc1522 += E1000_READ_REG(&sc->hw, PRC1522);
- sc->stats.gprc += E1000_READ_REG(&sc->hw, GPRC);
- sc->stats.bprc += E1000_READ_REG(&sc->hw, BPRC);
- sc->stats.mprc += E1000_READ_REG(&sc->hw, MPRC);
- sc->stats.gptc += E1000_READ_REG(&sc->hw, GPTC);
+ /* Handle the exceptions. */
+
+ if (sc->hw.mac_type >= em_82543) {
+ kstat_kv_u64(&kvs[em_stat_algnerrc]) +=
+ E1000_READ_REG(hw, ALGNERRC);
+ kstat_kv_u64(&kvs[em_stat_rxerrc]) +=
+ E1000_READ_REG(hw, RXERRC);
+ kstat_kv_u64(&kvs[em_stat_cexterr]) +=
+ E1000_READ_REG(hw, CEXTERR);
+ kstat_kv_u64(&kvs[em_stat_tncrs]) +=
+ E1000_READ_REG(hw, TNCRS);
+#if 0
+ sc->stats.tsctc +=
+ E1000_READ_REG(hw, TSCTC);
+ sc->stats.tsctfc +=
+ E1000_READ_REG(hw, TSCTFC);
+#endif
+ }
/* For the 64-bit byte counters the low dword must be read first. */
/* Both registers clear on the read of the high dword */
- sc->stats.gorcl += E1000_READ_REG(&sc->hw, GORCL);
- sc->stats.gorch += E1000_READ_REG(&sc->hw, GORCH);
- sc->stats.gotcl += E1000_READ_REG(&sc->hw, GOTCL);
- sc->stats.gotch += E1000_READ_REG(&sc->hw, GOTCH);
-
- sc->stats.rnbc += E1000_READ_REG(&sc->hw, RNBC);
- sc->stats.rfc += E1000_READ_REG(&sc->hw, RFC);
- sc->stats.rjc += E1000_READ_REG(&sc->hw, RJC);
-
- sc->stats.torl += E1000_READ_REG(&sc->hw, TORL);
- sc->stats.torh += E1000_READ_REG(&sc->hw, TORH);
- sc->stats.totl += E1000_READ_REG(&sc->hw, TOTL);
- sc->stats.toth += E1000_READ_REG(&sc->hw, TOTH);
-
- sc->stats.tpr += E1000_READ_REG(&sc->hw, TPR);
- sc->stats.tpt += E1000_READ_REG(&sc->hw, TPT);
- sc->stats.ptc64 += E1000_READ_REG(&sc->hw, PTC64);
- sc->stats.ptc127 += E1000_READ_REG(&sc->hw, PTC127);
- sc->stats.ptc255 += E1000_READ_REG(&sc->hw, PTC255);
- sc->stats.ptc511 += E1000_READ_REG(&sc->hw, PTC511);
- sc->stats.ptc1023 += E1000_READ_REG(&sc->hw, PTC1023);
- sc->stats.ptc1522 += E1000_READ_REG(&sc->hw, PTC1522);
- sc->stats.mptc += E1000_READ_REG(&sc->hw, MPTC);
- sc->stats.bptc += E1000_READ_REG(&sc->hw, BPTC);
- sc->stats.sdpc += E1000_READ_REG(&sc->hw, SDPC);
- sc->stats.mngpdc += E1000_READ_REG(&sc->hw, MGTPDC);
- sc->stats.mngprc += E1000_READ_REG(&sc->hw, MGTPRC);
- sc->stats.mngptc += E1000_READ_REG(&sc->hw, MGTPTC);
- sc->stats.b2ospc += E1000_READ_REG(&sc->hw, B2OSPC);
- sc->stats.o2bgptc += E1000_READ_REG(&sc->hw, O2BGPTC);
- sc->stats.b2ogprc += E1000_READ_REG(&sc->hw, B2OGPRC);
- sc->stats.o2bspc += E1000_READ_REG(&sc->hw, O2BSPC);
- sc->stats.rpthc += E1000_READ_REG(&sc->hw, RPTHC);
+ lo = E1000_READ_REG(hw, GORCL);
+ hi = E1000_READ_REG(hw, GORCL);
+ kstat_kv_u64(&kvs[em_stat_gorc]) +=
+ ((uint64_t)hi << 32) | (uint64_t)lo;
+
+ lo = E1000_READ_REG(hw, GOTCL);
+ hi = E1000_READ_REG(hw, GOTCL);
+ kstat_kv_u64(&kvs[em_stat_gotc]) +=
+ ((uint64_t)hi << 32) | (uint64_t)lo;
+
+ lo = E1000_READ_REG(hw, TORL);
+ hi = E1000_READ_REG(hw, TORH);
+ kstat_kv_u64(&kvs[em_stat_tor]) +=
+ ((uint64_t)hi << 32) | (uint64_t)lo;
+
+ lo = E1000_READ_REG(hw, TOTL);
+ hi = E1000_READ_REG(hw, TOTH);
+ kstat_kv_u64(&kvs[em_stat_tot]) +=
+ ((uint64_t)hi << 32) | (uint64_t)lo;
- if (sc->hw.mac_type >= em_82543) {
- sc->stats.tncrs +=
- E1000_READ_REG(&sc->hw, TNCRS);
- sc->stats.tsctc +=
- E1000_READ_REG(&sc->hw, TSCTC);
- sc->stats.tsctfc +=
- E1000_READ_REG(&sc->hw, TSCTFC);
+ getnanouptime(&ks->ks_updated);
+
+ return (0);
+}
+
+void
+em_kstat_attach(struct em_softc *sc)
+{
+ struct kstat *ks;
+ struct kstat_kv *kvs;
+ unsigned int i;
+
+ mtx_init(&sc->kstat_mtx, IPL_SOFTCLOCK);
+
+ ks = kstat_create(DEVNAME(sc), 0, "em-stats", 0,
+ KSTAT_T_KV, 0);
+ if (ks == NULL)
+ return;
+
+ kvs = mallocarray(nitems(em_counters), sizeof(*kvs),
+ M_DEVBUF, M_WAITOK|M_ZERO);
+ for (i = 0; i < nitems(em_counters); i++) {
+ const struct em_counter *c = &em_counters[i];
+ kstat_kv_unit_init(&kvs[i], c->name,
+ KSTAT_KV_T_COUNTER64, c->unit);
}
-#endif
- /* Fill out the OS statistics structure */
- ifp->if_collisions = colc;
+ ks->ks_softc = sc;
+ ks->ks_data = kvs;
+ ks->ks_datalen = nitems(em_counters) * sizeof(*kvs);
+ ks->ks_read = em_kstat_read;
+ kstat_set_mutex(ks, &sc->kstat_mtx);
- /* Rx Errors */
- ifp->if_ierrors =
- que->rx.dropped_pkts +
- rxerrc +
- crcerrs +
- algnerrc +
- ruc +
- roc +
- mpc +
- cexterr +
- sc->rx_overruns;
-
- /* Tx Errors */
- ifp->if_oerrors = ecol + latecol +
- sc->watchdog_events;
+ kstat_install(ks);
}
-#ifdef EM_DEBUG
-/**********************************************************************
- *
- * This routine is called only when IFF_DEBUG is enabled.
- * This routine provides a way to take a look at important statistics
- * maintained by the driver and hardware.
- *
- **********************************************************************/
+/******************************************************************************
+ * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
+ *****************************************************************************/
void
-em_print_hw_stats(struct em_softc *sc)
+em_tbi_adjust_stats(struct em_softc *sc, uint32_t frame_len, uint8_t *mac_addr)
{
- const char * const unit = DEVNAME(sc);
- struct em_queue *que;
+ struct em_hw *hw = &sc->hw;
+ struct kstat *ks = sc->kstat;
+ struct kstat_kv *kvs;
- printf("%s: Excessive collisions = %lld\n", unit,
- (long long)sc->stats.ecol);
- printf("%s: Symbol errors = %lld\n", unit,
- (long long)sc->stats.symerrs);
- printf("%s: Sequence errors = %lld\n", unit,
- (long long)sc->stats.sec);
- printf("%s: Defer count = %lld\n", unit,
- (long long)sc->stats.dc);
-
- printf("%s: Missed Packets = %lld\n", unit,
- (long long)sc->stats.mpc);
- printf("%s: Receive No Buffers = %lld\n", unit,
- (long long)sc->stats.rnbc);
- /* RLEC is inaccurate on some hardware, calculate our own */
- printf("%s: Receive Length Errors = %lld\n", unit,
- ((long long)sc->stats.roc +
- (long long)sc->stats.ruc));
- printf("%s: Receive errors = %lld\n", unit,
- (long long)sc->stats.rxerrc);
- printf("%s: Crc errors = %lld\n", unit,
- (long long)sc->stats.crcerrs);
- printf("%s: Alignment errors = %lld\n", unit,
- (long long)sc->stats.algnerrc);
- printf("%s: Carrier extension errors = %lld\n", unit,
- (long long)sc->stats.cexterr);
-
- printf("%s: RX overruns = %ld\n", unit,
- sc->rx_overruns);
- printf("%s: watchdog timeouts = %ld\n", unit,
- sc->watchdog_events);
-
- printf("%s: XON Rcvd = %lld\n", unit,
- (long long)sc->stats.xonrxc);
- printf("%s: XON Xmtd = %lld\n", unit,
- (long long)sc->stats.xontxc);
- printf("%s: XOFF Rcvd = %lld\n", unit,
- (long long)sc->stats.xoffrxc);
- printf("%s: XOFF Xmtd = %lld\n", unit,
- (long long)sc->stats.xofftxc);
-
- printf("%s: Good Packets Rcvd = %lld\n", unit,
- (long long)sc->stats.gprc);
- printf("%s: Good Packets Xmtd = %lld\n", unit,
- (long long)sc->stats.gptc);
- printf("%s: Switch Drop Packet Count = %lld\n", unit,
- (long long)sc->stats.sdpc);
- printf("%s: Management Packets Dropped Count = %lld\n", unit,
- (long long)sc->stats.mngptc);
- printf("%s: Management Packets Received Count = %lld\n", unit,
- (long long)sc->stats.mngprc);
- printf("%s: Management Packets Transmitted Count = %lld\n", unit,
- (long long)sc->stats.mngptc);
- printf("%s: OS2BMC Packets Sent by MC Count = %lld\n", unit,
- (long long)sc->stats.b2ospc);
- printf("%s: OS2BMC Packets Received by MC Count = %lld\n", unit,
- (long long)sc->stats.o2bgptc);
- printf("%s: OS2BMC Packets Received by Host Count = %lld\n", unit,
- (long long)sc->stats.b2ogprc);
- printf("%s: OS2BMC Packets Transmitted by Host Count = %lld\n", unit,
- (long long)sc->stats.o2bspc);
- printf("%s: Multicast Packets Received Count = %lld\n", unit,
- (long long)sc->stats.mprc);
- printf("%s: Rx Packets to Host Count = %lld\n", unit,
- (long long)sc->stats.rpthc);
- FOREACH_QUEUE(sc, que) {
- printf("%s: Queue %d Good Packets Received = %d\n", unit,
- que->me, E1000_READ_REG(&sc->hw, PQGPRC(que->me)));
+ if (ks == NULL)
+ return;
+
+ /* First adjust the frame length. */
+ frame_len--;
+
+ mtx_enter(&sc->kstat_mtx);
+ kvs = ks->ks_data;
+
+ /*
+ * We need to adjust the statistics counters, since the hardware
+ * counters overcount this packet as a CRC error and undercount the
+ * packet as a good packet
+ */
+
+ /* This packet should not be counted as a CRC error. */
+ kstat_kv_u64(&kvs[em_stat_crcerrs])--;
+ /* This packet does count as a Good Packet Received. */
+ kstat_kv_u64(&kvs[em_stat_gprc])++;
+
+ /* Adjust the Good Octets received counters */
+ kstat_kv_u64(&kvs[em_stat_gorc]) += frame_len;
+
+ /*
+ * Is this a broadcast or multicast? Check broadcast first, since
+ * the test for a multicast frame will test positive on a broadcast
+ * frame.
+ */
+ if (ETHER_IS_BROADCAST(mac_addr)) {
+ /* Broadcast packet */
+ kstat_kv_u64(&kvs[em_stat_bprc])++;
+ } else if (ETHER_IS_MULTICAST(mac_addr)) {
+ /* Multicast packet */
+ kstat_kv_u64(&kvs[em_stat_mprc])++;
}
+
+ if (frame_len == hw->max_frame_size) {
+ /*
+ * In this case, the hardware has overcounted the number of
+ * oversize frames.
+ */
+ kstat_kv_u64(&kvs[em_stat_roc])--;
+ }
+
+ /*
+ * Adjust the bin counters when the extra byte put the frame in the
+ * wrong bin. Remember that the frame_len was adjusted above.
+ */
+ if (frame_len == 64) {
+ kstat_kv_u64(&kvs[em_stat_prc64])++;
+ kstat_kv_u64(&kvs[em_stat_prc127])--;
+ } else if (frame_len == 127) {
+ kstat_kv_u64(&kvs[em_stat_prc127])++;
+ kstat_kv_u64(&kvs[em_stat_prc255])--;
+ } else if (frame_len == 255) {
+ kstat_kv_u64(&kvs[em_stat_prc255])++;
+ kstat_kv_u64(&kvs[em_stat_prc511])--;
+ } else if (frame_len == 511) {
+ kstat_kv_u64(&kvs[em_stat_prc511])++;
+ kstat_kv_u64(&kvs[em_stat_prc1023])--;
+ } else if (frame_len == 1023) {
+ kstat_kv_u64(&kvs[em_stat_prc1023])++;
+ kstat_kv_u64(&kvs[em_stat_prc1522])--;
+ } else if (frame_len == 1522) {
+ kstat_kv_u64(&kvs[em_stat_prc1522])++;
+ }
+
+ mtx_leave(&sc->kstat_mtx);
}
-#endif
+#endif /* NKSTAT > 0 */
+#ifndef SMALL_KERNEL
int
em_allocate_msix(struct em_softc *sc)
{
Index: if_em.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em.h,v
retrieving revision 1.77
diff -u -p -r1.77 if_em.h
--- if_em.h 22 Apr 2020 08:47:11 -0000 1.77
+++ if_em.h 7 Jul 2020 08:48:37 -0000
@@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "bpfilter.h"
#include "vlan.h"
+#include "kstat.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -50,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <sys/socket.h>
#include <sys/timeout.h>
#include <sys/atomic.h>
+#include <sys/kstat.h>
#include <net/if.h>
#include <net/if_media.h>
@@ -439,7 +441,6 @@ struct em_softc {
/* For 82544 PCI-X Workaround */
boolean_t pcix_82544;
- struct em_hw_stats stats;
int msix;
uint32_t msix_linkvec;
@@ -447,6 +448,9 @@ struct em_softc {
uint32_t msix_queuesmask;
int num_queues;
struct em_queue *queues;
+
+ struct kstat *kstat;
+ struct mutex kstat_mtx;
};
#define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
Index: if_em_hw.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_hw.c,v
retrieving revision 1.108
diff -u -p -r1.108 if_em_hw.c
--- if_em_hw.c 22 Apr 2020 08:47:11 -0000 1.108
+++ if_em_hw.c 7 Jul 2020 08:48:37 -0000
@@ -44,6 +44,7 @@
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/socket.h>
+#include <sys/kstat.h>
#include <net/if.h>
#include <net/if_media.h>
@@ -8027,88 +8028,6 @@ em_clear_hw_cntrs(struct em_hw *hw)
temp = E1000_READ_REG(hw, ICTXQMTC);
temp = E1000_READ_REG(hw, ICRXDMTC);
}
-
-#ifndef SMALL_KERNEL
-/******************************************************************************
- * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
- *
- * hw - Struct containing variables accessed by shared code
- * frame_len - The length of the frame in question
- * mac_addr - The Ethernet destination address of the frame in question
- *****************************************************************************/
-void
-em_tbi_adjust_stats(struct em_hw *hw, struct em_hw_stats *stats,
- uint32_t frame_len, uint8_t *mac_addr)
-{
- uint64_t carry_bit;
- /* First adjust the frame length. */
- frame_len--;
- /*
- * We need to adjust the statistics counters, since the hardware
- * counters overcount this packet as a CRC error and undercount the
- * packet as a good packet
- */
- /* This packet should not be counted as a CRC error. */
- stats->crcerrs--;
- /* This packet does count as a Good Packet Received. */
- stats->gprc++;
-
- /* Adjust the Good Octets received counters */
- carry_bit = 0x80000000 & stats->gorcl;
- stats->gorcl += frame_len;
- /*
- * If the high bit of Gorcl (the low 32 bits of the Good Octets
- * Received Count) was one before the addition, AND it is zero after,
- * then we lost the carry out, need to add one to Gorch (Good Octets
- * Received Count High). This could be simplified if all environments
- * supported 64-bit integers.
- */
- if (carry_bit && ((stats->gorcl & 0x80000000) == 0))
- stats->gorch++;
- /*
- * Is this a broadcast or multicast? Check broadcast first, since
- * the test for a multicast frame will test positive on a broadcast
- * frame.
- */
- if ((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
- /* Broadcast packet */
- stats->bprc++;
- else if (*mac_addr & 0x01)
- /* Multicast packet */
- stats->mprc++;
-
- if (frame_len == hw->max_frame_size) {
- /*
- * In this case, the hardware has overcounted the number of
- * oversize frames.
- */
- if (stats->roc > 0)
- stats->roc--;
- }
- /*
- * Adjust the bin counters when the extra byte put the frame in the
- * wrong bin. Remember that the frame_len was adjusted above.
- */
- if (frame_len == 64) {
- stats->prc64++;
- stats->prc127--;
- } else if (frame_len == 127) {
- stats->prc127++;
- stats->prc255--;
- } else if (frame_len == 255) {
- stats->prc255++;
- stats->prc511--;
- } else if (frame_len == 511) {
- stats->prc511++;
- stats->prc1023--;
- } else if (frame_len == 1023) {
- stats->prc1023++;
- stats->prc1522--;
- } else if (frame_len == 1522) {
- stats->prc1522++;
- }
-}
-#endif /* !SMALL_KERNEL */
/******************************************************************************
* Gets the current PCI bus type, speed, and width of the hardware
Index: if_em_hw.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_hw.h,v
retrieving revision 1.82
diff -u -p -r1.82 if_em_hw.h
--- if_em_hw.h 23 Mar 2020 15:02:51 -0000 1.82
+++ if_em_hw.h 7 Jul 2020 08:48:37 -0000
@@ -440,7 +440,6 @@ int32_t em_blink_led_start(struct em_hw
void em_clear_hw_cntrs(struct em_hw *hw);
void em_reset_adaptive(struct em_hw *hw);
void em_update_adaptive(struct em_hw *hw);
-void em_tbi_adjust_stats(struct em_hw *hw, struct em_hw_stats *stats, uint32_t
frame_len, uint8_t *mac_addr);
void em_get_bus_info(struct em_hw *hw);
void em_pci_set_mwi(struct em_hw *hw);
void em_pci_clear_mwi(struct em_hw *hw);