port the kstat code from re(4) to rge(4)
authordlg <dlg@openbsd.org>
Sun, 20 Nov 2022 23:47:51 +0000 (23:47 +0000)
committerdlg <dlg@openbsd.org>
Sun, 20 Nov 2022 23:47:51 +0000 (23:47 +0000)
this bit of the hardware works the same, so it's straightforward work.

ok jmatthew@

sys/dev/pci/if_rge.c
sys/dev/pci/if_rgereg.h

index 0a33920..c16ad52 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_rge.c,v 1.19 2022/04/21 05:08:39 kevlo Exp $       */
+/*     $OpenBSD: if_rge.c,v 1.20 2022/11/20 23:47:51 dlg Exp $ */
 
 /*
  * Copyright (c) 2019, 2020 Kevin Lo <kevlo@openbsd.org>
@@ -18,6 +18,7 @@
 
 #include "bpfilter.h"
 #include "vlan.h"
+#include "kstat.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <net/bpf.h>
 #endif
 
+#if NKSTAT > 0
+#include <sys/kstat.h>
+#endif
+
 #include <machine/bus.h>
 #include <machine/intr.h>
 
@@ -117,6 +122,10 @@ int                rge_wol(struct ifnet *, int);
 void           rge_wol_power(struct rge_softc *);
 #endif
 
+#if NKSTAT > 0
+void           rge_kstat_attach(struct rge_softc *);
+#endif
+
 static const struct {
        uint16_t reg;
        uint16_t val;
@@ -307,6 +316,10 @@ rge_attach(struct device *parent, struct device *self, void *aux)
 
        if_attach(ifp);
        ether_ifattach(ifp);
+
+#if NKSTAT > 0
+       rge_kstat_attach(sc);
+#endif
 }
 
 int
@@ -2462,3 +2475,224 @@ rge_wol_power(struct rge_softc *sc)
        RGE_SETBIT_1(sc, RGE_CFG2, RGE_CFG2_PMSTS_EN);
 }
 #endif
+
+#if NKSTAT > 0
+
+#define RGE_DTCCR_CMD          (1U << 3)
+#define RGE_DTCCR_LO           0x10
+#define RGE_DTCCR_HI           0x14
+
+struct rge_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 rge_kstats rge_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 rge_kstat_softc {
+       struct rge_stats        *rge_ks_sc_stats;
+
+       bus_dmamap_t             rge_ks_sc_map;
+       bus_dma_segment_t        rge_ks_sc_seg;
+       int                      rge_ks_sc_nsegs;
+
+       struct rwlock            rge_ks_sc_rwl;
+};
+
+static int
+rge_kstat_read(struct kstat *ks)
+{
+       struct rge_softc *sc = ks->ks_softc;
+       struct rge_kstat_softc *rge_ks_sc = ks->ks_ptr;
+       bus_dmamap_t map;
+       uint64_t cmd;
+       uint32_t reg;
+       uint8_t command;
+       int tmo;
+
+       command = RGE_READ_1(sc, RGE_CMD);
+       if (!ISSET(command, RGE_CMD_RXENB) || command == 0xff)
+               return (ENETDOWN);
+
+       map = rge_ks_sc->rge_ks_sc_map;
+       cmd = map->dm_segs[0].ds_addr | RGE_DTCCR_CMD;
+
+       bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+           BUS_DMASYNC_PREREAD);
+
+       RGE_WRITE_4(sc, RGE_DTCCR_HI, cmd >> 32);
+       bus_space_barrier(sc->rge_btag, sc->rge_bhandle, RGE_DTCCR_HI, 8,
+           BUS_SPACE_BARRIER_WRITE);
+       RGE_WRITE_4(sc, RGE_DTCCR_LO, cmd);
+       bus_space_barrier(sc->rge_btag, sc->rge_bhandle, RGE_DTCCR_LO, 4,
+           BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
+
+       tmo = 1000;
+       do {
+               reg = RGE_READ_4(sc, RGE_DTCCR_LO);
+               if (!ISSET(reg, RGE_DTCCR_CMD))
+                       break;
+
+               delay(10);
+               bus_space_barrier(sc->rge_btag, sc->rge_bhandle,
+                   RGE_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, RGE_DTCCR_CMD))
+               return (EIO);
+
+       nanouptime(&ks->ks_updated);
+
+       return (0);
+}
+
+static int
+rge_kstat_copy(struct kstat *ks, void *dst)
+{
+       struct rge_kstat_softc *rge_ks_sc = ks->ks_ptr;
+       struct rge_stats *rs = rge_ks_sc->rge_ks_sc_stats;
+       struct rge_kstats *kvs = dst;
+
+       *kvs = rge_kstats_tpl;
+       kstat_kv_u64(&kvs->tx_ok) = lemtoh64(&rs->rge_tx_ok);
+       kstat_kv_u64(&kvs->rx_ok) = lemtoh64(&rs->rge_rx_ok);
+       kstat_kv_u64(&kvs->tx_er) = lemtoh64(&rs->rge_tx_er);
+       kstat_kv_u32(&kvs->rx_er) = lemtoh32(&rs->rge_rx_er);
+       kstat_kv_u16(&kvs->miss_pkt) = lemtoh16(&rs->rge_miss_pkt);
+       kstat_kv_u16(&kvs->fae) = lemtoh16(&rs->rge_fae);
+       kstat_kv_u32(&kvs->tx_1col) = lemtoh32(&rs->rge_tx_1col);
+       kstat_kv_u32(&kvs->tx_mcol) = lemtoh32(&rs->rge_tx_mcol);
+       kstat_kv_u64(&kvs->rx_ok_phy) = lemtoh64(&rs->rge_rx_ok_phy);
+       kstat_kv_u64(&kvs->rx_ok_brd) = lemtoh64(&rs->rge_rx_ok_brd);
+       kstat_kv_u32(&kvs->rx_ok_mul) = lemtoh32(&rs->rge_rx_ok_mul);
+       kstat_kv_u16(&kvs->tx_abt) = lemtoh16(&rs->rge_tx_abt);
+       kstat_kv_u16(&kvs->tx_undrn) = lemtoh16(&rs->rge_tx_undrn);
+
+       return (0);
+}
+
+void
+rge_kstat_attach(struct rge_softc *sc)
+{
+       struct rge_kstat_softc *rge_ks_sc;
+       struct kstat *ks;
+
+       rge_ks_sc = malloc(sizeof(*rge_ks_sc), M_DEVBUF, M_NOWAIT);
+       if (rge_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 rge_stats), 1, sizeof(struct rge_stats), 0,
+           BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
+           &rge_ks_sc->rge_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 rge_stats), RGE_STATS_ALIGNMENT, 0,
+           &rge_ks_sc->rge_ks_sc_seg, 1, &rge_ks_sc->rge_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,
+           &rge_ks_sc->rge_ks_sc_seg, rge_ks_sc->rge_ks_sc_nsegs,
+           sizeof(struct rge_stats), (caddr_t *)&rge_ks_sc->rge_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, rge_ks_sc->rge_ks_sc_map,
+           (caddr_t)rge_ks_sc->rge_ks_sc_stats, sizeof(struct rge_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(rge_kstats_tpl);
+
+       rw_init(&rge_ks_sc->rge_ks_sc_rwl, "rgestats");
+       kstat_set_wlock(ks, &rge_ks_sc->rge_ks_sc_rwl);
+       ks->ks_softc = sc;
+       ks->ks_ptr = rge_ks_sc;
+       ks->ks_read = rge_kstat_read;
+       ks->ks_copy = rge_kstat_copy;
+
+       kstat_install(ks);
+
+       sc->sc_kstat = ks;
+
+       return;
+
+unload:
+       bus_dmamap_unload(sc->sc_dmat, rge_ks_sc->rge_ks_sc_map);
+unmap:
+       bus_dmamem_unmap(sc->sc_dmat,
+           (caddr_t)rge_ks_sc->rge_ks_sc_stats, sizeof(struct rge_stats));
+freedma:
+       bus_dmamem_free(sc->sc_dmat, &rge_ks_sc->rge_ks_sc_seg, 1);
+destroy:
+       bus_dmamap_destroy(sc->sc_dmat, rge_ks_sc->rge_ks_sc_map);
+free:
+       free(rge_ks_sc, M_DEVBUF, sizeof(*rge_ks_sc));
+}
+#endif /* NKSTAT > 0 */
index c9b21bc..42709eb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_rgereg.h,v 1.7 2021/03/30 00:55:08 kevlo Exp $     */
+/*     $OpenBSD: if_rgereg.h,v 1.8 2022/11/20 23:47:51 dlg Exp $       */
 
 /*
  * Copyright (c) 2019, 2020 Kevin Lo <kevlo@openbsd.org>
@@ -242,6 +242,27 @@ struct rge_rx_desc {
 #define RGE_RDEXTSTS_IPV4      0x40000000
 #define RGE_RDEXTSTS_IPV6      0x80000000
 
+ /*
+  * Statistics counter structure
+  */
+struct rge_stats {
+       uint64_t                rge_tx_ok;
+       uint64_t                rge_rx_ok;
+       uint64_t                rge_tx_er;
+       uint32_t                rge_rx_er;
+       uint16_t                rge_miss_pkt;
+       uint16_t                rge_fae;
+       uint32_t                rge_tx_1col;
+       uint32_t                rge_tx_mcol;
+       uint64_t                rge_rx_ok_phy;
+       uint64_t                rge_rx_ok_brd;
+       uint32_t                rge_rx_ok_mul;
+       uint16_t                rge_tx_abt;
+       uint16_t                rge_tx_undrn;
+} __packed __aligned(sizeof(uint64_t));
+
+#define RGE_STATS_ALIGNMENT    64
+
 struct rge_txq {
        struct mbuf             *txq_mbuf;
        bus_dmamap_t            txq_dmamap;
@@ -313,6 +334,8 @@ enum rge_mac_type {
 #define RGE_TXCFG_CONFIG       0x03000700
 #define RGE_RXCFG_CONFIG       0x40c00700
 
+struct kstat;
+
 struct rge_softc {
        struct device           sc_dev;
        struct arpcom           sc_arpcom;      /* Ethernet common data */
@@ -341,6 +364,8 @@ struct rge_softc {
        int                     rge_timerintr;
 #define RGE_IMTYPE_NONE                0
 #define RGE_IMTYPE_SIM         1
+
+       struct kstat            *sc_kstat;
 };
 
 /*