Index: cpu.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/arm64/cpu.c,v retrieving revision 1.99 diff -u -p -r1.99 cpu.c --- cpu.c 24 Oct 2023 13:20:09 -0000 1.99 +++ cpu.c 10 Nov 2023 19:04:36 -0000 @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "kstat.h" + #include #include #include @@ -25,6 +27,7 @@ #include #include #include +#include #include @@ -250,6 +253,10 @@ void cpu_psci_init(struct cpu_info *); void cpu_flush_bp_noop(void); void cpu_flush_bp_psci(void); +#if NKSTAT > 0 +void cpu_kstat_attach(struct cpu_info *ci); +#endif + void cpu_identify(struct cpu_info *ci) { @@ -947,6 +954,10 @@ cpu_attach(struct device *parent, struct cpu_psci_init(ci); +#if NKSTAT > 0 + cpu_kstat_attach(ci); +#endif + printf("\n"); } @@ -1817,3 +1828,114 @@ cpu_psci_init(struct cpu_info *ci) ci->ci_psci_suspend_param = OF_getpropint(node, "arm,psci-suspend-param", 0); } + +#if NKSTAT > 0 + +struct cpu_kstats { + struct kstat_kv ck_device; + struct kstat_kv ck_impl; + struct kstat_kv ck_part; + struct kstat_kv ck_var; + struct kstat_kv ck_rev; + + struct kstat_kv ck_freq; + struct kstat_kv ck_mv; +}; + +int +cpu_kstat_read(struct kstat *ks) +{ + struct cpu_kstats *ck = ks->ks_data; + + /* + * this is called from an arbitrary cpu via an ioctl syscall, + * and without KERNEL_LOCK held. + */ + + kstat_kv_u32(&ck->ck_freq) = arc4random(); + kstat_kv_u32(&ck->ck_mv) = arc4random(); + + getnanouptime(&ks->ks_updated); /* accuracy is not important here */ + + return (0); +} + +void +cpu_kstat_attach(struct cpu_info *ci) +{ + struct kstat *ks; + struct cpu_kstats *ck; + + uint64_t midr, impl, part; + const char *impl_name = NULL, *part_name = NULL; + const struct cpu_cores *coreselecter = cpu_cores_none; + size_t i; + + ks = kstat_create("mach", 0, "cpu", ci->ci_cpuid, KSTAT_T_KV, 0); + if (ks == NULL) { + printf("%s: unable to create cpu kstats\n", + ci->ci_dev->dv_xname); + /* printf? */ + return; + } + + ck = malloc(sizeof(*ck), M_DEVBUF, M_WAITOK); + + kstat_kv_init(&ck->ck_device, "device", KSTAT_KV_T_ISTR); + if (strlcpy(kstat_kv_istr(&ck->ck_device), ci->ci_dev->dv_xname, + sizeof(kstat_kv_istr(&ck->ck_device))) >= + sizeof(kstat_kv_istr(&ck->ck_device))) + panic("%s: devname too long", __func__); + + midr = READ_SPECIALREG(midr_el1); + impl = CPU_IMPL(midr); + part = CPU_PART(midr); + + for (i = 0; cpu_implementers[i].name; i++) { + if (impl == cpu_implementers[i].id) { + impl_name = cpu_implementers[i].name; + coreselecter = cpu_implementers[i].corelist; + break; + } + } + + if (impl_name) { + kstat_kv_init(&ck->ck_impl, "impl", KSTAT_KV_T_ISTR); + strlcpy(kstat_kv_istr(&ck->ck_impl), impl_name, + sizeof(kstat_kv_istr(&ck->ck_impl))); + } else + kstat_kv_init(&ck->ck_impl, "impl", KSTAT_KV_T_NULL); + + for (i = 0; coreselecter[i].name; i++) { + if (part == coreselecter[i].id) { + part_name = coreselecter[i].name; + break; + } + } + + if (part_name) { + kstat_kv_init(&ck->ck_part, "part", KSTAT_KV_T_ISTR); + strlcpy(kstat_kv_istr(&ck->ck_part), part_name, + sizeof(kstat_kv_istr(&ck->ck_part))); + } else + kstat_kv_init(&ck->ck_part, "part", KSTAT_KV_T_NULL); + + kstat_kv_init(&ck->ck_var, "var", KSTAT_KV_T_UINT32); + kstat_kv_u32(&ck->ck_var) = CPU_VAR(midr); + kstat_kv_init(&ck->ck_rev, "rev", KSTAT_KV_T_UINT32); + kstat_kv_u32(&ck->ck_rev) = CPU_REV(midr); + + kstat_kv_init(&ck->ck_freq, "freq", KSTAT_KV_T_UINT32); + kstat_kv_init(&ck->ck_mv, "mvolts?", KSTAT_KV_T_UINT32); + + ks->ks_softc = ci; + ks->ks_data = ck; + ks->ks_datalen = sizeof(*ck); + ks->ks_read = cpu_kstat_read; + + kstat_install(ks); + + /* XXX should we have a ci->ci_kstat = ks? */ +} + +#endif /* NKSTAT > 0 */