Index: conf/GENERIC =================================================================== RCS file: /cvs/src/sys/arch/arm64/conf/GENERIC,v diff -u -p -r1.296 GENERIC --- conf/GENERIC 23 Jun 2025 18:42:52 -0000 1.296 +++ conf/GENERIC 13 Jul 2025 06:15:05 -0000 @@ -36,6 +36,7 @@ config bsd swap generic mainbus0 at root cpu0 at mainbus? apm0 at mainbus? +amu0 at mainbus? efi0 at mainbus? smbios0 at efi? acpi0 at mainbus? Index: conf/files.arm64 =================================================================== RCS file: /cvs/src/sys/arch/arm64/conf/files.arm64,v diff -u -p -r1.74 files.arm64 --- conf/files.arm64 7 Jun 2025 15:11:12 -0000 1.74 +++ conf/files.arm64 13 Jul 2025 06:15:05 -0000 @@ -290,3 +290,7 @@ device apm attach apm at mainbus file arch/arm64/dev/apm.c apm needs-flag file arch/arm64/arm64/acpiapm.c apm + +device amu: xcall +attach amu at mainbus +file arch/arm64/dev/amu.c amu needs-flag Index: dev/amu.c =================================================================== RCS file: dev/amu.c diff -N dev/amu.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/amu.c 13 Jul 2025 06:15:05 -0000 @@ -0,0 +1,178 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2025 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * ARM Activity Monitor Unit + */ + +#include "kstat.h" +#if NKSTAT == 0 +#error amu(4) requires kstat(4) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* CPU Identification */ +#define CPU_IMPL_ARM 0x41 +#define CPU_PART_ARM_NEOVERSE_N1 0xd0c + +#define CPU_IMPL(midr) (((midr) >> 24) & 0xff) +#define CPU_PART(midr) (((midr) >> 4) & 0xfff) +#define CPU_VAR(midr) (((midr) >> 20) & 0xf) +#define CPU_REV(midr) (((midr) >> 0) & 0xf) + +struct amu_softc { + struct device sc_dev; +}; + +#define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) + +static int amu_match(struct device *, void *, void *); +static void amu_attach(struct device *, struct device *, void *); + +const struct cfattach amu_ca = { + sizeof(struct amu_softc), amu_match, amu_attach +}; + +struct cfdriver amu_cd = { + NULL, "amu", DV_DULL +}; + +static void amu_v0_attach(struct amu_softc *sc, + struct cpu_info *); + +static int +amu_match(struct device *parent, void *match, void *aux) +{ + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + CPU_INFO_FOREACH(cii, ci) { + if (CPU_IMPL(ci->ci_midr) == CPU_IMPL_ARM && + CPU_PART(ci->ci_midr) == CPU_PART_ARM_NEOVERSE_N1) + return (1); + } + + return (0); +} + +static void +amu_attach(struct device *parent, struct device *self, void *aux) +{ + struct amu_softc *sc = (struct amu_softc *)self; + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + printf("\n"); + + CPU_INFO_FOREACH(cii, ci) { + if (CPU_IMPL(ci->ci_midr) == CPU_IMPL_ARM && + CPU_PART(ci->ci_midr) == CPU_PART_ARM_NEOVERSE_N1) { + sched_peg_curproc(ci); + amu_v0_attach(sc, ci); + } + } + + atomic_clearbits_int(&curproc->p_flag, P_CPUPEG); +} + +static const char *amu_v0_events[] = { + "core-cycles", + "constant-cycles", + "instr-retired", + "first-miss", + "high-activity", +}; + +static void +amu_v0_read_xcall(void *arg) +{ + struct kstat *ks = arg; + struct kstat_kv *kvs = ks->ks_data; + unsigned long s; + + s = intr_disable(); + /* AMEVCNTR0_EL0 */ + kstat_kv_u64(&kvs[0]) = READ_SPECIALREG(s3_3_c15_c9_0); + /* AMEVCNTR1_EL0 */ + kstat_kv_u64(&kvs[1]) = READ_SPECIALREG(s3_3_c15_c9_1); + /* AMEVCNTR2_EL0 */ + kstat_kv_u64(&kvs[2]) = READ_SPECIALREG(s3_3_c15_c9_2); + /* AMEVCNTR3_EL0 */ + kstat_kv_u64(&kvs[3]) = READ_SPECIALREG(s3_3_c15_c9_3); + /* AMEVCNTR4_EL0 */ + kstat_kv_u64(&kvs[4]) = READ_SPECIALREG(s3_3_c15_c9_4); + nanouptime(&ks->ks_updated); + intr_restore(s); +} + +static int +amu_v0_read(struct kstat *ks) +{ + uint64_t now = getnsecuptime(); + uint64_t upd = TIMESPEC_TO_NSEC(&ks->ks_updated); + int64_t diff = now - upd; + + if (diff > 500000000) + cpu_xcall_sync(ks->ks_ptr, amu_v0_read_xcall, ks, "amurd"); + + return (0); +} + +static void +amu_v0_attach(struct amu_softc *sc, struct cpu_info *ci) +{ + struct kstat *ks; + struct kstat_kv *kvs; + size_t i; + + ks = kstat_create(ci->ci_dev->dv_xname, 0, "amu", 0, KSTAT_T_KV, 0); + if (ks == NULL) { + printf("%s: unable to create %s amu kstats\n", DEVNAME(sc), + ci->ci_dev->dv_xname); + return; + } + + kvs = mallocarray(nitems(amu_v0_events), sizeof(*kvs), + M_DEVBUF, M_WAITOK|M_ZERO); + for (i = 0; i < nitems(amu_v0_events); i++) { + kstat_kv_init(&kvs[i], amu_v0_events[i], + KSTAT_KV_T_COUNTER64); + } + + ks->ks_data = kvs; + ks->ks_datalen = nitems(amu_v0_events) * sizeof(*kvs); + ks->ks_softc = sc; + ks->ks_ptr = ci; + ks->ks_read = amu_v0_read; + + kstat_install(ks); +} Index: dev/aplintc.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/dev/aplintc.c,v diff -u -p -r1.19 aplintc.c --- dev/aplintc.c 6 Jul 2025 12:22:31 -0000 1.19 +++ dev/aplintc.c 13 Jul 2025 06:15:05 -0000 @@ -689,6 +689,10 @@ aplintc_handle_ipi(struct aplintc_softc #endif if (ISSET(reasons, 1 << ARM_IPI_HALT)) cpu_halt(); +#if NXCALL > 0 + if (ISSET(reasons, 1 << ARM_IPI_XCALL)) + cpu_xcall_dispatch(ci); +#endif } sc->sc_ipi_count.ec_count++; Index: dev/bcm2836_intr.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/dev/bcm2836_intr.c,v diff -u -p -r1.16 bcm2836_intr.c --- dev/bcm2836_intr.c 6 Jul 2025 12:22:31 -0000 1.16 +++ dev/bcm2836_intr.c 13 Jul 2025 06:15:05 -0000 @@ -638,6 +638,10 @@ bcm_intc_handle_ipi(void) db_enter(); } #endif +#if NXCALL > 0 + if (ISSET(mbox_val, 1 << ARM_IPI_XCALL)) + cpu_xcall_dispatch(curcpu()); +#endif } void Index: dev/mainbus.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/dev/mainbus.c,v diff -u -p -r1.32 mainbus.c --- dev/mainbus.c 18 Nov 2024 05:32:39 -0000 1.32 +++ dev/mainbus.c 13 Jul 2025 06:15:05 -0000 @@ -38,7 +38,8 @@ int mainbus_match_primary(struct device int mainbus_match_secondary(struct device *, void *, void *); void mainbus_attach_psci(struct device *); void mainbus_attach_efi(struct device *); -void mainbus_attach_apm(struct device *); +void mainbus_attach_subsystem(struct device *, const char *); +void mainbus_attach_late(struct device *); void mainbus_attach_framebuffer(struct device *); void mainbus_attach_firmware(struct device *); void mainbus_attach_resvmem(struct device *); @@ -147,7 +148,7 @@ mainbus_attach(struct device *parent, st sc->sc_rangeslen); } - mainbus_attach_apm(self); + mainbus_attach_subsystem(self, "apm"); /* Scan the whole tree. */ for (sc->sc_early = 2; sc->sc_early >= 0; sc->sc_early--) { @@ -156,13 +157,21 @@ mainbus_attach(struct device *parent, st } sc->sc_early = 0; + config_mountroot(self, mainbus_attach_late); + + thermal_init(); +} + +void +mainbus_attach_late(struct device *self) +{ /* * Delay attaching the framebuffer to give other drivers a * chance to claim it. */ - config_mountroot(self, mainbus_attach_framebuffer); + mainbus_attach_framebuffer(self); - thermal_init(); + mainbus_attach_subsystem(self, "amu"); } int @@ -399,15 +408,27 @@ mainbus_attach_efi(struct device *self) config_found(self, &fa, NULL); } -void -mainbus_attach_apm(struct device *self) +static int +mainbus_match_subsystem(struct device *parent, void *match, void *aux) { - struct fdt_attach_args fa; + struct cfdata *cf = match; + struct fdt_attach_args *fa = aux; - memset(&fa, 0, sizeof(fa)); - fa.fa_name = "apm"; + if (strcmp(cf->cf_driver->cd_name, fa->fa_name) == 0) + return cf->cf_attach->ca_match(parent, match, aux); - config_found(self, &fa, NULL); + return (0); +} + +void +mainbus_attach_subsystem(struct device *self, const char *name) +{ + struct fdt_attach_args fa = { .fa_name = name }; + void *match; + + match = config_search(mainbus_match_subsystem, self, &fa); + if (match != NULL) + config_attach(self, match, &fa, mainbus_print); } void