1 /* 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * Copyright (c) 2000, Michael Smith <msmith@freebsd.org> 4 * Copyright (c) 2000, BSDi 5 * Copyright (c) 2004, John Baldwin <jhb@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice unmodified, this list of conditions, and the following 13 * 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 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/bus.h> 36 #include <sys/kernel.h> 37 #include <sys/malloc.h> 38 #include <sys/sysctl.h> 39 #include <vm/vm.h> 40 #include <vm/pmap.h> 41 #include <machine/md_var.h> 42 #include <dev/pci/pcivar.h> 43 #include <dev/pci/pcireg.h> 44 #include <machine/pci_cfgreg.h> 45 #include <machine/segments.h> 46 #include <machine/pc/bios.h> 47 48 #define NUM_ISA_INTERRUPTS 16 49 50 /* 51 * A link device. Loosely based on the ACPI PCI link device. This doesn't 52 * try to support priorities for different ISA interrupts. 53 */ 54 struct pci_link { 55 TAILQ_ENTRY(pci_link) pl_links; 56 uint8_t pl_id; 57 uint8_t pl_irq; 58 uint16_t pl_irqmask; 59 int pl_references; 60 int pl_routed; 61 }; 62 63 struct pci_link_lookup { 64 struct pci_link **pci_link_ptr; 65 int bus; 66 int device; 67 int pin; 68 }; 69 70 struct pci_dev_lookup { 71 uint8_t link; 72 int bus; 73 int device; 74 int pin; 75 }; 76 77 typedef void pir_entry_handler(struct PIR_entry *entry, 78 struct PIR_intpin* intpin, void *arg); 79 80 static void pci_print_irqmask(u_int16_t irqs); 81 static int pci_pir_biosroute(int bus, int device, int func, int pin, 82 int irq); 83 static int pci_pir_choose_irq(struct pci_link *pci_link, int irqmask); 84 static void pci_pir_create_links(struct PIR_entry *entry, 85 struct PIR_intpin *intpin, void *arg); 86 static void pci_pir_dump_links(void); 87 static struct pci_link *pci_pir_find_link(uint8_t link_id); 88 static void pci_pir_find_link_handler(struct PIR_entry *entry, 89 struct PIR_intpin *intpin, void *arg); 90 static void pci_pir_initial_irqs(struct PIR_entry *entry, 91 struct PIR_intpin *intpin, void *arg); 92 static void pci_pir_parse(void); 93 static void pci_pir_print_intpin(struct PIR_entry *entry, 94 struct PIR_intpin *intpin, void *arg); 95 static void pci_pir_print_table(void); 96 static uint8_t pci_pir_search_irq(int bus, int device, int pin); 97 static int pci_pir_valid_irq(struct pci_link *pci_link, int irq); 98 static void pci_pir_walk_table(pir_entry_handler *handler, void *arg); 99 100 MALLOC_DEFINE(M_PIR, "$PIR", "$PIR structures"); 101 102 static struct PIR_table *pci_route_table; 103 static device_t pir_device; 104 static int pci_route_count, pir_bios_irqs, pir_parsed; 105 static TAILQ_HEAD(, pci_link) pci_links; 106 static int pir_interrupt_weight[NUM_ISA_INTERRUPTS]; 107 108 /* sysctl vars */ 109 SYSCTL_DECL(_hw_pci); 110 111 #ifdef PC98 112 /* IRQs 3, 5, 7, 9, 10, 11, 12, 13 */ 113 #define PCI_IRQ_OVERRIDE_MASK 0x3e68 114 #else 115 /* IRQs 3, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15 */ 116 #define PCI_IRQ_OVERRIDE_MASK 0xdef8 117 #endif 118 119 static uint32_t pci_irq_override_mask = PCI_IRQ_OVERRIDE_MASK; 120 TUNABLE_INT("hw.pci.irq_override_mask", &pci_irq_override_mask); 121 SYSCTL_INT(_hw_pci, OID_AUTO, irq_override_mask, CTLFLAG_RDTUN, 122 &pci_irq_override_mask, PCI_IRQ_OVERRIDE_MASK, 123 "Mask of allowed irqs to try to route when it has no good clue about\n" 124 "which irqs it should use."); 125 126 /* 127 * Look for the interrupt routing table. 128 * 129 * We use PCI BIOS's PIR table if it's available. $PIR is the standard way 130 * to do this. Sadly, some machines are not standards conforming and have 131 * _PIR instead. We shrug and cope by looking for both. 132 */ 133 void 134 pci_pir_open(void) 135 { 136 struct PIR_table *pt; 137 uint32_t sigaddr; 138 int i; 139 uint8_t ck, *cv; 140 141 /* Don't try if we've already found a table. */ 142 if (pci_route_table != NULL) 143 return; 144 145 /* Look for $PIR and then _PIR. */ 146 sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0); 147 if (sigaddr == 0) 148 sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0); 149 if (sigaddr == 0) 150 return; 151 152 /* If we found something, check the checksum and length. */ 153 /* XXX - Use pmap_mapdev()? */ 154 pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr); 155 if (pt->pt_header.ph_length <= sizeof(struct PIR_header)) 156 return; 157 for (cv = (u_int8_t *)pt, ck = 0, i = 0; 158 i < (pt->pt_header.ph_length); i++) 159 ck += cv[i]; 160 if (ck != 0) 161 return; 162 163 /* Ok, we've got a valid table. */ 164 pci_route_table = pt; 165 pci_route_count = (pt->pt_header.ph_length - 166 sizeof(struct PIR_header)) / 167 sizeof(struct PIR_entry); 168 if (bootverbose) { 169 printf("Found $PIR table, %d entries at %p\n", 170 pci_route_count, pci_route_table); 171 pci_pir_print_table(); 172 } 173 } 174 175 /* 176 * Find the pci_link structure for a given link ID. 177 */ 178 static struct pci_link * 179 pci_pir_find_link(uint8_t link_id) 180 { 181 struct pci_link *pci_link; 182 183 TAILQ_FOREACH(pci_link, &pci_links, pl_links) { 184 if (pci_link->pl_id == link_id) 185 return (pci_link); 186 } 187 return (NULL); 188 } 189 190 /* 191 * Find the link device associated with a PCI device in the table. 192 */ 193 static void 194 pci_pir_find_link_handler(struct PIR_entry *entry, struct PIR_intpin *intpin, 195 void *arg) 196 { 197 struct pci_link_lookup *lookup; 198 199 lookup = (struct pci_link_lookup *)arg; 200 if (entry->pe_bus == lookup->bus && 201 entry->pe_device == lookup->device && 202 intpin - entry->pe_intpin == lookup->pin) 203 *lookup->pci_link_ptr = pci_pir_find_link(intpin->link); 204 } 205 206 /* 207 * Check to see if a possible IRQ setting is valid. 208 */ 209 static int 210 pci_pir_valid_irq(struct pci_link *pci_link, int irq) 211 { 212 213 if (!PCI_INTERRUPT_VALID(irq)) 214 return (0); 215 return (pci_link->pl_irqmask & (1 << irq)); 216 } 217 218 /* 219 * Walk the $PIR executing the worker function for each valid intpin entry 220 * in the table. The handler is passed a pointer to both the entry and 221 * the intpin in the entry. 222 */ 223 static void 224 pci_pir_walk_table(pir_entry_handler *handler, void *arg) 225 { 226 struct PIR_entry *entry; 227 struct PIR_intpin *intpin; 228 int i, pin; 229 230 entry = &pci_route_table->pt_entry[0]; 231 for (i = 0; i < pci_route_count; i++, entry++) { 232 intpin = &entry->pe_intpin[0]; 233 for (pin = 0; pin < 4; pin++, intpin++) 234 if (intpin->link != 0) 235 handler(entry, intpin, arg); 236 } 237 } 238 239 static void 240 pci_pir_create_links(struct PIR_entry *entry, struct PIR_intpin *intpin, 241 void *arg) 242 { 243 struct pci_link *pci_link; 244 245 pci_link = pci_pir_find_link(intpin->link); 246 if (pci_link != NULL) { 247 pci_link->pl_references++; 248 if (intpin->irqs != pci_link->pl_irqmask) { 249 if (bootverbose) 250 printf( 251 "$PIR: Entry %d.%d.INT%c has different mask for link %#x, merging\n", 252 entry->pe_bus, entry->pe_device, 253 (intpin - entry->pe_intpin) + 'A', 254 pci_link->pl_id); 255 pci_link->pl_irqmask &= intpin->irqs; 256 } 257 } else { 258 pci_link = malloc(sizeof(struct pci_link), M_PIR, M_WAITOK); 259 pci_link->pl_id = intpin->link; 260 pci_link->pl_irqmask = intpin->irqs; 261 pci_link->pl_irq = PCI_INVALID_IRQ; 262 pci_link->pl_references = 1; 263 pci_link->pl_routed = 0; 264 TAILQ_INSERT_TAIL(&pci_links, pci_link, pl_links); 265 } 266 } 267 268 /* 269 * Look to see if any of the function on the PCI device at bus/device have 270 * an interrupt routed to intpin 'pin' by the BIOS. 271 */ 272 static uint8_t 273 pci_pir_search_irq(int bus, int device, int pin) 274 { 275 uint32_t value; 276 uint8_t func, maxfunc; 277 278 /* See if we have a valid device at function 0. */ 279 value = pci_cfgregread(bus, device, 0, PCIR_HDRTYPE, 1); 280 if ((value & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 281 return (PCI_INVALID_IRQ); 282 if (value & PCIM_MFDEV) 283 maxfunc = PCI_FUNCMAX; 284 else 285 maxfunc = 0; 286 287 /* Scan all possible functions at this device. */ 288 for (func = 0; func <= maxfunc; func++) { 289 value = pci_cfgregread(bus, device, func, PCIR_DEVVENDOR, 4); 290 if (value == 0xffffffff) 291 continue; 292 value = pci_cfgregread(bus, device, func, PCIR_INTPIN, 1); 293 294 /* 295 * See if it uses the pin in question. Note that the passed 296 * in pin uses 0 for A, .. 3 for D whereas the intpin 297 * register uses 0 for no interrupt, 1 for A, .. 4 for D. 298 */ 299 if (value != pin + 1) 300 continue; 301 value = pci_cfgregread(bus, device, func, PCIR_INTLINE, 1); 302 if (bootverbose) 303 printf( 304 "$PIR: Found matching pin for %d.%d.INT%c at func %d: %d\n", 305 bus, device, pin + 'A', func, value); 306 if (value != PCI_INVALID_IRQ) 307 return (value); 308 } 309 return (PCI_INVALID_IRQ); 310 } 311 312 /* 313 * Try to initialize IRQ based on this device's IRQ. 314 */ 315 static void 316 pci_pir_initial_irqs(struct PIR_entry *entry, struct PIR_intpin *intpin, 317 void *arg) 318 { 319 struct pci_link *pci_link; 320 uint8_t irq, pin; 321 322 pin = intpin - entry->pe_intpin; 323 pci_link = pci_pir_find_link(intpin->link); 324 irq = pci_pir_search_irq(entry->pe_bus, entry->pe_device, pin); 325 if (irq == PCI_INVALID_IRQ) 326 return; 327 if (pci_pir_valid_irq(pci_link, irq)) { 328 if (pci_link->pl_irq == PCI_INVALID_IRQ) { 329 pci_link->pl_irq = irq; 330 pci_link->pl_routed = 1; 331 } else if (pci_link->pl_irq != irq) 332 printf( 333 "$PIR: BIOS IRQ %d for %d.%d.INT%c does not match link %#x irq %d\n", 334 irq, entry->pe_bus, entry->pe_device, pin + 'A', 335 pci_link->pl_id, pci_link->pl_irq); 336 } else 337 printf( 338 "$PIR: BIOS IRQ %d for %d.%d.INT%c is not valid for link %#x\n", 339 irq, entry->pe_bus, entry->pe_device, pin + 'A', 340 pci_link->pl_id); 341 } 342 343 /* 344 * Parse $PIR to enumerate link devices and attempt to determine their 345 * initial state. This could perhaps be cleaner if we had drivers for the 346 * various interrupt routers as they could read the initial IRQ for each 347 * link. 348 */ 349 static void 350 pci_pir_parse(void) 351 { 352 char tunable_buffer[64]; 353 struct pci_link *pci_link; 354 int i, irq; 355 356 /* Only parse once. */ 357 if (pir_parsed) 358 return; 359 pir_parsed = 1; 360 361 /* Enumerate link devices. */ 362 TAILQ_INIT(&pci_links); 363 pci_pir_walk_table(pci_pir_create_links, NULL); 364 if (bootverbose) { 365 printf("$PIR: Links after initial probe:\n"); 366 pci_pir_dump_links(); 367 } 368 369 /* Check for unique IRQ masks. */ 370 TAILQ_FOREACH(pci_link, &pci_links, pl_links) { 371 if (pci_link->pl_irqmask != 0 && powerof2(pci_link->pl_irqmask)) 372 pci_link->pl_irq = ffs(pci_link->pl_irqmask) - 1; 373 } 374 375 /* 376 * Check to see if the BIOS has already routed any of the links by 377 * checking each device connected to each link to see if it has a 378 * valid IRQ. 379 */ 380 pci_pir_walk_table(pci_pir_initial_irqs, NULL); 381 if (bootverbose) { 382 printf("$PIR: Links after initial IRQ discovery:\n"); 383 pci_pir_dump_links(); 384 } 385 386 /* 387 * Allow the user to override the IRQ for a given link device as 388 * long as the override is valid or is 255 or 0 to clear a preset 389 * IRQ. 390 */ 391 i = 0; 392 TAILQ_FOREACH(pci_link, &pci_links, pl_links) { 393 snprintf(tunable_buffer, sizeof(tunable_buffer), 394 "hw.pci.link.%#x.irq", pci_link->pl_id); 395 if (getenv_int(tunable_buffer, &irq) == 0) 396 continue; 397 if (irq == 0) 398 irq = PCI_INVALID_IRQ; 399 if (irq == PCI_INVALID_IRQ || 400 pci_pir_valid_irq(pci_link, irq)) { 401 pci_link->pl_routed = 0; 402 pci_link->pl_irq = irq; 403 i = 1; 404 } 405 } 406 if (bootverbose && i) { 407 printf("$PIR: Links after tunable overrides:\n"); 408 pci_pir_dump_links(); 409 } 410 411 /* 412 * Build initial interrupt weights as well as bitmap of "known-good" 413 * IRQs that the BIOS has already used for PCI link devices. 414 */ 415 TAILQ_FOREACH(pci_link, &pci_links, pl_links) { 416 if (!PCI_INTERRUPT_VALID(pci_link->pl_irq)) 417 continue; 418 pir_bios_irqs |= 1 << pci_link->pl_irq; 419 pir_interrupt_weight[pci_link->pl_irq] += 420 pci_link->pl_references; 421 } 422 if (bootverbose) { 423 printf("$PIR: IRQs used by BIOS: "); 424 pci_print_irqmask(pir_bios_irqs); 425 printf("\n"); 426 printf("$PIR: Interrupt Weights:\n[ "); 427 for (i = 0; i < NUM_ISA_INTERRUPTS; i++) 428 printf(" %3d", i); 429 printf(" ]\n[ "); 430 for (i = 0; i < NUM_ISA_INTERRUPTS; i++) 431 printf(" %3d", pir_interrupt_weight[i]); 432 printf(" ]\n"); 433 } 434 } 435 436 /* 437 * Use the PCI BIOS to route an interrupt for a given device. 438 * 439 * Input: 440 * AX = PCIBIOS_ROUTE_INTERRUPT 441 * BH = bus 442 * BL = device [7:3] / function [2:0] 443 * CH = IRQ 444 * CL = Interrupt Pin (0x0A = A, ... 0x0D = D) 445 */ 446 static int 447 pci_pir_biosroute(int bus, int device, int func, int pin, int irq) 448 { 449 struct bios_regs args; 450 451 args.eax = PCIBIOS_ROUTE_INTERRUPT; 452 args.ebx = (bus << 8) | (device << 3) | func; 453 args.ecx = (irq << 8) | (0xa + pin); 454 return (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))); 455 } 456 457 458 /* 459 * Route a PCI interrupt using a link device from the $PIR. 460 */ 461 int 462 pci_pir_route_interrupt(int bus, int device, int func, int pin) 463 { 464 struct pci_link_lookup lookup; 465 struct pci_link *pci_link; 466 int error, irq; 467 468 if (pci_route_table == NULL) 469 return (PCI_INVALID_IRQ); 470 471 /* Lookup link device for this PCI device/pin. */ 472 pci_link = NULL; 473 lookup.bus = bus; 474 lookup.device = device; 475 lookup.pin = pin - 1; 476 lookup.pci_link_ptr = &pci_link; 477 pci_pir_walk_table(pci_pir_find_link_handler, &lookup); 478 if (pci_link == NULL) { 479 printf("$PIR: No matching entry for %d.%d.INT%c\n", bus, 480 device, pin - 1 + 'A'); 481 return (PCI_INVALID_IRQ); 482 } 483 484 /* 485 * Pick a new interrupt if we don't have one already. We look for 486 * an interrupt from several different sets. First, we check the 487 * set of PCI only interrupts from the $PIR. Second, we check the 488 * set of known-good interrupts that the BIOS has already used. 489 * Lastly, we check the "all possible valid IRQs" set. 490 */ 491 if (!PCI_INTERRUPT_VALID(pci_link->pl_irq)) { 492 irq = pci_pir_choose_irq(pci_link, 493 pci_route_table->pt_header.ph_pci_irqs); 494 if (!PCI_INTERRUPT_VALID(irq)) 495 irq = pci_pir_choose_irq(pci_link, pir_bios_irqs); 496 if (!PCI_INTERRUPT_VALID(irq)) 497 irq = pci_pir_choose_irq(pci_link, 498 pci_irq_override_mask); 499 if (!PCI_INTERRUPT_VALID(irq)) { 500 if (bootverbose) 501 printf( 502 "$PIR: Failed to route interrupt for %d:%d INT%c\n", 503 bus, device, pin - 1 + 'A'); 504 return (PCI_INVALID_IRQ); 505 } 506 pci_link->pl_irq = irq; 507 } 508 509 /* Ask the BIOS to route this IRQ if we haven't done so already. */ 510 if (!pci_link->pl_routed) { 511 error = pci_pir_biosroute(bus, device, func, pin - 1, 512 pci_link->pl_irq); 513 514 /* Ignore errors when routing a unique interrupt. */ 515 if (error && !powerof2(pci_link->pl_irqmask)) { 516 printf("$PIR: ROUTE_INTERRUPT failed.\n"); 517 return (PCI_INVALID_IRQ); 518 } 519 pci_link->pl_routed = 1; 520 521 /* Ensure the interrupt is set to level/low trigger. */ 522 KASSERT(pir_device != NULL, ("missing pir device")); 523 BUS_CONFIG_INTR(pir_device, pci_link->pl_irq, 524 INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW); 525 } 526 printf("$PIR: %d:%d INT%c routed to irq %d\n", bus, device, 527 pin - 1 + 'A', pci_link->pl_irq); 528 return (pci_link->pl_irq); 529 } 530 531 /* 532 * Try to pick an interrupt for the specified link from the interrupts 533 * set in the mask. 534 */ 535 static int 536 pci_pir_choose_irq(struct pci_link *pci_link, int irqmask) 537 { 538 int i, irq, realmask; 539 540 /* XXX: Need to have a #define of known bad IRQs to also mask out? */ 541 realmask = pci_link->pl_irqmask & irqmask; 542 if (realmask == 0) 543 return (PCI_INVALID_IRQ); 544 545 /* Find IRQ with lowest weight. */ 546 irq = PCI_INVALID_IRQ; 547 for (i = 0; i < NUM_ISA_INTERRUPTS; i++) { 548 if (!(realmask & 1 << i)) 549 continue; 550 if (irq == PCI_INVALID_IRQ || 551 pir_interrupt_weight[i] < pir_interrupt_weight[irq]) 552 irq = i; 553 } 554 if (bootverbose && PCI_INTERRUPT_VALID(irq)) { 555 printf("$PIR: Found IRQ %d for link %#x from ", irq, 556 pci_link->pl_id); 557 pci_print_irqmask(realmask); 558 printf("\n"); 559 } 560 return (irq); 561 } 562 563 static void 564 pci_print_irqmask(u_int16_t irqs) 565 { 566 int i, first; 567 568 if (irqs == 0) { 569 printf("none"); 570 return; 571 } 572 first = 1; 573 for (i = 0; i < 16; i++, irqs >>= 1) 574 if (irqs & 1) { 575 if (!first) 576 printf(" "); 577 else 578 first = 0; 579 printf("%d", i); 580 } 581 } 582 583 /* 584 * Dump the contents of a single intpin entry to the console. 585 */ 586 static void 587 pci_pir_print_intpin(struct PIR_entry *entry, struct PIR_intpin *intpin, 588 void *arg) 589 { 590 591 if (entry->pe_slot == 0) 592 printf("embedded "); 593 else 594 printf("slot %-3d ", entry->pe_slot); 595 printf(" %3d %3d %c 0x%02x ", entry->pe_bus, entry->pe_device, 596 intpin - entry->pe_intpin + 'A', intpin->link); 597 pci_print_irqmask(intpin->irqs); 598 printf("\n"); 599 } 600 601 /* 602 * Dump the contents of a PCI BIOS Interrupt Routing Table to the console. 603 */ 604 static void 605 pci_pir_print_table(void) 606 { 607 608 printf("PCI-Only Interrupts: "); 609 pci_print_irqmask(pci_route_table->pt_header.ph_pci_irqs); 610 printf("\nLocation Bus Device Pin Link IRQs\n"); 611 pci_pir_walk_table(pci_pir_print_intpin, NULL); 612 } 613 614 /* 615 * Display link devices. 616 */ 617 static void 618 pci_pir_dump_links(void) 619 { 620 struct pci_link *pci_link; 621 622 printf("Link IRQ Rtd Ref IRQs\n"); 623 TAILQ_FOREACH(pci_link, &pci_links, pl_links) { 624 printf("%#4x %3d %c %3d ", pci_link->pl_id, 625 pci_link->pl_irq, pci_link->pl_routed ? 'Y' : 'N', 626 pci_link->pl_references); 627 pci_print_irqmask(pci_link->pl_irqmask); 628 printf("\n"); 629 } 630 } 631 632 /* 633 * See if any interrupts for a given PCI bus are routed in the PIR. Don't 634 * even bother looking if the BIOS doesn't support routing anyways. If we 635 * are probing a PCI-PCI bridge, then require_parse will be true and we should 636 * only succeed if a host-PCI bridge has already attached and parsed the PIR. 637 */ 638 int 639 pci_pir_probe(int bus, int require_parse) 640 { 641 int i; 642 643 if (pci_route_table == NULL || (require_parse && !pir_parsed)) 644 return (0); 645 for (i = 0; i < pci_route_count; i++) 646 if (pci_route_table->pt_entry[i].pe_bus == bus) 647 return (1); 648 return (0); 649 } 650 651 /* 652 * The driver for the new-bus psuedo device pir0 for the $PIR table. 653 */ 654 655 static int 656 pir_probe(device_t dev) 657 { 658 char buf[64]; 659 660 snprintf(buf, sizeof(buf), "PCI Interrupt Routing Table: %d Entries", 661 pci_route_count); 662 device_set_desc_copy(dev, buf); 663 return (0); 664 } 665 666 static int 667 pir_attach(device_t dev) 668 { 669 670 pci_pir_parse(); 671 KASSERT(pir_device == NULL, ("Multiple pir devices")); 672 pir_device = dev; 673 return (0); 674 } 675 676 static void 677 pir_resume_find_device(struct PIR_entry *entry, struct PIR_intpin *intpin, 678 void *arg) 679 { 680 struct pci_dev_lookup *pd; 681 682 pd = (struct pci_dev_lookup *)arg; 683 if (intpin->link != pd->link || pd->bus != -1) 684 return; 685 pd->bus = entry->pe_bus; 686 pd->device = entry->pe_device; 687 pd->pin = intpin - entry->pe_intpin; 688 } 689 690 static int 691 pir_resume(device_t dev) 692 { 693 struct pci_dev_lookup pd; 694 struct pci_link *pci_link; 695 int error; 696 697 /* Ask the BIOS to re-route each link that was already routed. */ 698 TAILQ_FOREACH(pci_link, &pci_links, pl_links) { 699 if (!PCI_INTERRUPT_VALID(pci_link->pl_irq)) { 700 KASSERT(!pci_link->pl_routed, 701 ("link %#x is routed but has invalid PCI IRQ", 702 pci_link->pl_id)); 703 continue; 704 } 705 if (pci_link->pl_routed) { 706 pd.bus = -1; 707 pd.link = pci_link->pl_id; 708 pci_pir_walk_table(pir_resume_find_device, &pd); 709 KASSERT(pd.bus != -1, 710 ("did not find matching entry for link %#x in the $PIR table", 711 pci_link->pl_id)); 712 if (bootverbose) 713 device_printf(dev, 714 "Using %d.%d.INT%c to route link %#x to IRQ %d\n", 715 pd.bus, pd.device, pd.pin + 'A', 716 pci_link->pl_id, pci_link->pl_irq); 717 error = pci_pir_biosroute(pd.bus, pd.device, 0, pd.pin, 718 pci_link->pl_irq); 719 if (error) 720 device_printf(dev, 721 "ROUTE_INTERRUPT on resume for link %#x failed.\n", 722 pci_link->pl_id); 723 } 724 } 725 return (0); 726 } 727 728 static device_method_t pir_methods[] = { 729 /* Device interface */ 730 DEVMETHOD(device_probe, pir_probe), 731 DEVMETHOD(device_attach, pir_attach), 732 DEVMETHOD(device_resume, pir_resume), 733 734 { 0, 0 } 735 }; 736 737 static driver_t pir_driver = { 738 "pir", 739 pir_methods, 740 1, 741 }; 742 743 static devclass_t pir_devclass; 744 745 DRIVER_MODULE(pir, legacy, pir_driver, pir_devclass, 0, 0); 746