1 /* $OpenBSD: acpiprt.c,v 1.35 2009/03/31 20:59:00 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/proc.h> 20 #include <sys/signalvar.h> 21 #include <sys/systm.h> 22 #include <sys/device.h> 23 #include <sys/malloc.h> 24 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 <dev/pci/pcivar.h> 34 #include <dev/pci/pcidevs.h> 35 #include <dev/pci/ppbreg.h> 36 37 #include <machine/i82093reg.h> 38 #include <machine/i82093var.h> 39 40 #include <machine/mpbiosvar.h> 41 42 #include "ioapic.h" 43 44 struct acpiprt_map { 45 int bus, dev; 46 int pin; 47 int irq; 48 struct acpiprt_softc *sc; 49 struct aml_node *node; 50 SIMPLEQ_ENTRY(acpiprt_map) list; 51 }; 52 53 SIMPLEQ_HEAD(, acpiprt_map) acpiprt_map_list = 54 SIMPLEQ_HEAD_INITIALIZER(acpiprt_map_list); 55 56 int acpiprt_match(struct device *, void *, void *); 57 void acpiprt_attach(struct device *, struct device *, void *); 58 int acpiprt_getirq(union acpi_resource *crs, void *arg); 59 int acpiprt_getminbus(union acpi_resource *, void *); 60 int acpiprt_chooseirq(union acpi_resource *, void *); 61 62 struct acpiprt_softc { 63 struct device sc_dev; 64 65 struct acpi_softc *sc_acpi; 66 struct aml_node *sc_devnode; 67 68 int sc_bus; 69 }; 70 71 struct cfattach acpiprt_ca = { 72 sizeof(struct acpiprt_softc), acpiprt_match, acpiprt_attach 73 }; 74 75 struct cfdriver acpiprt_cd = { 76 NULL, "acpiprt", DV_DULL 77 }; 78 79 void acpiprt_prt_add(struct acpiprt_softc *, struct aml_value *); 80 int acpiprt_getpcibus(struct acpiprt_softc *, struct aml_node *); 81 void acpiprt_route_interrupt(int bus, int dev, int pin); 82 83 int 84 acpiprt_match(struct device *parent, void *match, void *aux) 85 { 86 struct acpi_attach_args *aa = aux; 87 struct cfdata *cf = match; 88 89 /* sanity */ 90 if (aa->aaa_name == NULL || 91 strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 || 92 aa->aaa_table != NULL) 93 return (0); 94 95 return (1); 96 } 97 98 void 99 acpiprt_attach(struct device *parent, struct device *self, void *aux) 100 { 101 struct acpiprt_softc *sc = (struct acpiprt_softc *)self; 102 struct acpi_attach_args *aa = aux; 103 struct aml_value res; 104 int i; 105 106 sc->sc_acpi = (struct acpi_softc *)parent; 107 sc->sc_devnode = aa->aaa_node; 108 sc->sc_bus = acpiprt_getpcibus(sc, sc->sc_devnode); 109 110 printf(": bus %d (%s)", sc->sc_bus, sc->sc_devnode->parent->name); 111 112 if (aml_evalnode(sc->sc_acpi, sc->sc_devnode, 0, NULL, &res)) { 113 printf(": no PCI interrupt routing table\n"); 114 return; 115 } 116 117 if (res.type != AML_OBJTYPE_PACKAGE) { 118 printf(": _PRT is not a package\n"); 119 aml_freevalue(&res); 120 return; 121 } 122 123 printf("\n"); 124 125 if (sc->sc_bus == -1) 126 return; 127 128 for (i = 0; i < res.length; i++) 129 acpiprt_prt_add(sc, res.v_package[i]); 130 131 aml_freevalue(&res); 132 } 133 134 int 135 acpiprt_getirq(union acpi_resource *crs, void *arg) 136 { 137 int *irq = (int *)arg; 138 int typ; 139 140 typ = AML_CRSTYPE(crs); 141 switch (typ) { 142 case SR_IRQ: 143 *irq = ffs(aml_letohost16(crs->sr_irq.irq_mask)) - 1; 144 break; 145 case LR_EXTIRQ: 146 *irq = aml_letohost32(crs->lr_extirq.irq[0]); 147 break; 148 default: 149 printf("unknown interrupt: %x\n", typ); 150 } 151 return (0); 152 } 153 154 int 155 acpiprt_pri[16] = { 156 0, /* 8254 Counter 0 */ 157 1, /* Keyboard */ 158 0, /* 8259 Slave */ 159 2, /* Serial Port A */ 160 2, /* Serial Port B */ 161 5, /* Parallel Port / Generic */ 162 2, /* Floppy Disk */ 163 4, /* Parallel Port / Generic */ 164 1, /* RTC */ 165 6, /* Generic */ 166 7, /* Generic */ 167 7, /* Generic */ 168 1, /* Mouse */ 169 0, /* FPU */ 170 2, /* Primary IDE */ 171 3 /* Secondary IDE */ 172 }; 173 174 int 175 acpiprt_chooseirq(union acpi_resource *crs, void *arg) 176 { 177 int *irq = (int *)arg; 178 int typ, i, pri = -1; 179 180 typ = AML_CRSTYPE(crs); 181 switch (typ) { 182 case SR_IRQ: 183 for (i = 0; i < sizeof(crs->sr_irq.irq_mask) * 8; i++) { 184 if (crs->sr_irq.irq_mask & (1 << i) && 185 acpiprt_pri[i] > pri) { 186 *irq = i; 187 pri = acpiprt_pri[*irq]; 188 } 189 } 190 break; 191 case LR_EXTIRQ: 192 /* First try non-8259 interrupts. */ 193 for (i = 0; i < crs->lr_extirq.irq_count; i++) { 194 if (crs->lr_extirq.irq[i] > 15) { 195 *irq = crs->lr_extirq.irq[i]; 196 return (0); 197 } 198 } 199 200 for (i = 0; i < crs->lr_extirq.irq_count; i++) { 201 if (acpiprt_pri[crs->lr_extirq.irq[i]] > pri) { 202 *irq = crs->lr_extirq.irq[i]; 203 pri = acpiprt_pri[*irq]; 204 } 205 } 206 break; 207 default: 208 printf("unknown interrupt: %x\n", typ); 209 } 210 return (0); 211 } 212 213 void 214 acpiprt_prt_add(struct acpiprt_softc *sc, struct aml_value *v) 215 { 216 struct aml_node *node; 217 struct aml_value res, *pp; 218 u_int64_t addr; 219 int pin, irq; 220 int64_t sta; 221 #if NIOAPIC > 0 222 struct mp_intr_map *map; 223 struct ioapic_softc *apic; 224 #endif 225 pci_chipset_tag_t pc = NULL; 226 pcitag_t tag; 227 pcireg_t reg; 228 int bus, dev, func, nfuncs; 229 struct acpiprt_map *p; 230 231 if (v->type != AML_OBJTYPE_PACKAGE || v->length != 4) { 232 printf("invalid mapping object\n"); 233 return; 234 } 235 236 addr = aml_val2int(v->v_package[0]); 237 pin = aml_val2int(v->v_package[1]); 238 if (pin > 3) { 239 return; 240 } 241 242 pp = v->v_package[2]; 243 if (pp->type == AML_OBJTYPE_STRING) { 244 node = aml_searchrel(sc->sc_devnode, pp->v_string); 245 if (node == NULL) { 246 printf("Invalid device\n"); 247 return; 248 } 249 pp = node->value; 250 } 251 if (pp->type == AML_OBJTYPE_NAMEREF) { 252 node = aml_searchrel(sc->sc_devnode, pp->v_nameref); 253 if (node == NULL) { 254 printf("Invalid device\n"); 255 return; 256 } 257 pp = node->value; 258 } 259 if (pp->type == AML_OBJTYPE_OBJREF) { 260 pp = pp->v_objref.ref; 261 } 262 if (pp->type == AML_OBJTYPE_DEVICE) { 263 node = pp->node; 264 if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta)) { 265 printf("no _STA method\n"); 266 return; 267 } 268 269 if ((sta & STA_PRESENT) == 0) 270 return; 271 272 if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res)) { 273 printf("no _CRS method\n"); 274 return; 275 } 276 277 if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) { 278 printf("invalid _CRS object\n"); 279 aml_freevalue(&res); 280 return; 281 } 282 aml_parse_resource(res.length, res.v_buffer, 283 acpiprt_getirq, &irq); 284 aml_freevalue(&res); 285 286 /* Pick a new IRQ if necessary. */ 287 if ((irq == 0 || irq == 2 || irq == 13) && 288 !aml_evalname(sc->sc_acpi, node, "_PRS", 0, NULL, &res)){ 289 if (res.type == AML_OBJTYPE_BUFFER && 290 res.length >= 5) { 291 aml_parse_resource(res.length, res.v_buffer, 292 acpiprt_chooseirq, &irq); 293 } 294 aml_freevalue(&res); 295 } 296 297 if ((p = malloc(sizeof(*p), M_ACPI, M_NOWAIT)) == NULL) 298 return; 299 p->bus = sc->sc_bus; 300 p->dev = ACPI_PCI_DEV(addr << 16); 301 p->pin = pin; 302 p->irq = irq; 303 p->sc = sc; 304 p->node = node; 305 SIMPLEQ_INSERT_TAIL(&acpiprt_map_list, p, list); 306 } else { 307 irq = aml_val2int(v->v_package[3]); 308 } 309 310 #ifdef ACPI_DEBUG 311 printf("%s: %s addr 0x%llx pin %d irq %d\n", 312 DEVNAME(sc), aml_nodename(pp->node), addr, pin, irq); 313 #endif 314 315 #if NIOAPIC > 0 316 if (nioapics > 0) { 317 apic = ioapic_find_bybase(irq); 318 if (apic == NULL) { 319 printf("%s: no apic found for irq %d\n", DEVNAME(sc), irq); 320 return; 321 } 322 323 map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO); 324 if (map == NULL) 325 return; 326 327 map->ioapic = apic; 328 map->ioapic_pin = irq - apic->sc_apic_vecbase; 329 map->bus_pin = ((addr >> 14) & 0x7c) | (pin & 0x3); 330 map->redir = IOAPIC_REDLO_ACTLO | IOAPIC_REDLO_LEVEL; 331 map->redir |= (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT); 332 333 map->ioapic_ih = APIC_INT_VIA_APIC | 334 ((apic->sc_apicid << APIC_INT_APIC_SHIFT) | 335 (map->ioapic_pin << APIC_INT_PIN_SHIFT)); 336 337 apic->sc_pins[map->ioapic_pin].ip_map = map; 338 339 map->next = mp_busses[sc->sc_bus].mb_intrs; 340 mp_busses[sc->sc_bus].mb_intrs = map; 341 342 return; 343 } 344 #endif 345 346 bus = sc->sc_bus; 347 dev = ACPI_PCI_DEV(addr << 16); 348 tag = pci_make_tag(pc, bus, dev, 0); 349 350 reg = pci_conf_read(pc, tag, PCI_BHLC_REG); 351 if (PCI_HDRTYPE_MULTIFN(reg)) 352 nfuncs = 8; 353 else 354 nfuncs = 1; 355 356 for (func = 0; func < nfuncs; func++) { 357 tag = pci_make_tag(pc, bus, dev, func); 358 reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); 359 if (PCI_INTERRUPT_PIN(reg) == pin + 1) { 360 reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); 361 reg |= irq << PCI_INTERRUPT_LINE_SHIFT; 362 pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg); 363 } 364 } 365 } 366 367 int 368 acpiprt_getminbus(union acpi_resource *crs, void *arg) 369 { 370 int *bbn = arg; 371 int typ = AML_CRSTYPE(crs); 372 373 /* Check for embedded bus number */ 374 if (typ == LR_WORD && crs->lr_word.type == 2) 375 *bbn = crs->lr_word._min; 376 return 0; 377 } 378 379 int 380 acpiprt_getpcibus(struct acpiprt_softc *sc, struct aml_node *node) 381 { 382 struct aml_node *parent = node->parent; 383 struct aml_value res; 384 pci_chipset_tag_t pc = NULL; 385 pcitag_t tag; 386 pcireg_t reg; 387 int bus, dev, func, rv; 388 int64_t ires; 389 390 if (parent == NULL) 391 return 0; 392 393 /* 394 * If our parent is a a bridge, it might have an address descriptor 395 * that tells us our bus number. 396 */ 397 if (aml_evalname(sc->sc_acpi, parent, "_CRS.", 0, NULL, &res) == 0) { 398 rv = -1; 399 if (res.type == AML_OBJTYPE_BUFFER) 400 aml_parse_resource(res.length, res.v_buffer, 401 acpiprt_getminbus, &rv); 402 aml_freevalue(&res); 403 if (rv != -1) 404 return rv; 405 } 406 407 /* 408 * If our parent is the root of the bus, it should specify the 409 * base bus number. 410 */ 411 if (aml_evalinteger(sc->sc_acpi, parent, "_BBN.", 0, NULL, &ires) == 0) { 412 return (ires); 413 } 414 415 /* 416 * If our parent is a PCI-PCI bridge, get our bus number from its 417 * PCI config space. 418 */ 419 if (aml_evalinteger(sc->sc_acpi, parent, "_ADR.", 0, NULL, &ires) == 0) { 420 bus = acpiprt_getpcibus(sc, parent); 421 dev = ACPI_PCI_DEV(ires << 16); 422 func = ACPI_PCI_FN(ires << 16); 423 424 /* 425 * Some systems return 255 as the device number for 426 * devices that are not really there. 427 */ 428 if (dev >= pci_bus_maxdevs(pc, bus)) 429 return (-1); 430 431 tag = pci_make_tag(pc, bus, dev, func); 432 433 /* Check whether the device is really there. */ 434 reg = pci_conf_read(pc, tag, PCI_ID_REG); 435 if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID) 436 return (-1); 437 438 /* Fetch bus number from PCI config space. */ 439 reg = pci_conf_read(pc, tag, PCI_CLASS_REG); 440 if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE && 441 PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI) { 442 reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO); 443 return (PPB_BUSINFO_SECONDARY(reg)); 444 } 445 } 446 return (0); 447 } 448 449 void 450 acpiprt_route_interrupt(int bus, int dev, int pin) 451 { 452 struct acpiprt_softc *sc; 453 struct acpiprt_map *p; 454 struct aml_node *node = NULL; 455 struct aml_value res, res2; 456 union acpi_resource *crs; 457 int irq, newirq; 458 int64_t sta; 459 460 SIMPLEQ_FOREACH(p, &acpiprt_map_list, list) { 461 if (p->bus == bus && p->dev == dev && p->pin == (pin - 1)) { 462 newirq = p->irq; 463 sc = p->sc; 464 node = p->node; 465 break; 466 } 467 } 468 if (node == NULL) 469 return; 470 471 if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta)) { 472 printf("no _STA method\n"); 473 return; 474 } 475 476 KASSERT(sta & STA_PRESENT); 477 478 if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res)) { 479 printf("no _CRS method\n"); 480 return; 481 } 482 if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) { 483 printf("invalid _CRS object\n"); 484 aml_freevalue(&res); 485 return; 486 } 487 aml_parse_resource(res.length, res.v_buffer, acpiprt_getirq, &irq); 488 489 /* Only re-route interrupts when necessary. */ 490 if ((sta & STA_ENABLED) && irq == newirq) { 491 aml_freevalue(&res); 492 return; 493 } 494 495 crs = (union acpi_resource *)res.v_buffer; 496 switch (AML_CRSTYPE(crs)) { 497 case SR_IRQ: 498 crs->sr_irq.irq_mask = htole16(1 << newirq); 499 break; 500 case LR_EXTIRQ: 501 crs->lr_extirq.irq[0] = htole32(newirq); 502 break; 503 } 504 505 if (aml_evalname(sc->sc_acpi, node, "_SRS", 1, &res, &res2)) { 506 printf("no _SRS method\n"); 507 aml_freevalue(&res); 508 return; 509 } 510 aml_freevalue(&res); 511 aml_freevalue(&res2); 512 } 513