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