re(4) hardware has some useful counters that are worth looking at:

dlg@router ~$ kstat re-stats 
re0:0:re-stats:0
            TxOk: 12697 packets
            RxOk: 22919 packets
            TxEr: 0 packets
            RxEr: 0 packets
         MissPkt: 0 packets
             FAE: 8371 packets
          Tx1Col: 0 packets
          TxMCol: 0 packets
         RxOkPhy: 22919 packets
         RxOkBrd: 0 packets
         RxOkMul: 0 packets
           TxAbt: 0 packets
         TxUndrn: 0 packets
re1:0:re-stats:0
            TxOk: 27098 packets
            RxOk: 19325 packets
            TxEr: 0 packets
            RxEr: 0 packets
         MissPkt: 20 packets
             FAE: 456 packets
          Tx1Col: 0 packets
          TxMCol: 0 packets
         RxOkPhy: 18340 packets
         RxOkBrd: 471 packets
         RxOkMul: 985 packets
           TxAbt: 0 packets
         TxUndrn: 0 packets

The most interesting (to me) is MissPkt, which shows how many packets
were missed because the rx fifo (ring?) was full.

The diff is bigger that I expected, half because the hardware is dumb,
and half because the driver is... in need of some general improvement.
The code just pushes the counters straight to userland to look at, which
means the 16 bit counters aren't accumulated in any way. If you're
scraping the numbers, you just have to make sure to do it often enough
that you won't miss an interval with them.

jmatthew@ and I have tested it a bit, but I'd like tests on old
boards if possible.

Index: re.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/re.c,v
retrieving revision 1.211
diff -u -p -r1.211 re.c
--- re.c        17 May 2021 11:59:53 -0000      1.211
+++ re.c        22 Apr 2022 00:45:04 -0000
@@ -109,6 +109,7 @@
 
 #include "bpfilter.h"
 #include "vlan.h"
+#include "kstat.h"
 
 #include <sys/param.h>
 #include <sys/endian.h>
@@ -135,6 +136,10 @@
 #include <net/bpf.h>
 #endif
 
+#if NKSTAT > 0
+#include <sys/kstat.h>
+#endif
+
 #include <dev/mii/mii.h>
 #include <dev/mii/miivar.h>
 
