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