1 /* $NetBSD: acpi_machdep.c,v 1.19 2018/03/20 12:14:52 bouyer Exp $ */ 2 3 /* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * Machine-dependent routines for ACPICA. 40 */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: acpi_machdep.c,v 1.19 2018/03/20 12:14:52 bouyer Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/bus.h> 48 #include <sys/cpu.h> 49 #include <sys/device.h> 50 51 #include <uvm/uvm_extern.h> 52 53 #include <machine/cpufunc.h> 54 #include <machine/bootinfo.h> 55 #include <machine/autoconf.h> 56 57 #include <dev/acpi/acpica.h> 58 #include <dev/acpi/acpivar.h> 59 #include <dev/acpi/acpi_mcfg.h> 60 61 #include <machine/acpi_machdep.h> 62 #include <machine/mpbiosvar.h> 63 #include <machine/mpacpi.h> 64 #include <machine/i82093reg.h> 65 #include <machine/i82093var.h> 66 #include <machine/pic.h> 67 68 #include <x86/efi.h> 69 70 #include <dev/pci/pcivar.h> 71 72 #include <dev/isa/isareg.h> 73 #include <dev/isa/isavar.h> 74 75 #include "ioapic.h" 76 77 #include "acpica.h" 78 #include "opt_mpbios.h" 79 #include "opt_acpi.h" 80 #include "opt_vga.h" 81 82 /* 83 * Default VBIOS reset method for non-HW accelerated VGA drivers. 84 */ 85 #ifdef VGA_POST 86 # define VBIOS_RESET_DEFAULT 2 87 #else 88 # define VBIOS_RESET_DEFAULT 1 89 #endif 90 91 ACPI_STATUS 92 acpi_md_OsInitialize(void) 93 { 94 return AE_OK; 95 } 96 97 ACPI_PHYSICAL_ADDRESS 98 acpi_md_OsGetRootPointer(void) 99 { 100 ACPI_PHYSICAL_ADDRESS PhysicalAddress; 101 ACPI_STATUS Status; 102 103 #ifndef XEN 104 /* If EFI is available, attempt to use it to locate the ACPI table. */ 105 if (efi_probe()) { 106 PhysicalAddress = efi_getcfgtblpa(&EFI_UUID_ACPI20); 107 if (!PhysicalAddress) 108 PhysicalAddress = efi_getcfgtblpa(&EFI_UUID_ACPI10); 109 if (PhysicalAddress) 110 return PhysicalAddress; 111 } 112 113 #endif 114 Status = AcpiFindRootPointer(&PhysicalAddress); 115 if (ACPI_FAILURE(Status)) 116 PhysicalAddress = 0; 117 118 return PhysicalAddress; 119 } 120 121 struct acpi_md_override { 122 int irq; 123 int pin; 124 int flags; 125 }; 126 127 #if NIOAPIC > 0 128 static ACPI_STATUS 129 acpi_md_findoverride(ACPI_SUBTABLE_HEADER *hdrp, void *aux) 130 { 131 ACPI_MADT_INTERRUPT_OVERRIDE *iop; 132 struct acpi_md_override *ovrp; 133 134 if (hdrp->Type != ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) { 135 return AE_OK; 136 } 137 138 iop = (void *)hdrp; 139 ovrp = aux; 140 if (iop->SourceIrq == ovrp->irq) { 141 ovrp->pin = iop->GlobalIrq; 142 ovrp->flags = iop->IntiFlags; 143 } 144 return AE_OK; 145 } 146 #endif 147 148 ACPI_STATUS 149 acpi_md_OsInstallInterruptHandler(uint32_t InterruptNumber, 150 ACPI_OSD_HANDLER ServiceRoutine, void *Context, void **cookiep, 151 const char *xname) 152 { 153 void *ih; 154 struct pic *pic; 155 #if NIOAPIC > 0 156 struct ioapic_softc *sc; 157 struct acpi_md_override ovr; 158 struct mp_intr_map tmpmap, *mip, **mipp = NULL; 159 #endif 160 int irq, pin, type, redir, mpflags; 161 162 /* 163 * ACPI interrupts default to level-triggered active-low. 164 */ 165 166 type = IST_LEVEL; 167 mpflags = (MPS_INTTR_LEVEL << 2) | MPS_INTPO_ACTLO; 168 redir = IOAPIC_REDLO_LEVEL | IOAPIC_REDLO_ACTLO; 169 170 #if NIOAPIC > 0 171 172 /* 173 * Apply any MADT override setting. 174 */ 175 176 ovr.irq = InterruptNumber; 177 ovr.pin = -1; 178 if (acpi_madt_map() == AE_OK) { 179 acpi_madt_walk(acpi_md_findoverride, &ovr); 180 acpi_madt_unmap(); 181 } else { 182 aprint_debug("acpi_madt_map() failed, can't check for MADT override\n"); 183 } 184 185 if (ovr.pin != -1) { 186 bool sci = InterruptNumber == AcpiGbl_FADT.SciInterrupt; 187 int polarity = ovr.flags & ACPI_MADT_POLARITY_MASK; 188 int trigger = ovr.flags & ACPI_MADT_TRIGGER_MASK; 189 190 InterruptNumber = ovr.pin; 191 if (polarity == ACPI_MADT_POLARITY_ACTIVE_HIGH || 192 (!sci && polarity == ACPI_MADT_POLARITY_CONFORMS)) { 193 mpflags &= ~MPS_INTPO_ACTLO; 194 mpflags |= MPS_INTPO_ACTHI; 195 redir &= ~IOAPIC_REDLO_ACTLO; 196 } 197 if (trigger == ACPI_MADT_TRIGGER_EDGE || 198 (!sci && trigger == ACPI_MADT_TRIGGER_CONFORMS)) { 199 type = IST_EDGE; 200 mpflags &= ~(MPS_INTTR_LEVEL << 2); 201 mpflags |= (MPS_INTTR_EDGE << 2); 202 redir &= ~IOAPIC_REDLO_LEVEL; 203 } 204 } 205 206 /* 207 * If the interrupt is handled via IOAPIC, update the map. 208 * If the map isn't set up yet, install a temporary one. 209 */ 210 211 sc = ioapic_find_bybase(InterruptNumber); 212 if (sc != NULL) { 213 pic = &sc->sc_pic; 214 215 if (pic->pic_type == PIC_IOAPIC) { 216 pin = (int)InterruptNumber - pic->pic_vecbase; 217 irq = -1; 218 } else { 219 irq = pin = (int)InterruptNumber; 220 } 221 222 mip = sc->sc_pins[pin].ip_map; 223 if (mip) { 224 mip->flags &= ~0xf; 225 mip->flags |= mpflags; 226 mip->redir &= ~(IOAPIC_REDLO_LEVEL | 227 IOAPIC_REDLO_ACTLO); 228 mip->redir |= redir; 229 } else { 230 mipp = &sc->sc_pins[pin].ip_map; 231 *mipp = &tmpmap; 232 tmpmap.redir = redir; 233 tmpmap.flags = mpflags; 234 } 235 } else 236 #endif 237 { 238 pic = &i8259_pic; 239 irq = pin = (int)InterruptNumber; 240 } 241 242 /* 243 * XXX probably, IPL_BIO is enough. 244 */ 245 ih = intr_establish_xname(irq, pic, pin, type, IPL_TTY, 246 (int (*)(void *)) ServiceRoutine, Context, false, xname); 247 248 #if NIOAPIC > 0 249 if (mipp) { 250 *mipp = NULL; 251 } 252 #endif 253 254 if (ih == NULL) 255 return AE_NO_MEMORY; 256 257 *cookiep = ih; 258 259 return AE_OK; 260 } 261 262 void 263 acpi_md_OsRemoveInterruptHandler(void *cookie) 264 { 265 intr_disestablish(cookie); 266 } 267 268 ACPI_STATUS 269 acpi_md_OsMapMemory(ACPI_PHYSICAL_ADDRESS PhysicalAddress, 270 uint32_t Length, void **LogicalAddress) 271 { 272 int rv; 273 274 rv = _x86_memio_map(x86_bus_space_mem, PhysicalAddress, 275 Length, 0, (bus_space_handle_t *)LogicalAddress); 276 277 return (rv != 0) ? AE_NO_MEMORY : AE_OK; 278 } 279 280 void 281 acpi_md_OsUnmapMemory(void *LogicalAddress, uint32_t Length) 282 { 283 (void) _x86_memio_unmap(x86_bus_space_mem, 284 (bus_space_handle_t)LogicalAddress, Length, NULL); 285 } 286 287 ACPI_STATUS 288 acpi_md_OsGetPhysicalAddress(void *LogicalAddress, 289 ACPI_PHYSICAL_ADDRESS *PhysicalAddress) 290 { 291 paddr_t pa; 292 293 if (pmap_extract(pmap_kernel(), (vaddr_t) LogicalAddress, &pa)) { 294 *PhysicalAddress = pa; 295 return AE_OK; 296 } 297 298 return AE_ERROR; 299 } 300 301 BOOLEAN 302 acpi_md_OsReadable(void *Pointer, uint32_t Length) 303 { 304 BOOLEAN rv = TRUE; 305 vaddr_t sva, eva; 306 pt_entry_t *pte; 307 308 sva = trunc_page((vaddr_t) Pointer); 309 eva = round_page((vaddr_t) Pointer + Length); 310 311 if (sva < VM_MIN_KERNEL_ADDRESS) 312 return FALSE; 313 314 for (; sva < eva; sva += PAGE_SIZE) { 315 pte = kvtopte(sva); 316 if ((*pte & PG_V) == 0) { 317 rv = FALSE; 318 break; 319 } 320 } 321 322 return rv; 323 } 324 325 BOOLEAN 326 acpi_md_OsWritable(void *Pointer, uint32_t Length) 327 { 328 BOOLEAN rv = TRUE; 329 vaddr_t sva, eva; 330 pt_entry_t *pte; 331 332 sva = trunc_page((vaddr_t) Pointer); 333 eva = round_page((vaddr_t) Pointer + Length); 334 335 if (sva < VM_MIN_KERNEL_ADDRESS) 336 return FALSE; 337 338 for (; sva < eva; sva += PAGE_SIZE) { 339 pte = kvtopte(sva); 340 if ((*pte & (PG_V|PG_W)) != (PG_V|PG_W)) { 341 rv = FALSE; 342 break; 343 } 344 } 345 346 return rv; 347 } 348 349 void 350 acpi_md_OsDisableInterrupt(void) 351 { 352 x86_disable_intr(); 353 } 354 355 void 356 acpi_md_OsEnableInterrupt(void) 357 { 358 x86_enable_intr(); 359 } 360 361 uint32_t 362 acpi_md_ncpus(void) 363 { 364 return kcpuset_countset(kcpuset_attached); 365 } 366 367 static bool 368 acpi_md_mcfg_validate(uint64_t addr, int bus_start, int *bus_end) 369 { 370 struct btinfo_memmap *bim; 371 uint64_t size, mapaddr, mapsize; 372 uint32_t type; 373 int i, n; 374 375 #ifndef XEN 376 if (lookup_bootinfo(BTINFO_EFIMEMMAP) != NULL) 377 bim = efi_get_e820memmap(); 378 else 379 #endif 380 bim = lookup_bootinfo(BTINFO_MEMMAP); 381 if (bim == NULL) 382 return false; 383 384 size = *bus_end - bus_start + 1; 385 size *= ACPIMCFG_SIZE_PER_BUS; 386 for (i = 0; i < bim->num; i++) { 387 mapaddr = bim->entry[i].addr; 388 mapsize = bim->entry[i].size; 389 type = bim->entry[i].type; 390 391 aprint_debug("MCFG: MEMMAP: 0x%016" PRIx64 392 "-0x%016" PRIx64 ", size=0x%016" PRIx64 393 ", type=%d(%s)\n", 394 mapaddr, mapaddr + mapsize - 1, mapsize, type, 395 (type == BIM_Memory) ? "Memory" : 396 (type == BIM_Reserved) ? "Reserved" : 397 (type == BIM_ACPI) ? "ACPI" : 398 (type == BIM_NVS) ? "NVS" : 399 (type == BIM_PMEM) ? "Persistent" : 400 (type == BIM_PRAM) ? "Persistent (Legacy)" : 401 "unknown"); 402 403 switch (type) { 404 case BIM_ACPI: 405 case BIM_Reserved: 406 if (addr < mapaddr || addr >= mapaddr + mapsize) 407 break; 408 409 /* full map */ 410 if (addr + size <= mapaddr + mapsize) 411 return true; 412 413 /* partial map */ 414 n = (mapsize - (addr - mapaddr)) / 415 ACPIMCFG_SIZE_PER_BUS; 416 /* bus_start == bus_end is not allowed. */ 417 if (n > 1) { 418 *bus_end = bus_start + n - 1; 419 return true; 420 } 421 aprint_debug("MCFG: bus %d-%d, address 0x%016" PRIx64 422 ": invalid size: request 0x%016" PRIx64 ", " 423 "actual 0x%016" PRIx64 "\n", 424 bus_start, *bus_end, addr, size, mapsize); 425 break; 426 } 427 } 428 aprint_debug("MCFG: bus %d-%d, address 0x%016" PRIx64 ": " 429 "no valid region\n", bus_start, *bus_end, addr); 430 return false; 431 } 432 433 static uint32_t 434 acpi_md_mcfg_read(bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t addr) 435 { 436 vaddr_t va = bsh + addr; 437 uint32_t data = (uint32_t) -1; 438 439 KASSERT(bst == x86_bus_space_mem); 440 441 __asm("movl %1, %0" : "=a" (data) : "m" (*(volatile uint32_t *)va)); 442 443 return data; 444 } 445 446 static void 447 acpi_md_mcfg_write(bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t addr, 448 uint32_t data) 449 { 450 vaddr_t va = bsh + addr; 451 452 KASSERT(bst == x86_bus_space_mem); 453 454 __asm("movl %1, %0" : "=m" (*(volatile uint32_t *)va) : "a" (data)); 455 } 456 457 static const struct acpimcfg_ops acpi_md_mcfg_ops = { 458 .ao_validate = acpi_md_mcfg_validate, 459 460 .ao_read = acpi_md_mcfg_read, 461 .ao_write = acpi_md_mcfg_write, 462 }; 463 464 void 465 acpi_md_callback(struct acpi_softc *sc) 466 { 467 #ifdef MPBIOS 468 if (!mpbios_scanned) 469 #endif 470 mpacpi_find_interrupts(sc); 471 472 #ifndef XEN 473 acpi_md_sleep_init(); 474 #endif 475 476 acpimcfg_init(x86_bus_space_mem, &acpi_md_mcfg_ops); 477 } 478 479 #ifndef XEN 480 void 481 device_acpi_register(device_t dev, void *aux) 482 { 483 device_t parent; 484 bool device_is_vga, device_is_pci, device_is_isa; 485 486 parent = device_parent(dev); 487 if (parent == NULL) 488 return; 489 490 device_is_vga = device_is_a(dev, "vga") || device_is_a(dev, "genfb"); 491 device_is_pci = device_is_a(parent, "pci"); 492 device_is_isa = device_is_a(parent, "isa"); 493 494 if (device_is_vga && (device_is_pci || device_is_isa)) { 495 extern int acpi_md_vbios_reset; 496 497 acpi_md_vbios_reset = VBIOS_RESET_DEFAULT; 498 } 499 } 500 #endif 501