1 /* $NetBSD: acpi_pci_link.c,v 1.5 2006/09/23 17:05:33 fvdl Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: acpi_pci_link.c,v 1.5 2006/09/23 17:05:33 fvdl Exp $"); 31 32 #include "opt_acpi.h" 33 #include <sys/param.h> 34 #include <sys/kernel.h> 35 #include <sys/malloc.h> 36 #include <sys/queue.h> 37 #include <sys/reboot.h> 38 39 #include <dev/acpi/acpica.h> 40 #include <dev/acpi/acpireg.h> 41 #include <dev/acpi/acpivar.h> 42 43 #include <dev/pci/pcireg.h> 44 #include <dev/pci/pcivar.h> 45 46 #define NUM_ISA_INTERRUPTS 16 47 #define NUM_ACPI_INTERRUPTS 256 48 49 #define PCI_INVALID_IRQ 255 50 #define PCI_INTERRUPT_VALID(x) ((x) != PCI_INVALID_IRQ && (x) != 0) 51 52 #define ACPI_SERIAL_BEGIN(x) 53 #define ACPI_SERIAL_END(x) 54 55 /* 56 * An ACPI PCI link device may contain multiple links. Each link has its 57 * own ACPI resource. _PRT entries specify which link is being used via 58 * the Source Index. 59 * 60 * XXX: A note about Source Indices and DPFs: Currently we assume that 61 * the DPF start and end tags are not counted towards the index that 62 * Source Index corresponds to. Also, we assume that when DPFs are in use 63 * they various sets overlap in terms of Indices. Here's an example 64 * resource list indicating these assumptions: 65 * 66 * Resource Index 67 * -------- ----- 68 * I/O Port 0 69 * Start DPF - 70 * IRQ 1 71 * MemIO 2 72 * Start DPF - 73 * IRQ 1 74 * MemIO 2 75 * End DPF - 76 * DMA Channel 3 77 * 78 * The XXX is because I'm not sure if this is a valid assumption to make. 79 */ 80 81 /* States during DPF processing. */ 82 #define DPF_OUTSIDE 0 83 #define DPF_FIRST 1 84 #define DPF_IGNORE 2 85 86 struct link; 87 88 struct acpi_pci_link_softc { 89 int pl_num_links; 90 int pl_crs_bad; 91 struct link *pl_links; 92 char pl_name[32]; 93 ACPI_HANDLE pl_handle; 94 void *pl_powerhook; 95 TAILQ_ENTRY(acpi_pci_link_softc) pl_list; 96 }; 97 98 static TAILQ_HEAD(, acpi_pci_link_softc) acpi_pci_linkdevs = 99 TAILQ_HEAD_INITIALIZER(acpi_pci_linkdevs); 100 101 102 struct link { 103 struct acpi_pci_link_softc *l_sc; 104 uint8_t l_bios_irq; 105 uint8_t l_irq; 106 uint8_t l_trig; 107 uint8_t l_pol; 108 uint8_t l_initial_irq; 109 int l_res_index; 110 int l_num_irqs; 111 int *l_irqs; 112 int l_references; 113 int l_routed:1; 114 int l_isa_irq:1; 115 ACPI_RESOURCE l_prs_template; 116 }; 117 118 struct link_count_request { 119 int in_dpf; 120 int count; 121 }; 122 123 struct link_res_request { 124 struct acpi_pci_link_softc *sc; 125 int in_dpf; 126 int res_index; 127 int link_index; 128 }; 129 130 MALLOC_DEFINE(M_PCI_LINK, "pci_link", "ACPI PCI Link structures"); 131 132 static int pci_link_interrupt_weights[NUM_ACPI_INTERRUPTS]; 133 static int pci_link_bios_isa_irqs; 134 135 static ACPI_STATUS acpi_count_irq_resources(ACPI_RESOURCE *, void *); 136 static ACPI_STATUS link_add_crs(ACPI_RESOURCE *, void *); 137 static ACPI_STATUS link_add_prs(ACPI_RESOURCE *, void *); 138 static int link_valid_irq(struct link *, int); 139 static void acpi_pci_link_dump(struct acpi_pci_link_softc *); 140 static int acpi_pci_link_attach(struct acpi_pci_link_softc *); 141 static uint8_t acpi_pci_link_search_irq(struct acpi_pci_link_softc *, int, int, 142 int); 143 static void acpi_pci_link_resume(int, void *); 144 static struct link *acpi_pci_link_lookup(struct acpi_pci_link_softc *, int); 145 static ACPI_STATUS acpi_pci_link_srs(struct acpi_pci_link_softc *, 146 ACPI_BUFFER *); 147 static ACPI_STATUS acpi_AppendBufferResource(ACPI_BUFFER *, ACPI_RESOURCE *); 148 149 static ACPI_STATUS 150 acpi_count_irq_resources(ACPI_RESOURCE *res, void *context) 151 { 152 struct link_count_request *req; 153 154 req = (struct link_count_request *)context; 155 switch (res->Type) { 156 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 157 switch (req->in_dpf) { 158 case DPF_OUTSIDE: 159 /* We've started the first DPF. */ 160 req->in_dpf = DPF_FIRST; 161 break; 162 case DPF_FIRST: 163 /* We've started the second DPF. */ 164 req->in_dpf = DPF_IGNORE; 165 break; 166 } 167 break; 168 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 169 /* We are finished with DPF parsing. */ 170 KASSERT(req->in_dpf != DPF_OUTSIDE); 171 req->in_dpf = DPF_OUTSIDE; 172 break; 173 case ACPI_RESOURCE_TYPE_IRQ: 174 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 175 /* 176 * Don't count resources if we are in a DPF set that we are 177 * ignoring. 178 */ 179 if (req->in_dpf != DPF_IGNORE) 180 req->count++; 181 } 182 return (AE_OK); 183 } 184 185 static ACPI_STATUS 186 link_add_crs(ACPI_RESOURCE *res, void *context) 187 { 188 struct link_res_request *req; 189 struct link *link; 190 191 req = (struct link_res_request *)context; 192 switch (res->Type) { 193 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 194 switch (req->in_dpf) { 195 case DPF_OUTSIDE: 196 /* We've started the first DPF. */ 197 req->in_dpf = DPF_FIRST; 198 break; 199 case DPF_FIRST: 200 /* We've started the second DPF. */ 201 panic( 202 "%s: Multiple dependent functions within a current resource", 203 __func__); 204 break; 205 } 206 break; 207 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 208 /* We are finished with DPF parsing. */ 209 KASSERT(req->in_dpf != DPF_OUTSIDE); 210 req->in_dpf = DPF_OUTSIDE; 211 break; 212 case ACPI_RESOURCE_TYPE_IRQ: 213 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 214 KASSERT(req->link_index < req->sc->pl_num_links); 215 link = &req->sc->pl_links[req->link_index]; 216 link->l_res_index = req->res_index; 217 req->link_index++; 218 req->res_index++; 219 220 /* 221 * Only use the current value if there's one IRQ. Some 222 * systems return multiple IRQs (which is nonsense for _CRS) 223 * when the link hasn't been programmed. 224 */ 225 if (res->Type == ACPI_RESOURCE_TYPE_IRQ) { 226 if (res->Data.Irq.InterruptCount == 1) { 227 link->l_irq = res->Data.Irq.Interrupts[0]; 228 link->l_trig = res->Data.Irq.Triggering; 229 link->l_pol = res->Data.Irq.Polarity; 230 } 231 } else if (res->Data.ExtendedIrq.InterruptCount == 1) { 232 link->l_irq = res->Data.ExtendedIrq.Interrupts[0]; 233 link->l_trig = res->Data.ExtendedIrq.Triggering; 234 link->l_pol = res->Data.ExtendedIrq.Polarity; 235 } 236 237 /* 238 * An IRQ of zero means that the link isn't routed. 239 */ 240 if (link->l_irq == 0) 241 link->l_irq = PCI_INVALID_IRQ; 242 break; 243 default: 244 req->res_index++; 245 } 246 return (AE_OK); 247 } 248 249 /* 250 * Populate the set of possible IRQs for each device. 251 */ 252 static ACPI_STATUS 253 link_add_prs(ACPI_RESOURCE *res, void *context) 254 { 255 struct link_res_request *req; 256 struct link *link; 257 UINT8 *irqs = NULL; 258 UINT32 *ext_irqs = NULL; 259 int i, is_ext_irq = 1; 260 261 req = (struct link_res_request *)context; 262 switch (res->Type) { 263 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 264 switch (req->in_dpf) { 265 case DPF_OUTSIDE: 266 /* We've started the first DPF. */ 267 req->in_dpf = DPF_FIRST; 268 break; 269 case DPF_FIRST: 270 /* We've started the second DPF. */ 271 req->in_dpf = DPF_IGNORE; 272 break; 273 } 274 break; 275 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 276 /* We are finished with DPF parsing. */ 277 KASSERT(req->in_dpf != DPF_OUTSIDE); 278 req->in_dpf = DPF_OUTSIDE; 279 break; 280 case ACPI_RESOURCE_TYPE_IRQ: 281 is_ext_irq = 0; 282 /* fall through */ 283 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 284 /* 285 * Don't parse resources if we are in a DPF set that we are 286 * ignoring. 287 */ 288 if (req->in_dpf == DPF_IGNORE) 289 break; 290 291 KASSERT(req->link_index < req->sc->pl_num_links); 292 link = &req->sc->pl_links[req->link_index]; 293 if (link->l_res_index == -1) { 294 KASSERT(req->sc->pl_crs_bad); 295 link->l_res_index = req->res_index; 296 } 297 req->link_index++; 298 req->res_index++; 299 300 /* 301 * Stash a copy of the resource for later use when 302 * doing _SRS. 303 * 304 * Note that in theory res->Length may exceed the size 305 * of ACPI_RESOURCE, due to variable length lists in 306 * subtypes. However, all uses of l_prs_template only 307 * rely on lists lengths of zero or one, for which 308 * sizeof(ACPI_RESOURCE) is sufficient space anyway. 309 * We cannot read longer than Length bytes, in case we 310 * read off the end of mapped memory. So we read 311 * whichever length is shortest, Length or 312 * sizeof(ACPI_RESOURCE). 313 */ 314 KASSERT(res->Length >= ACPI_RS_SIZE_MIN); 315 316 memset(&link->l_prs_template, 0, sizeof(link->l_prs_template)); 317 memcpy(&link->l_prs_template, res, 318 MIN(res->Length, sizeof(link->l_prs_template))); 319 320 if (is_ext_irq) { 321 link->l_num_irqs = 322 res->Data.ExtendedIrq.InterruptCount; 323 link->l_trig = res->Data.ExtendedIrq.Triggering; 324 link->l_pol = res->Data.ExtendedIrq.Polarity; 325 ext_irqs = res->Data.ExtendedIrq.Interrupts; 326 } else { 327 link->l_num_irqs = res->Data.Irq.InterruptCount; 328 link->l_trig = res->Data.Irq.Triggering; 329 link->l_pol = res->Data.Irq.Polarity; 330 irqs = res->Data.Irq.Interrupts; 331 } 332 if (link->l_num_irqs == 0) 333 break; 334 335 /* 336 * Save a list of the valid IRQs. Also, if all of the 337 * valid IRQs are ISA IRQs, then mark this link as 338 * routed via an ISA interrupt. 339 */ 340 link->l_isa_irq = TRUE; 341 link->l_irqs = malloc(sizeof(int) * link->l_num_irqs, 342 M_PCI_LINK, M_WAITOK | M_ZERO); 343 for (i = 0; i < link->l_num_irqs; i++) { 344 if (is_ext_irq) { 345 link->l_irqs[i] = ext_irqs[i]; 346 if (ext_irqs[i] >= NUM_ISA_INTERRUPTS) 347 link->l_isa_irq = FALSE; 348 } else { 349 link->l_irqs[i] = irqs[i]; 350 if (irqs[i] >= NUM_ISA_INTERRUPTS) 351 link->l_isa_irq = FALSE; 352 } 353 } 354 break; 355 default: 356 if (req->in_dpf == DPF_IGNORE) 357 break; 358 if (req->sc->pl_crs_bad) 359 aprint_normal("%s: Warning: possible resource %d " 360 "will be lost during _SRS\n", req->sc->pl_name, 361 req->res_index); 362 req->res_index++; 363 } 364 return (AE_OK); 365 } 366 367 static int 368 link_valid_irq(struct link *link, int irq) 369 { 370 int i; 371 372 /* Invalid interrupts are never valid. */ 373 if (!PCI_INTERRUPT_VALID(irq)) 374 return (FALSE); 375 376 /* Any interrupt in the list of possible interrupts is valid. */ 377 for (i = 0; i < link->l_num_irqs; i++) 378 if (link->l_irqs[i] == irq) 379 return (TRUE); 380 381 /* 382 * For links routed via an ISA interrupt, if the SCI is routed via 383 * an ISA interrupt, the SCI is always treated as a valid IRQ. 384 */ 385 if (link->l_isa_irq && AcpiGbl_FADT->SciInt == irq && 386 irq < NUM_ISA_INTERRUPTS) 387 return (TRUE); 388 389 /* If the interrupt wasn't found in the list it is not valid. */ 390 return (FALSE); 391 } 392 393 void 394 acpi_pci_link_state(void) 395 { 396 struct acpi_pci_link_softc *sc; 397 398 TAILQ_FOREACH(sc, &acpi_pci_linkdevs, pl_list) { 399 acpi_pci_link_dump(sc); 400 } 401 } 402 403 static void 404 acpi_pci_link_dump(struct acpi_pci_link_softc *sc) 405 { 406 struct link *link; 407 int i, j; 408 409 printf("Link Device %s:\n", sc->pl_name); 410 printf("Index IRQ Rtd Ref IRQs\n"); 411 for (i = 0; i < sc->pl_num_links; i++) { 412 link = &sc->pl_links[i]; 413 printf("%5d %3d %c %3d ", i, link->l_irq, 414 link->l_routed ? 'Y' : 'N', link->l_references); 415 if (link->l_num_irqs == 0) 416 printf(" none"); 417 else for (j = 0; j < link->l_num_irqs; j++) 418 printf(" %d", link->l_irqs[j]); 419 printf(" polarity %u trigger %u\n", link->l_pol, link->l_trig); 420 } 421 printf("\n"); 422 } 423 424 static int 425 acpi_pci_link_attach(struct acpi_pci_link_softc *sc) 426 { 427 struct link_count_request creq; 428 struct link_res_request rreq; 429 ACPI_STATUS status; 430 int i; 431 432 ACPI_SERIAL_BEGIN(pci_link); 433 434 /* 435 * Count the number of current resources so we know how big of 436 * a link array to allocate. On some systems, _CRS is broken, 437 * so for those systems try to derive the count from _PRS instead. 438 */ 439 creq.in_dpf = DPF_OUTSIDE; 440 creq.count = 0; 441 status = AcpiWalkResources(sc->pl_handle, "_CRS", 442 acpi_count_irq_resources, &creq); 443 sc->pl_crs_bad = ACPI_FAILURE(status); 444 if (sc->pl_crs_bad) { 445 creq.in_dpf = DPF_OUTSIDE; 446 creq.count = 0; 447 status = AcpiWalkResources(sc->pl_handle, "_PRS", 448 acpi_count_irq_resources, &creq); 449 if (ACPI_FAILURE(status)) { 450 aprint_error("%s: Unable to parse _CRS or _PRS: %s\n", 451 sc->pl_name, AcpiFormatException(status)); 452 ACPI_SERIAL_END(pci_link); 453 return (ENXIO); 454 } 455 } 456 sc->pl_num_links = creq.count; 457 if (creq.count == 0) { 458 ACPI_SERIAL_END(pci_link); 459 return (0); 460 } 461 sc->pl_links = malloc(sizeof(struct link) * sc->pl_num_links, 462 M_PCI_LINK, M_WAITOK | M_ZERO); 463 464 /* Initialize the child links. */ 465 for (i = 0; i < sc->pl_num_links; i++) { 466 sc->pl_links[i].l_irq = PCI_INVALID_IRQ; 467 sc->pl_links[i].l_bios_irq = PCI_INVALID_IRQ; 468 sc->pl_links[i].l_sc = sc; 469 sc->pl_links[i].l_isa_irq = FALSE; 470 sc->pl_links[i].l_res_index = -1; 471 } 472 473 /* Try to read the current settings from _CRS if it is valid. */ 474 if (!sc->pl_crs_bad) { 475 rreq.in_dpf = DPF_OUTSIDE; 476 rreq.link_index = 0; 477 rreq.res_index = 0; 478 rreq.sc = sc; 479 status = AcpiWalkResources(sc->pl_handle, "_CRS", 480 link_add_crs, &rreq); 481 if (ACPI_FAILURE(status)) { 482 aprint_error("%s: Unable to parse _CRS: %s\n", 483 sc->pl_name, AcpiFormatException(status)); 484 goto fail; 485 } 486 } 487 488 /* 489 * Try to read the possible settings from _PRS. Note that if the 490 * _CRS is toast, we depend on having a working _PRS. However, if 491 * _CRS works, then it is ok for _PRS to be missing. 492 */ 493 rreq.in_dpf = DPF_OUTSIDE; 494 rreq.link_index = 0; 495 rreq.res_index = 0; 496 rreq.sc = sc; 497 status = AcpiWalkResources(sc->pl_handle, "_PRS", 498 link_add_prs, &rreq); 499 if (ACPI_FAILURE(status) && 500 (status != AE_NOT_FOUND || sc->pl_crs_bad)) { 501 aprint_error("%s: Unable to parse _PRS: %s\n", 502 sc->pl_name, AcpiFormatException(status)); 503 goto fail; 504 } 505 if (boothowto & AB_VERBOSE) { 506 aprint_normal("%s: Links after initial probe:\n", sc->pl_name); 507 acpi_pci_link_dump(sc); 508 } 509 510 /* Verify initial IRQs if we have _PRS. */ 511 if (status != AE_NOT_FOUND) 512 for (i = 0; i < sc->pl_num_links; i++) 513 if (!link_valid_irq(&sc->pl_links[i], 514 sc->pl_links[i].l_irq)) 515 sc->pl_links[i].l_irq = PCI_INVALID_IRQ; 516 if (boothowto & AB_VERBOSE) { 517 printf("%s: Links after initial validation:\n", sc->pl_name); 518 acpi_pci_link_dump(sc); 519 } 520 521 /* Save initial IRQs. */ 522 for (i = 0; i < sc->pl_num_links; i++) 523 sc->pl_links[i].l_initial_irq = sc->pl_links[i].l_irq; 524 525 /* 526 * Try to disable this link. If successful, set the current IRQ to 527 * zero and flags to indicate this link is not routed. If we can't 528 * run _DIS (i.e., the method doesn't exist), assume the initial 529 * IRQ was routed by the BIOS. 530 */ 531 #if 0 /* XXX causes spontaneaous resets on some systems. Disabled for now. */ 532 if (ACPI_SUCCESS(AcpiEvaluateObject(sc->pl_handle, "_DIS", NULL, 533 NULL))) 534 for (i = 0; i < sc->pl_num_links; i++) 535 sc->pl_links[i].l_irq = PCI_INVALID_IRQ; 536 else 537 #endif 538 for (i = 0; i < sc->pl_num_links; i++) 539 if (PCI_INTERRUPT_VALID(sc->pl_links[i].l_irq)) 540 sc->pl_links[i].l_routed = TRUE; 541 if (boothowto & AB_VERBOSE) { 542 printf("%s: Links after disable:\n", sc->pl_name); 543 acpi_pci_link_dump(sc); 544 } 545 ACPI_SERIAL_END(pci_link); 546 return (0); 547 fail: 548 ACPI_SERIAL_END(pci_link); 549 for (i = 0; i < sc->pl_num_links; i++) 550 if (sc->pl_links[i].l_irqs != NULL) 551 free(sc->pl_links[i].l_irqs, M_PCI_LINK); 552 free(sc->pl_links, M_PCI_LINK); 553 return (ENXIO); 554 } 555 556 static uint8_t 557 acpi_pci_link_search_irq(struct acpi_pci_link_softc *sc, int bus, int device, 558 int pin) 559 { 560 uint32_t value; 561 uint8_t func, maxfunc, ipin, iline; 562 pcitag_t tag; 563 564 tag = pci_make_tag(acpi_softc->sc_pc, bus, device, 0); 565 /* See if we have a valid device at function 0. */ 566 value = pci_conf_read(acpi_softc->sc_pc, tag, PCI_BHLC_REG); 567 if (PCI_HDRTYPE_TYPE(value) > PCI_HDRTYPE_PCB) 568 return (PCI_INVALID_IRQ); 569 if (PCI_HDRTYPE_MULTIFN(value)) 570 maxfunc = 7; 571 else 572 maxfunc = 0; 573 574 /* Scan all possible functions at this device. */ 575 for (func = 0; func <= maxfunc; func++) { 576 tag = pci_make_tag(acpi_softc->sc_pc, bus, device, func); 577 value = pci_conf_read(acpi_softc->sc_pc, tag, PCI_ID_REG); 578 if (PCI_VENDOR(value) == 0xffff) 579 continue; 580 value = pci_conf_read(acpi_softc->sc_pc, tag, 581 PCI_INTERRUPT_REG); 582 ipin = PCI_INTERRUPT_PIN(value); 583 iline = PCI_INTERRUPT_LINE(value); 584 585 /* 586 * See if it uses the pin in question. Note that the passed 587 * in pin uses 0 for A, .. 3 for D whereas the intpin 588 * register uses 0 for no interrupt, 1 for A, .. 4 for D. 589 */ 590 if (ipin != pin + 1) 591 continue; 592 aprint_verbose( 593 "%s: ACPI: Found matching pin for %d.%d.INT%c" 594 " at func %d: %d\n", 595 sc->pl_name, bus, device, pin + 'A', func, iline); 596 if (PCI_INTERRUPT_VALID(iline)) 597 return (iline); 598 } 599 return (PCI_INVALID_IRQ); 600 } 601 602 /* 603 * Find the link structure that corresponds to the resource index passed in 604 * via 'source_index'. 605 */ 606 static struct link * 607 acpi_pci_link_lookup(struct acpi_pci_link_softc *sc, int source_index) 608 { 609 int i; 610 611 for (i = 0; i < sc->pl_num_links; i++) 612 if (sc->pl_links[i].l_res_index == source_index) 613 return (&sc->pl_links[i]); 614 return (NULL); 615 } 616 617 void 618 acpi_pci_link_add_reference(void *v, int index, int bus, int slot, int pin) 619 { 620 struct acpi_pci_link_softc *sc = v; 621 struct link *link; 622 uint8_t bios_irq; 623 624 /* Bump the reference count. */ 625 ACPI_SERIAL_BEGIN(pci_link); 626 link = acpi_pci_link_lookup(sc, index); 627 if (link == NULL) { 628 printf("%s: apparently invalid index %d\n", sc->pl_name, index); 629 ACPI_SERIAL_END(pci_link); 630 return; 631 } 632 link->l_references++; 633 if (link->l_routed) 634 pci_link_interrupt_weights[link->l_irq]++; 635 636 /* 637 * The BIOS only routes interrupts via ISA IRQs using the ATPICs 638 * (8259As). Thus, if this link is routed via an ISA IRQ, go 639 * look to see if the BIOS routed an IRQ for this link at the 640 * indicated (bus, slot, pin). If so, we prefer that IRQ for 641 * this link and add that IRQ to our list of known-good IRQs. 642 * This provides a good work-around for link devices whose _CRS 643 * method is either broken or bogus. We only use the value 644 * returned by _CRS if we can't find a valid IRQ via this method 645 * in fact. 646 * 647 * If this link is not routed via an ISA IRQ (because we are using 648 * APIC for example), then don't bother looking up the BIOS IRQ 649 * as if we find one it won't be valid anyway. 650 */ 651 if (!link->l_isa_irq) { 652 ACPI_SERIAL_END(pci_link); 653 return; 654 } 655 656 /* Try to find a BIOS IRQ setting from any matching devices. */ 657 bios_irq = acpi_pci_link_search_irq(sc, bus, slot, pin); 658 if (!PCI_INTERRUPT_VALID(bios_irq)) { 659 ACPI_SERIAL_END(pci_link); 660 return; 661 } 662 663 /* Validate the BIOS IRQ. */ 664 if (!link_valid_irq(link, bios_irq)) { 665 printf("%s: BIOS IRQ %u for %d.%d.INT%c is invalid\n", 666 sc->pl_name, bios_irq, (int)bus, slot, pin + 'A'); 667 } else if (!PCI_INTERRUPT_VALID(link->l_bios_irq)) { 668 link->l_bios_irq = bios_irq; 669 if (bios_irq < NUM_ISA_INTERRUPTS) 670 pci_link_bios_isa_irqs |= (1 << bios_irq); 671 if (bios_irq != link->l_initial_irq && 672 PCI_INTERRUPT_VALID(link->l_initial_irq)) 673 printf( 674 "%s: BIOS IRQ %u does not match initial IRQ %u\n", 675 sc->pl_name, bios_irq, link->l_initial_irq); 676 } else if (bios_irq != link->l_bios_irq) 677 printf( 678 "%s: BIOS IRQ %u for %d.%d.INT%c does not match " 679 "previous BIOS IRQ %u\n", 680 sc->pl_name, bios_irq, (int)bus, slot, pin + 'A', 681 link->l_bios_irq); 682 ACPI_SERIAL_END(pci_link); 683 } 684 685 static ACPI_STATUS 686 acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf) 687 { 688 ACPI_RESOURCE *resource, *end, newres, *resptr; 689 ACPI_BUFFER crsbuf; 690 ACPI_STATUS status; 691 struct link *link; 692 int i, in_dpf; 693 694 /* Fetch the _CRS. */ 695 crsbuf.Pointer = NULL; 696 crsbuf.Length = ACPI_ALLOCATE_BUFFER; 697 status = AcpiGetCurrentResources(sc->pl_handle, &crsbuf); 698 if (ACPI_SUCCESS(status) && crsbuf.Pointer == NULL) 699 status = AE_NO_MEMORY; 700 if (ACPI_FAILURE(status)) { 701 aprint_verbose("%s: Unable to fetch current resources: %s\n", 702 sc->pl_name, AcpiFormatException(status)); 703 return (status); 704 } 705 706 /* Fill in IRQ resources via link structures. */ 707 srsbuf->Pointer = NULL; 708 link = sc->pl_links; 709 i = 0; 710 in_dpf = DPF_OUTSIDE; 711 resource = (ACPI_RESOURCE *)crsbuf.Pointer; 712 end = (ACPI_RESOURCE *)((char *)crsbuf.Pointer + crsbuf.Length); 713 for (;;) { 714 switch (resource->Type) { 715 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 716 switch (in_dpf) { 717 case DPF_OUTSIDE: 718 /* We've started the first DPF. */ 719 in_dpf = DPF_FIRST; 720 break; 721 case DPF_FIRST: 722 /* We've started the second DPF. */ 723 panic( 724 "%s: Multiple dependent functions within a current resource", 725 __func__); 726 break; 727 } 728 resptr = NULL; 729 break; 730 case ACPI_RESOURCE_TYPE_END_DEPENDENT: 731 /* We are finished with DPF parsing. */ 732 KASSERT(in_dpf != DPF_OUTSIDE); 733 in_dpf = DPF_OUTSIDE; 734 resptr = NULL; 735 break; 736 case ACPI_RESOURCE_TYPE_IRQ: 737 newres = link->l_prs_template; 738 resptr = &newres; 739 resptr->Data.Irq.InterruptCount = 1; 740 if (PCI_INTERRUPT_VALID(link->l_irq)) { 741 KASSERT(link->l_irq < NUM_ISA_INTERRUPTS); 742 resptr->Data.Irq.Interrupts[0] = link->l_irq; 743 resptr->Data.Irq.Triggering = link->l_trig; 744 resptr->Data.Irq.Polarity = link->l_pol; 745 } else 746 resptr->Data.Irq.Interrupts[0] = 0; 747 link++; 748 i++; 749 break; 750 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 751 newres = link->l_prs_template; 752 resptr = &newres; 753 resptr->Data.ExtendedIrq.InterruptCount = 1; 754 if (PCI_INTERRUPT_VALID(link->l_irq)) { 755 resptr->Data.ExtendedIrq.Interrupts[0] = 756 link->l_irq; 757 resptr->Data.ExtendedIrq.Triggering = 758 link->l_trig; 759 resptr->Data.ExtendedIrq.Polarity = link->l_pol; 760 } else 761 resptr->Data.ExtendedIrq.Interrupts[0] = 0; 762 link++; 763 i++; 764 break; 765 default: 766 resptr = resource; 767 } 768 if (resptr != NULL) { 769 status = acpi_AppendBufferResource(srsbuf, resptr); 770 if (ACPI_FAILURE(status)) { 771 printf("%s: Unable to build resources: %s\n", 772 sc->pl_name, AcpiFormatException(status)); 773 if (srsbuf->Pointer != NULL) 774 AcpiOsFree(srsbuf->Pointer); 775 AcpiOsFree(crsbuf.Pointer); 776 return (status); 777 } 778 } 779 if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG) 780 break; 781 resource = ACPI_NEXT_RESOURCE(resource); 782 if (resource >= end) 783 break; 784 } 785 AcpiOsFree(crsbuf.Pointer); 786 return (AE_OK); 787 } 788 789 static ACPI_STATUS 790 acpi_pci_link_srs_from_links(struct acpi_pci_link_softc *sc, 791 ACPI_BUFFER *srsbuf) 792 { 793 ACPI_RESOURCE newres; 794 ACPI_STATUS status; 795 struct link *link; 796 int i; 797 798 /* Start off with an empty buffer. */ 799 srsbuf->Pointer = NULL; 800 link = sc->pl_links; 801 for (i = 0; i < sc->pl_num_links; i++) { 802 803 /* Add a new IRQ resource from each link. */ 804 link = &sc->pl_links[i]; 805 newres = link->l_prs_template; 806 if (newres.Type == ACPI_RESOURCE_TYPE_IRQ) { 807 808 /* Build an IRQ resource. */ 809 newres.Data.Irq.InterruptCount = 1; 810 if (PCI_INTERRUPT_VALID(link->l_irq)) { 811 KASSERT(link->l_irq < NUM_ISA_INTERRUPTS); 812 newres.Data.Irq.Interrupts[0] = link->l_irq; 813 newres.Data.Irq.Triggering = link->l_trig; 814 newres.Data.Irq.Polarity = link->l_pol; 815 } else 816 newres.Data.Irq.Interrupts[0] = 0; 817 } else { 818 819 /* Build an ExtIRQ resuorce. */ 820 newres.Data.ExtendedIrq.InterruptCount = 1; 821 if (PCI_INTERRUPT_VALID(link->l_irq)) { 822 newres.Data.ExtendedIrq.Interrupts[0] = 823 link->l_irq; 824 newres.Data.ExtendedIrq.Triggering = 825 link->l_trig; 826 newres.Data.ExtendedIrq.Polarity = 827 link->l_pol; 828 } else { 829 newres.Data.ExtendedIrq.Interrupts[0] = 0; 830 } 831 } 832 833 /* Add the new resource to the end of the _SRS buffer. */ 834 status = acpi_AppendBufferResource(srsbuf, &newres); 835 if (ACPI_FAILURE(status)) { 836 printf("%s: Unable to build resources: %s\n", 837 sc->pl_name, AcpiFormatException(status)); 838 if (srsbuf->Pointer != NULL) 839 AcpiOsFree(srsbuf->Pointer); 840 return (status); 841 } 842 } 843 return (AE_OK); 844 } 845 846 static ACPI_STATUS 847 acpi_pci_link_srs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf) 848 { 849 ACPI_STATUS status; 850 851 if (sc->pl_crs_bad) 852 status = acpi_pci_link_srs_from_links(sc, srsbuf); 853 else 854 status = acpi_pci_link_srs_from_crs(sc, srsbuf); 855 856 /* Write out new resources via _SRS. */ 857 return AcpiSetCurrentResources(sc->pl_handle, srsbuf); 858 } 859 860 static ACPI_STATUS 861 acpi_pci_link_route_irqs(struct acpi_pci_link_softc *sc, int *irq, int *pol, 862 int *trig) 863 { 864 ACPI_RESOURCE *resource, *end; 865 ACPI_BUFFER srsbuf; 866 ACPI_STATUS status; 867 struct link *link; 868 int i, is_ext = 0; 869 870 status = acpi_pci_link_srs(sc, &srsbuf); 871 if (ACPI_FAILURE(status)) { 872 printf("%s: _SRS failed: %s\n", 873 sc->pl_name, AcpiFormatException(status)); 874 return (status); 875 } 876 /* 877 * Perform acpi_config_intr() on each IRQ resource if it was just 878 * routed for the first time. 879 */ 880 link = sc->pl_links; 881 i = 0; 882 resource = (ACPI_RESOURCE *)srsbuf.Pointer; 883 end = (ACPI_RESOURCE *)((char *)srsbuf.Pointer + srsbuf.Length); 884 for (;;) { 885 if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG) 886 break; 887 switch (resource->Type) { 888 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 889 is_ext = 1; 890 /* FALLTHROUGH */ 891 case ACPI_RESOURCE_TYPE_IRQ: 892 /* 893 * Only configure the interrupt and update the 894 * weights if this link has a valid IRQ and was 895 * previously unrouted. 896 */ 897 if (!link->l_routed && 898 PCI_INTERRUPT_VALID(link->l_irq)) { 899 *trig = is_ext ? 900 resource->Data.ExtendedIrq.Triggering : 901 resource->Data.Irq.Triggering; 902 *pol = is_ext ? 903 resource->Data.ExtendedIrq.Polarity : 904 resource->Data.Irq.Polarity; 905 *irq = is_ext ? 906 resource->Data.ExtendedIrq.Interrupts[0] : 907 resource->Data.Irq.Interrupts[0]; 908 link->l_routed = TRUE; 909 pci_link_interrupt_weights[link->l_irq] += 910 link->l_references; 911 } 912 link++; 913 i++; 914 break; 915 } 916 resource = ACPI_NEXT_RESOURCE(resource); 917 if (resource >= end) 918 break; 919 } 920 AcpiOsFree(srsbuf.Pointer); 921 return (AE_OK); 922 } 923 924 static void 925 acpi_pci_link_resume(int why, void *arg) 926 { 927 struct acpi_pci_link_softc *sc = arg; 928 ACPI_BUFFER srsbuf; 929 930 switch (why) { 931 case PWR_RESUME: 932 ACPI_SERIAL_BEGIN(pci_link); 933 if (ACPI_SUCCESS(acpi_pci_link_srs(sc, &srsbuf))) 934 AcpiOsFree(srsbuf.Pointer); 935 ACPI_SERIAL_END(pci_link); 936 default: 937 break; 938 } 939 } 940 941 /* 942 * Pick an IRQ to use for this unrouted link. 943 */ 944 static uint8_t 945 acpi_pci_link_choose_irq(struct acpi_pci_link_softc *sc, struct link *link) 946 { 947 u_int8_t best_irq, pos_irq; 948 int best_weight, pos_weight, i; 949 950 KASSERT(!link->l_routed); 951 KASSERT(!PCI_INTERRUPT_VALID(link->l_irq)); 952 953 /* 954 * If we have a valid BIOS IRQ, use that. We trust what the BIOS 955 * says it routed over what _CRS says the link thinks is routed. 956 */ 957 if (PCI_INTERRUPT_VALID(link->l_bios_irq)) 958 return (link->l_bios_irq); 959 960 /* 961 * If we don't have a BIOS IRQ but do have a valid IRQ from _CRS, 962 * then use that. 963 */ 964 if (PCI_INTERRUPT_VALID(link->l_initial_irq)) 965 return (link->l_initial_irq); 966 967 /* 968 * Ok, we have no useful hints, so we have to pick from the 969 * possible IRQs. For ISA IRQs we only use interrupts that 970 * have already been used by the BIOS. 971 */ 972 best_irq = PCI_INVALID_IRQ; 973 best_weight = INT_MAX; 974 for (i = 0; i < link->l_num_irqs; i++) { 975 pos_irq = link->l_irqs[i]; 976 if (pos_irq < NUM_ISA_INTERRUPTS && 977 (pci_link_bios_isa_irqs & 1 << pos_irq) == 0) 978 continue; 979 pos_weight = pci_link_interrupt_weights[pos_irq]; 980 if (pos_weight < best_weight) { 981 best_weight = pos_weight; 982 best_irq = pos_irq; 983 } 984 } 985 986 /* 987 * If this is an ISA IRQ, try using the SCI if it is also an ISA 988 * interrupt as a fallback. 989 */ 990 if (link->l_isa_irq) { 991 pos_irq = AcpiGbl_FADT->SciInt; 992 pos_weight = pci_link_interrupt_weights[pos_irq]; 993 if (pos_weight < best_weight) { 994 best_weight = pos_weight; 995 best_irq = pos_irq; 996 } 997 } 998 999 if (PCI_INTERRUPT_VALID(best_irq)) { 1000 aprint_verbose("%s: Picked IRQ %u with weight %d\n", 1001 sc->pl_name, best_irq, best_weight); 1002 } else 1003 printf("%s: Unable to choose an IRQ\n", sc->pl_name); 1004 return (best_irq); 1005 } 1006 1007 int 1008 acpi_pci_link_route_interrupt(void *v, int index, int *irq, int *pol, int *trig) 1009 { 1010 struct acpi_pci_link_softc *sc = v; 1011 struct link *link; 1012 1013 ACPI_SERIAL_BEGIN(pci_link); 1014 link = acpi_pci_link_lookup(sc, index); 1015 if (link == NULL) 1016 panic("%s: apparently invalid index %d", __func__, index); 1017 1018 /* 1019 * If this link device is already routed to an interrupt, just return 1020 * the interrupt it is routed to. 1021 */ 1022 if (link->l_routed) { 1023 KASSERT(PCI_INTERRUPT_VALID(link->l_irq)); 1024 ACPI_SERIAL_END(pci_link); 1025 *irq = link->l_irq; 1026 *pol = link->l_pol; 1027 *trig = link->l_trig; 1028 return (link->l_irq); 1029 } 1030 1031 /* Choose an IRQ if we need one. */ 1032 if (!PCI_INTERRUPT_VALID(link->l_irq)) { 1033 link->l_irq = acpi_pci_link_choose_irq(sc, link); 1034 1035 /* 1036 * Try to route the interrupt we picked. If it fails, then 1037 * assume the interrupt is not routed. 1038 */ 1039 if (PCI_INTERRUPT_VALID(link->l_irq)) { 1040 acpi_pci_link_route_irqs(sc, irq, pol, trig); 1041 if (!link->l_routed) 1042 link->l_irq = PCI_INVALID_IRQ; 1043 else { 1044 link->l_pol = *pol; 1045 link->l_trig = *trig; 1046 } 1047 } 1048 } 1049 ACPI_SERIAL_END(pci_link); 1050 1051 return (link->l_irq); 1052 } 1053 1054 /* 1055 * This is gross, but we abuse the identify routine to perform one-time 1056 * SYSINIT() style initialization for the driver. 1057 */ 1058 static void 1059 acpi_pci_link_init(struct acpi_pci_link_softc *sc) 1060 { 1061 ACPI_BUFFER buf; 1062 1063 /* 1064 * If the SCI is an ISA IRQ, add it to the bitmask of known good 1065 * ISA IRQs. 1066 * 1067 * XXX: If we are using the APIC, the SCI might have been 1068 * rerouted to an APIC pin in which case this is invalid. However, 1069 * if we are using the APIC, we also shouldn't be having any PCI 1070 * interrupts routed via ISA IRQs, so this is probably ok. 1071 */ 1072 if (AcpiGbl_FADT->SciInt < NUM_ISA_INTERRUPTS) 1073 pci_link_bios_isa_irqs |= (1 << AcpiGbl_FADT->SciInt); 1074 1075 sc->pl_powerhook = powerhook_establish(acpi_pci_link_resume, sc); 1076 if (sc->pl_powerhook == NULL) 1077 aprint_normal("can't establish powerhook\n"); 1078 1079 buf.Length = sizeof (sc->pl_name); 1080 buf.Pointer = sc->pl_name; 1081 1082 if (ACPI_FAILURE(AcpiGetName(sc->pl_handle, ACPI_SINGLE_NAME, &buf))) 1083 snprintf(sc->pl_name, sizeof (sc->pl_name), "%s", 1084 "ACPI link device"); 1085 1086 acpi_pci_link_attach(sc); 1087 } 1088 1089 void * 1090 acpi_pci_link_devbyhandle(ACPI_HANDLE handle) 1091 { 1092 struct acpi_pci_link_softc *sc; 1093 1094 TAILQ_FOREACH(sc, &acpi_pci_linkdevs, pl_list) { 1095 if (sc->pl_handle == handle) 1096 return sc; 1097 } 1098 1099 sc = malloc(sizeof (*sc), M_PCI_LINK, M_NOWAIT|M_ZERO); 1100 if (sc == NULL) 1101 return NULL; 1102 1103 sc->pl_handle = handle; 1104 1105 acpi_pci_link_init(sc); 1106 1107 TAILQ_INSERT_TAIL(&acpi_pci_linkdevs, sc, pl_list); 1108 1109 return (void *)sc; 1110 } 1111 1112 ACPI_HANDLE 1113 acpi_pci_link_handle(void *v) 1114 { 1115 struct acpi_pci_link_softc *sc = v; 1116 1117 return sc->pl_handle; 1118 } 1119 1120 char * 1121 acpi_pci_link_name(void *v) 1122 { 1123 struct acpi_pci_link_softc *sc = v; 1124 1125 return sc->pl_name; 1126 } 1127 1128 1129 /* 1130 * Append an ACPI_RESOURCE to an ACPI_BUFFER. 1131 * 1132 * Given a pointer to an ACPI_RESOURCE structure, expand the ACPI_BUFFER 1133 * provided to contain it. If the ACPI_BUFFER is empty, allocate a sensible 1134 * backing block. If the ACPI_RESOURCE is NULL, return an empty set of 1135 * resources. 1136 */ 1137 #define ACPI_INITIAL_RESOURCE_BUFFER_SIZE 512 1138 1139 static ACPI_STATUS 1140 acpi_AppendBufferResource(ACPI_BUFFER *buf, ACPI_RESOURCE *res) 1141 { 1142 ACPI_RESOURCE *rp; 1143 void *newp; 1144 1145 /* Initialise the buffer if necessary. */ 1146 if (buf->Pointer == NULL) { 1147 buf->Length = ACPI_INITIAL_RESOURCE_BUFFER_SIZE; 1148 if ((buf->Pointer = AcpiOsAllocate(buf->Length)) == NULL) 1149 return (AE_NO_MEMORY); 1150 rp = (ACPI_RESOURCE *)buf->Pointer; 1151 rp->Type = ACPI_RESOURCE_TYPE_END_TAG; 1152 rp->Length = 0; 1153 } 1154 1155 if (res == NULL) 1156 return (AE_OK); 1157 1158 /* 1159 * Scan the current buffer looking for the terminator. 1160 * This will either find the terminator or hit the end 1161 * of the buffer and return an error. 1162 */ 1163 rp = (ACPI_RESOURCE *)buf->Pointer; 1164 for (;;) { 1165 /* Range check, don't go outside the buffer */ 1166 if (rp >= (ACPI_RESOURCE *)((u_int8_t *)buf->Pointer + 1167 buf->Length)) 1168 return (AE_BAD_PARAMETER); 1169 if (rp->Type == ACPI_RESOURCE_TYPE_END_TAG || rp->Length == 0) 1170 break; 1171 rp = ACPI_NEXT_RESOURCE(rp); 1172 } 1173 1174 /* 1175 * Check the size of the buffer and expand if required. 1176 * 1177 * Required size is: 1178 * size of existing resources before terminator + 1179 * size of new resource and header + 1180 * size of terminator. 1181 * 1182 * Note that this loop should really only run once, unless 1183 * for some reason we are stuffing a *really* huge resource. 1184 */ 1185 while ((((u_int8_t *)rp - (u_int8_t *)buf->Pointer) + 1186 res->Length + ACPI_RS_SIZE_NO_DATA + 1187 ACPI_RS_SIZE_MIN) >= buf->Length) { 1188 if ((newp = AcpiOsAllocate(buf->Length * 2)) == NULL) 1189 return (AE_NO_MEMORY); 1190 memcpy(newp, buf->Pointer, buf->Length); 1191 rp = (ACPI_RESOURCE *)((u_int8_t *)newp + 1192 ((u_int8_t *)rp - (u_int8_t *)buf->Pointer)); 1193 AcpiOsFree(buf->Pointer); 1194 buf->Pointer = newp; 1195 buf->Length += buf->Length; 1196 } 1197 1198 /* Insert the new resource. */ 1199 memcpy(rp, res, res->Length + ACPI_RS_SIZE_NO_DATA); 1200 1201 /* And add the terminator. */ 1202 rp = ACPI_NEXT_RESOURCE(rp); 1203 rp->Type = ACPI_RESOURCE_TYPE_END_TAG; 1204 rp->Length = 0; 1205 1206 return (AE_OK); 1207 } 1208