1 /* $OpenBSD: acpimadt.c,v 1.34 2016/07/10 20:41:19 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2006 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/malloc.h> 22 23 #include <machine/apicvar.h> 24 #include <machine/cpuvar.h> 25 #include <machine/bus.h> 26 27 #include <dev/acpi/acpireg.h> 28 #include <dev/acpi/acpivar.h> 29 #include <dev/acpi/acpidev.h> 30 #include <dev/acpi/amltypes.h> 31 #include <dev/acpi/dsdt.h> 32 33 #include <machine/i8259.h> 34 #include <machine/i82093reg.h> 35 #include <machine/i82093var.h> 36 #include <machine/i82489reg.h> 37 #include <machine/i82489var.h> 38 39 #include <machine/mpbiosvar.h> 40 41 #include "ioapic.h" 42 43 u_int8_t acpi_lapic_flags[LAPIC_MAP_SIZE]; 44 45 int acpimadt_match(struct device *, void *, void *); 46 void acpimadt_attach(struct device *, struct device *, void *); 47 48 struct cfattach acpimadt_ca = { 49 sizeof(struct device), acpimadt_match, acpimadt_attach 50 }; 51 52 struct cfdriver acpimadt_cd = { 53 NULL, "acpimadt", DV_DULL 54 }; 55 56 int acpimadt_validate(struct acpi_madt *); 57 int acpimadt_cfg_intr(int, u_int32_t *); 58 int acpimadt_print(void *, const char *); 59 60 int 61 acpimadt_match(struct device *parent, void *match, void *aux) 62 { 63 struct acpi_attach_args *aaa = aux; 64 struct acpi_table_header *hdr; 65 66 /* 67 * If we do not have a table, it is not us 68 */ 69 if (aaa->aaa_table == NULL) 70 return (0); 71 72 /* 73 * If it is an MADT table, we can attach 74 */ 75 hdr = (struct acpi_table_header *)aaa->aaa_table; 76 if (memcmp(hdr->signature, MADT_SIG, sizeof(MADT_SIG) - 1) != 0) 77 return (0); 78 79 return (1); 80 } 81 82 int 83 acpimadt_validate(struct acpi_madt *madt) 84 { 85 caddr_t addr = (caddr_t)(madt + 1); 86 87 while (addr < (caddr_t)madt + madt->hdr.length) { 88 union acpi_madt_entry *entry = (union acpi_madt_entry *)addr; 89 u_int8_t length = entry->madt_lapic.length; 90 91 if (length < 2) 92 return (0); 93 94 if (addr + length > (caddr_t)madt + madt->hdr.length) 95 return (0); 96 97 switch (entry->madt_lapic.apic_type) { 98 case ACPI_MADT_LAPIC: 99 if (length != sizeof(entry->madt_lapic)) 100 return (0); 101 break; 102 case ACPI_MADT_IOAPIC: 103 if (length != sizeof(entry->madt_ioapic)) 104 return (0); 105 break; 106 case ACPI_MADT_OVERRIDE: 107 if (length != sizeof(entry->madt_override)) 108 return (0); 109 break; 110 case ACPI_MADT_NMI: 111 if (length != sizeof(entry->madt_nmi)) 112 return (0); 113 break; 114 case ACPI_MADT_LAPIC_NMI: 115 if (length != sizeof(entry->madt_lapic_nmi)) 116 return (0); 117 break; 118 case ACPI_MADT_LAPIC_OVERRIDE: 119 if (length != sizeof(entry->madt_lapic_override)) 120 return (0); 121 break; 122 case ACPI_MADT_IO_SAPIC: 123 if (length != sizeof(entry->madt_io_sapic)) 124 return (0); 125 break; 126 case ACPI_MADT_LOCAL_SAPIC: 127 if (length != sizeof(entry->madt_local_sapic)) 128 return (0); 129 break; 130 case ACPI_MADT_PLATFORM_INT: 131 if (length != sizeof(entry->madt_platform_int)) 132 return (0); 133 break; 134 case ACPI_MADT_X2APIC: 135 if (length != sizeof(entry->madt_x2apic)) 136 return (0); 137 break; 138 case ACPI_MADT_X2APIC_NMI: 139 if (length != sizeof(entry->madt_x2apic_nmi)) 140 return (0); 141 break; 142 } 143 144 addr += length; 145 } 146 147 return (1); 148 } 149 150 struct mp_bus acpimadt_busses[256]; 151 struct mp_bus acpimadt_isa_bus; 152 153 int 154 acpimadt_cfg_intr(int flags, u_int32_t *redir) 155 { 156 int mpspo = (flags >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK; 157 int mpstrig = (flags >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK; 158 159 *redir &= ~IOAPIC_REDLO_DEL_MASK; 160 switch (mpspo) { 161 case MPS_INTPO_DEF: 162 case MPS_INTPO_ACTHI: 163 *redir &= ~IOAPIC_REDLO_ACTLO; 164 break; 165 case MPS_INTPO_ACTLO: 166 *redir |= IOAPIC_REDLO_ACTLO; 167 break; 168 default: 169 return (0); 170 } 171 172 *redir |= (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT); 173 174 switch (mpstrig) { 175 case MPS_INTTR_LEVEL: 176 *redir |= IOAPIC_REDLO_LEVEL; 177 break; 178 case MPS_INTTR_DEF: 179 case MPS_INTTR_EDGE: 180 *redir &= ~IOAPIC_REDLO_LEVEL; 181 break; 182 default: 183 return (0); 184 } 185 186 return (1); 187 } 188 189 static u_int8_t lapic_map[256]; 190 191 void 192 acpimadt_attach(struct device *parent, struct device *self, void *aux) 193 { 194 struct acpi_softc *acpi_sc = (struct acpi_softc *)parent; 195 struct device *mainbus = parent->dv_parent->dv_parent; 196 struct acpi_attach_args *aaa = aux; 197 struct acpi_madt *madt = (struct acpi_madt *)aaa->aaa_table; 198 caddr_t addr = (caddr_t)(madt + 1); 199 struct aml_value arg; 200 struct mp_intr_map *map; 201 struct ioapic_softc *apic; 202 int nlapic_nmis = 0; 203 int pin; 204 205 /* Do some sanity checks before committing to run in APIC mode. */ 206 if (!acpimadt_validate(madt)) { 207 printf(": invalid, skipping\n"); 208 return; 209 } 210 211 printf(" addr 0x%x", madt->local_apic_address); 212 if (madt->flags & ACPI_APIC_PCAT_COMPAT) 213 printf(": PC-AT compat"); 214 printf("\n"); 215 216 /* Tell the BIOS we will be using APIC mode. */ 217 memset(&arg, 0, sizeof(arg)); 218 arg.type = AML_OBJTYPE_INTEGER; 219 arg.v_integer = 1; 220 221 aml_evalname(acpi_sc, NULL, "\\_PIC", 1, &arg, NULL); 222 223 mp_busses = acpimadt_busses; 224 mp_nbusses = nitems(acpimadt_busses); 225 mp_isa_bus = &acpimadt_isa_bus; 226 227 lapic_boot_init(madt->local_apic_address); 228 229 /* 1st pass, get CPUs and IOAPICs */ 230 while (addr < (caddr_t)madt + madt->hdr.length) { 231 union acpi_madt_entry *entry = (union acpi_madt_entry *)addr; 232 struct cpu_attach_args caa; 233 struct apic_attach_args aaa; 234 235 switch (entry->madt_lapic.apic_type) { 236 case ACPI_MADT_LAPIC: 237 dprintf("%s: LAPIC: acpi_proc_id %x, apic_id %x, flags 0x%x\n", 238 self->dv_xname, entry->madt_lapic.acpi_proc_id, 239 entry->madt_lapic.apic_id, 240 entry->madt_lapic.flags); 241 242 if ((entry->madt_lapic.flags & ACPI_PROC_ENABLE) == 0) 243 break; 244 245 lapic_map[entry->madt_lapic.acpi_proc_id] = 246 entry->madt_lapic.apic_id; 247 acpi_lapic_flags[entry->madt_lapic.acpi_proc_id] = 248 entry->madt_lapic.flags; 249 250 memset(&caa, 0, sizeof(struct cpu_attach_args)); 251 if (lapic_cpu_number() == entry->madt_lapic.apic_id) 252 caa.cpu_role = CPU_ROLE_BP; 253 else { 254 caa.cpu_role = CPU_ROLE_AP; 255 ncpusfound++; 256 } 257 caa.caa_name = "cpu"; 258 caa.cpu_number = entry->madt_lapic.apic_id; 259 #ifdef MULTIPROCESSOR 260 caa.cpu_func = &mp_cpu_funcs; 261 #endif 262 #ifdef __i386__ 263 /* 264 * XXX utterly wrong. These are the 265 * cpu_feature/cpu_id from the BSP cpu, now 266 * being given to another cpu. This is 267 * bullshit. 268 */ 269 extern int cpu_id, cpu_feature; 270 caa.cpu_signature = cpu_id; 271 caa.feature_flags = cpu_feature; 272 #endif 273 274 config_found(mainbus, &caa, acpimadt_print); 275 break; 276 case ACPI_MADT_IOAPIC: 277 dprintf("%s: IOAPIC: acpi_ioapic_id %x, address 0x%x, global_int_base 0x%x\n", 278 self->dv_xname, entry->madt_ioapic.acpi_ioapic_id, 279 entry->madt_ioapic.address, 280 entry->madt_ioapic.global_int_base); 281 282 memset(&aaa, 0, sizeof(struct apic_attach_args)); 283 aaa.aaa_name = "ioapic"; 284 aaa.apic_id = entry->madt_ioapic.acpi_ioapic_id; 285 aaa.apic_address = entry->madt_ioapic.address; 286 aaa.apic_vecbase = entry->madt_ioapic.global_int_base; 287 288 config_found(mainbus, &aaa, acpimadt_print); 289 break; 290 case ACPI_MADT_LAPIC_NMI: 291 nlapic_nmis++; 292 break; 293 case ACPI_MADT_X2APIC: 294 dprintf("%s: X2APIC: acpi_proc_uid %x, apic_id %x, flags 0x%x\n", 295 self->dv_xname, entry->madt_x2apic.acpi_proc_uid, 296 entry->madt_x2apic.apic_id, 297 entry->madt_x2apic.flags); 298 299 if (entry->madt_x2apic.apic_id > 255 || 300 (entry->madt_x2apic.flags & ACPI_PROC_ENABLE) == 0) 301 break; 302 303 memset(&caa, 0, sizeof(struct cpu_attach_args)); 304 if (lapic_cpu_number() == entry->madt_x2apic.apic_id) 305 caa.cpu_role = CPU_ROLE_BP; 306 else { 307 caa.cpu_role = CPU_ROLE_AP; 308 ncpusfound++; 309 } 310 caa.caa_name = "cpu"; 311 caa.cpu_number = entry->madt_x2apic.apic_id; 312 #ifdef MULTIPROCESSOR 313 caa.cpu_func = &mp_cpu_funcs; 314 #endif 315 #ifdef __i386__ 316 /* 317 * XXX utterly wrong. These are the 318 * cpu_feature/cpu_id from the BSP cpu, now 319 * being given to another cpu. This is 320 * bullshit. 321 */ 322 extern int cpu_id, cpu_feature; 323 caa.cpu_signature = cpu_id; 324 caa.feature_flags = cpu_feature; 325 #endif 326 327 config_found(mainbus, &caa, acpimadt_print); 328 break; 329 } 330 addr += entry->madt_lapic.length; 331 } 332 333 mp_intrs = mallocarray(nlapic_nmis, sizeof(struct mp_intr_map), 334 M_DEVBUF, M_NOWAIT); 335 if (mp_intrs == NULL) 336 return; 337 338 /* 2nd pass, get interrupt overrides */ 339 addr = (caddr_t)(madt + 1); 340 while (addr < (caddr_t)madt + madt->hdr.length) { 341 union acpi_madt_entry *entry = (union acpi_madt_entry *)addr; 342 343 switch (entry->madt_lapic.apic_type) { 344 case ACPI_MADT_LAPIC: 345 case ACPI_MADT_IOAPIC: 346 break; 347 348 case ACPI_MADT_OVERRIDE: 349 dprintf("%s: OVERRIDE: bus %x, source %x, global_int %x, flags %x\n", 350 self->dv_xname, entry->madt_override.bus, 351 entry->madt_override.source, 352 entry->madt_override.global_int, 353 entry->madt_override.flags); 354 355 pin = entry->madt_override.global_int; 356 apic = ioapic_find_bybase(pin); 357 358 map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO); 359 if (map == NULL) 360 return; 361 362 map->ioapic = apic; 363 map->ioapic_pin = pin - apic->sc_apic_vecbase; 364 map->bus_pin = entry->madt_override.source; 365 map->flags = entry->madt_override.flags; 366 367 if (!acpimadt_cfg_intr(entry->madt_override.flags, &map->redir)) { 368 printf("%s: bogus override for pin %d\n", 369 self->dv_xname, pin); 370 free(map, M_DEVBUF, sizeof(*map)); 371 break; 372 } 373 374 map->ioapic_ih = APIC_INT_VIA_APIC | 375 ((apic->sc_apicid << APIC_INT_APIC_SHIFT) | 376 (pin << APIC_INT_PIN_SHIFT)); 377 378 apic->sc_pins[pin].ip_map = map; 379 380 map->next = mp_isa_bus->mb_intrs; 381 mp_isa_bus->mb_intrs = map; 382 break; 383 384 case ACPI_MADT_LAPIC_NMI: 385 dprintf("%s: LAPIC_NMI: acpi_proc_id %x, local_apic_lint %x, flags %x\n", 386 self->dv_xname, entry->madt_lapic_nmi.acpi_proc_id, 387 entry->madt_lapic_nmi.local_apic_lint, 388 entry->madt_lapic_nmi.flags); 389 390 pin = entry->madt_lapic_nmi.local_apic_lint; 391 392 map = &mp_intrs[mp_nintrs++]; 393 memset(map, 0, sizeof *map); 394 map->cpu_id = lapic_map[entry->madt_lapic_nmi.acpi_proc_id]; 395 map->ioapic_pin = pin; 396 map->flags = entry->madt_lapic_nmi.flags; 397 398 if ((pin != 0 && pin != 1) || 399 !acpimadt_cfg_intr(entry->madt_lapic_nmi.flags, &map->redir)) { 400 printf("%s: bogus nmi for apid %d\n", 401 self->dv_xname, map->cpu_id); 402 mp_nintrs--; 403 break; 404 } 405 406 map->redir &= ~IOAPIC_REDLO_DEL_MASK; 407 map->redir |= (IOAPIC_REDLO_DEL_NMI << IOAPIC_REDLO_DEL_SHIFT); 408 break; 409 410 case ACPI_MADT_X2APIC: 411 case ACPI_MADT_X2APIC_NMI: 412 break; 413 414 default: 415 printf("%s: unknown apic structure type %x\n", 416 self->dv_xname, entry->madt_lapic.apic_type); 417 } 418 419 addr += entry->madt_lapic.length; 420 } 421 422 /* 423 * ISA interrupts are supposed to be identity mapped unless 424 * there is an override, in which case we will already have a 425 * mapping for the interrupt. 426 */ 427 for (pin = 0; pin < ICU_LEN; pin++) { 428 /* Skip if we already have a mapping for this interrupt. */ 429 for (map = mp_isa_bus->mb_intrs; map != NULL; map = map->next) 430 if (map->bus_pin == pin) 431 break; 432 if (map != NULL) 433 continue; 434 435 apic = ioapic_find_bybase(pin); 436 437 map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO); 438 if (map == NULL) 439 return; 440 441 map->ioapic = apic; 442 map->ioapic_pin = pin; 443 map->bus_pin = pin; 444 map->redir = (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT); 445 446 map->ioapic_ih = APIC_INT_VIA_APIC | 447 ((apic->sc_apicid << APIC_INT_APIC_SHIFT) | 448 (pin << APIC_INT_PIN_SHIFT)); 449 450 apic->sc_pins[pin].ip_map = map; 451 452 map->next = mp_isa_bus->mb_intrs; 453 mp_isa_bus->mb_intrs = map; 454 } 455 } 456 457 int 458 acpimadt_print(void *aux, const char *pnp) 459 { 460 struct apic_attach_args *aaa = aux; 461 462 if (pnp) 463 printf("%s at %s:", aaa->aaa_name, pnp); 464 465 return (UNCONF); 466 } 467