1*388bf930Sjmcneill /* $NetBSD: cpu_acpi.c,v 1.17 2024/12/30 19:17:21 jmcneill Exp $ */ 297d57f80Sjmcneill 397d57f80Sjmcneill /*- 497d57f80Sjmcneill * Copyright (c) 2018 The NetBSD Foundation, Inc. 597d57f80Sjmcneill * All rights reserved. 697d57f80Sjmcneill * 797d57f80Sjmcneill * This code is derived from software contributed to The NetBSD Foundation 897d57f80Sjmcneill * by Jared McNeill <jmcneill@invisible.ca>. 997d57f80Sjmcneill * 1097d57f80Sjmcneill * Redistribution and use in source and binary forms, with or without 1197d57f80Sjmcneill * modification, are permitted provided that the following conditions 1297d57f80Sjmcneill * are met: 1397d57f80Sjmcneill * 1. Redistributions of source code must retain the above copyright 1497d57f80Sjmcneill * notice, this list of conditions and the following disclaimer. 1597d57f80Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright 1697d57f80Sjmcneill * notice, this list of conditions and the following disclaimer in the 1797d57f80Sjmcneill * documentation and/or other materials provided with the distribution. 1897d57f80Sjmcneill * 1997d57f80Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2097d57f80Sjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2197d57f80Sjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2297d57f80Sjmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2397d57f80Sjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2497d57f80Sjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2597d57f80Sjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2697d57f80Sjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2797d57f80Sjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2897d57f80Sjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2997d57f80Sjmcneill * POSSIBILITY OF SUCH DAMAGE. 3097d57f80Sjmcneill */ 3197d57f80Sjmcneill 32c3589be4Sjmcneill #include "tprof.h" 336f2828aaSryo #include "opt_multiprocessor.h" 34c3589be4Sjmcneill 3597d57f80Sjmcneill #include <sys/cdefs.h> 36*388bf930Sjmcneill __KERNEL_RCSID(0, "$NetBSD: cpu_acpi.c,v 1.17 2024/12/30 19:17:21 jmcneill Exp $"); 3797d57f80Sjmcneill 3897d57f80Sjmcneill #include <sys/param.h> 3997d57f80Sjmcneill #include <sys/bus.h> 4097d57f80Sjmcneill #include <sys/cpu.h> 4197d57f80Sjmcneill #include <sys/device.h> 42c3589be4Sjmcneill #include <sys/interrupt.h> 43c3589be4Sjmcneill #include <sys/kcpuset.h> 44*388bf930Sjmcneill #include <sys/kmem.h> 4529224e5eSjmcneill #include <sys/reboot.h> 4697d57f80Sjmcneill 4797d57f80Sjmcneill #include <dev/acpi/acpireg.h> 4897d57f80Sjmcneill #include <dev/acpi/acpivar.h> 49397fdee4Sjmcneill #include <dev/acpi/acpi_srat.h> 50*388bf930Sjmcneill #include <external/bsd/acpica/dist/include/amlresrc.h> 5197d57f80Sjmcneill 5297d57f80Sjmcneill #include <arm/armreg.h> 5397d57f80Sjmcneill #include <arm/cpu.h> 5497d57f80Sjmcneill #include <arm/cpufunc.h> 55e1281176Sskrll #include <arm/cpuvar.h> 5697d57f80Sjmcneill #include <arm/locore.h> 5797d57f80Sjmcneill 5897d57f80Sjmcneill #include <arm/arm/psci.h> 5997d57f80Sjmcneill 60*388bf930Sjmcneill #define LPI_IDLE_FACTOR 3 61*388bf930Sjmcneill 62c3589be4Sjmcneill #if NTPROF > 0 63c3589be4Sjmcneill #include <dev/tprof/tprof_armv8.h> 64c3589be4Sjmcneill #endif 65c3589be4Sjmcneill 6697d57f80Sjmcneill static int cpu_acpi_match(device_t, cfdata_t, void *); 6797d57f80Sjmcneill static void cpu_acpi_attach(device_t, device_t, void *); 6897d57f80Sjmcneill 69*388bf930Sjmcneill static void cpu_acpi_probe_lpi(device_t, struct cpu_info *ci); 70*388bf930Sjmcneill void cpu_acpi_lpi_idle(void); 71*388bf930Sjmcneill 72c3589be4Sjmcneill #if NTPROF > 0 73c3589be4Sjmcneill static void cpu_acpi_tprof_init(device_t); 74c3589be4Sjmcneill #endif 75c3589be4Sjmcneill 760a668ec7Spho CFATTACH_DECL2_NEW(cpu_acpi, 0, 770a668ec7Spho cpu_acpi_match, cpu_acpi_attach, NULL, NULL, 780a668ec7Spho cpu_rescan, cpu_childdetached); 7997d57f80Sjmcneill 806f2828aaSryo #ifdef MULTIPROCESSOR 8197d57f80Sjmcneill static register_t 8297d57f80Sjmcneill cpu_acpi_mpstart_pa(void) 8397d57f80Sjmcneill { 84e6c2e807Sskrll 85e6c2e807Sskrll return (register_t)KERN_VTOPHYS((vaddr_t)cpu_mpstart); 8697d57f80Sjmcneill } 876f2828aaSryo #endif /* MULTIPROCESSOR */ 8897d57f80Sjmcneill 8997d57f80Sjmcneill static int 9097d57f80Sjmcneill cpu_acpi_match(device_t parent, cfdata_t cf, void *aux) 9197d57f80Sjmcneill { 9297d57f80Sjmcneill ACPI_SUBTABLE_HEADER *hdrp = aux; 9373fbce2bSjmcneill ACPI_MADT_GENERIC_INTERRUPT *gicc; 9497d57f80Sjmcneill 9573fbce2bSjmcneill if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_INTERRUPT) 9673fbce2bSjmcneill return 0; 9773fbce2bSjmcneill 9873fbce2bSjmcneill gicc = (ACPI_MADT_GENERIC_INTERRUPT *)hdrp; 9973fbce2bSjmcneill 10073fbce2bSjmcneill return (gicc->Flags & ACPI_MADT_ENABLED) != 0; 10197d57f80Sjmcneill } 10297d57f80Sjmcneill 10397d57f80Sjmcneill static void 10497d57f80Sjmcneill cpu_acpi_attach(device_t parent, device_t self, void *aux) 10597d57f80Sjmcneill { 10647ed2bf4Sjmcneill prop_dictionary_t dict = device_properties(self); 10797d57f80Sjmcneill ACPI_MADT_GENERIC_INTERRUPT *gicc = aux; 10897d57f80Sjmcneill const uint64_t mpidr = gicc->ArmMpidr; 10992a57f01Sjmcneill const int unit = device_unit(self); 11092a57f01Sjmcneill struct cpu_info *ci = &cpu_info_store[unit]; 111397fdee4Sjmcneill struct acpisrat_node *node; 11297d57f80Sjmcneill 1136f2828aaSryo #ifdef MULTIPROCESSOR 11429224e5eSjmcneill if (cpu_mpidr_aff_read() != mpidr && (boothowto & RB_MD1) == 0) { 11597d57f80Sjmcneill const u_int cpuindex = device_unit(self); 1166f2828aaSryo int error; 11797d57f80Sjmcneill 11897d57f80Sjmcneill cpu_mpidr[cpuindex] = mpidr; 119999b9562Sjmcneill cpu_dcache_wb_range((vaddr_t)&cpu_mpidr[cpuindex], 120999b9562Sjmcneill sizeof(cpu_mpidr[cpuindex])); 12197d57f80Sjmcneill 12297d57f80Sjmcneill /* XXX support spin table */ 12397d57f80Sjmcneill error = psci_cpu_on(mpidr, cpu_acpi_mpstart_pa(), 0); 12497d57f80Sjmcneill if (error != PSCI_SUCCESS) { 12597d57f80Sjmcneill aprint_error_dev(self, "failed to start CPU\n"); 12697d57f80Sjmcneill return; 12797d57f80Sjmcneill } 12897d57f80Sjmcneill 12969120ac1Sskrll sev(); 13097d57f80Sjmcneill 13197d57f80Sjmcneill for (u_int i = 0x10000000; i > 0; i--) { 13229224e5eSjmcneill if (cpu_hatched_p(cpuindex)) 13397d57f80Sjmcneill break; 13497d57f80Sjmcneill } 13597d57f80Sjmcneill } 1366f2828aaSryo #endif /* MULTIPROCESSOR */ 13797d57f80Sjmcneill 13847ed2bf4Sjmcneill /* Assume that less efficient processors are faster. */ 13947ed2bf4Sjmcneill prop_dictionary_set_uint32(dict, "capacity_dmips_mhz", 14047ed2bf4Sjmcneill gicc->EfficiencyClass); 14147ed2bf4Sjmcneill 14292a57f01Sjmcneill /* Store the ACPI Processor UID in cpu_info */ 14392a57f01Sjmcneill ci->ci_acpiid = gicc->Uid; 14492a57f01Sjmcneill 145397fdee4Sjmcneill /* Scan SRAT for NUMA info. */ 146397fdee4Sjmcneill if (cpu_mpidr_aff_read() == mpidr) { 147397fdee4Sjmcneill acpisrat_init(); 148397fdee4Sjmcneill } 149397fdee4Sjmcneill node = acpisrat_get_node(gicc->Uid); 150397fdee4Sjmcneill if (node != NULL) { 151397fdee4Sjmcneill ci->ci_numa_id = node->nodeid; 152397fdee4Sjmcneill } 153397fdee4Sjmcneill 15497d57f80Sjmcneill /* Attach the CPU */ 15597d57f80Sjmcneill cpu_attach(self, mpidr); 156c3589be4Sjmcneill 157*388bf930Sjmcneill /* Probe for low-power idle states. */ 158*388bf930Sjmcneill cpu_acpi_probe_lpi(self, ci); 159*388bf930Sjmcneill 160c3589be4Sjmcneill #if NTPROF > 0 1616724c56eSjmcneill if (cpu_mpidr_aff_read() == mpidr && armv8_pmu_detect()) 162c3589be4Sjmcneill config_interrupts(self, cpu_acpi_tprof_init); 163c3589be4Sjmcneill #endif 16497d57f80Sjmcneill } 165c3589be4Sjmcneill 166*388bf930Sjmcneill static void 167*388bf930Sjmcneill cpu_acpi_probe_lpi(device_t dev, struct cpu_info *ci) 168*388bf930Sjmcneill { 169*388bf930Sjmcneill ACPI_HANDLE hdl; 170*388bf930Sjmcneill ACPI_BUFFER buf; 171*388bf930Sjmcneill ACPI_OBJECT *obj, *lpi; 172*388bf930Sjmcneill ACPI_STATUS rv; 173*388bf930Sjmcneill uint32_t levelid; 174*388bf930Sjmcneill uint32_t numlpi; 175*388bf930Sjmcneill uint32_t n; 176*388bf930Sjmcneill int enable_lpi; 177*388bf930Sjmcneill 178*388bf930Sjmcneill if (get_bootconf_option(boot_args, "nolpi", 179*388bf930Sjmcneill BOOTOPT_TYPE_BOOLEAN, &enable_lpi) && 180*388bf930Sjmcneill !enable_lpi) { 181*388bf930Sjmcneill return; 182*388bf930Sjmcneill } 183*388bf930Sjmcneill 184*388bf930Sjmcneill hdl = acpi_match_cpu_info(ci); 185*388bf930Sjmcneill if (hdl == NULL) { 186*388bf930Sjmcneill return; 187*388bf930Sjmcneill } 188*388bf930Sjmcneill rv = AcpiGetHandle(hdl, "_LPI", &hdl); 189*388bf930Sjmcneill if (ACPI_FAILURE(rv)) { 190*388bf930Sjmcneill return; 191*388bf930Sjmcneill } 192*388bf930Sjmcneill rv = acpi_eval_struct(hdl, NULL, &buf); 193*388bf930Sjmcneill if (ACPI_FAILURE(rv)) { 194*388bf930Sjmcneill return; 195*388bf930Sjmcneill } 196*388bf930Sjmcneill 197*388bf930Sjmcneill obj = buf.Pointer; 198*388bf930Sjmcneill if (obj->Type != ACPI_TYPE_PACKAGE || 199*388bf930Sjmcneill obj->Package.Count < 3 || 200*388bf930Sjmcneill obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER || 201*388bf930Sjmcneill obj->Package.Elements[2].Type != ACPI_TYPE_INTEGER) { 202*388bf930Sjmcneill goto out; 203*388bf930Sjmcneill } 204*388bf930Sjmcneill levelid = obj->Package.Elements[1].Integer.Value; 205*388bf930Sjmcneill if (levelid != 0) { 206*388bf930Sjmcneill /* We depend on platform coordination for now. */ 207*388bf930Sjmcneill goto out; 208*388bf930Sjmcneill } 209*388bf930Sjmcneill numlpi = obj->Package.Elements[2].Integer.Value; 210*388bf930Sjmcneill if (obj->Package.Count < 3 + numlpi || numlpi == 0) { 211*388bf930Sjmcneill goto out; 212*388bf930Sjmcneill } 213*388bf930Sjmcneill ci->ci_lpi = kmem_zalloc(sizeof(*ci->ci_lpi) * numlpi, KM_SLEEP); 214*388bf930Sjmcneill for (n = 0; n < numlpi; n++) { 215*388bf930Sjmcneill lpi = &obj->Package.Elements[3 + n]; 216*388bf930Sjmcneill if (lpi->Type != ACPI_TYPE_PACKAGE || 217*388bf930Sjmcneill lpi->Package.Count < 10 || 218*388bf930Sjmcneill lpi->Package.Elements[0].Type != ACPI_TYPE_INTEGER || 219*388bf930Sjmcneill lpi->Package.Elements[1].Type != ACPI_TYPE_INTEGER || 220*388bf930Sjmcneill lpi->Package.Elements[2].Type != ACPI_TYPE_INTEGER || 221*388bf930Sjmcneill lpi->Package.Elements[3].Type != ACPI_TYPE_INTEGER || 222*388bf930Sjmcneill !(lpi->Package.Elements[6].Type == ACPI_TYPE_BUFFER || 223*388bf930Sjmcneill lpi->Package.Elements[6].Type == ACPI_TYPE_INTEGER)) { 224*388bf930Sjmcneill continue; 225*388bf930Sjmcneill } 226*388bf930Sjmcneill 227*388bf930Sjmcneill if ((lpi->Package.Elements[2].Integer.Value & 1) == 0) { 228*388bf930Sjmcneill /* LPI state is not enabled */ 229*388bf930Sjmcneill continue; 230*388bf930Sjmcneill } 231*388bf930Sjmcneill 232*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].min_res 233*388bf930Sjmcneill = lpi->Package.Elements[0].Integer.Value; 234*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].wakeup_latency = 235*388bf930Sjmcneill lpi->Package.Elements[1].Integer.Value; 236*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].save_restore_flags = 237*388bf930Sjmcneill lpi->Package.Elements[3].Integer.Value; 238*388bf930Sjmcneill if (ci->ci_lpi[ci->ci_nlpi].save_restore_flags != 0) { 239*388bf930Sjmcneill /* Not implemented yet */ 240*388bf930Sjmcneill continue; 241*388bf930Sjmcneill } 242*388bf930Sjmcneill if (lpi->Package.Elements[6].Type == ACPI_TYPE_INTEGER) { 243*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].reg_addr = 244*388bf930Sjmcneill lpi->Package.Elements[6].Integer.Value; 245*388bf930Sjmcneill } else { 246*388bf930Sjmcneill ACPI_GENERIC_ADDRESS addr; 247*388bf930Sjmcneill 248*388bf930Sjmcneill KASSERT(lpi->Package.Elements[6].Type == 249*388bf930Sjmcneill ACPI_TYPE_BUFFER); 250*388bf930Sjmcneill 251*388bf930Sjmcneill if (lpi->Package.Elements[6].Buffer.Length < 252*388bf930Sjmcneill sizeof(AML_RESOURCE_GENERIC_REGISTER)) { 253*388bf930Sjmcneill continue; 254*388bf930Sjmcneill } 255*388bf930Sjmcneill memcpy(&addr, lpi->Package.Elements[6].Buffer.Pointer + 256*388bf930Sjmcneill sizeof(AML_RESOURCE_LARGE_HEADER), sizeof(addr)); 257*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].reg_addr = addr.Address; 258*388bf930Sjmcneill } 259*388bf930Sjmcneill 260*388bf930Sjmcneill if (lpi->Package.Elements[9].Type == ACPI_TYPE_STRING) { 261*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].name = 262*388bf930Sjmcneill kmem_asprintf("LPI state %s", 263*388bf930Sjmcneill lpi->Package.Elements[9].String.Pointer); 264*388bf930Sjmcneill } else { 265*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].name = 266*388bf930Sjmcneill kmem_asprintf("LPI state %u", n + 1); 267*388bf930Sjmcneill } 268*388bf930Sjmcneill 269*388bf930Sjmcneill aprint_verbose_dev(ci->ci_dev, 270*388bf930Sjmcneill "%s: min res %u, wakeup latency %u, flags %#x, " 271*388bf930Sjmcneill "register %#x\n", 272*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].name, 273*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].min_res, 274*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].wakeup_latency, 275*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].save_restore_flags, 276*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].reg_addr); 277*388bf930Sjmcneill 278*388bf930Sjmcneill evcnt_attach_dynamic(&ci->ci_lpi[ci->ci_nlpi].events, 279*388bf930Sjmcneill EVCNT_TYPE_MISC, NULL, ci->ci_cpuname, 280*388bf930Sjmcneill ci->ci_lpi[ci->ci_nlpi].name); 281*388bf930Sjmcneill 282*388bf930Sjmcneill ci->ci_nlpi++; 283*388bf930Sjmcneill } 284*388bf930Sjmcneill 285*388bf930Sjmcneill if (ci->ci_nlpi > 0) { 286*388bf930Sjmcneill extern void (*arm_cpu_idle)(void); 287*388bf930Sjmcneill arm_cpu_idle = cpu_acpi_lpi_idle; 288*388bf930Sjmcneill } 289*388bf930Sjmcneill 290*388bf930Sjmcneill out: 291*388bf930Sjmcneill ACPI_FREE(buf.Pointer); 292*388bf930Sjmcneill } 293*388bf930Sjmcneill 294*388bf930Sjmcneill static inline void 295*388bf930Sjmcneill cpu_acpi_idle(uint32_t addr) 296*388bf930Sjmcneill { 297*388bf930Sjmcneill if (addr == LPI_REG_ADDR_WFI) { 298*388bf930Sjmcneill asm volatile("dsb sy; wfi"); 299*388bf930Sjmcneill } else { 300*388bf930Sjmcneill psci_cpu_suspend(addr); 301*388bf930Sjmcneill } 302*388bf930Sjmcneill } 303*388bf930Sjmcneill 304*388bf930Sjmcneill void 305*388bf930Sjmcneill cpu_acpi_lpi_idle(void) 306*388bf930Sjmcneill { 307*388bf930Sjmcneill struct cpu_info *ci = curcpu(); 308*388bf930Sjmcneill struct timeval start, end; 309*388bf930Sjmcneill int n; 310*388bf930Sjmcneill 311*388bf930Sjmcneill DISABLE_INTERRUPT(); 312*388bf930Sjmcneill 313*388bf930Sjmcneill microuptime(&start); 314*388bf930Sjmcneill for (n = ci->ci_nlpi - 1; n >= 0; n--) { 315*388bf930Sjmcneill if (ci->ci_last_idle > 316*388bf930Sjmcneill LPI_IDLE_FACTOR * ci->ci_lpi[n].min_res) { 317*388bf930Sjmcneill cpu_acpi_idle(ci->ci_lpi[n].reg_addr); 318*388bf930Sjmcneill ci->ci_lpi[n].events.ev_count++; 319*388bf930Sjmcneill break; 320*388bf930Sjmcneill } 321*388bf930Sjmcneill } 322*388bf930Sjmcneill if (n == -1) { 323*388bf930Sjmcneill /* Nothing in _LPI, let's just WFI. */ 324*388bf930Sjmcneill cpu_acpi_idle(LPI_REG_ADDR_WFI); 325*388bf930Sjmcneill } 326*388bf930Sjmcneill microuptime(&end); 327*388bf930Sjmcneill timersub(&end, &start, &end); 328*388bf930Sjmcneill 329*388bf930Sjmcneill ci->ci_last_idle = end.tv_sec * 1000000 + end.tv_usec; 330*388bf930Sjmcneill 331*388bf930Sjmcneill ENABLE_INTERRUPT(); 332*388bf930Sjmcneill } 333*388bf930Sjmcneill 334c3589be4Sjmcneill #if NTPROF > 0 335c3589be4Sjmcneill static struct cpu_info * 336c3589be4Sjmcneill cpu_acpi_find_processor(UINT32 uid) 337c3589be4Sjmcneill { 338c3589be4Sjmcneill CPU_INFO_ITERATOR cii; 339c3589be4Sjmcneill struct cpu_info *ci; 340c3589be4Sjmcneill 341c3589be4Sjmcneill for (CPU_INFO_FOREACH(cii, ci)) { 342c3589be4Sjmcneill if (ci->ci_acpiid == uid) 343c3589be4Sjmcneill return ci; 344c3589be4Sjmcneill } 345c3589be4Sjmcneill 346c3589be4Sjmcneill return NULL; 347c3589be4Sjmcneill } 348c3589be4Sjmcneill 349c3589be4Sjmcneill static ACPI_STATUS 350c3589be4Sjmcneill cpu_acpi_tprof_intr_establish(ACPI_SUBTABLE_HEADER *hdrp, void *aux) 351c3589be4Sjmcneill { 352c3589be4Sjmcneill device_t dev = aux; 353c3589be4Sjmcneill ACPI_MADT_GENERIC_INTERRUPT *gicc; 354c3589be4Sjmcneill struct cpu_info *ci; 355c3589be4Sjmcneill char xname[16]; 356c3589be4Sjmcneill kcpuset_t *set; 357c3589be4Sjmcneill int error; 358c3589be4Sjmcneill void *ih; 359c3589be4Sjmcneill 360c3589be4Sjmcneill if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_INTERRUPT) 361c3589be4Sjmcneill return AE_OK; 362c3589be4Sjmcneill 363c3589be4Sjmcneill gicc = (ACPI_MADT_GENERIC_INTERRUPT *)hdrp; 364c3589be4Sjmcneill if ((gicc->Flags & ACPI_MADT_ENABLED) == 0) 365c3589be4Sjmcneill return AE_OK; 366c3589be4Sjmcneill 3674d197dd7Sjmcneill const bool cpu_primary_p = cpu_info_store[0].ci_cpuid == gicc->ArmMpidr; 368c3589be4Sjmcneill const bool intr_ppi_p = gicc->PerformanceInterrupt < 32; 369999b9562Sjmcneill const int type = (gicc->Flags & ACPI_MADT_PERFORMANCE_IRQ_MODE) ? 370999b9562Sjmcneill IST_EDGE : IST_LEVEL; 371c3589be4Sjmcneill 372c3589be4Sjmcneill if (intr_ppi_p && !cpu_primary_p) 373c3589be4Sjmcneill return AE_OK; 374c3589be4Sjmcneill 375c3589be4Sjmcneill ci = cpu_acpi_find_processor(gicc->Uid); 376c3589be4Sjmcneill if (ci == NULL) { 377999b9562Sjmcneill aprint_error_dev(dev, "couldn't find processor %#x\n", 378999b9562Sjmcneill gicc->Uid); 379c3589be4Sjmcneill return AE_OK; 380c3589be4Sjmcneill } 381c3589be4Sjmcneill 382c3589be4Sjmcneill if (intr_ppi_p) { 383c3589be4Sjmcneill strlcpy(xname, "pmu", sizeof(xname)); 384c3589be4Sjmcneill } else { 385c3589be4Sjmcneill snprintf(xname, sizeof(xname), "pmu %s", cpu_name(ci)); 386c3589be4Sjmcneill } 387c3589be4Sjmcneill 388999b9562Sjmcneill ih = intr_establish_xname(gicc->PerformanceInterrupt, IPL_HIGH, 389999b9562Sjmcneill type | IST_MPSAFE, armv8_pmu_intr, NULL, xname); 390c3589be4Sjmcneill if (ih == NULL) { 391999b9562Sjmcneill aprint_error_dev(dev, "couldn't establish %s interrupt\n", 392999b9562Sjmcneill xname); 393c3589be4Sjmcneill return AE_OK; 394c3589be4Sjmcneill } 395c3589be4Sjmcneill 396c3589be4Sjmcneill if (!intr_ppi_p) { 397c3589be4Sjmcneill kcpuset_create(&set, true); 398c3589be4Sjmcneill kcpuset_set(set, cpu_index(ci)); 399c3589be4Sjmcneill error = interrupt_distribute(ih, set, NULL); 400c3589be4Sjmcneill kcpuset_destroy(set); 401c3589be4Sjmcneill 402c3589be4Sjmcneill if (error) { 403999b9562Sjmcneill aprint_error_dev(dev, 404999b9562Sjmcneill "failed to distribute %s interrupt: %d\n", 405c3589be4Sjmcneill xname, error); 406c3589be4Sjmcneill return AE_OK; 407c3589be4Sjmcneill } 408c3589be4Sjmcneill } 409c3589be4Sjmcneill 410999b9562Sjmcneill aprint_normal("%s: PMU interrupting on irq %d\n", cpu_name(ci), 411999b9562Sjmcneill gicc->PerformanceInterrupt); 412c3589be4Sjmcneill 413c3589be4Sjmcneill return AE_OK; 414c3589be4Sjmcneill } 415c3589be4Sjmcneill 416c3589be4Sjmcneill static void 417c3589be4Sjmcneill cpu_acpi_tprof_init(device_t self) 418c3589be4Sjmcneill { 419367f8a70Sskrll int err = armv8_pmu_init(); 420367f8a70Sskrll if (err) { 421367f8a70Sskrll aprint_error_dev(self, 422367f8a70Sskrll "failed to initialize PMU event counter\n"); 423367f8a70Sskrll return; 424367f8a70Sskrll } 425c3589be4Sjmcneill 426c3589be4Sjmcneill if (acpi_madt_map() != AE_OK) { 427999b9562Sjmcneill aprint_error_dev(self, 428999b9562Sjmcneill "failed to map MADT, performance counters not available\n"); 429c3589be4Sjmcneill return; 430c3589be4Sjmcneill } 431c3589be4Sjmcneill acpi_madt_walk(cpu_acpi_tprof_intr_establish, self); 432c3589be4Sjmcneill acpi_madt_unmap(); 433c3589be4Sjmcneill } 434c3589be4Sjmcneill #endif 435