1 /* $NetBSD: acpi_machdep.c,v 1.10 2015/10/06 15:06:05 christos 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.10 2015/10/06 15:06:05 christos 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 56 #include <dev/acpi/acpica.h> 57 #include <dev/acpi/acpivar.h> 58 #include <dev/acpi/acpi_mcfg.h> 59 60 #include <machine/acpi_machdep.h> 61 #include <machine/mpbiosvar.h> 62 #include <machine/mpacpi.h> 63 #include <machine/i82093reg.h> 64 #include <machine/i82093var.h> 65 #include <machine/pic.h> 66 67 #include <dev/pci/pcivar.h> 68 69 #include <dev/isa/isareg.h> 70 #include <dev/isa/isavar.h> 71 72 #include "ioapic.h" 73 74 #include "acpica.h" 75 #include "opt_mpbios.h" 76 #include "opt_acpi.h" 77 78 ACPI_STATUS 79 acpi_md_OsInitialize(void) 80 { 81 return AE_OK; 82 } 83 84 ACPI_PHYSICAL_ADDRESS 85 acpi_md_OsGetRootPointer(void) 86 { 87 ACPI_PHYSICAL_ADDRESS PhysicalAddress; 88 ACPI_STATUS Status; 89 90 Status = AcpiFindRootPointer(&PhysicalAddress); 91 92 if (ACPI_FAILURE(Status)) 93 PhysicalAddress = 0; 94 95 return PhysicalAddress; 96 } 97 98 struct acpi_md_override { 99 int irq; 100 int pin; 101 int flags; 102 }; 103 104 #if NIOAPIC > 0 105 static ACPI_STATUS 106 acpi_md_findoverride(ACPI_SUBTABLE_HEADER *hdrp, void *aux) 107 { 108 ACPI_MADT_INTERRUPT_OVERRIDE *iop; 109 struct acpi_md_override *ovrp; 110 111 if (hdrp->Type != ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) { 112 return AE_OK; 113 } 114 115 iop = (void *)hdrp; 116 ovrp = aux; 117 if (iop->SourceIrq == ovrp->irq) { 118 ovrp->pin = iop->GlobalIrq; 119 ovrp->flags = iop->IntiFlags; 120 } 121 return AE_OK; 122 } 123 #endif 124 125 ACPI_STATUS 126 acpi_md_OsInstallInterruptHandler(uint32_t InterruptNumber, 127 ACPI_OSD_HANDLER ServiceRoutine, void *Context, void **cookiep) 128 { 129 void *ih; 130 struct pic *pic; 131 #if NIOAPIC > 0 132 struct ioapic_softc *sc; 133 struct acpi_md_override ovr; 134 struct mp_intr_map tmpmap, *mip, **mipp = NULL; 135 #endif 136 int irq, pin, type, redir, mpflags; 137 138 /* 139 * ACPI interrupts default to level-triggered active-low. 140 */ 141 142 type = IST_LEVEL; 143 mpflags = (MPS_INTTR_LEVEL << 2) | MPS_INTPO_ACTLO; 144 redir = IOAPIC_REDLO_LEVEL | IOAPIC_REDLO_ACTLO; 145 146 #if NIOAPIC > 0 147 148 /* 149 * Apply any MADT override setting. 150 */ 151 152 ovr.irq = InterruptNumber; 153 ovr.pin = -1; 154 if (acpi_madt_map() == AE_OK) { 155 acpi_madt_walk(acpi_md_findoverride, &ovr); 156 acpi_madt_unmap(); 157 } else { 158 aprint_debug("acpi_madt_map() failed, can't check for MADT override\n"); 159 } 160 161 if (ovr.pin != -1) { 162 bool sci = InterruptNumber == AcpiGbl_FADT.SciInterrupt; 163 int polarity = ovr.flags & ACPI_MADT_POLARITY_MASK; 164 int trigger = ovr.flags & ACPI_MADT_TRIGGER_MASK; 165 166 InterruptNumber = ovr.pin; 167 if (polarity == ACPI_MADT_POLARITY_ACTIVE_HIGH || 168 (!sci && polarity == ACPI_MADT_POLARITY_CONFORMS)) { 169 mpflags &= ~MPS_INTPO_ACTLO; 170 mpflags |= MPS_INTPO_ACTHI; 171 redir &= ~IOAPIC_REDLO_ACTLO; 172 } 173 if (trigger == ACPI_MADT_TRIGGER_EDGE || 174 (!sci && trigger == ACPI_MADT_TRIGGER_CONFORMS)) { 175 type = IST_EDGE; 176 mpflags &= ~(MPS_INTTR_LEVEL << 2); 177 mpflags |= (MPS_INTTR_EDGE << 2); 178 redir &= ~IOAPIC_REDLO_LEVEL; 179 } 180 } 181 182 /* 183 * If the interrupt is handled via IOAPIC, update the map. 184 * If the map isn't set up yet, install a temporary one. 185 */ 186 187 sc = ioapic_find_bybase(InterruptNumber); 188 if (sc != NULL) { 189 pic = &sc->sc_pic; 190 191 if (pic->pic_type == PIC_IOAPIC) { 192 pin = (int)InterruptNumber - pic->pic_vecbase; 193 irq = -1; 194 } else { 195 irq = pin = (int)InterruptNumber; 196 } 197 198 mip = sc->sc_pins[pin].ip_map; 199 if (mip) { 200 mip->flags &= ~0xf; 201 mip->flags |= mpflags; 202 mip->redir &= ~(IOAPIC_REDLO_LEVEL | 203 IOAPIC_REDLO_ACTLO); 204 mip->redir |= redir; 205 } else { 206 mipp = &sc->sc_pins[pin].ip_map; 207 *mipp = &tmpmap; 208 tmpmap.redir = redir; 209 tmpmap.flags = mpflags; 210 } 211 } else 212 #endif 213 { 214 pic = &i8259_pic; 215 irq = pin = (int)InterruptNumber; 216 } 217 218 /* 219 * XXX probably, IPL_BIO is enough. 220 */ 221 ih = intr_establish(irq, pic, pin, type, IPL_TTY, 222 (int (*)(void *)) ServiceRoutine, Context, false); 223 224 #if NIOAPIC > 0 225 if (mipp) { 226 *mipp = NULL; 227 } 228 #endif 229 230 if (ih == NULL) 231 return AE_NO_MEMORY; 232 233 *cookiep = ih; 234 235 return AE_OK; 236 } 237 238 void 239 acpi_md_OsRemoveInterruptHandler(void *cookie) 240 { 241 intr_disestablish(cookie); 242 } 243 244 ACPI_STATUS 245 acpi_md_OsMapMemory(ACPI_PHYSICAL_ADDRESS PhysicalAddress, 246 uint32_t Length, void **LogicalAddress) 247 { 248 int rv; 249 250 rv = _x86_memio_map(x86_bus_space_mem, PhysicalAddress, 251 Length, 0, (bus_space_handle_t *)LogicalAddress); 252 253 return (rv != 0) ? AE_NO_MEMORY : AE_OK; 254 } 255 256 void 257 acpi_md_OsUnmapMemory(void *LogicalAddress, uint32_t Length) 258 { 259 (void) _x86_memio_unmap(x86_bus_space_mem, 260 (bus_space_handle_t)LogicalAddress, Length, NULL); 261 } 262 263 ACPI_STATUS 264 acpi_md_OsGetPhysicalAddress(void *LogicalAddress, 265 ACPI_PHYSICAL_ADDRESS *PhysicalAddress) 266 { 267 paddr_t pa; 268 269 if (pmap_extract(pmap_kernel(), (vaddr_t) LogicalAddress, &pa)) { 270 *PhysicalAddress = pa; 271 return AE_OK; 272 } 273 274 return AE_ERROR; 275 } 276 277 BOOLEAN 278 acpi_md_OsReadable(void *Pointer, uint32_t Length) 279 { 280 BOOLEAN rv = TRUE; 281 vaddr_t sva, eva; 282 pt_entry_t *pte; 283 284 sva = trunc_page((vaddr_t) Pointer); 285 eva = round_page((vaddr_t) Pointer + Length); 286 287 if (sva < VM_MIN_KERNEL_ADDRESS) 288 return FALSE; 289 290 for (; sva < eva; sva += PAGE_SIZE) { 291 pte = kvtopte(sva); 292 if ((*pte & PG_V) == 0) { 293 rv = FALSE; 294 break; 295 } 296 } 297 298 return rv; 299 } 300 301 BOOLEAN 302 acpi_md_OsWritable(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|PG_W)) != (PG_V|PG_W)) { 317 rv = FALSE; 318 break; 319 } 320 } 321 322 return rv; 323 } 324 325 void 326 acpi_md_OsDisableInterrupt(void) 327 { 328 x86_disable_intr(); 329 } 330 331 void 332 acpi_md_OsEnableInterrupt(void) 333 { 334 x86_enable_intr(); 335 } 336 337 uint32_t 338 acpi_md_ncpus(void) 339 { 340 return kcpuset_countset(kcpuset_attached); 341 } 342 343 static bool 344 acpi_md_mcfg_validate(uint64_t addr, int bus_start, int *bus_end) 345 { 346 struct btinfo_memmap *bim; 347 uint64_t size, mapaddr, mapsize; 348 uint32_t type; 349 int i, n; 350 351 bim = lookup_bootinfo(BTINFO_MEMMAP); 352 if (bim == NULL) 353 return false; 354 355 size = *bus_end - bus_start + 1; 356 size *= ACPIMCFG_SIZE_PER_BUS; 357 for (i = 0; i < bim->num; i++) { 358 mapaddr = bim->entry[i].addr; 359 mapsize = bim->entry[i].size; 360 type = bim->entry[i].type; 361 362 aprint_debug("MCFG: MEMMAP: 0x%016" PRIx64 "-0x%016" PRIx64 363 ", size=0x%016" PRIx64 ", type=%d(%s)\n", 364 mapaddr, mapaddr + mapsize - 1, mapsize, type, 365 (type == BIM_Memory) ? "Memory" : 366 (type == BIM_Reserved) ? "Reserved" : 367 (type == BIM_ACPI) ? "ACPI" : 368 (type == BIM_NVS) ? "NVS" : 369 "unknown"); 370 371 switch (type) { 372 case BIM_ACPI: 373 case BIM_Reserved: 374 if (addr < mapaddr || addr >= mapaddr + mapsize) 375 break; 376 377 /* full map */ 378 if (addr + size <= mapaddr + mapsize) 379 return true; 380 381 /* partial map */ 382 n = (mapsize - (addr - mapaddr)) / 383 ACPIMCFG_SIZE_PER_BUS; 384 /* bus_start == bus_end is not allowed. */ 385 if (n > 1) { 386 *bus_end = bus_start + n - 1; 387 return true; 388 } 389 aprint_debug("MCFG: bus %d-%d, address 0x%016" PRIx64 390 ": invalid size: request 0x%016" PRIx64 ", " 391 "actual 0x%016" PRIx64 "\n", 392 bus_start, *bus_end, addr, size, mapsize); 393 break; 394 } 395 } 396 aprint_debug("MCFG: bus %d-%d, address 0x%016" PRIx64 ": " 397 "no valid region\n", bus_start, *bus_end, addr); 398 return false; 399 } 400 401 static uint32_t 402 acpi_md_mcfg_read(bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t addr) 403 { 404 vaddr_t va = bsh + addr; 405 uint32_t data = (uint32_t) -1; 406 407 KASSERT(bst == x86_bus_space_mem); 408 409 __asm("movl %1, %0" : "=a" (data) : "m" (*(volatile uint32_t *)va)); 410 411 return data; 412 } 413 414 static void 415 acpi_md_mcfg_write(bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t addr, 416 uint32_t data) 417 { 418 vaddr_t va = bsh + addr; 419 420 KASSERT(bst == x86_bus_space_mem); 421 422 __asm("movl %1, %0" : "=m" (*(volatile uint32_t *)va) : "a" (data)); 423 } 424 425 static const struct acpimcfg_ops acpi_md_mcfg_ops = { 426 .ao_validate = acpi_md_mcfg_validate, 427 428 .ao_read = acpi_md_mcfg_read, 429 .ao_write = acpi_md_mcfg_write, 430 }; 431 432 void 433 acpi_md_callback(struct acpi_softc *sc) 434 { 435 #ifdef MPBIOS 436 if (!mpbios_scanned) 437 #endif 438 mpacpi_find_interrupts(sc); 439 440 #ifndef XEN 441 acpi_md_sleep_init(); 442 #endif 443 444 acpimcfg_init(x86_bus_space_mem, &acpi_md_mcfg_ops); 445 } 446