@@ -192,6 +197,9 @@ void        re_setup_intr(struct rl_softc *, in
 #ifndef SMALL_KERNEL
 int    re_wol(struct ifnet*, int);
 #endif
+#if NKSTAT > 0
+void   re_kstat_attach(struct rl_softc *);
+#endif
 
 void   in_delayed_cksum(struct mbuf *);
 
@@ -1073,6 +1081,10 @@ re_attach(struct rl_softc *sc, const cha
        if_attach(ifp);
        ether_ifattach(ifp);
 
+#if NKSTAT > 0
+       re_kstat_attach(sc);
+#endif
+
        return (0);
 
 fail_8:
@@ -2378,3 +2390,224 @@ re_wol(struct ifnet *ifp, int enable)
        return (0);
 }
 #endif
+
+#if NKSTAT > 0
+
+#define RE_DTCCR_CMD           (1U << 3)
+#define RE_DTCCR_LO            0x10
+#define RE_DTCCR_HI            0x14
+
+struct re_kstats {
+       struct kstat_kv         tx_ok;
+       struct kstat_kv         rx_ok;
+       struct kstat_kv         tx_er;
+       struct kstat_kv         rx_er;
+       struct kstat_kv         miss_pkt;
+       struct kstat_kv         fae;
+       struct kstat_kv         tx_1col;
+       struct kstat_kv         tx_mcol;
+       struct kstat_kv         rx_ok_phy;
+       struct kstat_kv         rx_ok_brd;
+       struct kstat_kv         rx_ok_mul;
+       struct kstat_kv         tx_abt;
+       struct kstat_kv         tx_undrn;
+};
+
+static const struct re_kstats re_kstats_tpl = {
+       .tx_ok =        KSTAT_KV_UNIT_INITIALIZER("TxOk",
+                           KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
+       .rx_ok =        KSTAT_KV_UNIT_INITIALIZER("RxOk",
+                           KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
+       .tx_er =        KSTAT_KV_UNIT_INITIALIZER("TxEr",
+                           KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
+       .rx_er =        KSTAT_KV_UNIT_INITIALIZER("RxEr",
+                           KSTAT_KV_T_COUNTER32, KSTAT_KV_U_PACKETS),
+       .miss_pkt =     KSTAT_KV_UNIT_INITIALIZER("MissPkt",
+                           KSTAT_KV_T_COUNTER16, KSTAT_KV_U_PACKETS),
+       .fae =          KSTAT_KV_UNIT_INITIALIZER("FAE",
+                           KSTAT_KV_T_COUNTER16, KSTAT_KV_U_PACKETS),
+       .tx_1col =      KSTAT_KV_UNIT_INITIALIZER("Tx1Col",
+                           KSTAT_KV_T_COUNTER32, KSTAT_KV_U_PACKETS),
+       .tx_mcol =      KSTAT_KV_UNIT_INITIALIZER("TxMCol",
+                           KSTAT_KV_T_COUNTER32, KSTAT_KV_U_PACKETS),
+       .rx_ok_phy =    KSTAT_KV_UNIT_INITIALIZER("RxOkPhy",
+                           KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
+       .rx_ok_brd =    KSTAT_KV_UNIT_INITIALIZER("RxOkBrd",
+                           KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
+       .rx_ok_mul =    KSTAT_KV_UNIT_INITIALIZER("RxOkMul",
+                           KSTAT_KV_T_COUNTER32, KSTAT_KV_U_PACKETS),
+       .tx_abt =       KSTAT_KV_UNIT_INITIALIZER("TxAbt",
+                           KSTAT_KV_T_COUNTER16, KSTAT_KV_U_PACKETS),
+       .tx_undrn =     KSTAT_KV_UNIT_INITIALIZER("TxUndrn",
+                           KSTAT_KV_T_COUNTER16, KSTAT_KV_U_PACKETS),
+};
+
+struct re_kstat_softc {
+       struct re_stats         *re_ks_sc_stats;
+
+       bus_dmamap_t             re_ks_sc_map;
+       bus_dma_segment_t        re_ks_sc_seg;
+       int                      re_ks_sc_nsegs;
+
+       struct rwlock            re_ks_sc_rwl;
+};
+
+static int
+re_kstat_read(struct kstat *ks)
+{
+       struct rl_softc *sc = ks->ks_softc;
+       struct re_kstat_softc *re_ks_sc = ks->ks_ptr;
+       bus_dmamap_t map;
+       uint64_t cmd;
+       uint32_t reg;
+       uint8_t command;
+       int tmo;
+
+       command = CSR_READ_1(sc, RL_COMMAND);
+       if (!ISSET(command, RL_CMD_RX_ENB) || command == 0xff)
+               return (ENETDOWN);
+
+       map = re_ks_sc->re_ks_sc_map;
+       cmd = map->dm_segs[0].ds_addr | RE_DTCCR_CMD;
+
+       bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+           BUS_DMASYNC_PREREAD);
+
+       CSR_WRITE_4(sc, RE_DTCCR_HI, cmd >> 32);
+       bus_space_barrier(sc->rl_btag, sc->rl_bhandle, RE_DTCCR_HI, 8,
+           BUS_SPACE_BARRIER_WRITE);
+       CSR_WRITE_4(sc, RE_DTCCR_LO, cmd);
+       bus_space_barrier(sc->rl_btag, sc->rl_bhandle, RE_DTCCR_LO, 4,
+           BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
+       
+       tmo = 1000;
+       do {
+               reg = CSR_READ_4(sc, RE_DTCCR_LO);
+               if (!ISSET(reg, RE_DTCCR_CMD))
+                       break;
+
+               delay(10);
+               bus_space_barrier(sc->rl_btag, sc->rl_bhandle, RE_DTCCR_LO, 4,
+                   BUS_SPACE_BARRIER_READ);
+       } while (--tmo);
+
+       bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+           BUS_DMASYNC_POSTREAD);
+
+       if (ISSET(reg, RE_DTCCR_CMD))
+               return (EIO);
+
+       nanouptime(&ks->ks_updated);
+
+       return (0);
+}
+
+static int
+re_kstat_copy(struct kstat *ks, void *dst)
+{
+       struct re_kstat_softc *re_ks_sc = ks->ks_ptr;
+       struct re_stats *rs = re_ks_sc->re_ks_sc_stats;
+       struct re_kstats *kvs = dst;
+
+       *kvs = re_kstats_tpl;
+       kstat_kv_u64(&kvs->tx_ok) = lemtoh64(&rs->re_tx_ok);
+       kstat_kv_u64(&kvs->rx_ok) = lemtoh64(&rs->re_rx_ok);
+       kstat_kv_u64(&kvs->tx_er) = lemtoh64(&rs->re_tx_er);
+       kstat_kv_u32(&kvs->rx_er) = lemtoh32(&rs->re_rx_er);
+       kstat_kv_u16(&kvs->miss_pkt) = lemtoh16(&rs->re_miss_pkt);
+       kstat_kv_u16(&kvs->fae) = lemtoh16(&rs->re_fae);
+       kstat_kv_u32(&kvs->tx_1col) = lemtoh32(&rs->re_tx_1col);
+       kstat_kv_u32(&kvs->tx_mcol) = lemtoh32(&rs->re_tx_mcol);
+       kstat_kv_u64(&kvs->rx_ok_phy) = lemtoh64(&rs->re_rx_ok_phy);
+       kstat_kv_u64(&kvs->rx_ok_brd) = lemtoh64(&rs->re_rx_ok_brd);
+       kstat_kv_u32(&kvs->rx_ok_mul) = lemtoh64(&rs->re_rx_ok_mul);
+       kstat_kv_u16(&kvs->tx_abt) = lemtoh64(&rs->re_tx_abt);
+       kstat_kv_u16(&kvs->tx_undrn) = lemtoh64(&rs->re_tx_undrn);
+
+       return (0);
+}
+
+void
+re_kstat_attach(struct rl_softc *sc)
+{
+       struct re_kstat_softc *re_ks_sc;
+       struct kstat *ks;
+
+       re_ks_sc = malloc(sizeof(*re_ks_sc), M_DEVBUF, M_NOWAIT);
+       if (re_ks_sc == NULL) {
+               printf("%s: cannot allocate kstat softc\n",
+                   sc->sc_dev.dv_xname);
+               return;
+       }
+
+       if (bus_dmamap_create(sc->sc_dmat, 
+           sizeof(struct re_stats), 1, sizeof(struct re_stats), 0,
+           BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
+           &re_ks_sc->re_ks_sc_map) != 0) {
+               printf("%s: cannot create counter dma memory map\n",
+                   sc->sc_dev.dv_xname);
+               goto free;
+       }
+
+       if (bus_dmamem_alloc(sc->sc_dmat,
+           sizeof(struct re_stats), RE_STATS_ALIGNMENT, 0,
+           &re_ks_sc->re_ks_sc_seg, 1, &re_ks_sc->re_ks_sc_nsegs,
+           BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0) {
+               printf("%s: cannot allocate counter dma memory\n",
+                   sc->sc_dev.dv_xname);
+               goto destroy;
+       }
+
+       if (bus_dmamem_map(sc->sc_dmat,
+           &re_ks_sc->re_ks_sc_seg, re_ks_sc->re_ks_sc_nsegs,
+           sizeof(struct re_stats), (caddr_t *)&re_ks_sc->re_ks_sc_stats,
+           BUS_DMA_NOWAIT) != 0) {
+               printf("%s: cannot map counter dma memory\n",
+                   sc->sc_dev.dv_xname);
+               goto freedma;
+       }
+
+       if (bus_dmamap_load(sc->sc_dmat, re_ks_sc->re_ks_sc_map,
+           (caddr_t)re_ks_sc->re_ks_sc_stats, sizeof(struct re_stats),
+           NULL, BUS_DMA_NOWAIT) != 0) {
+               printf("%s: cannot load counter dma memory\n",
+                   sc->sc_dev.dv_xname);
+               goto unmap;
+       }
+
+       ks = kstat_create(sc->sc_dev.dv_xname, 0, "re-stats", 0,
+           KSTAT_T_KV, 0);
+       if (ks == NULL) {
+               printf("%s: cannot create re-stats kstat\n",
+                   sc->sc_dev.dv_xname);
+               goto unload;
+       }
+
+       ks->ks_datalen = sizeof(re_kstats_tpl);
+
+       rw_init(&re_ks_sc->re_ks_sc_rwl, "restats");
+       kstat_set_wlock(ks, &re_ks_sc->re_ks_sc_rwl);
+       ks->ks_softc = sc;
+       ks->ks_ptr = re_ks_sc;
+       ks->ks_read = re_kstat_read;
+       ks->ks_copy = re_kstat_copy;
+
+       kstat_install(ks);
+
+       sc->rl_kstat = ks;
+
+       return;
+
+unload:
+       bus_dmamap_unload(sc->sc_dmat, re_ks_sc->re_ks_sc_map);
+unmap:
+       bus_dmamem_unmap(sc->sc_dmat,
+           (caddr_t)re_ks_sc->re_ks_sc_stats, sizeof(struct re_stats));
+freedma:
+       bus_dmamem_free(sc->sc_dmat, &re_ks_sc->re_ks_sc_seg, 1);
+destroy:
+       bus_dmamap_destroy(sc->sc_dmat, re_ks_sc->re_ks_sc_map);
+free:
+       free(re_ks_sc, M_DEVBUF, sizeof(*re_ks_sc));
+}
+#endif /* NKSTAT > 0 */
Index: rtl81x9reg.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/rtl81x9reg.h,v
retrieving revision 1.103
diff -u -p -r1.103 rtl81x9reg.h
--- rtl81x9reg.h        9 Jan 2022 05:42:38 -0000       1.103
+++ rtl81x9reg.h        22 Apr 2022 00:45:04 -0000
@@ -690,24 +690,24 @@ struct rl_desc {
 /*
  * Statistics counter structure (8139C+ and 8169 only)
  */
-struct rl_stats {
-       u_int32_t               rl_tx_pkts_lo;
-       u_int32_t               rl_tx_pkts_hi;
-       u_int32_t               rl_tx_errs_lo;
-       u_int32_t               rl_tx_errs_hi;
-       u_int32_t               rl_tx_errs;
-       u_int16_t               rl_missed_pkts;
-       u_int16_t               rl_rx_framealign_errs;
-       u_int32_t               rl_tx_onecoll;
-       u_int32_t               rl_tx_multicolls;
-       u_int32_t               rl_rx_ucasts_hi;
-       u_int32_t               rl_rx_ucasts_lo;
-       u_int32_t               rl_rx_bcasts_lo;
-       u_int32_t               rl_rx_bcasts_hi;
-       u_int32_t               rl_rx_mcasts;
-       u_int16_t               rl_tx_aborts;
-       u_int16_t               rl_rx_underruns;
-};
+
+struct re_stats {
+       uint64_t                re_tx_ok;
+       uint64_t                re_rx_ok;
+       uint64_t                re_tx_er;
+       uint32_t                re_rx_er;
+       uint16_t                re_miss_pkt;
+       uint16_t                re_fae;
+       uint32_t                re_tx_1col;
+       uint32_t                re_tx_mcol;
+       uint64_t                re_rx_ok_phy;
+       uint64_t                re_rx_ok_brd;
+       uint32_t                re_rx_ok_mul;
+       uint16_t                re_tx_abt;
+       uint16_t                re_tx_undrn;
+} __packed __aligned(sizeof(uint64_t));
+
+#define RE_STATS_ALIGNMENT     64
 
 /*
  * Rx/Tx descriptor parameters (8139C+ and 8169 only)
@@ -858,6 +858,8 @@ struct rl_list_data {
        int                     rl_rx_listnseg;
 };
 
+struct kstat;
+
 struct rl_softc {
        struct device           sc_dev;         /* us, as a device */
        void *                  sc_ih;          /* interrupt vectoring */
@@ -930,6 +932,8 @@ struct rl_softc {
 #define        RL_IMTYPE_SIM           1       /* simulated */
 #define        RL_IMTYPE_HW            2       /* hardware based */
        int                     rl_timerintr;
+
+       struct kstat            *rl_kstat;
 };
 
 /*

Reply via email to