1 1.28 jmcneill /* $NetBSD: acpi_machdep.c,v 1.28 2024/12/30 12:19:21 jmcneill Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2018 The NetBSD Foundation, Inc. 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jmcneill * by Jared McNeill <jmcneill (at) invisible.ca>. 9 1.1 jmcneill * 10 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 11 1.1 jmcneill * modification, are permitted provided that the following conditions 12 1.1 jmcneill * are met: 13 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 14 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 15 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 17 1.1 jmcneill * documentation and/or other materials provided with the distribution. 18 1.1 jmcneill * 19 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jmcneill * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jmcneill */ 31 1.1 jmcneill 32 1.5 jmcneill #include "pci.h" 33 1.5 jmcneill 34 1.1 jmcneill #include <sys/cdefs.h> 35 1.28 jmcneill __KERNEL_RCSID(0, "$NetBSD: acpi_machdep.c,v 1.28 2024/12/30 12:19:21 jmcneill Exp $"); 36 1.1 jmcneill 37 1.1 jmcneill #include <sys/param.h> 38 1.1 jmcneill #include <sys/systm.h> 39 1.1 jmcneill #include <sys/bus.h> 40 1.1 jmcneill #include <sys/cpu.h> 41 1.1 jmcneill #include <sys/device.h> 42 1.17 jmcneill #include <sys/kmem.h> 43 1.1 jmcneill 44 1.1 jmcneill #include <uvm/uvm_extern.h> 45 1.1 jmcneill 46 1.1 jmcneill #include <dev/fdt/fdtvar.h> 47 1.1 jmcneill 48 1.1 jmcneill #include <dev/acpi/acpica.h> 49 1.1 jmcneill #include <dev/acpi/acpivar.h> 50 1.5 jmcneill #if NPCI > 0 51 1.2 jmcneill #include <dev/acpi/acpi_mcfg.h> 52 1.5 jmcneill #endif 53 1.27 jmcneill #include <arm/acpi/acpi_iort.h> 54 1.1 jmcneill 55 1.7 jmcneill #include <arm/arm/efi_runtime.h> 56 1.7 jmcneill 57 1.1 jmcneill #include <arm/pic/picvar.h> 58 1.1 jmcneill 59 1.1 jmcneill #include <arm/locore.h> 60 1.1 jmcneill 61 1.1 jmcneill #include <machine/acpi_machdep.h> 62 1.1 jmcneill 63 1.1 jmcneill extern struct bus_space arm_generic_bs_tag; 64 1.14 jmcneill extern struct arm32_bus_dma_tag acpi_coherent_dma_tag; 65 1.14 jmcneill extern struct arm32_bus_dma_tag arm_generic_dma_tag; 66 1.14 jmcneill 67 1.25 jmcneill struct acpi_intrhandler { 68 1.25 jmcneill int (*ah_fn)(void *); 69 1.25 jmcneill void *ah_arg; 70 1.25 jmcneill TAILQ_ENTRY(acpi_intrhandler) ah_list; 71 1.25 jmcneill }; 72 1.25 jmcneill 73 1.25 jmcneill struct acpi_intrvec { 74 1.25 jmcneill int ai_irq; 75 1.25 jmcneill int ai_ipl; 76 1.25 jmcneill int ai_type; 77 1.25 jmcneill bool ai_mpsafe; 78 1.25 jmcneill int ai_refcnt; 79 1.25 jmcneill void *ai_arg; 80 1.25 jmcneill void *ai_ih; 81 1.25 jmcneill TAILQ_HEAD(, acpi_intrhandler) ai_handlers; 82 1.25 jmcneill TAILQ_ENTRY(acpi_intrvec) ai_list; 83 1.25 jmcneill }; 84 1.25 jmcneill 85 1.25 jmcneill static TAILQ_HEAD(, acpi_intrvec) acpi_intrvecs = 86 1.25 jmcneill TAILQ_HEAD_INITIALIZER(acpi_intrvecs); 87 1.25 jmcneill 88 1.19 jmcneill bus_dma_tag_t arm_acpi_dma32_tag(struct acpi_softc *, struct acpi_devnode *); 89 1.19 jmcneill bus_dma_tag_t arm_acpi_dma64_tag(struct acpi_softc *, struct acpi_devnode *); 90 1.1 jmcneill 91 1.7 jmcneill static int 92 1.7 jmcneill acpi_md_pmapflags(paddr_t pa) 93 1.7 jmcneill { 94 1.7 jmcneill int len; 95 1.7 jmcneill 96 1.7 jmcneill const int chosen = OF_finddevice("/chosen"); 97 1.7 jmcneill if (chosen == -1) 98 1.7 jmcneill return 0; 99 1.7 jmcneill 100 1.7 jmcneill const uint32_t *map = fdtbus_get_prop(chosen, "netbsd,uefi-memmap", &len); 101 1.7 jmcneill if (map == NULL) 102 1.7 jmcneill return 0; 103 1.7 jmcneill 104 1.7 jmcneill while (len >= 28) { 105 1.8 jmcneill const uint32_t type = be32dec(&map[0]); 106 1.7 jmcneill const uint64_t phys_start = be64dec(&map[1]); 107 1.7 jmcneill const uint64_t num_pages = be64dec(&map[3]); 108 1.7 jmcneill const uint64_t attr = be64dec(&map[5]); 109 1.7 jmcneill 110 1.7 jmcneill if (pa >= phys_start && pa < phys_start + (num_pages * EFI_PAGE_SIZE)) { 111 1.8 jmcneill switch (type) { 112 1.8 jmcneill case EFI_MD_TYPE_RECLAIM: 113 1.8 jmcneill /* ACPI table memory */ 114 1.7 jmcneill return PMAP_WRITE_BACK; 115 1.8 jmcneill 116 1.8 jmcneill case EFI_MD_TYPE_IOMEM: 117 1.8 jmcneill case EFI_MD_TYPE_IOPORT: 118 1.28 jmcneill return PMAP_DEV_NP; 119 1.8 jmcneill 120 1.8 jmcneill default: 121 1.8 jmcneill if ((attr & EFI_MD_ATTR_WB) != 0) 122 1.8 jmcneill return PMAP_WRITE_BACK; 123 1.8 jmcneill else if ((attr & EFI_MD_ATTR_WC) != 0) 124 1.8 jmcneill return PMAP_WRITE_COMBINE; 125 1.8 jmcneill else if ((attr & EFI_MD_ATTR_WT) != 0) 126 1.8 jmcneill return 0; /* XXX */ 127 1.8 jmcneill 128 1.28 jmcneill return PMAP_DEV_NP; 129 1.8 jmcneill } 130 1.7 jmcneill } 131 1.7 jmcneill 132 1.7 jmcneill map += 7; 133 1.7 jmcneill len -= 28; 134 1.7 jmcneill } 135 1.7 jmcneill 136 1.7 jmcneill /* Not found; assume device memory */ 137 1.7 jmcneill return PMAP_DEV; 138 1.7 jmcneill } 139 1.7 jmcneill 140 1.1 jmcneill ACPI_STATUS 141 1.1 jmcneill acpi_md_OsInitialize(void) 142 1.1 jmcneill { 143 1.1 jmcneill return AE_OK; 144 1.1 jmcneill } 145 1.1 jmcneill 146 1.1 jmcneill ACPI_PHYSICAL_ADDRESS 147 1.1 jmcneill acpi_md_OsGetRootPointer(void) 148 1.1 jmcneill { 149 1.1 jmcneill uint64_t pa; 150 1.1 jmcneill 151 1.1 jmcneill const int chosen = OF_finddevice("/chosen"); 152 1.1 jmcneill if (chosen == -1) 153 1.1 jmcneill return 0; 154 1.1 jmcneill 155 1.1 jmcneill if (of_getprop_uint64(chosen, "netbsd,acpi-root-table", &pa) != 0) 156 1.1 jmcneill return 0; 157 1.1 jmcneill 158 1.1 jmcneill return (ACPI_PHYSICAL_ADDRESS)pa; 159 1.1 jmcneill } 160 1.1 jmcneill 161 1.1 jmcneill ACPI_STATUS 162 1.1 jmcneill acpi_md_OsInstallInterruptHandler(UINT32 irq, ACPI_OSD_HANDLER handler, void *context, 163 1.1 jmcneill void **cookiep, const char *xname) 164 1.1 jmcneill { 165 1.6 jmcneill return AE_NOT_IMPLEMENTED; 166 1.1 jmcneill } 167 1.1 jmcneill 168 1.1 jmcneill void 169 1.1 jmcneill acpi_md_OsRemoveInterruptHandler(void *cookie) 170 1.1 jmcneill { 171 1.1 jmcneill intr_disestablish(cookie); 172 1.1 jmcneill } 173 1.1 jmcneill 174 1.1 jmcneill ACPI_STATUS 175 1.1 jmcneill acpi_md_OsMapMemory(ACPI_PHYSICAL_ADDRESS pa, UINT32 size, void **vap) 176 1.1 jmcneill { 177 1.1 jmcneill paddr_t spa, epa, curpa; 178 1.1 jmcneill vaddr_t va, curva; 179 1.1 jmcneill 180 1.1 jmcneill spa = trunc_page(pa); 181 1.1 jmcneill epa = round_page(pa + size); 182 1.1 jmcneill 183 1.1 jmcneill va = uvm_km_alloc(kernel_map, epa - spa, 0, UVM_KMF_VAONLY); 184 1.1 jmcneill if (va == 0) 185 1.1 jmcneill return AE_NO_MEMORY; 186 1.1 jmcneill 187 1.7 jmcneill const int pmapflags = acpi_md_pmapflags(spa); 188 1.7 jmcneill 189 1.7 jmcneill aprint_debug("%s: 0x%lx 0x%x flags = %#x\n", __func__, pa, size, pmapflags); 190 1.7 jmcneill 191 1.1 jmcneill for (curpa = spa, curva = va; curpa < epa; curpa += PAGE_SIZE, curva += PAGE_SIZE) 192 1.7 jmcneill pmap_kenter_pa(curva, curpa, VM_PROT_READ | VM_PROT_WRITE, pmapflags); 193 1.1 jmcneill pmap_update(pmap_kernel()); 194 1.1 jmcneill 195 1.1 jmcneill *vap = (void *)(va + (pa - spa)); 196 1.1 jmcneill 197 1.1 jmcneill return AE_OK; 198 1.1 jmcneill } 199 1.1 jmcneill 200 1.1 jmcneill void 201 1.1 jmcneill acpi_md_OsUnmapMemory(void *va, UINT32 size) 202 1.1 jmcneill { 203 1.1 jmcneill vaddr_t ova; 204 1.1 jmcneill vsize_t osz; 205 1.1 jmcneill 206 1.1 jmcneill ova = trunc_page((vaddr_t)va); 207 1.3 jmcneill osz = round_page((vaddr_t)va + size) - ova; 208 1.1 jmcneill 209 1.1 jmcneill pmap_kremove(ova, osz); 210 1.1 jmcneill pmap_update(pmap_kernel()); 211 1.1 jmcneill uvm_km_free(kernel_map, ova, osz, UVM_KMF_VAONLY); 212 1.1 jmcneill } 213 1.1 jmcneill 214 1.1 jmcneill ACPI_STATUS 215 1.1 jmcneill acpi_md_OsGetPhysicalAddress(void *va, ACPI_PHYSICAL_ADDRESS *pap) 216 1.1 jmcneill { 217 1.1 jmcneill paddr_t pa; 218 1.1 jmcneill 219 1.1 jmcneill if (!pmap_extract(pmap_kernel(), (vaddr_t)va, &pa)) 220 1.1 jmcneill return AE_ERROR; 221 1.1 jmcneill 222 1.1 jmcneill *pap = pa; 223 1.1 jmcneill 224 1.1 jmcneill return AE_OK; 225 1.1 jmcneill } 226 1.1 jmcneill 227 1.1 jmcneill BOOLEAN 228 1.1 jmcneill acpi_md_OsReadable(void *va, UINT32 len) 229 1.1 jmcneill { 230 1.1 jmcneill vaddr_t sva, eva; 231 1.1 jmcneill pt_entry_t *pte; 232 1.1 jmcneill 233 1.1 jmcneill sva = trunc_page((vaddr_t)va); 234 1.1 jmcneill eva = round_page((vaddr_t)va + len); 235 1.1 jmcneill 236 1.1 jmcneill if (sva < VM_MIN_KERNEL_ADDRESS) 237 1.1 jmcneill return FALSE; 238 1.1 jmcneill 239 1.1 jmcneill for (; sva < eva; sva += PAGE_SIZE) { 240 1.1 jmcneill pte = kvtopte(sva); 241 1.10 skrll if ((*pte & (LX_BLKPAG_AF|LX_BLKPAG_AP)) != (LX_BLKPAG_AF|LX_BLKPAG_AP_RO)) 242 1.1 jmcneill return FALSE; 243 1.1 jmcneill } 244 1.1 jmcneill 245 1.1 jmcneill return TRUE; 246 1.1 jmcneill } 247 1.1 jmcneill 248 1.1 jmcneill BOOLEAN 249 1.1 jmcneill acpi_md_OsWritable(void *va, UINT32 len) 250 1.1 jmcneill { 251 1.1 jmcneill vaddr_t sva, eva; 252 1.1 jmcneill pt_entry_t *pte; 253 1.1 jmcneill 254 1.1 jmcneill sva = trunc_page((vaddr_t)va); 255 1.1 jmcneill eva = round_page((vaddr_t)va + len); 256 1.1 jmcneill 257 1.1 jmcneill if (sva < VM_MIN_KERNEL_ADDRESS) 258 1.1 jmcneill return FALSE; 259 1.1 jmcneill 260 1.1 jmcneill for (; sva < eva; sva += PAGE_SIZE) { 261 1.1 jmcneill pte = kvtopte(sva); 262 1.9 skrll if ((*pte & (LX_BLKPAG_AF|LX_BLKPAG_AP)) != (LX_BLKPAG_AF|LX_BLKPAG_AP_RW)) 263 1.1 jmcneill return FALSE; 264 1.1 jmcneill } 265 1.1 jmcneill 266 1.1 jmcneill return TRUE; 267 1.1 jmcneill } 268 1.1 jmcneill 269 1.1 jmcneill void 270 1.1 jmcneill acpi_md_OsEnableInterrupt(void) 271 1.1 jmcneill { 272 1.1 jmcneill cpsie(I32_bit); 273 1.1 jmcneill } 274 1.1 jmcneill 275 1.1 jmcneill void 276 1.1 jmcneill acpi_md_OsDisableInterrupt(void) 277 1.1 jmcneill { 278 1.1 jmcneill cpsid(I32_bit); 279 1.1 jmcneill } 280 1.1 jmcneill 281 1.25 jmcneill static struct acpi_intrvec * 282 1.25 jmcneill acpi_md_intr_lookup(int irq) 283 1.25 jmcneill { 284 1.25 jmcneill struct acpi_intrvec *ai; 285 1.25 jmcneill 286 1.25 jmcneill TAILQ_FOREACH(ai, &acpi_intrvecs, ai_list) { 287 1.25 jmcneill if (ai->ai_irq == irq) { 288 1.25 jmcneill return ai; 289 1.25 jmcneill } 290 1.25 jmcneill } 291 1.25 jmcneill 292 1.25 jmcneill return NULL; 293 1.25 jmcneill } 294 1.25 jmcneill 295 1.25 jmcneill static int 296 1.25 jmcneill acpi_md_intr(void *arg) 297 1.25 jmcneill { 298 1.25 jmcneill struct acpi_intrvec *ai = arg; 299 1.25 jmcneill struct acpi_intrhandler *ah; 300 1.25 jmcneill int rv = 0; 301 1.25 jmcneill 302 1.25 jmcneill TAILQ_FOREACH(ah, &ai->ai_handlers, ah_list) { 303 1.25 jmcneill rv += ah->ah_fn(ah->ah_arg); 304 1.25 jmcneill } 305 1.25 jmcneill 306 1.25 jmcneill return rv; 307 1.25 jmcneill } 308 1.25 jmcneill 309 1.6 jmcneill void * 310 1.6 jmcneill acpi_md_intr_establish(uint32_t irq, int ipl, int type, int (*handler)(void *), void *arg, bool mpsafe, const char *xname) 311 1.6 jmcneill { 312 1.25 jmcneill struct acpi_intrvec *ai; 313 1.25 jmcneill struct acpi_intrhandler *ah; 314 1.25 jmcneill 315 1.25 jmcneill ai = acpi_md_intr_lookup(irq); 316 1.25 jmcneill if (ai == NULL) { 317 1.25 jmcneill ai = kmem_zalloc(sizeof(*ai), KM_SLEEP); 318 1.25 jmcneill ai->ai_refcnt = 0; 319 1.25 jmcneill ai->ai_irq = irq; 320 1.25 jmcneill ai->ai_ipl = ipl; 321 1.25 jmcneill ai->ai_type = type; 322 1.25 jmcneill ai->ai_mpsafe = mpsafe; 323 1.25 jmcneill ai->ai_arg = arg; 324 1.25 jmcneill TAILQ_INIT(&ai->ai_handlers); 325 1.25 jmcneill if (arg == NULL) { 326 1.25 jmcneill ai->ai_ih = intr_establish_xname(irq, ipl, 327 1.25 jmcneill type | (mpsafe ? IST_MPSAFE : 0), handler, NULL, 328 1.25 jmcneill xname); 329 1.25 jmcneill } else { 330 1.25 jmcneill ai->ai_ih = intr_establish_xname(irq, ipl, 331 1.25 jmcneill type | (mpsafe ? IST_MPSAFE : 0), acpi_md_intr, ai, 332 1.25 jmcneill xname); 333 1.25 jmcneill } 334 1.25 jmcneill if (ai->ai_ih == NULL) { 335 1.25 jmcneill kmem_free(ai, sizeof(*ai)); 336 1.25 jmcneill return NULL; 337 1.25 jmcneill } 338 1.25 jmcneill TAILQ_INSERT_TAIL(&acpi_intrvecs, ai, ai_list); 339 1.25 jmcneill } else { 340 1.25 jmcneill if (ai->ai_arg == NULL) { 341 1.25 jmcneill printf("ACPI: cannot share irq with NULL arg\n"); 342 1.25 jmcneill return NULL; 343 1.25 jmcneill } 344 1.25 jmcneill if (ai->ai_ipl != ipl) { 345 1.25 jmcneill printf("ACPI: cannot share irq with different ipl\n"); 346 1.25 jmcneill return NULL; 347 1.25 jmcneill } 348 1.25 jmcneill if (ai->ai_type != type) { 349 1.25 jmcneill printf("ACPI: cannot share edge and level interrupts\n"); 350 1.25 jmcneill return NULL; 351 1.25 jmcneill } 352 1.25 jmcneill if (ai->ai_mpsafe != mpsafe) { 353 1.25 jmcneill printf("ACPI: cannot share between mpsafe/non-mpsafe\n"); 354 1.25 jmcneill return NULL; 355 1.25 jmcneill } 356 1.25 jmcneill } 357 1.25 jmcneill 358 1.25 jmcneill ai->ai_refcnt++; 359 1.25 jmcneill 360 1.25 jmcneill ah = kmem_zalloc(sizeof(*ah), KM_SLEEP); 361 1.25 jmcneill ah->ah_fn = handler; 362 1.25 jmcneill ah->ah_arg = arg; 363 1.25 jmcneill TAILQ_INSERT_TAIL(&ai->ai_handlers, ah, ah_list); 364 1.25 jmcneill 365 1.25 jmcneill return ai->ai_ih; 366 1.25 jmcneill } 367 1.25 jmcneill 368 1.25 jmcneill void 369 1.25 jmcneill acpi_md_intr_disestablish(void *ih) 370 1.25 jmcneill { 371 1.25 jmcneill struct acpi_intrvec *ai; 372 1.25 jmcneill struct acpi_intrhandler *ah; 373 1.25 jmcneill 374 1.25 jmcneill TAILQ_FOREACH(ai, &acpi_intrvecs, ai_list) { 375 1.25 jmcneill if (ai->ai_ih == ih) { 376 1.25 jmcneill KASSERT(ai->ai_refcnt > 0); 377 1.25 jmcneill if (ai->ai_refcnt > 1) { 378 1.25 jmcneill panic("%s: cannot disestablish shared irq", __func__); 379 1.25 jmcneill } 380 1.25 jmcneill 381 1.25 jmcneill TAILQ_REMOVE(&acpi_intrvecs, ai, ai_list); 382 1.25 jmcneill ah = TAILQ_FIRST(&ai->ai_handlers); 383 1.25 jmcneill kmem_free(ah, sizeof(*ah)); 384 1.25 jmcneill intr_disestablish(ai->ai_ih); 385 1.25 jmcneill kmem_free(ai, sizeof(*ai)); 386 1.25 jmcneill return; 387 1.25 jmcneill } 388 1.25 jmcneill } 389 1.25 jmcneill 390 1.25 jmcneill panic("%s: interrupt not established", __func__); 391 1.6 jmcneill } 392 1.6 jmcneill 393 1.6 jmcneill void 394 1.11 thorpej acpi_md_intr_mask(void *ih) 395 1.11 thorpej { 396 1.12 jmcneill intr_mask(ih); 397 1.11 thorpej } 398 1.11 thorpej 399 1.11 thorpej void 400 1.11 thorpej acpi_md_intr_unmask(void *ih) 401 1.11 thorpej { 402 1.12 jmcneill intr_unmask(ih); 403 1.11 thorpej } 404 1.11 thorpej 405 1.1 jmcneill int 406 1.1 jmcneill acpi_md_sleep(int state) 407 1.1 jmcneill { 408 1.1 jmcneill printf("ERROR: ACPI sleep not implemented on this platform\n"); 409 1.1 jmcneill return -1; 410 1.1 jmcneill } 411 1.1 jmcneill 412 1.1 jmcneill uint32_t 413 1.1 jmcneill acpi_md_pdc(void) 414 1.1 jmcneill { 415 1.1 jmcneill return 0; 416 1.1 jmcneill } 417 1.1 jmcneill 418 1.1 jmcneill uint32_t 419 1.1 jmcneill acpi_md_ncpus(void) 420 1.1 jmcneill { 421 1.1 jmcneill return kcpuset_countset(kcpuset_attached); 422 1.1 jmcneill } 423 1.1 jmcneill 424 1.1 jmcneill static ACPI_STATUS 425 1.4 jmcneill acpi_md_madt_probe_cpu(ACPI_SUBTABLE_HEADER *hdrp, void *aux) 426 1.1 jmcneill { 427 1.1 jmcneill struct acpi_softc * const sc = aux; 428 1.1 jmcneill 429 1.4 jmcneill if (hdrp->Type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) 430 1.22 thorpej config_found(sc->sc_dev, hdrp, NULL, 431 1.23 thorpej CFARGS(.iattr = "acpimadtbus")); 432 1.4 jmcneill 433 1.4 jmcneill return AE_OK; 434 1.4 jmcneill } 435 1.4 jmcneill 436 1.4 jmcneill static ACPI_STATUS 437 1.4 jmcneill acpi_md_madt_probe_gic(ACPI_SUBTABLE_HEADER *hdrp, void *aux) 438 1.4 jmcneill { 439 1.4 jmcneill struct acpi_softc * const sc = aux; 440 1.4 jmcneill 441 1.4 jmcneill if (hdrp->Type == ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR) 442 1.22 thorpej config_found(sc->sc_dev, hdrp, NULL, 443 1.23 thorpej CFARGS(.iattr = "acpimadtbus")); 444 1.1 jmcneill 445 1.1 jmcneill return AE_OK; 446 1.1 jmcneill } 447 1.1 jmcneill 448 1.1 jmcneill static ACPI_STATUS 449 1.1 jmcneill acpi_md_gtdt_probe(ACPI_GTDT_HEADER *hdrp, void *aux) 450 1.1 jmcneill { 451 1.1 jmcneill struct acpi_softc * const sc = aux; 452 1.1 jmcneill 453 1.22 thorpej config_found(sc->sc_dev, hdrp, NULL, 454 1.23 thorpej CFARGS(.iattr = "acpigtdtbus")); 455 1.1 jmcneill 456 1.1 jmcneill return AE_OK; 457 1.1 jmcneill } 458 1.1 jmcneill 459 1.13 jmcneill #if NPCI > 0 460 1.13 jmcneill static struct bus_space acpi_md_mcfg_bs_tag; 461 1.13 jmcneill 462 1.13 jmcneill static int 463 1.13 jmcneill acpi_md_mcfg_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flag, 464 1.13 jmcneill bus_space_handle_t *bshp) 465 1.13 jmcneill { 466 1.13 jmcneill return arm_generic_bs_tag.bs_map(t, bpa, size, 467 1.26 jmcneill flag | BUS_SPACE_MAP_NONPOSTED, bshp); 468 1.13 jmcneill } 469 1.13 jmcneill #endif 470 1.13 jmcneill 471 1.1 jmcneill void 472 1.1 jmcneill acpi_md_callback(struct acpi_softc *sc) 473 1.1 jmcneill { 474 1.5 jmcneill #if NPCI > 0 475 1.13 jmcneill acpi_md_mcfg_bs_tag = arm_generic_bs_tag; 476 1.13 jmcneill acpi_md_mcfg_bs_tag.bs_map = acpi_md_mcfg_bs_map; 477 1.13 jmcneill acpimcfg_init(&acpi_md_mcfg_bs_tag, NULL); 478 1.5 jmcneill #endif 479 1.2 jmcneill 480 1.1 jmcneill if (acpi_madt_map() != AE_OK) 481 1.1 jmcneill panic("Failed to map MADT"); 482 1.4 jmcneill acpi_madt_walk(acpi_md_madt_probe_cpu, sc); 483 1.4 jmcneill acpi_madt_walk(acpi_md_madt_probe_gic, sc); 484 1.1 jmcneill acpi_madt_unmap(); 485 1.1 jmcneill 486 1.1 jmcneill if (acpi_gtdt_map() != AE_OK) 487 1.1 jmcneill panic("Failed to map GTDT"); 488 1.1 jmcneill acpi_gtdt_walk(acpi_md_gtdt_probe, sc); 489 1.1 jmcneill acpi_gtdt_unmap(); 490 1.1 jmcneill } 491 1.14 jmcneill 492 1.15 jmcneill static const char * const module_hid[] = { 493 1.15 jmcneill "ACPI0004", /* Module device */ 494 1.15 jmcneill NULL 495 1.15 jmcneill }; 496 1.15 jmcneill 497 1.17 jmcneill static ACPI_HANDLE 498 1.17 jmcneill arm_acpi_dma_module(struct acpi_softc *sc, struct acpi_devnode *ad) 499 1.17 jmcneill { 500 1.17 jmcneill ACPI_HANDLE tmp; 501 1.17 jmcneill ACPI_STATUS rv; 502 1.17 jmcneill 503 1.17 jmcneill /* 504 1.17 jmcneill * Search up the tree for a module device with a _DMA method. 505 1.17 jmcneill */ 506 1.17 jmcneill for (; ad != NULL; ad = ad->ad_parent) { 507 1.17 jmcneill if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) 508 1.17 jmcneill continue; 509 1.17 jmcneill if (!acpi_match_hid(ad->ad_devinfo, module_hid)) 510 1.17 jmcneill continue; 511 1.17 jmcneill rv = AcpiGetHandle(ad->ad_handle, "_DMA", &tmp); 512 1.17 jmcneill if (ACPI_SUCCESS(rv)) 513 1.17 jmcneill return ad->ad_handle; 514 1.17 jmcneill } 515 1.17 jmcneill 516 1.17 jmcneill return NULL; 517 1.17 jmcneill } 518 1.17 jmcneill 519 1.17 jmcneill static void 520 1.17 jmcneill arm_acpi_dma_init_ranges(struct acpi_softc *sc, struct acpi_devnode *ad, 521 1.17 jmcneill struct arm32_bus_dma_tag *dmat, uint32_t flags) 522 1.15 jmcneill { 523 1.15 jmcneill struct acpi_resources res; 524 1.15 jmcneill struct acpi_mem *mem; 525 1.17 jmcneill ACPI_HANDLE module; 526 1.27 jmcneill ACPI_IORT_NAMED_COMPONENT *nc; 527 1.15 jmcneill ACPI_STATUS rv; 528 1.27 jmcneill uintptr_t dma_mask; 529 1.17 jmcneill int n; 530 1.17 jmcneill 531 1.17 jmcneill module = arm_acpi_dma_module(sc, ad->ad_parent); 532 1.17 jmcneill if (module == NULL) { 533 1.17 jmcneill default_tag: 534 1.27 jmcneill rv = acpi_iort_named_component(ad, &nc); 535 1.27 jmcneill if (ACPI_SUCCESS(rv) && nc->MemoryAddressLimit != 0) { 536 1.27 jmcneill dma_mask = __BITS(nc->MemoryAddressLimit - 1, 0); 537 1.27 jmcneill } else { 538 1.27 jmcneill dma_mask = UINTPTR_MAX; 539 1.27 jmcneill } 540 1.27 jmcneill 541 1.17 jmcneill /* No translation required */ 542 1.17 jmcneill dmat->_nranges = 1; 543 1.17 jmcneill dmat->_ranges = kmem_zalloc(sizeof(*dmat->_ranges), KM_SLEEP); 544 1.17 jmcneill dmat->_ranges[0].dr_sysbase = 0; 545 1.17 jmcneill dmat->_ranges[0].dr_busbase = 0; 546 1.27 jmcneill dmat->_ranges[0].dr_len = dma_mask; 547 1.17 jmcneill dmat->_ranges[0].dr_flags = flags; 548 1.17 jmcneill return; 549 1.17 jmcneill } 550 1.15 jmcneill 551 1.24 jmcneill rv = acpi_resource_parse_any(sc->sc_dev, module, "_DMA", &res, 552 1.15 jmcneill &acpi_resource_parse_ops_quiet); 553 1.17 jmcneill if (ACPI_FAILURE(rv)) { 554 1.17 jmcneill aprint_error_dev(sc->sc_dev, 555 1.17 jmcneill "failed to parse _DMA on %s: %s\n", 556 1.17 jmcneill acpi_name(module), AcpiFormatException(rv)); 557 1.17 jmcneill goto default_tag; 558 1.17 jmcneill } 559 1.17 jmcneill if (res.ar_nmem == 0) { 560 1.17 jmcneill acpi_resource_cleanup(&res); 561 1.17 jmcneill goto default_tag; 562 1.17 jmcneill } 563 1.15 jmcneill 564 1.17 jmcneill dmat->_nranges = res.ar_nmem; 565 1.17 jmcneill dmat->_ranges = kmem_zalloc(sizeof(*dmat->_ranges) * res.ar_nmem, 566 1.17 jmcneill KM_SLEEP); 567 1.17 jmcneill 568 1.17 jmcneill for (n = 0; n < res.ar_nmem; n++) { 569 1.17 jmcneill mem = acpi_res_mem(&res, n); 570 1.17 jmcneill dmat->_ranges[n].dr_busbase = mem->ar_base; 571 1.18 jmcneill dmat->_ranges[n].dr_sysbase = mem->ar_xbase; 572 1.17 jmcneill dmat->_ranges[n].dr_len = mem->ar_length; 573 1.17 jmcneill dmat->_ranges[n].dr_flags = flags; 574 1.17 jmcneill 575 1.17 jmcneill aprint_debug_dev(sc->sc_dev, 576 1.18 jmcneill "%s: DMA sys %#lx-%#lx bus %#lx-%#lx%s\n", 577 1.17 jmcneill acpi_name(ad->ad_handle), 578 1.17 jmcneill dmat->_ranges[n].dr_sysbase, 579 1.18 jmcneill dmat->_ranges[n].dr_sysbase + dmat->_ranges[n].dr_len - 1, 580 1.17 jmcneill dmat->_ranges[n].dr_busbase, 581 1.18 jmcneill dmat->_ranges[n].dr_busbase + dmat->_ranges[n].dr_len - 1, 582 1.17 jmcneill flags ? " (coherent)" : ""); 583 1.15 jmcneill } 584 1.15 jmcneill 585 1.15 jmcneill acpi_resource_cleanup(&res); 586 1.15 jmcneill } 587 1.15 jmcneill 588 1.17 jmcneill static uint32_t 589 1.17 jmcneill arm_acpi_dma_flags(struct acpi_softc *sc, struct acpi_devnode *ad) 590 1.16 jmcneill { 591 1.17 jmcneill ACPI_INTEGER cca = 1; /* default cache coherent */ 592 1.16 jmcneill ACPI_STATUS rv; 593 1.16 jmcneill 594 1.16 jmcneill for (; ad != NULL; ad = ad->ad_parent) { 595 1.16 jmcneill if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) 596 1.16 jmcneill continue; 597 1.17 jmcneill 598 1.17 jmcneill rv = acpi_eval_integer(ad->ad_handle, "_CCA", &cca); 599 1.16 jmcneill if (ACPI_SUCCESS(rv)) 600 1.17 jmcneill break; 601 1.16 jmcneill } 602 1.16 jmcneill 603 1.17 jmcneill return cca ? _BUS_DMAMAP_COHERENT : 0; 604 1.16 jmcneill } 605 1.16 jmcneill 606 1.19 jmcneill bus_dma_tag_t 607 1.19 jmcneill arm_acpi_dma32_tag(struct acpi_softc *sc, struct acpi_devnode *ad) 608 1.19 jmcneill { 609 1.19 jmcneill bus_dma_tag_t dmat64, dmat32; 610 1.19 jmcneill int error; 611 1.19 jmcneill 612 1.19 jmcneill if (ad->ad_dmat != NULL) 613 1.19 jmcneill return ad->ad_dmat; 614 1.19 jmcneill 615 1.19 jmcneill dmat64 = arm_acpi_dma64_tag(sc, ad); 616 1.19 jmcneill 617 1.19 jmcneill const uint32_t flags = arm_acpi_dma_flags(sc, ad); 618 1.19 jmcneill error = bus_dmatag_subregion(dmat64, 0, UINT32_MAX, &dmat32, flags); 619 1.19 jmcneill if (error != 0) 620 1.19 jmcneill panic("arm_acpi_dma32_tag: bus_dmatag_subregion returned %d", 621 1.19 jmcneill error); 622 1.19 jmcneill 623 1.19 jmcneill return dmat32; 624 1.19 jmcneill } 625 1.19 jmcneill __strong_alias(acpi_get_dma_tag,arm_acpi_dma32_tag); 626 1.17 jmcneill 627 1.14 jmcneill bus_dma_tag_t 628 1.19 jmcneill arm_acpi_dma64_tag(struct acpi_softc *sc, struct acpi_devnode *ad) 629 1.14 jmcneill { 630 1.17 jmcneill struct arm32_bus_dma_tag *dmat; 631 1.14 jmcneill 632 1.19 jmcneill if (ad->ad_dmat64 != NULL) 633 1.19 jmcneill return ad->ad_dmat64; 634 1.20 skrll 635 1.17 jmcneill dmat = kmem_alloc(sizeof(*dmat), KM_SLEEP); 636 1.17 jmcneill *dmat = arm_generic_dma_tag; 637 1.14 jmcneill 638 1.17 jmcneill const uint32_t flags = arm_acpi_dma_flags(sc, ad); 639 1.17 jmcneill arm_acpi_dma_init_ranges(sc, ad, dmat, flags); 640 1.15 jmcneill 641 1.15 jmcneill return dmat; 642 1.14 jmcneill } 643 1.19 jmcneill __strong_alias(acpi_get_dma64_tag,arm_acpi_dma64_tag); 644