diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2020-07-07 04:42:36 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2020-07-07 04:42:36 +0000 |
commit | 4e27bf411c9c56d5ffb8174ed592412ffb91f1c9 (patch) | |
tree | 26247668380b056b462bed1919296386f5a92b9b /sys/dev | |
parent | f791f099684704cbfc4c303d96c592cf6a1be130 (diff) |
add kstat support for some of the counters the chip maintains.
mcx keeps a bunch of different counters relating to the port. this
diff adds support for reading them off the hardware and then unpacking
them into kstat_kv structs for userland to look at.
jmatthew@ checked over it.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_mcx.c | 564 |
1 files changed, 479 insertions, 85 deletions
diff --git a/sys/dev/pci/if_mcx.c b/sys/dev/pci/if_mcx.c index c639ccb0baf..55210050d72 100644 --- a/sys/dev/pci/if_mcx.c +++ b/sys/dev/pci/if_mcx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mcx.c,v 1.59 2020/06/30 04:39:46 jmatthew Exp $ */ +/* $OpenBSD: if_mcx.c,v 1.60 2020/07/07 04:42:35 dlg Exp $ */ /* * Copyright (c) 2017 David Gwynne <dlg@openbsd.org> @@ -19,6 +19,7 @@ #include "bpfilter.h" #include "vlan.h" +#include "kstat.h" #include <sys/param.h> #include <sys/systm.h> @@ -44,6 +45,10 @@ #include <net/bpf.h> #endif +#if NKSTAT > 0 +#include <sys/kstat.h> +#endif + #include <netinet/in.h> #include <netinet/if_ether.h> @@ -142,6 +147,8 @@ CTASSERT(ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN == MCX_SQ_INLINE_SIZE); #define MCX_REG_PAOS 0x5006 #define MCX_REG_PFCC 0x5007 #define MCX_REG_PPCNT 0x5008 +#define MCX_REG_MTCAP 0x9009 /* mgmt temp capabilities */ +#define MCX_REG_MTMP 0x900a /* mgmt temp */ #define MCX_REG_MCIA 0x9014 #define MCX_ETHER_CAP_SGMII 0 @@ -430,6 +437,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 +448,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 +460,134 @@ CTASSERT(sizeof(struct mcx_reg_ppcnt) == 256); 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(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, + + mcx_ppcnt_rfc2863_count +}; +CTASSERT(mcx_ppcnt_rfc2863_count * sizeof(uint64_t) == 0x68); + +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_ieee8023) == 0x98); - -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; +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, + + mcx_ppcnt_rfc3635_count }; -CTASSERT(sizeof(struct mcx_ppcnt_rfc2863) == 0x68); +CTASSERT((mcx_ppcnt_rfc3635_count * sizeof(uint64_t)) == 0x80); -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; +struct mcx_reg_mtcap { + uint8_t _reserved1[3]; + uint8_t mtcap_sensor_count; + uint8_t _reserved2[4]; + + uint64_t mtcap_sensor_map; }; -CTASSERT(sizeof(struct mcx_ppcnt_rfc2819) == 0xa8); - -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; + +struct mcx_reg_mtmp { + uint8_t _reserved1[2]; + uint16_t mtmp_sensor_index; + + uint8_t _reserved2[2]; + uint16_t mtmp_temperature; + + uint16_t mtmp_mte_mtr; +#define MCX_REG_MTMP_MTE (1 << 15) +#define MCX_REG_MTMP_MTR (1 << 14) + uint16_t mtmp_max_temperature; + + uint16_t mtmp_tee; +#define MCX_REG_MTMP_TEE_NOPE (0 << 14) +#define MCX_REG_MTMP_TEE_GENERATE (1 << 14) +#define MCX_REG_MTMP_TEE_GENERATE_ONE (2 << 14) + uint16_t mtmp_temperature_threshold_hi; + + uint8_t _reserved3[2]; + uint16_t mtmp_temperature_threshold_lo; + + uint8_t _reserved4[4]; + + uint8_t mtmp_sensor_name[8]; }; -CTASSERT(sizeof(struct mcx_ppcnt_rfc3635) == 0x80); +CTASSERT(sizeof(struct mcx_reg_mtmp) == 0x20); +CTASSERT(offsetof(struct mcx_reg_mtmp, mtmp_sensor_name) == 0x18); #define MCX_MCIA_EEPROM_BYTES 32 struct mcx_reg_mcia { @@ -2124,12 +2175,25 @@ 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; + unsigned int sc_kstat_mtmp_count; + struct kstat **sc_kstat_mtmp; +#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 *); @@ -2569,6 +2633,10 @@ mcx_attach(struct device *parent, struct device *self, void *aux) } 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: @@ -7131,3 +7199,329 @@ mcx_hwmem_free(struct mcx_softc *sc, struct mcx_hwmem *mhm) mhm->mhm_npages = 0; } + +#if NKSTAT > 0 +struct mcx_ppcnt { + const char *name; + enum kstat_kv_unit unit; +}; + +static const struct mcx_ppcnt mcx_ppcnt_ieee8023_tpl[] = { + { "Good Tx", KSTAT_KV_U_PACKETS, }, + { "Good Rx", KSTAT_KV_U_PACKETS, }, + { "FCS errs", KSTAT_KV_U_PACKETS, }, + { "Alignment Errs", KSTAT_KV_U_PACKETS, }, + { "Good Tx", KSTAT_KV_U_BYTES, }, + { "Good Rx", KSTAT_KV_U_BYTES, }, + { "Multicast Tx", KSTAT_KV_U_PACKETS, }, + { "Broadcast Tx", KSTAT_KV_U_PACKETS, }, + { "Multicast Rx", KSTAT_KV_U_PACKETS, }, + { "Broadcast Rx", KSTAT_KV_U_PACKETS, }, + { "In Range Len", KSTAT_KV_U_PACKETS, }, + { "Out Of Range Len", KSTAT_KV_U_PACKETS, }, + { "Frame Too Long", KSTAT_KV_U_PACKETS, }, + { "Symbol Errs", KSTAT_KV_U_PACKETS, }, + { "MAC Ctrl Tx", KSTAT_KV_U_PACKETS, }, + { "MAC Ctrl Rx", KSTAT_KV_U_PACKETS, }, + { "MAC Ctrl Unsup", KSTAT_KV_U_PACKETS, }, + { "Pause Rx", KSTAT_KV_U_PACKETS, }, + { "Pause Tx", KSTAT_KV_U_PACKETS, }, +}; +CTASSERT(nitems(mcx_ppcnt_ieee8023_tpl) == mcx_ppcnt_ieee8023_count); + +static const struct mcx_ppcnt mcx_ppcnt_rfc2863_tpl[] = { + { "Rx Bytes", KSTAT_KV_U_BYTES, }, + { "Rx Unicast", KSTAT_KV_U_PACKETS, }, + { "Rx Discards", KSTAT_KV_U_PACKETS, }, + { "Rx Errors", KSTAT_KV_U_PACKETS, }, + { "Rx Unknown Proto", KSTAT_KV_U_PACKETS, }, + { "Tx Bytes", KSTAT_KV_U_BYTES, }, + { "Tx Unicast", KSTAT_KV_U_PACKETS, }, + { "Tx Discards", KSTAT_KV_U_PACKETS, }, + { "Tx Errors", KSTAT_KV_U_PACKETS, }, + { "Rx Multicast", KSTAT_KV_U_PACKETS, }, + { "Rx Broadcast", KSTAT_KV_U_PACKETS, }, + { "Tx Multicast", KSTAT_KV_U_PACKETS, }, + { "Tx Broadcast", KSTAT_KV_U_PACKETS, }, +}; +CTASSERT(nitems(mcx_ppcnt_rfc2863_tpl) == mcx_ppcnt_rfc2863_count); + +static const struct mcx_ppcnt mcx_ppcnt_rfc2819_tpl[] = { + { "Drop Events", KSTAT_KV_U_PACKETS, }, + { "Octets", KSTAT_KV_U_BYTES, }, + { "Packets", KSTAT_KV_U_PACKETS, }, + { "Broadcasts", KSTAT_KV_U_PACKETS, }, + { "Multicasts", KSTAT_KV_U_PACKETS, }, + { "CRC Align Errs", KSTAT_KV_U_PACKETS, }, + { "Undersize", KSTAT_KV_U_PACKETS, }, + { "Oversize", KSTAT_KV_U_PACKETS, }, + { "Fragments", KSTAT_KV_U_PACKETS, }, + { "Jabbers", KSTAT_KV_U_PACKETS, }, + { "Collisions", KSTAT_KV_U_NONE, }, + { "64B", KSTAT_KV_U_PACKETS, }, + { "65-127B", KSTAT_KV_U_PACKETS, }, + { "128-255B", KSTAT_KV_U_PACKETS, }, + { "256-511B", KSTAT_KV_U_PACKETS, }, + { "512-1023B", KSTAT_KV_U_PACKETS, }, + { "1024-1518B", KSTAT_KV_U_PACKETS, }, + { "1519-2047B", KSTAT_KV_U_PACKETS, }, + { "2048-4095B", KSTAT_KV_U_PACKETS, }, + { "4096-8191B", KSTAT_KV_U_PACKETS, }, + { "8192-10239B", KSTAT_KV_U_PACKETS, }, +}; +CTASSERT(nitems(mcx_ppcnt_rfc2819_tpl) == mcx_ppcnt_rfc2819_count); + +static const struct mcx_ppcnt mcx_ppcnt_rfc3635_tpl[] = { + { "Alignment Errs", KSTAT_KV_U_PACKETS, }, + { "FCS Errs", KSTAT_KV_U_PACKETS, }, + { "Single Colls", KSTAT_KV_U_PACKETS, }, + { "Multiple Colls", KSTAT_KV_U_PACKETS, }, + { "SQE Test Errs", KSTAT_KV_U_NONE, }, + { "Deferred Tx", KSTAT_KV_U_PACKETS, }, + { "Late Colls", KSTAT_KV_U_NONE, }, + { "Exess Colls", KSTAT_KV_U_NONE, }, + { "Int MAC Tx Errs", KSTAT_KV_U_PACKETS, }, + { "CSM Sense Errs", KSTAT_KV_U_NONE, }, + { "Too Long", KSTAT_KV_U_PACKETS, }, + { "Int MAC Rx Errs", KSTAT_KV_U_PACKETS, }, + { "Symbol Errs", KSTAT_KV_U_NONE, }, + { "Unknown Control", KSTAT_KV_U_PACKETS, }, + { "Pause Rx", KSTAT_KV_U_PACKETS, }, + { "Pause Tx", KSTAT_KV_U_PACKETS, }, +}; +CTASSERT(nitems(mcx_ppcnt_rfc3635_tpl) == mcx_ppcnt_rfc3635_count); + +struct mcx_kstat_ppcnt { + const char *ksp_name; + const struct mcx_ppcnt *ksp_tpl; + unsigned int ksp_n; + uint8_t ksp_grp; +}; + +static const struct mcx_kstat_ppcnt mcx_kstat_ppcnt_ieee8023 = { + .ksp_name = "ieee802.3", + .ksp_tpl = mcx_ppcnt_ieee8023_tpl, + .ksp_n = nitems(mcx_ppcnt_ieee8023_tpl), + .ksp_grp = MCX_REG_PPCNT_GRP_IEEE8023, +}; + +static const struct mcx_kstat_ppcnt mcx_kstat_ppcnt_rfc2863 = { + .ksp_name = "rfc2863", + .ksp_tpl = mcx_ppcnt_rfc2863_tpl, + .ksp_n = nitems(mcx_ppcnt_rfc2863_tpl), + .ksp_grp = MCX_REG_PPCNT_GRP_RFC2863, +}; + +static const struct mcx_kstat_ppcnt mcx_kstat_ppcnt_rfc2819 = { + .ksp_name = "rfc2819", + .ksp_tpl = mcx_ppcnt_rfc2819_tpl, + .ksp_n = nitems(mcx_ppcnt_rfc2819_tpl), + .ksp_grp = MCX_REG_PPCNT_GRP_RFC2819, +}; + +static const struct mcx_kstat_ppcnt mcx_kstat_ppcnt_rfc3635 = { + .ksp_name = "rfc3635", + .ksp_tpl = mcx_ppcnt_rfc3635_tpl, + .ksp_n = nitems(mcx_ppcnt_rfc3635_tpl), + .ksp_grp = MCX_REG_PPCNT_GRP_RFC3635, +}; + +static int mcx_kstat_ppcnt_read(struct kstat *); + +static void mcx_kstat_attach_tmps(struct mcx_softc *sc); + +static struct kstat * +mcx_kstat_attach_ppcnt(struct mcx_softc *sc, + const struct mcx_kstat_ppcnt *ksp) +{ + struct kstat *ks; + struct kstat_kv *kvs; + unsigned int i; + + ks = kstat_create(DEVNAME(sc), 0, ksp->ksp_name, 0, KSTAT_T_KV, 0); + if (ks == NULL) + return (NULL); + + kvs = mallocarray(ksp->ksp_n, sizeof(*kvs), + M_DEVBUF, M_WAITOK); + + for (i = 0; i < ksp->ksp_n; i++) { + const struct mcx_ppcnt *tpl = &ksp->ksp_tpl[i]; + + kstat_kv_unit_init(&kvs[i], tpl->name, + KSTAT_KV_T_COUNTER64, tpl->unit); + } + + ks->ks_softc = sc; + ks->ks_ptr = (void *)ksp; + ks->ks_data = kvs; + ks->ks_datalen = ksp->ksp_n * sizeof(*kvs); + ks->ks_read = mcx_kstat_ppcnt_read; + + kstat_install(ks); + + return (ks); +} + +static void +mcx_kstat_attach(struct mcx_softc *sc) +{ + sc->sc_kstat_ieee8023 = mcx_kstat_attach_ppcnt(sc, + &mcx_kstat_ppcnt_ieee8023); + sc->sc_kstat_rfc2863 = mcx_kstat_attach_ppcnt(sc, + &mcx_kstat_ppcnt_rfc2863); + sc->sc_kstat_rfc2819 = mcx_kstat_attach_ppcnt(sc, + &mcx_kstat_ppcnt_rfc2819); + sc->sc_kstat_rfc3635 = mcx_kstat_attach_ppcnt(sc, + &mcx_kstat_ppcnt_rfc3635); + + mcx_kstat_attach_tmps(sc); +} + +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, + }; + struct kstat_kv *kvs = ks->ks_data; + uint64_t *vs = (uint64_t *)&ppcnt.ppcnt_counter_set; + unsigned int i; + 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); + + nanouptime(&ks->ks_updated); + + for (i = 0; i < ksp->ksp_n; i++) + kstat_kv_u64(&kvs[i]) = bemtoh64(&vs[i]); + + return (0); +} + +struct mcx_kstat_mtmp { + struct kstat_kv ktmp_name; + struct kstat_kv ktmp_temperature; + struct kstat_kv ktmp_threshold_lo; + struct kstat_kv ktmp_threshold_hi; +}; + +static const struct timeval mcx_kstat_mtmp_rate = { 1, 0 }; + +static int mcx_kstat_mtmp_read(struct kstat *); + +static void +mcx_kstat_attach_tmps(struct mcx_softc *sc) +{ + struct kstat *ks; + struct mcx_reg_mtcap mtcap; + struct mcx_kstat_mtmp *ktmp; + uint64_t map; + unsigned int i, n; + + memset(&mtcap, 0, sizeof(mtcap)); + + if (mcx_access_hca_reg(sc, MCX_REG_MTCAP, MCX_REG_OP_READ, + &mtcap, sizeof(mtcap)) != 0) { + /* unable to find temperature sensors */ + return; + } + + sc->sc_kstat_mtmp_count = mtcap.mtcap_sensor_count; + sc->sc_kstat_mtmp = mallocarray(sc->sc_kstat_mtmp_count, + sizeof(*sc->sc_kstat_mtmp), M_DEVBUF, M_WAITOK); + + n = 0; + map = bemtoh64(&mtcap.mtcap_sensor_map); + for (i = 0; i < sizeof(map) * NBBY; i++) { + if (!ISSET(map, (1ULL << i))) + continue; + + ks = kstat_create(DEVNAME(sc), 0, "temperature", i, + KSTAT_T_KV, 0); + if (ks == NULL) { + /* unable to attach temperature sensor %u, i */ + continue; + } + + ktmp = malloc(sizeof(*ktmp), M_DEVBUF, M_WAITOK|M_ZERO); + kstat_kv_init(&ktmp->ktmp_name, "name", KSTAT_KV_T_ISTR); + kstat_kv_init(&ktmp->ktmp_temperature, "temperature", + KSTAT_KV_T_TEMP); + kstat_kv_init(&ktmp->ktmp_threshold_lo, "lo threshold", + KSTAT_KV_T_TEMP); + kstat_kv_init(&ktmp->ktmp_threshold_hi, "hi threshold", + KSTAT_KV_T_TEMP); + + ks->ks_data = ktmp; + ks->ks_datalen = sizeof(*ktmp); + TIMEVAL_TO_TIMESPEC(&mcx_kstat_mtmp_rate, &ks->ks_interval); + ks->ks_read = mcx_kstat_mtmp_read; + + ks->ks_softc = sc; + kstat_install(ks); + + sc->sc_kstat_mtmp[n++] = ks; + if (n >= sc->sc_kstat_mtmp_count) + break; + } +} + +static uint64_t +mcx_tmp_to_uK(uint16_t *t) +{ + int64_t mt = (int16_t)bemtoh16(t); /* 0.125 C units */ + mt *= 1000000 / 8; /* convert to uC */ + mt += 273150000; /* convert to uK */ + + return (mt); +} + +static int +mcx_kstat_mtmp_read(struct kstat *ks) +{ + struct mcx_softc *sc = ks->ks_softc; + struct mcx_kstat_mtmp *ktmp = ks->ks_data; + struct mcx_reg_mtmp mtmp; + int rv; + struct timeval updated; + + TIMESPEC_TO_TIMEVAL(&updated, &ks->ks_updated); + + if (!ratecheck(&updated, &mcx_kstat_mtmp_rate)) + return (0); + + memset(&mtmp, 0, sizeof(mtmp)); + htobem16(&mtmp.mtmp_sensor_index, ks->ks_unit); + + KERNEL_LOCK(); /* XXX */ + rv = mcx_access_hca_reg(sc, MCX_REG_MTMP, MCX_REG_OP_READ, + &mtmp, sizeof(mtmp)); + KERNEL_UNLOCK(); + if (rv != 0) + return (EIO); + + memset(kstat_kv_istr(&ktmp->ktmp_name), 0, + sizeof(kstat_kv_istr(&ktmp->ktmp_name))); + memcpy(kstat_kv_istr(&ktmp->ktmp_name), + mtmp.mtmp_sensor_name, sizeof(mtmp.mtmp_sensor_name)); + kstat_kv_temp(&ktmp->ktmp_temperature) = + mcx_tmp_to_uK(&mtmp.mtmp_temperature); + kstat_kv_temp(&ktmp->ktmp_threshold_lo) = + mcx_tmp_to_uK(&mtmp.mtmp_temperature_threshold_lo); + kstat_kv_temp(&ktmp->ktmp_threshold_hi) = + mcx_tmp_to_uK(&mtmp.mtmp_temperature_threshold_hi); + + TIMEVAL_TO_TIMESPEC(&updated, &ks->ks_updated); + + return (0); +} +#endif /* NKSTAT > 0 */ |