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