diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2020-07-17 02:58:15 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2020-07-17 02:58:15 +0000 |
commit | e631141509a5f73fcd5725b4feb2d55056875dca (patch) | |
tree | d29e5280d1e2bce3acf03fd968a554c1beb938cc /sys | |
parent | 1b54105f6a84816f0d15212caa903c46b79ffa1f (diff) |
add kstats to myx.
myx is unusually minimal, so there's not a lot of information that
the chip provides. the most interesting is the number of packets
the chip drops cos of a lack of space on the rx rings.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pci/if_myx.c | 207 |
1 files changed, 206 insertions, 1 deletions
diff --git a/sys/dev/pci/if_myx.c b/sys/dev/pci/if_myx.c index c2885f88eb7..c155cea092a 100644 --- a/sys/dev/pci/if_myx.c +++ b/sys/dev/pci/if_myx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_myx.c,v 1.109 2020/07/10 13:26:38 patrick Exp $ */ +/* $OpenBSD: if_myx.c,v 1.110 2020/07/17 02:58:14 dlg Exp $ */ /* * Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org> @@ -21,6 +21,7 @@ */ #include "bpfilter.h" +#include "kstat.h" #include <sys/param.h> #include <sys/systm.h> @@ -35,6 +36,7 @@ #include <sys/proc.h> #include <sys/queue.h> #include <sys/rwlock.h> +#include <sys/kstat.h> #include <machine/bus.h> #include <machine/intr.h> @@ -159,6 +161,12 @@ struct myx_softc { volatile u_int8_t sc_linkdown; struct rwlock sc_sff_lock; + +#if NKSTAT > 0 + struct mutex sc_kstat_mtx; + struct timeout sc_kstat_tmo; + struct kstat *sc_kstat; +#endif }; #define MYX_RXSMALL_SIZE MCLBYTES @@ -230,6 +238,12 @@ void myx_tx_free(struct myx_softc *); void myx_refill(void *); +#if NKSTAT > 0 +void myx_kstat_attach(struct myx_softc *); +void myx_kstat_start(struct myx_softc *); +void myx_kstat_stop(struct myx_softc *); +#endif + struct cfdriver myx_cd = { NULL, "myx", DV_IFNET }; @@ -504,6 +518,10 @@ myx_attachhook(struct device *self) goto freecmd; } +#if NKSTAT > 0 + myx_kstat_attach(sc); +#endif + ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_xflags = IFXF_MPSAFE; @@ -1235,6 +1253,10 @@ myx_up(struct myx_softc *sc) SET(ifp->if_flags, IFF_RUNNING); ifq_restart(&ifp->if_snd); +#if NKSTAT > 0 + timeout_add_sec(&sc->sc_kstat_tmo, 1); +#endif + return; empty_rx_ring_big: @@ -1402,6 +1424,11 @@ myx_down(struct myx_softc *sc) myx_tx_empty(sc); myx_tx_free(sc); +#if NKSTAT > 0 + myx_kstat_stop(sc); + sc->sc_sts = NULL; +#endif + /* the sleep shizz above already synced this dmamem */ myx_dmamem_free(sc, &sc->sc_sts_dma); @@ -2063,3 +2090,181 @@ myx_tx_free(struct myx_softc *sc) free(sc->sc_tx_slots, M_DEVBUF, sizeof(*ms) * sc->sc_tx_ring_count); } + +#if NKSTAT > 0 +enum myx_counters { + myx_stat_dropped_pause, + myx_stat_dropped_ucast_filtered, + myx_stat_dropped_bad_crc32, + myx_stat_dropped_bad_phy, + myx_stat_dropped_mcast_filtered, + myx_stat_send_done, + myx_stat_dropped_link_overflow, + myx_stat_dropped_link, + myx_stat_dropped_runt, + myx_stat_dropped_overrun, + myx_stat_dropped_no_small_bufs, + myx_stat_dropped_no_large_bufs, + + myx_ncounters, +}; + +struct myx_counter { + const char *mc_name; + unsigned int mc_offset; +}; + +#define MYX_C_OFF(_f) offsetof(struct myx_status, _f) + +static const struct myx_counter myx_counters[myx_ncounters] = { + { "pause drops", MYX_C_OFF(ms_dropped_pause), }, + { "ucast filtered", MYX_C_OFF(ms_dropped_unicast), }, + { "bad crc32", MYX_C_OFF(ms_dropped_pause), }, + { "bad phy", MYX_C_OFF(ms_dropped_phyerr), }, + { "mcast filtered", MYX_C_OFF(ms_dropped_mcast), }, + { "tx done", MYX_C_OFF(ms_txdonecnt), }, + { "rx discards", MYX_C_OFF(ms_dropped_linkoverflow), }, + { "rx errors", MYX_C_OFF(ms_dropped_linkerror), }, + { "rx undersize", MYX_C_OFF(ms_dropped_runt), }, + { "rx oversize", MYX_C_OFF(ms_dropped_overrun), }, + { "small discards", MYX_C_OFF(ms_dropped_smallbufunderrun), }, + { "large discards", MYX_C_OFF(ms_dropped_bigbufunderrun), }, +}; + +struct myx_kstats { + struct kstat_kv mk_counters[myx_ncounters]; + struct kstat_kv mk_rdma_tags_available; +}; + +struct myx_kstat_cache { + uint32_t mkc_counters[myx_ncounters]; +}; + +struct myx_kstat_state { + struct myx_kstat_cache mks_caches[2]; + unsigned int mks_gen; +}; + +int +myx_kstat_read(struct kstat *ks) +{ + struct myx_softc *sc = ks->ks_softc; + struct myx_kstats *mk = ks->ks_data; + struct myx_kstat_state *mks = ks->ks_ptr; + unsigned int gen = (mks->mks_gen++ & 1); + struct myx_kstat_cache *omkc = &mks->mks_caches[gen]; + struct myx_kstat_cache *nmkc = &mks->mks_caches[!gen]; + unsigned int i = 0; + + volatile struct myx_status *sts = sc->sc_sts; + bus_dmamap_t map = sc->sc_sts_dma.mxm_map; + + if (sc->sc_sts == NULL) + return (0); /* counters are valid, just not updated */ + + getnanouptime(&ks->ks_updated); + + bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, + BUS_DMASYNC_POSTREAD); + for (i = 0; i < myx_ncounters; i++) { + const struct myx_counter *mc = &myx_counters[i]; + nmkc->mkc_counters[i] = + bemtoh32((uint32_t *)((uint8_t *)sts + mc->mc_offset)); + } + + kstat_kv_u32(&mk->mk_rdma_tags_available) = + bemtoh32(&sts->ms_rdmatags_available); + bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, + BUS_DMASYNC_PREREAD); + + for (i = 0; i < myx_ncounters; i++) { + kstat_kv_u64(&mk->mk_counters[i]) += + nmkc->mkc_counters[i] - omkc->mkc_counters[i]; + } + + return (0); +} + +void +myx_kstat_tick(void *arg) +{ + struct myx_softc *sc = arg; + + if (!ISSET(sc->sc_ac.ac_if.if_flags, IFF_RUNNING)) + return; + + timeout_add_sec(&sc->sc_kstat_tmo, 4); + + if (!mtx_enter_try(&sc->sc_kstat_mtx)) + return; + + myx_kstat_read(sc->sc_kstat); + + mtx_leave(&sc->sc_kstat_mtx); +} + +void +myx_kstat_start(struct myx_softc *sc) +{ + if (sc->sc_kstat == NULL) + return; + + myx_kstat_tick(sc); +} + +void +myx_kstat_stop(struct myx_softc *sc) +{ + struct myx_kstat_state *mks; + + if (sc->sc_kstat == NULL) + return; + + timeout_del_barrier(&sc->sc_kstat_tmo); + + mks = sc->sc_kstat->ks_ptr; + + mtx_enter(&sc->sc_kstat_mtx); + memset(mks, 0, sizeof(*mks)); + mtx_leave(&sc->sc_kstat_mtx); +} + +void +myx_kstat_attach(struct myx_softc *sc) +{ + struct kstat *ks; + struct myx_kstats *mk; + struct myx_kstat_state *mks; + unsigned int i; + + mtx_init(&sc->sc_kstat_mtx, IPL_SOFTCLOCK); + timeout_set(&sc->sc_kstat_tmo, myx_kstat_tick, sc); + + ks = kstat_create(DEVNAME(sc), 0, "myx-stats", 0, KSTAT_T_KV, 0); + if (ks == NULL) + return; + + mk = malloc(sizeof(*mk), M_DEVBUF, M_WAITOK|M_ZERO); + for (i = 0; i < myx_ncounters; i++) { + const struct myx_counter *mc = &myx_counters[i]; + + kstat_kv_unit_init(&mk->mk_counters[i], mc->mc_name, + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + } + kstat_kv_init(&mk->mk_rdma_tags_available, "rdma tags free", + KSTAT_KV_T_UINT32); + + mks = malloc(sizeof(*mks), M_DEVBUF, M_WAITOK|M_ZERO); + /* these start at 0 */ + + kstat_set_mutex(ks, &sc->sc_kstat_mtx); + ks->ks_data = mk; + ks->ks_datalen = sizeof(*mk); + ks->ks_read = myx_kstat_read; + ks->ks_ptr = mks; + + ks->ks_softc = sc; + sc->sc_kstat = ks; + kstat_install(ks); +} +#endif /* NKSTAT > 0 */ |