Index: if_mcx.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_mcx.c,v retrieving revision 1.58 diff -u -p -r1.58 if_mcx.c --- if_mcx.c 26 Jun 2020 05:05:42 -0000 1.58 +++ if_mcx.c 26 Jun 2020 09:30:50 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mcx.c,v 1.58 2020/06/26 05:05:42 dlg Exp $ */ +/* $OpenBSD: if_mcx.c,v 1.57 2020/06/26 03:07:10 dlg Exp $ */ /* * Copyright (c) 2017 David Gwynne @@ -19,6 +19,7 @@ #include "bpfilter.h" #include "vlan.h" +#include "kstat.h" #include #include @@ -44,6 +45,10 @@ #include #endif +#if NKSTAT > 0 +#include +#endif + #include #include @@ -430,6 +435,9 @@ struct mcx_reg_pmlp { } __packed __aligned(4); struct mcx_reg_ppcnt { + uint8_t ppcnt_swid; + uint8_t ppcnt_local_port; + uint8_t ppcnt_pnat; uint8_t ppcnt_grp; #define MCX_REG_PPCNT_GRP_IEEE8023 0x00 #define MCX_REG_PPCNT_GRP_RFC2863 0x01 @@ -438,13 +446,10 @@ struct mcx_reg_ppcnt { #define MCX_REG_PPCNT_GRP_PER_PRIO 0x10 #define MCX_REG_PPCNT_GRP_PER_TC 0x11 #define MCX_REG_PPCNT_GRP_PER_RX_BUFFER 0x11 - uint8_t ppcnt_pnat; - uint8_t ppcnt_local_port; - uint8_t ppcnt_swid; - uint8_t ppcnt_prio_tc; - uint8_t ppcnt_reserved1[2]; uint8_t ppcnt_clr; + uint8_t ppcnt_reserved1[2]; + uint8_t ppcnt_prio_tc; #define MCX_REG_PPCNT_CLR (1 << 7) uint8_t ppcnt_counter_set[248]; @@ -453,90 +458,98 @@ CTASSERT(sizeof(struct mcx_reg_ppcnt) == CTASSERT((offsetof(struct mcx_reg_ppcnt, ppcnt_counter_set) % sizeof(uint64_t)) == 0); -struct mcx_ppcnt_ieee8023 { - uint64_t frames_transmitted_ok; - uint64_t frames_received_ok; - uint64_t frame_check_sequence_errors; - uint64_t alignment_errors; - uint64_t octets_transmitted_ok; - uint64_t octets_received_ok; - uint64_t multicast_frames_xmitted_ok; - uint64_t broadcast_frames_xmitted_ok; - uint64_t multicast_frames_received_ok; - uint64_t broadcast_frames_received_ok; - uint64_t in_range_length_errors; - uint64_t out_of_range_length_field; - uint64_t frame_too_long_errors; - uint64_t symbol_error_during_carrier; - uint64_t mac_control_frames_transmitted; - uint64_t mac_control_frames_received; - uint64_t unsupported_opcodes_received; - uint64_t pause_mac_ctrl_frames_received; - uint64_t pause_mac_ctrl_frames_transmitted; +enum mcx_ppcnt_ieee8023 { + frames_transmitted_ok, + frames_received_ok, + frame_check_sequence_errors, + alignment_errors, + octets_transmitted_ok, + octets_received_ok, + multicast_frames_xmitted_ok, + broadcast_frames_xmitted_ok, + multicast_frames_received_ok, + broadcast_frames_received_ok, + in_range_length_errors, + out_of_range_length_field, + frame_too_long_errors, + symbol_error_during_carrier, + mac_control_frames_transmitted, + mac_control_frames_received, + unsupported_opcodes_received, + pause_mac_ctrl_frames_received, + pause_mac_ctrl_frames_transmitted, + + mcx_ppcnt_ieee8023_count }; -CTASSERT(sizeof(struct mcx_ppcnt_ieee8023) == 0x98); +CTASSERT(mcx_ppcnt_ieee8023_count * sizeof(uint64_t) == 0x98); + +enum mcx_ppcnt_rfc2863 { + in_octets, + in_ucast_pkts, + in_discards, + in_errors, + in_unknown_protos, + out_octets, + out_ucast_pkts, + out_discards, + out_errors, + in_multicast_pkts, + in_broadcast_pkts, + out_multicast_pkts, + out_broadcast_pkts, -struct mcx_ppcnt_rfc2863 { - uint64_t in_octets; - uint64_t in_ucast_pkts; - uint64_t in_discards; - uint64_t in_errors; - uint64_t in_unknown_protos; - uint64_t out_octets; - uint64_t out_ucast_pkts; - uint64_t out_discards; - uint64_t out_errors; - uint64_t in_multicast_pkts; - uint64_t in_broadcast_pkts; - uint64_t out_multicast_pkts; - uint64_t out_broadcast_pkts; + mcx_ppcnt_rfc2863_count }; -CTASSERT(sizeof(struct mcx_ppcnt_rfc2863) == 0x68); +CTASSERT(mcx_ppcnt_rfc2863_count * sizeof(uint64_t) == 0x68); -struct mcx_ppcnt_rfc2819 { - uint64_t drop_events; - uint64_t octets; - uint64_t pkts; - uint64_t broadcast_pkts; - uint64_t multicast_pkts; - uint64_t crc_align_errors; - uint64_t undersize_pkts; - uint64_t oversize_pkts; - uint64_t fragments; - uint64_t jabbers; - uint64_t collisions; - uint64_t pkts64octets; - uint64_t pkts65to127octets; - uint64_t pkts128to255octets; - uint64_t pkts256to511octets; - uint64_t pkts512to1023octets; - uint64_t pkts1024to1518octets; - uint64_t pkts1519to2047octets; - uint64_t pkts2048to4095octets; - uint64_t pkts4096to8191octets; - uint64_t pkts8192to10239octets; +enum mcx_ppcnt_rfc2819 { + drop_events, + octets, + pkts, + broadcast_pkts, + multicast_pkts, + crc_align_errors, + undersize_pkts, + oversize_pkts, + fragments, + jabbers, + collisions, + pkts64octets, + pkts65to127octets, + pkts128to255octets, + pkts256to511octets, + pkts512to1023octets, + pkts1024to1518octets, + pkts1519to2047octets, + pkts2048to4095octets, + pkts4096to8191octets, + pkts8192to10239octets, + + mcx_ppcnt_rfc2819_count }; -CTASSERT(sizeof(struct mcx_ppcnt_rfc2819) == 0xa8); +CTASSERT((mcx_ppcnt_rfc2819_count * sizeof(uint64_t)) == 0xa8); + +enum mcx_ppcnt_rfc3635 { + dot3stats_alignment_errors, + dot3stats_fcs_errors, + dot3stats_single_collision_frames, + dot3stats_multiple_collision_frames, + dot3stats_sqe_test_errors, + dot3stats_deferred_transmissions, + dot3stats_late_collisions, + dot3stats_excessive_collisions, + dot3stats_internal_mac_transmit_errors, + dot3stats_carrier_sense_errors, + dot3stats_frame_too_longs, + dot3stats_internal_mac_receive_errors, + dot3stats_symbol_errors, + dot3control_in_unknown_opcodes, + dot3in_pause_frames, + dot3out_pause_frames, -struct mcx_ppcnt_rfc3635 { - uint64_t alignment_errors; - uint64_t fcs_errors; - uint64_t single_collision_frames; - uint64_t multiple_collision_frames; - uint64_t sqe_test_errors; - uint64_t deferred_transmissions; - uint64_t late_collisions; - uint64_t excessive_collisions; - uint64_t internal_mac_transmit_errors; - uint64_t carrier_sense_errors; - uint64_t frame_too_longs; - uint64_t internal_mac_receive_errors; - uint64_t symbol_errors; - uint64_t control_in_unknown_opcodes; - uint64_t control_in_pause_frames; - uint64_t control_out_pause_frames; + mcx_ppcnt_rfc3635_count }; -CTASSERT(sizeof(struct mcx_ppcnt_rfc3635) == 0x80); +CTASSERT((mcx_ppcnt_rfc3635_count * sizeof(uint64_t)) == 0x80); #define MCX_MCIA_EEPROM_BYTES 32 struct mcx_reg_mcia { @@ -2124,12 +2137,23 @@ struct mcx_softc { unsigned int sc_nqueues; int sc_num_cq; + +#if NKSTAT > 0 + struct kstat *sc_kstat_ieee8023; + struct kstat *sc_kstat_rfc2863; + struct kstat *sc_kstat_rfc2819; + struct kstat *sc_kstat_rfc3635; +#endif }; #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) static int mcx_match(struct device *, void *, void *); static void mcx_attach(struct device *, struct device *, void *); +#if NKSTAT > 0 +static void mcx_kstat_attach(struct mcx_softc *); +#endif + static int mcx_version(struct mcx_softc *); static int mcx_init_wait(struct mcx_softc *); static int mcx_enable_hca(struct mcx_softc *); @@ -2568,6 +2592,10 @@ mcx_attach(struct device *parent, struct } sc->sc_extra_mcast = 0; memset(sc->sc_mcast_flows, 0, sizeof(sc->sc_mcast_flows)); + +#if NKSTAT > 0 + mcx_kstat_attach(sc); +#endif return; teardown: @@ -7130,3 +7158,318 @@ mcx_hwmem_free(struct mcx_softc *sc, str mhm->mhm_npages = 0; } + +#if NKSTAT > 0 +static const struct kstat_kv mcx_kstat_ieee8023_tpl[] = { + KSTAT_KV_UNIT_INITIALIZER("Good Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Good Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("FCS Errs", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Alignment Errs", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Good Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES), + KSTAT_KV_UNIT_INITIALIZER("Good Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES), + KSTAT_KV_UNIT_INITIALIZER("Multicast Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Broadcast Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Multicast Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Broadcast Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("In Range Len", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Out Of Range Len", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Frame Too Long", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Symbol Errs", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("MAC Ctrl Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("MAC Ctrl Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("MAC Ctrl Unsup", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Pause Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Pause Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), +}; +CTASSERT(nitems(mcx_kstat_ieee8023_tpl) == mcx_ppcnt_ieee8023_count); + +static const struct kstat_kv mcx_kstat_rfc2863_tpl[] = { + KSTAT_KV_UNIT_INITIALIZER("Rx Bytes", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES), + KSTAT_KV_UNIT_INITIALIZER("Rx Unicast", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Rx Discards", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Rx Errors", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Rx Unknown Proto", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Tx Bytes", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES), + KSTAT_KV_UNIT_INITIALIZER("Tx Unicast", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Tx Discards", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Tx Errors", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Rx Multicast", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Rx Broadcast", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Tx Multicast", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Tx Broadcast", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), +}; +CTASSERT(nitems(mcx_kstat_rfc2863_tpl) == mcx_ppcnt_rfc2863_count); + +static const struct kstat_kv mcx_kstat_rfc2819_tpl[] = { + KSTAT_KV_UNIT_INITIALIZER("Drop Events", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Octets", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES), + KSTAT_KV_UNIT_INITIALIZER("Packets", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Broadcasts", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Multicasts", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("CRC Align Errs", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Undersize", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Oversize", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Fragments", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Jabbers", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Collisions", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_NONE), + KSTAT_KV_UNIT_INITIALIZER("64B", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("65-127B", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("128-255B", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("256-511B", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("512-1023B", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("1024-1518B", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("1519-2047B", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("2048-4095B", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("4096-8191B", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("8192-10239B", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), +}; +CTASSERT(nitems(mcx_kstat_rfc2819_tpl) == mcx_ppcnt_rfc2819_count); + +static const struct kstat_kv mcx_kstat_rfc3635_tpl[] = { + KSTAT_KV_UNIT_INITIALIZER("Alignment Errs", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("FCS Errs", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Single Colls", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Multiple Colls", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("SQE Test Errs", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_NONE), + KSTAT_KV_UNIT_INITIALIZER("Deferred Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Late Colls", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_NONE), + KSTAT_KV_UNIT_INITIALIZER("Exess Colls", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_NONE), + KSTAT_KV_UNIT_INITIALIZER("Int MAC Tx Errs", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("CSM Sense Errs", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_NONE), + KSTAT_KV_UNIT_INITIALIZER("Too Long", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Int MAC Rx Errs", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Symbol Errs", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_NONE), + KSTAT_KV_UNIT_INITIALIZER("Unknown Control", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Pause Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), + KSTAT_KV_UNIT_INITIALIZER("Pause Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), +}; +CTASSERT(nitems(mcx_kstat_rfc3635_tpl) == mcx_ppcnt_rfc3635_count); + +struct mcx_kstat_ppcnt { + const struct kstat_kv *ksp_tpl; + unsigned int ksp_n; + uint8_t ksp_grp; +}; + +static const struct mcx_kstat_ppcnt mcx_kstat_ppcnt_ieee8023 = { + .ksp_tpl = mcx_kstat_ieee8023_tpl, + .ksp_n = nitems(mcx_kstat_ieee8023_tpl), + .ksp_grp = MCX_REG_PPCNT_GRP_IEEE8023, +}; + +static const struct mcx_kstat_ppcnt mcx_kstat_ppcnt_rfc2863 = { + .ksp_tpl = mcx_kstat_rfc2863_tpl, + .ksp_n = nitems(mcx_kstat_rfc2863_tpl), + .ksp_grp = MCX_REG_PPCNT_GRP_RFC2863, +}; + +static const struct mcx_kstat_ppcnt mcx_kstat_ppcnt_rfc2819 = { + .ksp_tpl = mcx_kstat_rfc2819_tpl, + .ksp_n = nitems(mcx_kstat_rfc2819_tpl), + .ksp_grp = MCX_REG_PPCNT_GRP_RFC2819, +}; + +static const struct mcx_kstat_ppcnt mcx_kstat_ppcnt_rfc3635 = { + .ksp_tpl = mcx_kstat_rfc3635_tpl, + .ksp_n = nitems(mcx_kstat_rfc3635_tpl), + .ksp_grp = MCX_REG_PPCNT_GRP_RFC3635, +}; + +static int mcx_kstat_ppcnt_read(struct kstat *); +static int mcx_kstat_ppcnt_copy(struct kstat *, void *); + +static void +mcx_kstat_attach(struct mcx_softc *sc) +{ + struct kstat *ks; + + ks = kstat_create(DEVNAME(sc), 0, "ieee802.3", 0, KSTAT_T_KV, 0); + if (ks != NULL) { + /* keep counters in between read and copy */ + ks->ks_data = mallocarray(mcx_kstat_ppcnt_ieee8023.ksp_n, + sizeof(uint64_t), M_DEVBUF, M_WAITOK); + + /* but the template models what we want to copy out */ + ks->ks_datalen = sizeof(mcx_kstat_ieee8023_tpl); + + + ks->ks_softc = sc; + ks->ks_ptr = (void *)&mcx_kstat_ppcnt_ieee8023; + ks->ks_read = mcx_kstat_ppcnt_read; + ks->ks_copy = mcx_kstat_ppcnt_copy; + + kstat_install(ks); + sc->sc_kstat_ieee8023 = ks; + } + + ks = kstat_create(DEVNAME(sc), 0, "rfc2863", 0, KSTAT_T_KV, 0); + if (ks != NULL) { + /* keep counters in between read and copy */ + ks->ks_data = mallocarray(mcx_kstat_ppcnt_rfc2863.ksp_n, + sizeof(uint64_t), M_DEVBUF, M_WAITOK); + + /* but the template models what we want to copy out */ + ks->ks_datalen = sizeof(mcx_kstat_rfc2863_tpl); + + + ks->ks_softc = sc; + ks->ks_ptr = (void *)&mcx_kstat_ppcnt_rfc2863; + ks->ks_read = mcx_kstat_ppcnt_read; + ks->ks_copy = mcx_kstat_ppcnt_copy; + + kstat_install(ks); + sc->sc_kstat_rfc2863 = ks; + } + + ks = kstat_create(DEVNAME(sc), 0, "rfc2819", 0, KSTAT_T_KV, 0); + if (ks != NULL) { + /* keep counters in between read and copy */ + ks->ks_data = mallocarray(mcx_kstat_ppcnt_rfc2819.ksp_n, + sizeof(uint64_t), M_DEVBUF, M_WAITOK); + + /* but the template models what we want to copy out */ + ks->ks_datalen = sizeof(mcx_kstat_rfc2819_tpl); + + + ks->ks_softc = sc; + ks->ks_ptr = (void *)&mcx_kstat_ppcnt_rfc2819; + ks->ks_read = mcx_kstat_ppcnt_read; + ks->ks_copy = mcx_kstat_ppcnt_copy; + + kstat_install(ks); + sc->sc_kstat_rfc2819 = ks; + } + + ks = kstat_create(DEVNAME(sc), 0, "rfc3635", 0, KSTAT_T_KV, 0); + if (ks != NULL) { + /* keep counters in between read and copy */ + ks->ks_data = mallocarray(mcx_kstat_ppcnt_rfc3635.ksp_n, + sizeof(uint64_t), M_DEVBUF, M_WAITOK); + + /* but the template models what we want to copy out */ + ks->ks_datalen = sizeof(mcx_kstat_rfc3635_tpl); + + + ks->ks_softc = sc; + ks->ks_ptr = (void *)&mcx_kstat_ppcnt_rfc3635; + ks->ks_read = mcx_kstat_ppcnt_read; + ks->ks_copy = mcx_kstat_ppcnt_copy; + + kstat_install(ks); + sc->sc_kstat_rfc3635 = ks; + } +} + +static int +mcx_kstat_ppcnt_read(struct kstat *ks) +{ + struct mcx_softc *sc = ks->ks_softc; + struct mcx_kstat_ppcnt *ksp = ks->ks_ptr; + struct mcx_reg_ppcnt ppcnt = { + .ppcnt_grp = ksp->ksp_grp, + .ppcnt_local_port = 1, + }; + int rv; + + KERNEL_LOCK(); /* XXX */ + rv = mcx_access_hca_reg(sc, MCX_REG_PPCNT, MCX_REG_OP_READ, + &ppcnt, sizeof(ppcnt)); + KERNEL_UNLOCK(); + if (rv != 0) + return (EIO); + + memcpy(ks->ks_data, ppcnt.ppcnt_counter_set, + ksp->ksp_n * sizeof(uint64_t)); + + nanouptime(&ks->ks_updated); + + return (0); +} + +static int +mcx_kstat_ppcnt_copy(struct kstat *ks, void *dst) +{ + struct mcx_kstat_ppcnt *ksp = ks->ks_ptr; + struct kstat_kv *kvs = dst; + struct kstat_kv *kv; + uint64_t *vs = ks->ks_data; + unsigned int i; + + for (i = 0; i < ksp->ksp_n; i++) { + kv = &kvs[i]; + *kv = ksp->ksp_tpl[i]; + kstat_kv_u64(kv) = bemtoh64(&vs[i]); + } + + return (0); +} +#endif /* NKSTAT > 0 */