1*4ced5fcbSjmcneill /* $NetBSD: acpi_machdep.c,v 1.28 2024/12/30 12:19:21 jmcneill Exp $ */ 2a55241bdSjmcneill 3a55241bdSjmcneill /*- 4a55241bdSjmcneill * Copyright (c) 2018 The NetBSD Foundation, Inc. 5a55241bdSjmcneill * All rights reserved. 6a55241bdSjmcneill * 7a55241bdSjmcneill * This code is derived from software contributed to The NetBSD Foundation 8a55241bdSjmcneill * by Jared McNeill <jmcneill@invisible.ca>. 9a55241bdSjmcneill * 10a55241bdSjmcneill * Redistribution and use in source and binary forms, with or without 11a55241bdSjmcneill * modification, are permitted provided that the following conditions 12a55241bdSjmcneill * are met: 13a55241bdSjmcneill * 1. Redistributions of source code must retain the above copyright 14a55241bdSjmcneill * notice, this list of conditions and the following disclaimer. 15a55241bdSjmcneill * 2. Redistributions in binary form must reproduce the above copyright 16a55241bdSjmcneill * notice, this list of conditions and the following disclaimer in the 17a55241bdSjmcneill * documentation and/or other materials provided with the distribution. 18a55241bdSjmcneill * 19a55241bdSjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20a55241bdSjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21a55241bdSjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22a55241bdSjmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23a55241bdSjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24a55241bdSjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25a55241bdSjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26a55241bdSjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27a55241bdSjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28a55241bdSjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29a55241bdSjmcneill * POSSIBILITY OF SUCH DAMAGE. 30a55241bdSjmcneill */ 31a55241bdSjmcneill 32193d42ddSjmcneill #include "pci.h" 33193d42ddSjmcneill 34a55241bdSjmcneill #include <sys/cdefs.h> 35*4ced5fcbSjmcneill __KERNEL_RCSID(0, "$NetBSD: acpi_machdep.c,v 1.28 2024/12/30 12:19:21 jmcneill Exp $"); 36a55241bdSjmcneill 37a55241bdSjmcneill #include <sys/param.h> 38a55241bdSjmcneill #include <sys/systm.h> 39a55241bdSjmcneill #include <sys/bus.h> 40a55241bdSjmcneill #include <sys/cpu.h> 41a55241bdSjmcneill #include <sys/device.h> 42a4285215Sjmcneill #include <sys/kmem.h> 43a55241bdSjmcneill 44a55241bdSjmcneill #include <uvm/uvm_extern.h> 45a55241bdSjmcneill 46a55241bdSjmcneill #include <dev/fdt/fdtvar.h> 47a55241bdSjmcneill 48a55241bdSjmcneill #include <dev/acpi/acpica.h> 49a55241bdSjmcneill #include <dev/acpi/acpivar.h> 50193d42ddSjmcneill #if NPCI > 0 51e2ed649eSjmcneill #include <dev/acpi/acpi_mcfg.h> 52193d42ddSjmcneill #endif 53172ad57dSjmcneill #include <arm/acpi/acpi_iort.h> 54a55241bdSjmcneill 556cef9d10Sjmcneill #include <arm/arm/efi_runtime.h> 566cef9d10Sjmcneill 57a55241bdSjmcneill #include <arm/pic/picvar.h> 58a55241bdSjmcneill 59a55241bdSjmcneill #include <arm/locore.h> 60a55241bdSjmcneill 61a55241bdSjmcneill #include <machine/acpi_machdep.h> 62a55241bdSjmcneill 63a55241bdSjmcneill extern struct bus_space arm_generic_bs_tag; 643d25b0deSjmcneill extern struct arm32_bus_dma_tag acpi_coherent_dma_tag; 653d25b0deSjmcneill extern struct arm32_bus_dma_tag arm_generic_dma_tag; 663d25b0deSjmcneill 67deb170c0Sjmcneill struct acpi_intrhandler { 68deb170c0Sjmcneill int (*ah_fn)(void *); 69deb170c0Sjmcneill void *ah_arg; 70deb170c0Sjmcneill TAILQ_ENTRY(acpi_intrhandler) ah_list; 71deb170c0Sjmcneill }; 72deb170c0Sjmcneill 73deb170c0Sjmcneill struct acpi_intrvec { 74deb170c0Sjmcneill int ai_irq; 75deb170c0Sjmcneill int ai_ipl; 76deb170c0Sjmcneill int ai_type; 77deb170c0Sjmcneill bool ai_mpsafe; 78deb170c0Sjmcneill int ai_refcnt; 79deb170c0Sjmcneill void *ai_arg; 80deb170c0Sjmcneill void *ai_ih; 81deb170c0Sjmcneill TAILQ_HEAD(, acpi_intrhandler) ai_handlers; 82deb170c0Sjmcneill TAILQ_ENTRY(acpi_intrvec) ai_list; 83deb170c0Sjmcneill }; 84deb170c0Sjmcneill 85deb170c0Sjmcneill static TAILQ_HEAD(, acpi_intrvec) acpi_intrvecs = 86deb170c0Sjmcneill TAILQ_HEAD_INITIALIZER(acpi_intrvecs); 87deb170c0Sjmcneill 88a496d771Sjmcneill bus_dma_tag_t arm_acpi_dma32_tag(struct acpi_softc *, struct acpi_devnode *); 89a496d771Sjmcneill bus_dma_tag_t arm_acpi_dma64_tag(struct acpi_softc *, struct acpi_devnode *); 90a55241bdSjmcneill 916cef9d10Sjmcneill static int 926cef9d10Sjmcneill acpi_md_pmapflags(paddr_t pa) 936cef9d10Sjmcneill { 946cef9d10Sjmcneill int len; 956cef9d10Sjmcneill 966cef9d10Sjmcneill const int chosen = OF_finddevice("/chosen"); 976cef9d10Sjmcneill if (chosen == -1) 986cef9d10Sjmcneill return 0; 996cef9d10Sjmcneill 1006cef9d10Sjmcneill const uint32_t *map = fdtbus_get_prop(chosen, "netbsd,uefi-memmap", &len); 1016cef9d10Sjmcneill if (map == NULL) 1026cef9d10Sjmcneill return 0; 1036cef9d10Sjmcneill 1046cef9d10Sjmcneill while (len >= 28) { 105614bfd57Sjmcneill const uint32_t type = be32dec(&map[0]); 1066cef9d10Sjmcneill const uint64_t phys_start = be64dec(&map[1]); 1076cef9d10Sjmcneill const uint64_t num_pages = be64dec(&map[3]); 1086cef9d10Sjmcneill const uint64_t attr = be64dec(&map[5]); 1096cef9d10Sjmcneill 1106cef9d10Sjmcneill if (pa >= phys_start && pa < phys_start + (num_pages * EFI_PAGE_SIZE)) { 111614bfd57Sjmcneill switch (type) { 112614bfd57Sjmcneill case EFI_MD_TYPE_RECLAIM: 113614bfd57Sjmcneill /* ACPI table memory */ 114614bfd57Sjmcneill return PMAP_WRITE_BACK; 115614bfd57Sjmcneill 116614bfd57Sjmcneill case EFI_MD_TYPE_IOMEM: 117614bfd57Sjmcneill case EFI_MD_TYPE_IOPORT: 118*4ced5fcbSjmcneill return PMAP_DEV_NP; 119614bfd57Sjmcneill 120614bfd57Sjmcneill default: 121614bfd57Sjmcneill if ((attr & EFI_MD_ATTR_WB) != 0) 122614bfd57Sjmcneill return PMAP_WRITE_BACK; 1236cef9d10Sjmcneill else if ((attr & EFI_MD_ATTR_WC) != 0) 1246cef9d10Sjmcneill return PMAP_WRITE_COMBINE; 1256cef9d10Sjmcneill else if ((attr & EFI_MD_ATTR_WT) != 0) 1266cef9d10Sjmcneill return 0; /* XXX */ 127614bfd57Sjmcneill 128*4ced5fcbSjmcneill return PMAP_DEV_NP; 1296cef9d10Sjmcneill } 130614bfd57Sjmcneill } 1316cef9d10Sjmcneill 1326cef9d10Sjmcneill map += 7; 1336cef9d10Sjmcneill len -= 28; 1346cef9d10Sjmcneill } 1356cef9d10Sjmcneill 1366cef9d10Sjmcneill /* Not found; assume device memory */ 1376cef9d10Sjmcneill return PMAP_DEV; 1386cef9d10Sjmcneill } 1396cef9d10Sjmcneill 140a55241bdSjmcneill ACPI_STATUS 141a55241bdSjmcneill acpi_md_OsInitialize(void) 142a55241bdSjmcneill { 143a55241bdSjmcneill return AE_OK; 144a55241bdSjmcneill } 145a55241bdSjmcneill 146a55241bdSjmcneill ACPI_PHYSICAL_ADDRESS 147a55241bdSjmcneill acpi_md_OsGetRootPointer(void) 148a55241bdSjmcneill { 149a55241bdSjmcneill uint64_t pa; 150a55241bdSjmcneill 151a55241bdSjmcneill const int chosen = OF_finddevice("/chosen"); 152a55241bdSjmcneill if (chosen == -1) 153a55241bdSjmcneill return 0; 154a55241bdSjmcneill 155a55241bdSjmcneill if (of_getprop_uint64(chosen, "netbsd,acpi-root-table", &pa) != 0) 156a55241bdSjmcneill return 0; 157a55241bdSjmcneill 158a55241bdSjmcneill return (ACPI_PHYSICAL_ADDRESS)pa; 159a55241bdSjmcneill } 160a55241bdSjmcneill 161a55241bdSjmcneill ACPI_STATUS 162a55241bdSjmcneill acpi_md_OsInstallInterruptHandler(UINT32 irq, ACPI_OSD_HANDLER handler, void *context, 163a55241bdSjmcneill void **cookiep, const char *xname) 164a55241bdSjmcneill { 165f608d081Sjmcneill return AE_NOT_IMPLEMENTED; 166a55241bdSjmcneill } 167a55241bdSjmcneill 168a55241bdSjmcneill void 169a55241bdSjmcneill acpi_md_OsRemoveInterruptHandler(void *cookie) 170a55241bdSjmcneill { 171a55241bdSjmcneill intr_disestablish(cookie); 172a55241bdSjmcneill } 173a55241bdSjmcneill 174a55241bdSjmcneill ACPI_STATUS 175a55241bdSjmcneill acpi_md_OsMapMemory(ACPI_PHYSICAL_ADDRESS pa, UINT32 size, void **vap) 176a55241bdSjmcneill { 177a55241bdSjmcneill paddr_t spa, epa, curpa; 178a55241bdSjmcneill vaddr_t va, curva; 179a55241bdSjmcneill 180a55241bdSjmcneill spa = trunc_page(pa); 181a55241bdSjmcneill epa = round_page(pa + size); 182a55241bdSjmcneill 183a55241bdSjmcneill va = uvm_km_alloc(kernel_map, epa - spa, 0, UVM_KMF_VAONLY); 184a55241bdSjmcneill if (va == 0) 185a55241bdSjmcneill return AE_NO_MEMORY; 186a55241bdSjmcneill 1876cef9d10Sjmcneill const int pmapflags = acpi_md_pmapflags(spa); 1886cef9d10Sjmcneill 1896cef9d10Sjmcneill aprint_debug("%s: 0x%lx 0x%x flags = %#x\n", __func__, pa, size, pmapflags); 1906cef9d10Sjmcneill 191a55241bdSjmcneill for (curpa = spa, curva = va; curpa < epa; curpa += PAGE_SIZE, curva += PAGE_SIZE) 1926cef9d10Sjmcneill pmap_kenter_pa(curva, curpa, VM_PROT_READ | VM_PROT_WRITE, pmapflags); 193a55241bdSjmcneill pmap_update(pmap_kernel()); 194a55241bdSjmcneill 195a55241bdSjmcneill *vap = (void *)(va + (pa - spa)); 196a55241bdSjmcneill 197a55241bdSjmcneill return AE_OK; 198a55241bdSjmcneill } 199a55241bdSjmcneill 200a55241bdSjmcneill void 201a55241bdSjmcneill acpi_md_OsUnmapMemory(void *va, UINT32 size) 202a55241bdSjmcneill { 203a55241bdSjmcneill vaddr_t ova; 204a55241bdSjmcneill vsize_t osz; 205a55241bdSjmcneill 206a55241bdSjmcneill ova = trunc_page((vaddr_t)va); 207ab34a45fSjmcneill osz = round_page((vaddr_t)va + size) - ova; 208a55241bdSjmcneill 209a55241bdSjmcneill pmap_kremove(ova, osz); 210a55241bdSjmcneill pmap_update(pmap_kernel()); 211a55241bdSjmcneill uvm_km_free(kernel_map, ova, osz, UVM_KMF_VAONLY); 212a55241bdSjmcneill } 213a55241bdSjmcneill 214a55241bdSjmcneill ACPI_STATUS 215a55241bdSjmcneill acpi_md_OsGetPhysicalAddress(void *va, ACPI_PHYSICAL_ADDRESS *pap) 216a55241bdSjmcneill { 217a55241bdSjmcneill paddr_t pa; 218a55241bdSjmcneill 219a55241bdSjmcneill if (!pmap_extract(pmap_kernel(), (vaddr_t)va, &pa)) 220a55241bdSjmcneill return AE_ERROR; 221a55241bdSjmcneill 222a55241bdSjmcneill *pap = pa; 223a55241bdSjmcneill 224a55241bdSjmcneill return AE_OK; 225a55241bdSjmcneill } 226a55241bdSjmcneill 227a55241bdSjmcneill BOOLEAN 228a55241bdSjmcneill acpi_md_OsReadable(void *va, UINT32 len) 229a55241bdSjmcneill { 230a55241bdSjmcneill vaddr_t sva, eva; 231a55241bdSjmcneill pt_entry_t *pte; 232a55241bdSjmcneill 233a55241bdSjmcneill sva = trunc_page((vaddr_t)va); 234a55241bdSjmcneill eva = round_page((vaddr_t)va + len); 235a55241bdSjmcneill 236a55241bdSjmcneill if (sva < VM_MIN_KERNEL_ADDRESS) 237a55241bdSjmcneill return FALSE; 238a55241bdSjmcneill 239a55241bdSjmcneill for (; sva < eva; sva += PAGE_SIZE) { 240a55241bdSjmcneill pte = kvtopte(sva); 2417528e213Sskrll if ((*pte & (LX_BLKPAG_AF|LX_BLKPAG_AP)) != (LX_BLKPAG_AF|LX_BLKPAG_AP_RO)) 242a55241bdSjmcneill return FALSE; 243a55241bdSjmcneill } 244a55241bdSjmcneill 245a55241bdSjmcneill return TRUE; 246a55241bdSjmcneill } 247a55241bdSjmcneill 248a55241bdSjmcneill BOOLEAN 249a55241bdSjmcneill acpi_md_OsWritable(void *va, UINT32 len) 250a55241bdSjmcneill { 251a55241bdSjmcneill vaddr_t sva, eva; 252a55241bdSjmcneill pt_entry_t *pte; 253a55241bdSjmcneill 254a55241bdSjmcneill sva = trunc_page((vaddr_t)va); 255a55241bdSjmcneill eva = round_page((vaddr_t)va + len); 256a55241bdSjmcneill 257a55241bdSjmcneill if (sva < VM_MIN_KERNEL_ADDRESS) 258a55241bdSjmcneill return FALSE; 259a55241bdSjmcneill 260a55241bdSjmcneill for (; sva < eva; sva += PAGE_SIZE) { 261a55241bdSjmcneill pte = kvtopte(sva); 2626e28f0b2Sskrll if ((*pte & (LX_BLKPAG_AF|LX_BLKPAG_AP)) != (LX_BLKPAG_AF|LX_BLKPAG_AP_RW)) 263a55241bdSjmcneill return FALSE; 264a55241bdSjmcneill } 265a55241bdSjmcneill 266a55241bdSjmcneill return TRUE; 267a55241bdSjmcneill } 268a55241bdSjmcneill 269a55241bdSjmcneill void 270a55241bdSjmcneill acpi_md_OsEnableInterrupt(void) 271a55241bdSjmcneill { 272a55241bdSjmcneill cpsie(I32_bit); 273a55241bdSjmcneill } 274a55241bdSjmcneill 275a55241bdSjmcneill void 276a55241bdSjmcneill acpi_md_OsDisableInterrupt(void) 277a55241bdSjmcneill { 278a55241bdSjmcneill cpsid(I32_bit); 279a55241bdSjmcneill } 280a55241bdSjmcneill 281deb170c0Sjmcneill static struct acpi_intrvec * 282deb170c0Sjmcneill acpi_md_intr_lookup(int irq) 283deb170c0Sjmcneill { 284deb170c0Sjmcneill struct acpi_intrvec *ai; 285deb170c0Sjmcneill 286deb170c0Sjmcneill TAILQ_FOREACH(ai, &acpi_intrvecs, ai_list) { 287deb170c0Sjmcneill if (ai->ai_irq == irq) { 288deb170c0Sjmcneill return ai; 289deb170c0Sjmcneill } 290deb170c0Sjmcneill } 291deb170c0Sjmcneill 292deb170c0Sjmcneill return NULL; 293deb170c0Sjmcneill } 294deb170c0Sjmcneill 295deb170c0Sjmcneill static int 296deb170c0Sjmcneill acpi_md_intr(void *arg) 297deb170c0Sjmcneill { 298deb170c0Sjmcneill struct acpi_intrvec *ai = arg; 299deb170c0Sjmcneill struct acpi_intrhandler *ah; 300deb170c0Sjmcneill int rv = 0; 301deb170c0Sjmcneill 302deb170c0Sjmcneill TAILQ_FOREACH(ah, &ai->ai_handlers, ah_list) { 303deb170c0Sjmcneill rv += ah->ah_fn(ah->ah_arg); 304deb170c0Sjmcneill } 305deb170c0Sjmcneill 306deb170c0Sjmcneill return rv; 307deb170c0Sjmcneill } 308deb170c0Sjmcneill 309f608d081Sjmcneill void * 310f608d081Sjmcneill acpi_md_intr_establish(uint32_t irq, int ipl, int type, int (*handler)(void *), void *arg, bool mpsafe, const char *xname) 311f608d081Sjmcneill { 312deb170c0Sjmcneill struct acpi_intrvec *ai; 313deb170c0Sjmcneill struct acpi_intrhandler *ah; 314deb170c0Sjmcneill 315deb170c0Sjmcneill ai = acpi_md_intr_lookup(irq); 316deb170c0Sjmcneill if (ai == NULL) { 317deb170c0Sjmcneill ai = kmem_zalloc(sizeof(*ai), KM_SLEEP); 318deb170c0Sjmcneill ai->ai_refcnt = 0; 319deb170c0Sjmcneill ai->ai_irq = irq; 320deb170c0Sjmcneill ai->ai_ipl = ipl; 321deb170c0Sjmcneill ai->ai_type = type; 322deb170c0Sjmcneill ai->ai_mpsafe = mpsafe; 323deb170c0Sjmcneill ai->ai_arg = arg; 324deb170c0Sjmcneill TAILQ_INIT(&ai->ai_handlers); 325deb170c0Sjmcneill if (arg == NULL) { 326deb170c0Sjmcneill ai->ai_ih = intr_establish_xname(irq, ipl, 327deb170c0Sjmcneill type | (mpsafe ? IST_MPSAFE : 0), handler, NULL, 328deb170c0Sjmcneill xname); 329deb170c0Sjmcneill } else { 330deb170c0Sjmcneill ai->ai_ih = intr_establish_xname(irq, ipl, 331deb170c0Sjmcneill type | (mpsafe ? IST_MPSAFE : 0), acpi_md_intr, ai, 332deb170c0Sjmcneill xname); 333deb170c0Sjmcneill } 334deb170c0Sjmcneill if (ai->ai_ih == NULL) { 335deb170c0Sjmcneill kmem_free(ai, sizeof(*ai)); 336deb170c0Sjmcneill return NULL; 337deb170c0Sjmcneill } 338deb170c0Sjmcneill TAILQ_INSERT_TAIL(&acpi_intrvecs, ai, ai_list); 339deb170c0Sjmcneill } else { 340deb170c0Sjmcneill if (ai->ai_arg == NULL) { 341deb170c0Sjmcneill printf("ACPI: cannot share irq with NULL arg\n"); 342deb170c0Sjmcneill return NULL; 343deb170c0Sjmcneill } 344deb170c0Sjmcneill if (ai->ai_ipl != ipl) { 345deb170c0Sjmcneill printf("ACPI: cannot share irq with different ipl\n"); 346deb170c0Sjmcneill return NULL; 347deb170c0Sjmcneill } 348deb170c0Sjmcneill if (ai->ai_type != type) { 349deb170c0Sjmcneill printf("ACPI: cannot share edge and level interrupts\n"); 350deb170c0Sjmcneill return NULL; 351deb170c0Sjmcneill } 352deb170c0Sjmcneill if (ai->ai_mpsafe != mpsafe) { 353deb170c0Sjmcneill printf("ACPI: cannot share between mpsafe/non-mpsafe\n"); 354deb170c0Sjmcneill return NULL; 355deb170c0Sjmcneill } 356deb170c0Sjmcneill } 357deb170c0Sjmcneill 358deb170c0Sjmcneill ai->ai_refcnt++; 359deb170c0Sjmcneill 360deb170c0Sjmcneill ah = kmem_zalloc(sizeof(*ah), KM_SLEEP); 361deb170c0Sjmcneill ah->ah_fn = handler; 362deb170c0Sjmcneill ah->ah_arg = arg; 363deb170c0Sjmcneill TAILQ_INSERT_TAIL(&ai->ai_handlers, ah, ah_list); 364deb170c0Sjmcneill 365deb170c0Sjmcneill return ai->ai_ih; 366deb170c0Sjmcneill } 367deb170c0Sjmcneill 368deb170c0Sjmcneill void 369deb170c0Sjmcneill acpi_md_intr_disestablish(void *ih) 370deb170c0Sjmcneill { 371deb170c0Sjmcneill struct acpi_intrvec *ai; 372deb170c0Sjmcneill struct acpi_intrhandler *ah; 373deb170c0Sjmcneill 374deb170c0Sjmcneill TAILQ_FOREACH(ai, &acpi_intrvecs, ai_list) { 375deb170c0Sjmcneill if (ai->ai_ih == ih) { 376deb170c0Sjmcneill KASSERT(ai->ai_refcnt > 0); 377deb170c0Sjmcneill if (ai->ai_refcnt > 1) { 378deb170c0Sjmcneill panic("%s: cannot disestablish shared irq", __func__); 379deb170c0Sjmcneill } 380deb170c0Sjmcneill 381deb170c0Sjmcneill TAILQ_REMOVE(&acpi_intrvecs, ai, ai_list); 382deb170c0Sjmcneill ah = TAILQ_FIRST(&ai->ai_handlers); 383deb170c0Sjmcneill kmem_free(ah, sizeof(*ah)); 384deb170c0Sjmcneill intr_disestablish(ai->ai_ih); 385deb170c0Sjmcneill kmem_free(ai, sizeof(*ai)); 386deb170c0Sjmcneill return; 387deb170c0Sjmcneill } 388deb170c0Sjmcneill } 389deb170c0Sjmcneill 390deb170c0Sjmcneill panic("%s: interrupt not established", __func__); 391f608d081Sjmcneill } 392f608d081Sjmcneill 393f608d081Sjmcneill void 394659765daSthorpej acpi_md_intr_mask(void *ih) 395659765daSthorpej { 396d7ae102bSjmcneill intr_mask(ih); 397659765daSthorpej } 398659765daSthorpej 399659765daSthorpej void 400659765daSthorpej acpi_md_intr_unmask(void *ih) 401659765daSthorpej { 402d7ae102bSjmcneill intr_unmask(ih); 403659765daSthorpej } 404659765daSthorpej 405a55241bdSjmcneill int 406a55241bdSjmcneill acpi_md_sleep(int state) 407a55241bdSjmcneill { 408a55241bdSjmcneill printf("ERROR: ACPI sleep not implemented on this platform\n"); 409a55241bdSjmcneill return -1; 410a55241bdSjmcneill } 411a55241bdSjmcneill 412a55241bdSjmcneill uint32_t 413a55241bdSjmcneill acpi_md_pdc(void) 414a55241bdSjmcneill { 415a55241bdSjmcneill return 0; 416a55241bdSjmcneill } 417a55241bdSjmcneill 418a55241bdSjmcneill uint32_t 419a55241bdSjmcneill acpi_md_ncpus(void) 420a55241bdSjmcneill { 421a55241bdSjmcneill return kcpuset_countset(kcpuset_attached); 422a55241bdSjmcneill } 423a55241bdSjmcneill 424a55241bdSjmcneill static ACPI_STATUS 4251c576135Sjmcneill acpi_md_madt_probe_cpu(ACPI_SUBTABLE_HEADER *hdrp, void *aux) 426a55241bdSjmcneill { 427a55241bdSjmcneill struct acpi_softc * const sc = aux; 428a55241bdSjmcneill 4291c576135Sjmcneill if (hdrp->Type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) 4302685996bSthorpej config_found(sc->sc_dev, hdrp, NULL, 431c7fb772bSthorpej CFARGS(.iattr = "acpimadtbus")); 4321c576135Sjmcneill 4331c576135Sjmcneill return AE_OK; 4341c576135Sjmcneill } 4351c576135Sjmcneill 4361c576135Sjmcneill static ACPI_STATUS 4371c576135Sjmcneill acpi_md_madt_probe_gic(ACPI_SUBTABLE_HEADER *hdrp, void *aux) 4381c576135Sjmcneill { 4391c576135Sjmcneill struct acpi_softc * const sc = aux; 4401c576135Sjmcneill 4411c576135Sjmcneill if (hdrp->Type == ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR) 4422685996bSthorpej config_found(sc->sc_dev, hdrp, NULL, 443c7fb772bSthorpej CFARGS(.iattr = "acpimadtbus")); 444a55241bdSjmcneill 445a55241bdSjmcneill return AE_OK; 446a55241bdSjmcneill } 447a55241bdSjmcneill 448a55241bdSjmcneill static ACPI_STATUS 449a55241bdSjmcneill acpi_md_gtdt_probe(ACPI_GTDT_HEADER *hdrp, void *aux) 450a55241bdSjmcneill { 451a55241bdSjmcneill struct acpi_softc * const sc = aux; 452a55241bdSjmcneill 4532685996bSthorpej config_found(sc->sc_dev, hdrp, NULL, 454c7fb772bSthorpej CFARGS(.iattr = "acpigtdtbus")); 455a55241bdSjmcneill 456a55241bdSjmcneill return AE_OK; 457a55241bdSjmcneill } 458a55241bdSjmcneill 459059f233aSjmcneill #if NPCI > 0 460059f233aSjmcneill static struct bus_space acpi_md_mcfg_bs_tag; 461059f233aSjmcneill 462059f233aSjmcneill static int 463059f233aSjmcneill acpi_md_mcfg_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flag, 464059f233aSjmcneill bus_space_handle_t *bshp) 465059f233aSjmcneill { 466059f233aSjmcneill return arm_generic_bs_tag.bs_map(t, bpa, size, 4675158b98cSjmcneill flag | BUS_SPACE_MAP_NONPOSTED, bshp); 468059f233aSjmcneill } 469059f233aSjmcneill #endif 470059f233aSjmcneill 471a55241bdSjmcneill void 472a55241bdSjmcneill acpi_md_callback(struct acpi_softc *sc) 473a55241bdSjmcneill { 474193d42ddSjmcneill #if NPCI > 0 475059f233aSjmcneill acpi_md_mcfg_bs_tag = arm_generic_bs_tag; 476059f233aSjmcneill acpi_md_mcfg_bs_tag.bs_map = acpi_md_mcfg_bs_map; 477059f233aSjmcneill acpimcfg_init(&acpi_md_mcfg_bs_tag, NULL); 478193d42ddSjmcneill #endif 479e2ed649eSjmcneill 480a55241bdSjmcneill if (acpi_madt_map() != AE_OK) 481a55241bdSjmcneill panic("Failed to map MADT"); 4821c576135Sjmcneill acpi_madt_walk(acpi_md_madt_probe_cpu, sc); 4831c576135Sjmcneill acpi_madt_walk(acpi_md_madt_probe_gic, sc); 484a55241bdSjmcneill acpi_madt_unmap(); 485a55241bdSjmcneill 486a55241bdSjmcneill if (acpi_gtdt_map() != AE_OK) 487a55241bdSjmcneill panic("Failed to map GTDT"); 488a55241bdSjmcneill acpi_gtdt_walk(acpi_md_gtdt_probe, sc); 489a55241bdSjmcneill acpi_gtdt_unmap(); 490a55241bdSjmcneill } 4913d25b0deSjmcneill 492d69f9e19Sjmcneill static const char * const module_hid[] = { 493d69f9e19Sjmcneill "ACPI0004", /* Module device */ 494d69f9e19Sjmcneill NULL 495d69f9e19Sjmcneill }; 496d69f9e19Sjmcneill 497c1448d3eSjmcneill static ACPI_HANDLE 498c1448d3eSjmcneill arm_acpi_dma_module(struct acpi_softc *sc, struct acpi_devnode *ad) 499c1448d3eSjmcneill { 500c1448d3eSjmcneill ACPI_HANDLE tmp; 501c1448d3eSjmcneill ACPI_STATUS rv; 502c1448d3eSjmcneill 503c1448d3eSjmcneill /* 504c1448d3eSjmcneill * Search up the tree for a module device with a _DMA method. 505c1448d3eSjmcneill */ 506c1448d3eSjmcneill for (; ad != NULL; ad = ad->ad_parent) { 507c1448d3eSjmcneill if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) 508c1448d3eSjmcneill continue; 509c1448d3eSjmcneill if (!acpi_match_hid(ad->ad_devinfo, module_hid)) 510c1448d3eSjmcneill continue; 511c1448d3eSjmcneill rv = AcpiGetHandle(ad->ad_handle, "_DMA", &tmp); 512c1448d3eSjmcneill if (ACPI_SUCCESS(rv)) 513c1448d3eSjmcneill return ad->ad_handle; 514c1448d3eSjmcneill } 515c1448d3eSjmcneill 516c1448d3eSjmcneill return NULL; 517c1448d3eSjmcneill } 518c1448d3eSjmcneill 519a4285215Sjmcneill static void 520a4285215Sjmcneill arm_acpi_dma_init_ranges(struct acpi_softc *sc, struct acpi_devnode *ad, 521a4285215Sjmcneill struct arm32_bus_dma_tag *dmat, uint32_t flags) 522a4285215Sjmcneill { 523a4285215Sjmcneill struct acpi_resources res; 524a4285215Sjmcneill struct acpi_mem *mem; 525a4285215Sjmcneill ACPI_HANDLE module; 526172ad57dSjmcneill ACPI_IORT_NAMED_COMPONENT *nc; 527a4285215Sjmcneill ACPI_STATUS rv; 528172ad57dSjmcneill uintptr_t dma_mask; 529a4285215Sjmcneill int n; 530a4285215Sjmcneill 531a4285215Sjmcneill module = arm_acpi_dma_module(sc, ad->ad_parent); 532a4285215Sjmcneill if (module == NULL) { 533a4285215Sjmcneill default_tag: 534172ad57dSjmcneill rv = acpi_iort_named_component(ad, &nc); 535172ad57dSjmcneill if (ACPI_SUCCESS(rv) && nc->MemoryAddressLimit != 0) { 536172ad57dSjmcneill dma_mask = __BITS(nc->MemoryAddressLimit - 1, 0); 537172ad57dSjmcneill } else { 538172ad57dSjmcneill dma_mask = UINTPTR_MAX; 539172ad57dSjmcneill } 540172ad57dSjmcneill 541a4285215Sjmcneill /* No translation required */ 542a4285215Sjmcneill dmat->_nranges = 1; 543a4285215Sjmcneill dmat->_ranges = kmem_zalloc(sizeof(*dmat->_ranges), KM_SLEEP); 544a4285215Sjmcneill dmat->_ranges[0].dr_sysbase = 0; 545a4285215Sjmcneill dmat->_ranges[0].dr_busbase = 0; 546172ad57dSjmcneill dmat->_ranges[0].dr_len = dma_mask; 547a4285215Sjmcneill dmat->_ranges[0].dr_flags = flags; 548a4285215Sjmcneill return; 549a4285215Sjmcneill } 550a4285215Sjmcneill 551514dd0dbSjmcneill rv = acpi_resource_parse_any(sc->sc_dev, module, "_DMA", &res, 552a4285215Sjmcneill &acpi_resource_parse_ops_quiet); 553a4285215Sjmcneill if (ACPI_FAILURE(rv)) { 554a4285215Sjmcneill aprint_error_dev(sc->sc_dev, 555a4285215Sjmcneill "failed to parse _DMA on %s: %s\n", 556a4285215Sjmcneill acpi_name(module), AcpiFormatException(rv)); 557a4285215Sjmcneill goto default_tag; 558a4285215Sjmcneill } 559a4285215Sjmcneill if (res.ar_nmem == 0) { 560a4285215Sjmcneill acpi_resource_cleanup(&res); 561a4285215Sjmcneill goto default_tag; 562a4285215Sjmcneill } 563a4285215Sjmcneill 564a4285215Sjmcneill dmat->_nranges = res.ar_nmem; 565a4285215Sjmcneill dmat->_ranges = kmem_zalloc(sizeof(*dmat->_ranges) * res.ar_nmem, 566a4285215Sjmcneill KM_SLEEP); 567a4285215Sjmcneill 568a4285215Sjmcneill for (n = 0; n < res.ar_nmem; n++) { 569a4285215Sjmcneill mem = acpi_res_mem(&res, n); 570a4285215Sjmcneill dmat->_ranges[n].dr_busbase = mem->ar_base; 5710dc1816eSjmcneill dmat->_ranges[n].dr_sysbase = mem->ar_xbase; 572a4285215Sjmcneill dmat->_ranges[n].dr_len = mem->ar_length; 573a4285215Sjmcneill dmat->_ranges[n].dr_flags = flags; 574a4285215Sjmcneill 575a4285215Sjmcneill aprint_debug_dev(sc->sc_dev, 5760dc1816eSjmcneill "%s: DMA sys %#lx-%#lx bus %#lx-%#lx%s\n", 577a4285215Sjmcneill acpi_name(ad->ad_handle), 578a4285215Sjmcneill dmat->_ranges[n].dr_sysbase, 5790dc1816eSjmcneill dmat->_ranges[n].dr_sysbase + dmat->_ranges[n].dr_len - 1, 580a4285215Sjmcneill dmat->_ranges[n].dr_busbase, 5810dc1816eSjmcneill dmat->_ranges[n].dr_busbase + dmat->_ranges[n].dr_len - 1, 582a4285215Sjmcneill flags ? " (coherent)" : ""); 583a4285215Sjmcneill } 584a4285215Sjmcneill 585a4285215Sjmcneill acpi_resource_cleanup(&res); 586a4285215Sjmcneill } 587a4285215Sjmcneill 588a4285215Sjmcneill static uint32_t 589a4285215Sjmcneill arm_acpi_dma_flags(struct acpi_softc *sc, struct acpi_devnode *ad) 590a4285215Sjmcneill { 591a4285215Sjmcneill ACPI_INTEGER cca = 1; /* default cache coherent */ 592a4285215Sjmcneill ACPI_STATUS rv; 593a4285215Sjmcneill 594a4285215Sjmcneill for (; ad != NULL; ad = ad->ad_parent) { 595a4285215Sjmcneill if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) 596a4285215Sjmcneill continue; 597a4285215Sjmcneill 598a4285215Sjmcneill rv = acpi_eval_integer(ad->ad_handle, "_CCA", &cca); 599a4285215Sjmcneill if (ACPI_SUCCESS(rv)) 600a4285215Sjmcneill break; 601a4285215Sjmcneill } 602a4285215Sjmcneill 603a4285215Sjmcneill return cca ? _BUS_DMAMAP_COHERENT : 0; 604a4285215Sjmcneill } 605a4285215Sjmcneill 6063d25b0deSjmcneill bus_dma_tag_t 607a496d771Sjmcneill arm_acpi_dma32_tag(struct acpi_softc *sc, struct acpi_devnode *ad) 6083d25b0deSjmcneill { 609a496d771Sjmcneill bus_dma_tag_t dmat64, dmat32; 610a496d771Sjmcneill int error; 6113d25b0deSjmcneill 612a4285215Sjmcneill if (ad->ad_dmat != NULL) 613a4285215Sjmcneill return ad->ad_dmat; 6143d25b0deSjmcneill 615a496d771Sjmcneill dmat64 = arm_acpi_dma64_tag(sc, ad); 616a496d771Sjmcneill 617a496d771Sjmcneill const uint32_t flags = arm_acpi_dma_flags(sc, ad); 618a496d771Sjmcneill error = bus_dmatag_subregion(dmat64, 0, UINT32_MAX, &dmat32, flags); 619a496d771Sjmcneill if (error != 0) 620a496d771Sjmcneill panic("arm_acpi_dma32_tag: bus_dmatag_subregion returned %d", 621a496d771Sjmcneill error); 622a496d771Sjmcneill 623a496d771Sjmcneill return dmat32; 624a496d771Sjmcneill } 625a496d771Sjmcneill __strong_alias(acpi_get_dma_tag,arm_acpi_dma32_tag); 626a496d771Sjmcneill 627a496d771Sjmcneill bus_dma_tag_t 628a496d771Sjmcneill arm_acpi_dma64_tag(struct acpi_softc *sc, struct acpi_devnode *ad) 629a496d771Sjmcneill { 630a496d771Sjmcneill struct arm32_bus_dma_tag *dmat; 631a496d771Sjmcneill 632a496d771Sjmcneill if (ad->ad_dmat64 != NULL) 633a496d771Sjmcneill return ad->ad_dmat64; 634a496d771Sjmcneill 635a4285215Sjmcneill dmat = kmem_alloc(sizeof(*dmat), KM_SLEEP); 636a4285215Sjmcneill *dmat = arm_generic_dma_tag; 637d69f9e19Sjmcneill 638a4285215Sjmcneill const uint32_t flags = arm_acpi_dma_flags(sc, ad); 639a4285215Sjmcneill arm_acpi_dma_init_ranges(sc, ad, dmat, flags); 640d69f9e19Sjmcneill 641d69f9e19Sjmcneill return dmat; 6423d25b0deSjmcneill } 643a496d771Sjmcneill __strong_alias(acpi_get_dma64_tag,arm_acpi_dma64_tag); 644