1 /* 2 * Copyright 2011, Michael Lotz mmlr@mlotz.ch. 3 * Copyright 2009, Clemens Zeidler haiku@clemens-zeidler.de. 4 * All rights reserved. 5 * 6 * Distributed under the terms of the MIT License. 7 */ 8 9 10 #include "acpi_irq_routing_table.h" 11 12 #include "acpi.h" 13 14 #include <int.h> 15 16 #include <PCI.h> 17 18 19 //#define TRACE_PRT 20 #ifdef TRACE_PRT 21 # define TRACE(x...) dprintf("IRQRoutingTable: " x) 22 #else 23 # define TRACE(x...) 24 #endif 25 26 27 const char* kACPIPciRootName = "PNP0A03"; 28 const char* kACPIPciExpressRootName = "PNP0A08"; 29 // Note that some configurations will still return the PCI express root 30 // when querying for the standard PCI root. This is due to the compatible ID 31 // fields in ACPI. TODO: Query both/the correct root device. 32 33 // TODO: as per PCI 3.0, the PCI module hardcodes it in various places as well. 34 static const uint8 kMaxPCIFunctionCount = 8; 35 static const uint8 kMaxPCIDeviceCount = 32; 36 // TODO: actually this is mechanism dependent 37 #if defined(__i386__) || defined(__x86_64__) 38 static const uint8 kMaxISAInterrupts = 16; 39 #else 40 static const uint8 kMaxISAInterrupts = 0; 41 #endif 42 43 irq_descriptor::irq_descriptor() 44 : 45 irq(0), 46 shareable(false), 47 polarity(B_HIGH_ACTIVE_POLARITY), 48 trigger_mode(B_EDGE_TRIGGERED) 49 { 50 } 51 52 53 void 54 print_irq_descriptor(const irq_descriptor& descriptor) 55 { 56 const char* activeHighString = "active high"; 57 const char* activeLowString = " active low"; 58 const char* levelTriggeredString = "level triggered"; 59 const char* edgeTriggeredString = "edge triggered"; 60 61 dprintf("irq: %u, shareable: %u, polarity: %s, trigger_mode: %s\n", 62 descriptor.irq, descriptor.shareable, 63 descriptor.polarity == B_HIGH_ACTIVE_POLARITY ? activeHighString 64 : activeLowString, 65 descriptor.trigger_mode == B_LEVEL_TRIGGERED ? levelTriggeredString 66 : edgeTriggeredString); 67 } 68 69 70 static void 71 print_irq_routing_entry(const irq_routing_entry& entry) 72 { 73 dprintf("address 0x%04" B_PRIx64 "; pin %u;", entry.device_address, 74 entry.pin); 75 76 if (entry.source_index != 0) 77 dprintf(" GSI %" B_PRIu32 ";", entry.source_index); 78 else 79 dprintf(" source %p %" B_PRIu32 ";", entry.source, entry.source_index); 80 81 dprintf(" pci %u:%u pin %u func mask %" B_PRIx32 "; bios irq: %u; gsi %u;" 82 " config 0x%02x\n", entry.pci_bus, entry.pci_device, entry.pin + 1, 83 entry.pci_function_mask, entry.bios_irq, entry.irq, 84 entry.polarity | entry.trigger_mode); 85 } 86 87 88 void 89 print_irq_routing_table(const IRQRoutingTable& table) 90 { 91 dprintf("IRQ routing table with %i entries\n", (int)table.Count()); 92 for (int i = 0; i < table.Count(); i++) 93 print_irq_routing_entry(table.ElementAt(i)); 94 } 95 96 97 static status_t 98 update_pci_info_for_entry(pci_module_info* pci, const irq_routing_entry& entry) 99 { 100 uint32 updateCount = 0; 101 for (uint8 function = 0; function < kMaxPCIFunctionCount; function++) { 102 if ((entry.pci_function_mask & (1 << function)) == 0) 103 continue; 104 105 if (pci->update_interrupt_line(entry.pci_bus, entry.pci_device, 106 function, entry.irq) == B_OK) { 107 updateCount++; 108 } 109 } 110 111 return updateCount > 0 ? B_OK : B_ENTRY_NOT_FOUND; 112 } 113 114 115 static status_t 116 fill_pci_info_for_entry(pci_module_info* pci, irq_routing_entry& entry) 117 { 118 // check the base device at function 0 119 uint8 headerType = pci->read_pci_config(entry.pci_bus, entry.pci_device, 0, 120 PCI_header_type, 1); 121 if (headerType == 0xff) { 122 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 " entry not found\n", 123 entry.pci_bus, entry.pci_device); 124 // the device is not present 125 return B_ENTRY_NOT_FOUND; 126 } 127 128 // we have a device, check how many functions we need to iterate 129 uint8 functionCount = 1; 130 if ((headerType & PCI_multifunction) != 0) 131 functionCount = kMaxPCIFunctionCount; 132 133 for (uint8 function = 0; function < functionCount; function++) { 134 // check for device presence by looking for a valid vendor 135 uint16 vendorId = pci->read_pci_config(entry.pci_bus, entry.pci_device, 136 function, PCI_vendor_id, 2); 137 if (vendorId == 0xffff) { 138 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " vendor 0xffff\n", 139 entry.pci_bus, entry.pci_device, function); 140 continue; 141 } 142 143 uint8 interruptPin = pci->read_pci_config(entry.pci_bus, 144 entry.pci_device, function, PCI_interrupt_pin, 1); 145 146 // Finally match the pin with the entry, note that PCI pins are 1 based 147 // while ACPI ones are 0 based. 148 if (interruptPin != entry.pin + 1) { 149 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " IRQ Pin %" B_PRIu8 150 " != %" B_PRIu8 "\n", entry.pci_bus, entry.pci_device, function, 151 interruptPin, entry.pin + 1); 152 continue; 153 } 154 155 if (entry.bios_irq == 0) { 156 // Keep the originally assigned IRQ around so we can use it for 157 // white listing PCI IRQs in the ISA space as those are basically 158 // guaranteed not to overlap with ISA devices. Those white listed 159 // entries can then be used if we only have a 16 pin IO-APIC or if 160 // there are only legacy IRQ resources available for configuration 161 // (with bitmasks of 16 bits, limiting their range to ISA IRQs). 162 entry.bios_irq = pci->read_pci_config(entry.pci_bus, 163 entry.pci_device, function, PCI_interrupt_line, 1); 164 } 165 166 entry.pci_function_mask |= 1 << function; 167 } 168 169 return entry.pci_function_mask != 0 ? B_OK : B_ENTRY_NOT_FOUND; 170 } 171 172 173 static status_t 174 choose_link_device_configurations(acpi_module_info* acpi, 175 IRQRoutingTable& routingTable, 176 interrupt_available_check_function checkFunction) 177 { 178 /* 179 Before configuring the link devices we have to take a few things into 180 consideration: 181 * Multiple PCI devices / functions may link to the same PCI link 182 device, so we must ensure that we don't try to configure different 183 IRQs for each device, overwriting the previous config of the 184 respective link device. 185 * If we can't use non-ISA IRQs then we must ensure that we don't 186 configure any IRQs that overlaps with ISA devices (as they use 187 different triggering modes and polarity they aren't compatible). 188 Since the ISA bus isn't enumerable we don't have any clues as to 189 where an ISA device might be connected. The only safe assumption 190 therefore is to only use IRQs that are known to be usable for PCI 191 devices. In our case we can use all the previously assigned PCI 192 interrupt_line IRQs as stored in the bios_irq field. 193 */ 194 195 uint16 validForPCI = 0; // only applies to the ISA IRQs 196 uint16 irqUsage[256]; 197 memset(irqUsage, 0, sizeof(irqUsage)); 198 199 // find all unique link devices and resolve their possible IRQs 200 Vector<link_device*> links; 201 for (int i = 0; i < routingTable.Count(); i++) { 202 irq_routing_entry& irqEntry = routingTable.ElementAt(i); 203 204 if (irqEntry.bios_irq != 0 && irqEntry.bios_irq != 255) { 205 if (irqEntry.bios_irq < kMaxISAInterrupts) 206 validForPCI |= (1 << irqEntry.bios_irq); 207 } 208 209 if (irqEntry.source == NULL) { 210 // populate all hardwired GSI entries into our map 211 irqUsage[irqEntry.irq]++; 212 if (irqEntry.irq < kMaxISAInterrupts) 213 validForPCI |= (1 << irqEntry.irq); 214 continue; 215 } 216 217 link_device* link = NULL; 218 for (int j = 0; j < links.Count(); j++) { 219 link_device* existing = links.ElementAt(j); 220 if (existing->handle == irqEntry.source) { 221 link = existing; 222 break; 223 } 224 } 225 226 if (link != NULL) { 227 link->used_by.PushBack(&irqEntry); 228 continue; 229 } 230 231 // A new link device, read possible IRQs and fill them in. 232 link = new(std::nothrow) link_device; 233 if (link == NULL) { 234 panic("ran out of memory while configuring irq link devices"); 235 return B_NO_MEMORY; 236 } 237 238 link->handle = irqEntry.source; 239 status_t status = read_possible_irqs(acpi, link->handle, 240 link->possible_irqs); 241 if (status != B_OK) { 242 panic("failed to read possible irqs of link device"); 243 delete link; 244 return status; 245 } 246 247 status = read_current_irq(acpi, link->handle, link->current_irq); 248 if (status != B_OK) { 249 panic("failed to read current irq of link device"); 250 delete link; 251 return status; 252 } 253 254 if (link->current_irq.irq < kMaxISAInterrupts) 255 validForPCI |= (1 << link->current_irq.irq); 256 257 link->used_by.PushBack(&irqEntry); 258 links.PushBack(link); 259 } 260 261 for (int i = 0; i < links.Count(); i++) { 262 link_device* link = links.ElementAt(i); 263 264 int bestIRQIndex = 0; 265 uint16 bestIRQUsage = UINT16_MAX; 266 for (int j = 0; j < link->possible_irqs.Count(); j++) { 267 irq_descriptor& possibleIRQ = link->possible_irqs.ElementAt(j); 268 if (!checkFunction(possibleIRQ.irq)) { 269 // we can't address this pin 270 continue; 271 } 272 273 if (possibleIRQ.irq < kMaxISAInterrupts 274 && (validForPCI & (1 << possibleIRQ.irq)) == 0) { 275 // better avoid that if possible 276 continue; 277 } 278 279 if (irqUsage[possibleIRQ.irq] < bestIRQUsage) { 280 bestIRQIndex = j; 281 bestIRQUsage = irqUsage[possibleIRQ.irq]; 282 } 283 } 284 285 // pick that one and update the counts 286 irq_descriptor& chosenDescriptor 287 = link->possible_irqs.ElementAt(bestIRQIndex); 288 if (!checkFunction(chosenDescriptor.irq)) { 289 dprintf("chosen irq %u is not addressable\n", chosenDescriptor.irq); 290 return B_ERROR; 291 } 292 293 irqUsage[chosenDescriptor.irq] += link->used_by.Count(); 294 295 for (int j = 0; j < link->used_by.Count(); j++) { 296 irq_routing_entry* irqEntry = link->used_by.ElementAt(j); 297 irqEntry->needs_configuration = j == 0; // only configure once 298 irqEntry->irq = chosenDescriptor.irq; 299 irqEntry->polarity = chosenDescriptor.polarity; 300 irqEntry->trigger_mode = chosenDescriptor.trigger_mode; 301 } 302 303 delete link; 304 } 305 306 return B_OK; 307 } 308 309 310 static status_t 311 configure_link_devices(acpi_module_info* acpi, IRQRoutingTable& routingTable) 312 { 313 for (int i = 0; i < routingTable.Count(); i++) { 314 irq_routing_entry& irqEntry = routingTable.ElementAt(i); 315 if (!irqEntry.needs_configuration) 316 continue; 317 318 irq_descriptor configuration; 319 configuration.irq = irqEntry.irq; 320 configuration.polarity = irqEntry.polarity; 321 configuration.trigger_mode = irqEntry.trigger_mode; 322 323 status_t status = set_current_irq(acpi, irqEntry.source, configuration); 324 if (status != B_OK) { 325 dprintf("failed to set irq on link device, keeping current\n"); 326 print_irq_descriptor(configuration); 327 328 // we failed to set the resource, fall back to current 329 read_current_irq(acpi, irqEntry.source, configuration); 330 for (int j = i; j < routingTable.Count(); j++) { 331 irq_routing_entry& other = routingTable.ElementAt(j); 332 if (other.source == irqEntry.source) { 333 other.irq = configuration.irq; 334 other.polarity = configuration.polarity; 335 other.trigger_mode = configuration.trigger_mode; 336 } 337 } 338 } 339 340 irqEntry.needs_configuration = false; 341 } 342 343 return B_OK; 344 } 345 346 347 static status_t 348 evaluate_integer(acpi_module_info* acpi, acpi_handle handle, 349 const char* method, uint64& value) 350 { 351 acpi_object_type result; 352 acpi_data resultBuffer; 353 resultBuffer.pointer = &result; 354 resultBuffer.length = sizeof(result); 355 356 status_t status = acpi->evaluate_method(handle, method, NULL, 357 &resultBuffer); 358 if (status != B_OK) 359 return status; 360 361 if (result.object_type != ACPI_TYPE_INTEGER) 362 return B_BAD_TYPE; 363 364 value = result.integer.integer; 365 return B_OK; 366 } 367 368 369 static status_t 370 handle_routing_table_entry(acpi_module_info* acpi, pci_module_info* pci, 371 const acpi_pci_routing_table* acpiTable, uint8 currentBus, 372 irq_routing_entry& irqEntry) 373 { 374 bool noSource = acpiTable->Source[0] == '\0'; 375 // The above line would be correct according to specs... 376 noSource = acpiTable->SourceIndex != 0; 377 // ... but we use this one as there seem to be quirks where 378 // a source is indicated but not actually present. With a source 379 // index != 0 a GSI is generally indicated. 380 381 status_t status; 382 acpi_handle source; 383 if (!noSource) { 384 status = acpi->get_handle(NULL, acpiTable->Source, &source); 385 if (status != B_OK) { 386 dprintf("failed to get handle to link device\n"); 387 return status; 388 } 389 } 390 391 memset(&irqEntry, 0, sizeof(irq_routing_entry)); 392 irqEntry.device_address = acpiTable->Address; 393 irqEntry.pin = acpiTable->Pin; 394 irqEntry.source = noSource ? NULL : source; 395 irqEntry.source_index = acpiTable->SourceIndex; 396 irqEntry.pci_bus = currentBus; 397 irqEntry.pci_device = (uint8)(acpiTable->Address >> 16); 398 399 status = fill_pci_info_for_entry(pci, irqEntry); 400 if (status != B_OK) { 401 // Note: This isn't necesarily fatal, as there can be many entries in 402 // the table pointing to disabled/optional devices. Also they can be 403 // used to describe the full actual wireing regardless of the presence 404 // of devices, in which case many entries won't have a match. 405 #ifdef TRACE_PRT 406 dprintf("no matching PCI device for irq entry: "); 407 print_irq_routing_entry(irqEntry); 408 #endif 409 } else { 410 #ifdef TRACE_PRT 411 dprintf("found matching PCI device for irq entry: "); 412 print_irq_routing_entry(irqEntry); 413 #endif 414 } 415 416 if (noSource) { 417 // fill in the GSI and config 418 irqEntry.needs_configuration = false; 419 irqEntry.irq = irqEntry.source_index; 420 irqEntry.polarity = B_LOW_ACTIVE_POLARITY; 421 irqEntry.trigger_mode = B_LEVEL_TRIGGERED; 422 } 423 424 return B_OK; 425 } 426 427 428 irq_routing_entry* 429 find_routing_table_entry(IRQRoutingTable& table, uint8 bus, uint8 device, 430 uint8 pin) 431 { 432 for (int i = 0; i < table.Count(); i++) { 433 irq_routing_entry& irqEntry = table.ElementAt(i); 434 if (irqEntry.pci_bus != bus || irqEntry.pci_device != device) 435 continue; 436 437 if (irqEntry.pin + 1 == pin) 438 return &irqEntry; 439 } 440 441 return NULL; 442 } 443 444 445 static status_t 446 ensure_all_functions_matched(pci_module_info* pci, uint8 bus, 447 IRQRoutingTable& matchedTable, IRQRoutingTable& unmatchedTable, 448 Vector<pci_address>& parents) 449 { 450 for (uint8 device = 0; device < kMaxPCIDeviceCount; device++) { 451 if (pci->read_pci_config(bus, device, 0, PCI_vendor_id, 2) == 0xffff) { 452 TRACE("PCI bus %" B_PRIu8 ":%" B_PRIu8 " not present.\n", 453 bus, device); 454 // not present 455 continue; 456 } 457 458 uint8 headerType = pci->read_pci_config(bus, device, 0, 459 PCI_header_type, 1); 460 461 uint8 functionCount = 1; 462 if ((headerType & PCI_multifunction) != 0) 463 functionCount = kMaxPCIFunctionCount; 464 465 for (uint8 function = 0; function < functionCount; function++) { 466 // check for device presence by looking for a valid vendor 467 if (pci->read_pci_config(bus, device, function, PCI_vendor_id, 2) 468 == 0xffff) { 469 // not present 470 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " " 471 "not present.\n", bus, device, function); 472 continue; 473 } 474 475 if (function > 0) { 476 headerType = pci->read_pci_config(bus, device, function, 477 PCI_header_type, 1); 478 } 479 480 // if this is a bridge, recurse down 481 if ((headerType & PCI_header_type_mask) 482 == PCI_header_type_PCI_to_PCI_bridge) { 483 484 pci_address pciAddress; 485 pciAddress.segment = 0; 486 pciAddress.bus = bus; 487 pciAddress.device = device; 488 pciAddress.function = function; 489 490 parents.PushBack(pciAddress); 491 492 uint8 secondaryBus = pci->read_pci_config(bus, device, function, 493 PCI_secondary_bus, 1); 494 if (secondaryBus != 0xff) { 495 ensure_all_functions_matched(pci, secondaryBus, 496 matchedTable, unmatchedTable, parents); 497 } 498 499 parents.PopBack(); 500 } 501 502 uint8 interruptPin = pci->read_pci_config(bus, device, function, 503 PCI_interrupt_pin, 1); 504 if (interruptPin == 0 || interruptPin > 4) { 505 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " " 506 "not routed.\n", bus, device, function); 507 // not routed 508 continue; 509 } 510 511 irq_routing_entry* irqEntry = find_routing_table_entry(matchedTable, 512 bus, device, interruptPin); 513 if (irqEntry != NULL) { 514 // we already have a matching entry for that device/pin, make 515 // sure the function mask includes us 516 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " " 517 "already matched. Will mask.\n", bus, device, function); 518 irqEntry->pci_function_mask |= 1 << function; 519 continue; 520 } 521 522 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " has %" B_PRIu8 " " 523 "parents, searching them...\n", bus, device, function, 524 parents.Count()); 525 526 // This function has no matching routing table entry yet. Try to 527 // figure one out in the parent, based on the device number and 528 // interrupt pin. 529 bool matched = false; 530 uint8 parentPin = ((device + interruptPin - 1) % 4) + 1; 531 for (int i = parents.Count() - 1; i >= 0; i--) { 532 pci_address& parent = parents.ElementAt(i); 533 irqEntry = find_routing_table_entry(matchedTable, parent.bus, 534 parent.device, parentPin); 535 if (irqEntry == NULL) { 536 // try the unmatched table as well 537 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " " 538 "no matchedTable entry.\n", bus, device, function); 539 irqEntry = find_routing_table_entry(unmatchedTable, 540 parent.bus, parent.device, parentPin); 541 } 542 543 if (irqEntry == NULL) { 544 // no match in that parent, go further up 545 parentPin = ((parent.device + parentPin - 1) % 4) + 1; 546 547 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " " 548 "no unmatchedTable entry, looking at parent pin %" 549 B_PRIu8 "...\n", bus, device, function, parentPin); 550 continue; 551 } 552 553 // found a match, make a copy and add it to the table 554 irq_routing_entry newEntry = *irqEntry; 555 newEntry.device_address = (device << 16) | 0xffff; 556 newEntry.pin = interruptPin - 1; 557 newEntry.pci_bus = bus; 558 newEntry.pci_device = device; 559 newEntry.pci_function_mask = 1 << function; 560 561 uint8 biosIRQ = pci->read_pci_config(bus, device, function, 562 PCI_interrupt_line, 1); 563 if (biosIRQ != 0 && biosIRQ != 255) { 564 if (newEntry.bios_irq != 0 && newEntry.bios_irq != 255 565 && newEntry.bios_irq != biosIRQ) { 566 // If the function was actually routed to that pin, 567 // the two bios irqs should match. If they don't 568 // that means we're not correct in our routing 569 // assumption. 570 panic("calculated irq routing doesn't match bios for " 571 "PCI %u:%u:%u", bus, device, function); 572 return B_ERROR; 573 } 574 575 newEntry.bios_irq = biosIRQ; 576 } 577 578 dprintf("calculated irq routing entry: "); 579 print_irq_routing_entry(newEntry); 580 581 matchedTable.PushBack(newEntry); 582 matched = true; 583 break; 584 } 585 586 if (!matched) { 587 uint32 interrupt_line = pci->read_pci_config(bus, device, 588 function, PCI_interrupt_line, 1); 589 // On x86, interrupt line 255 means "unknown" or "no connection" 590 // (PCI Local Bus spec 3.0, section 6.2.4 / page 223, footnote.) 591 if (interrupt_line == 0 || interrupt_line == 255) { 592 dprintf("assuming no interrupt use on PCI device" 593 " %u:%u:%u (bios irq 0, interrupt line %" B_PRId32 ")\n", 594 bus, device, function, interrupt_line); 595 continue; 596 } 597 598 dprintf("WARNING: unable to find irq routing for PCI " 599 "%" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 ". Device may be " 600 "unstable / broken.\n", bus, device, function); 601 return B_ERROR; 602 } 603 } 604 } 605 606 return B_OK; 607 } 608 609 610 static status_t 611 read_irq_routing_table_recursive(acpi_module_info* acpi, pci_module_info* pci, 612 acpi_handle device, uint8 currentBus, IRQRoutingTable& table, 613 IRQRoutingTable& unmatchedTable, bool rootBridge, 614 interrupt_available_check_function checkFunction) 615 { 616 if (!rootBridge) { 617 // check if this actually is a bridge 618 uint64 value; 619 pci_address pciAddress; 620 pciAddress.bus = currentBus; 621 if (evaluate_integer(acpi, device, "_ADR", value) == B_OK) { 622 pciAddress.device = (uint8)(value >> 16); 623 pciAddress.function = (uint8)value; 624 } else { 625 pciAddress.device = 0; 626 pciAddress.function = 0; 627 } 628 629 if (pciAddress.device >= kMaxPCIDeviceCount 630 || pciAddress.function >= kMaxPCIFunctionCount) { 631 // we don't seem to be on the PCI bus anymore 632 // (just a different type of device) 633 return B_OK; 634 } 635 636 // Verify that the device is really present... 637 uint16 deviceID = pci->read_pci_config(pciAddress.bus, 638 pciAddress.device, pciAddress.function, PCI_device_id, 2); 639 if (deviceID == 0xffff) { 640 // Not present or disabled. 641 TRACE("device not present\n"); 642 return B_OK; 643 } 644 645 // ... and that it really is a PCI bridge we support. 646 uint8 baseClass = pci->read_pci_config(pciAddress.bus, 647 pciAddress.device, pciAddress.function, PCI_class_base, 1); 648 uint8 subClass = pci->read_pci_config(pciAddress.bus, 649 pciAddress.device, pciAddress.function, PCI_class_sub, 1); 650 if (baseClass != PCI_bridge || subClass != PCI_pci) { 651 // Not a bridge or an unsupported one. 652 TRACE("not a PCI bridge\n"); 653 return B_OK; 654 } 655 656 uint8 headerType = pci->read_pci_config(pciAddress.bus, 657 pciAddress.device, pciAddress.function, PCI_header_type, 1); 658 659 switch (headerType & PCI_header_type_mask) { 660 case PCI_header_type_PCI_to_PCI_bridge: 661 case PCI_header_type_cardbus: 662 TRACE("found a PCI bridge (0x%02x)\n", headerType); 663 break; 664 665 default: 666 // Unsupported header type. 667 TRACE("unsupported header type (0x%02x)\n", headerType); 668 return B_OK; 669 } 670 671 // Find the secondary bus number (the "downstream" bus number for the 672 // attached devices) in the bridge configuration. 673 uint8 secondaryBus = pci->read_pci_config(pciAddress.bus, 674 pciAddress.device, pciAddress.function, PCI_secondary_bus, 1); 675 if (secondaryBus == 255) { 676 // The bus below this bridge is inactive, nothing to do. 677 TRACE("secondary bus is inactive\n"); 678 return B_OK; 679 } 680 681 // The secondary bus cannot be the same as the current one. 682 if (secondaryBus == currentBus) { 683 dprintf("invalid secondary bus %u on primary bus %u," 684 " can't configure irq routing of devices below\n", 685 secondaryBus, currentBus); 686 // TODO: Maybe we want to just return B_OK anyway so that we don't 687 // fail this step. We ensure that we matched all devices at the 688 // end of preparation, so we'd detect missing child devices anyway 689 // and it would not cause us to fail for empty misconfigured busses 690 // that we don't actually care about. 691 return B_ERROR; 692 } 693 694 // Everything below is now on the secondary bus. 695 TRACE("now scanning bus %u\n", secondaryBus); 696 currentBus = secondaryBus; 697 } 698 699 acpi_data buffer; 700 buffer.pointer = NULL; 701 buffer.length = ACPI_ALLOCATE_BUFFER; 702 status_t status = acpi->get_irq_routing_table(device, &buffer); 703 if (status == B_OK) { 704 TRACE("found irq routing table\n"); 705 706 acpi_pci_routing_table* acpiTable 707 = (acpi_pci_routing_table*)buffer.pointer; 708 while (acpiTable->Length) { 709 irq_routing_entry irqEntry; 710 status = handle_routing_table_entry(acpi, pci, acpiTable, 711 currentBus, irqEntry); 712 if (status == B_OK) { 713 if (irqEntry.source == NULL && !checkFunction(irqEntry.irq)) { 714 dprintf("hardwired irq %u not addressable\n", irqEntry.irq); 715 free(buffer.pointer); 716 return B_ERROR; 717 } 718 719 if (irqEntry.pci_function_mask != 0) 720 table.PushBack(irqEntry); 721 else 722 unmatchedTable.PushBack(irqEntry); 723 } 724 725 acpiTable = (acpi_pci_routing_table*)((uint8*)acpiTable 726 + acpiTable->Length); 727 } 728 729 free(buffer.pointer); 730 } else { 731 TRACE("no irq routing table present\n"); 732 } 733 734 // recurse down the ACPI child devices 735 acpi_data pathBuffer; 736 pathBuffer.pointer = NULL; 737 pathBuffer.length = ACPI_ALLOCATE_BUFFER; 738 status = acpi->ns_handle_to_pathname(device, &pathBuffer); 739 if (status != B_OK) { 740 dprintf("failed to resolve handle to path\n"); 741 return status; 742 } 743 744 char childName[255]; 745 void* counter = NULL; 746 while (acpi->get_next_entry(ACPI_TYPE_DEVICE, (char*)pathBuffer.pointer, 747 childName, sizeof(childName), &counter) == B_OK) { 748 749 acpi_handle childHandle; 750 status = acpi->get_handle(NULL, childName, &childHandle); 751 if (status != B_OK) { 752 dprintf("failed to get handle to child \"%s\"\n", childName); 753 break; 754 } 755 756 TRACE("recursing down to child \"%s\"\n", childName); 757 status = read_irq_routing_table_recursive(acpi, pci, childHandle, 758 currentBus, table, unmatchedTable, false, checkFunction); 759 if (status != B_OK) 760 break; 761 } 762 763 free(pathBuffer.pointer); 764 return status; 765 } 766 767 768 static status_t 769 read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable& table, 770 interrupt_available_check_function checkFunction) 771 { 772 char rootPciName[255]; 773 acpi_handle rootPciHandle; 774 rootPciName[0] = 0; 775 status_t status = acpi->get_device(kACPIPciRootName, 0, rootPciName, 255); 776 if (status != B_OK) 777 return status; 778 779 status = acpi->get_handle(NULL, rootPciName, &rootPciHandle); 780 if (status != B_OK) 781 return status; 782 783 // We reset the root bus to 0 here. Any failed evaluation means default 784 // values, so we don't have to do anything in the error case. 785 uint8 rootBus = 0; 786 787 uint64 value; 788 if (evaluate_integer(acpi, rootPciHandle, "_BBN", value) == B_OK) 789 rootBus = (uint8)value; 790 791 #if 0 792 // TODO: handle 793 if (evaluate_integer(acpi, rootPciHandle, "_SEG", value) == B_OK) 794 rootPciAddress.segment = (uint8)value; 795 #endif 796 797 pci_module_info* pci; 798 status = get_module(B_PCI_MODULE_NAME, (module_info**)&pci); 799 if (status != B_OK) { 800 // shouldn't happen, since the PCI module is a dependency of the 801 // ACPI module and we shouldn't be here at all if it wasn't loaded 802 dprintf("failed to get PCI module!\n"); 803 return status; 804 } 805 806 IRQRoutingTable unmatchedTable; 807 status = read_irq_routing_table_recursive(acpi, pci, rootPciHandle, rootBus, 808 table, unmatchedTable, true, checkFunction); 809 if (status != B_OK) { 810 put_module(B_PCI_MODULE_NAME); 811 return status; 812 } 813 814 if (table.Count() == 0) { 815 put_module(B_PCI_MODULE_NAME); 816 return B_ERROR; 817 } 818 819 // Now go through all the PCI devices and verify that they have a routing 820 // table entry. For the devices without a match, we calculate their pins 821 // on the bridges and try to match these in the parent routing table. We 822 // do this recursively going up the tree until we find a match or arrive 823 // at the top. 824 Vector<pci_address> parents; 825 status = ensure_all_functions_matched(pci, rootBus, table, unmatchedTable, 826 parents); 827 828 put_module(B_PCI_MODULE_NAME); 829 return status; 830 } 831 832 833 status_t 834 prepare_irq_routing(acpi_module_info* acpi, IRQRoutingTable& routingTable, 835 interrupt_available_check_function checkFunction) 836 { 837 status_t status = read_irq_routing_table(acpi, routingTable, checkFunction); 838 if (status != B_OK) 839 return status; 840 841 // resolve desired configuration of link devices 842 return choose_link_device_configurations(acpi, routingTable, checkFunction); 843 } 844 845 846 status_t 847 enable_irq_routing(acpi_module_info* acpi, IRQRoutingTable& routingTable) 848 { 849 // configure the link devices; also resolves GSIs for link based entries 850 status_t status = configure_link_devices(acpi, routingTable); 851 if (status != B_OK) { 852 panic("failed to configure link devices"); 853 return status; 854 } 855 856 pci_module_info* pci; 857 status = get_module(B_PCI_MODULE_NAME, (module_info**)&pci); 858 if (status != B_OK) { 859 // shouldn't happen, since the PCI module is a dependency of the 860 // ACPI module and we shouldn't be here at all if it wasn't loaded 861 dprintf("failed to get PCI module!\n"); 862 return status; 863 } 864 865 // update the PCI info now that all GSIs are known 866 for (int i = 0; i < routingTable.Count(); i++) { 867 irq_routing_entry& irqEntry = routingTable.ElementAt(i); 868 869 status = update_pci_info_for_entry(pci, irqEntry); 870 if (status != B_OK) { 871 dprintf("failed to update interrupt_line for PCI %u:%u mask %" 872 B_PRIx32 "\n", irqEntry.pci_bus, irqEntry.pci_device, 873 irqEntry.pci_function_mask); 874 } 875 } 876 877 put_module(B_PCI_MODULE_NAME); 878 return B_OK; 879 } 880 881 882 static status_t 883 read_irq_descriptor(acpi_module_info* acpi, acpi_handle device, 884 bool readCurrent, irq_descriptor* _descriptor, 885 irq_descriptor_list* descriptorList) 886 { 887 acpi_data buffer; 888 buffer.pointer = NULL; 889 buffer.length = ACPI_ALLOCATE_BUFFER; 890 891 status_t status; 892 if (readCurrent) 893 status = acpi->get_current_resources(device, &buffer); 894 else 895 status = acpi->get_possible_resources(device, &buffer); 896 897 if (status != B_OK) { 898 dprintf("failed to read %s resources for irq\n", 899 readCurrent ? "current" : "possible"); 900 free(buffer.pointer); 901 return status; 902 } 903 904 irq_descriptor descriptor; 905 descriptor.irq = 255; 906 907 acpi_resource* resource = (acpi_resource*)buffer.pointer; 908 while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) { 909 switch (resource->Type) { 910 case ACPI_RESOURCE_TYPE_IRQ: 911 { 912 acpi_resource_irq& irq = resource->Data.Irq; 913 if (irq.InterruptCount < 1) { 914 dprintf("acpi irq resource with no interrupts\n"); 915 break; 916 } 917 918 descriptor.shareable = irq.Shareable != 0; 919 descriptor.trigger_mode = irq.Triggering == 0 920 ? B_LEVEL_TRIGGERED : B_EDGE_TRIGGERED; 921 descriptor.polarity = irq.Polarity == 0 922 ? B_HIGH_ACTIVE_POLARITY : B_LOW_ACTIVE_POLARITY; 923 924 if (readCurrent) 925 descriptor.irq = irq.Interrupts[0]; 926 else { 927 for (uint16 i = 0; i < irq.InterruptCount; i++) { 928 descriptor.irq = irq.Interrupts[i]; 929 descriptorList->PushBack(descriptor); 930 } 931 } 932 933 #ifdef TRACE_PRT 934 dprintf("acpi irq resource (%s):\n", 935 readCurrent ? "current" : "possible"); 936 dprintf("\ttriggering: %s\n", 937 irq.Triggering == 0 ? "level" : "edge"); 938 dprintf("\tpolarity: %s active\n", 939 irq.Polarity == 0 ? "high" : "low"); 940 dprintf("\tshareable: %s\n", irq.Shareable != 0 ? "yes" : "no"); 941 dprintf("\tcount: %u\n", irq.InterruptCount); 942 if (irq.InterruptCount > 0) { 943 dprintf("\tinterrupts:"); 944 for (uint16 i = 0; i < irq.InterruptCount; i++) 945 dprintf(" %u", irq.Interrupts[i]); 946 dprintf("\n"); 947 } 948 #endif 949 break; 950 } 951 952 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 953 { 954 acpi_resource_extended_irq& irq = resource->Data.ExtendedIrq; 955 if (irq.InterruptCount < 1) { 956 dprintf("acpi extended irq resource with no interrupts\n"); 957 break; 958 } 959 960 descriptor.shareable = irq.Shareable != 0; 961 descriptor.trigger_mode = irq.Triggering == 0 962 ? B_LEVEL_TRIGGERED : B_EDGE_TRIGGERED; 963 descriptor.polarity = irq.Polarity == 0 964 ? B_HIGH_ACTIVE_POLARITY : B_LOW_ACTIVE_POLARITY; 965 966 if (readCurrent) 967 descriptor.irq = irq.Interrupts[0]; 968 else { 969 for (uint16 i = 0; i < irq.InterruptCount; i++) { 970 descriptor.irq = irq.Interrupts[i]; 971 descriptorList->PushBack(descriptor); 972 } 973 } 974 975 #ifdef TRACE_PRT 976 dprintf("acpi extended irq resource (%s):\n", 977 readCurrent ? "current" : "possible"); 978 dprintf("\tproducer: %s\n", 979 irq.ProducerConsumer ? "yes" : "no"); 980 dprintf("\ttriggering: %s\n", 981 irq.Triggering == 0 ? "level" : "edge"); 982 dprintf("\tpolarity: %s active\n", 983 irq.Polarity == 0 ? "high" : "low"); 984 dprintf("\tshareable: %s\n", irq.Shareable != 0 ? "yes" : "no"); 985 dprintf("\tcount: %u\n", irq.InterruptCount); 986 if (irq.InterruptCount > 0) { 987 dprintf("\tinterrupts:"); 988 for (uint16 i = 0; i < irq.InterruptCount; i++) 989 dprintf(" %u", irq.Interrupts[i]); 990 dprintf("\n"); 991 } 992 #endif 993 break; 994 } 995 } 996 997 if (descriptor.irq != 255) 998 break; 999 1000 resource = (acpi_resource*)((uint8*)resource + resource->Length); 1001 } 1002 1003 free(buffer.pointer); 1004 1005 if (descriptor.irq == 255) 1006 return B_ERROR; 1007 1008 if (readCurrent) 1009 *_descriptor = descriptor; 1010 1011 return B_OK; 1012 } 1013 1014 1015 status_t 1016 read_current_irq(acpi_module_info* acpi, acpi_handle device, 1017 irq_descriptor& descriptor) 1018 { 1019 return read_irq_descriptor(acpi, device, true, &descriptor, NULL); 1020 } 1021 1022 1023 status_t 1024 read_possible_irqs(acpi_module_info* acpi, acpi_handle device, 1025 irq_descriptor_list& descriptorList) 1026 { 1027 return read_irq_descriptor(acpi, device, false, NULL, &descriptorList); 1028 } 1029 1030 1031 status_t 1032 set_current_irq(acpi_module_info* acpi, acpi_handle device, 1033 const irq_descriptor& descriptor) 1034 { 1035 acpi_data buffer; 1036 buffer.pointer = NULL; 1037 buffer.length = ACPI_ALLOCATE_BUFFER; 1038 1039 status_t status = acpi->get_current_resources(device, &buffer); 1040 if (status != B_OK) { 1041 dprintf("failed to read current resources for irq\n"); 1042 return status; 1043 } 1044 1045 bool irqWritten = false; 1046 acpi_resource* resource = (acpi_resource*)buffer.pointer; 1047 while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) { 1048 switch (resource->Type) { 1049 case ACPI_RESOURCE_TYPE_IRQ: 1050 { 1051 acpi_resource_irq& irq = resource->Data.Irq; 1052 if (irq.InterruptCount < 1) { 1053 dprintf("acpi irq resource with no interrupts\n"); 1054 break; 1055 } 1056 1057 irq.Triggering 1058 = descriptor.trigger_mode == B_LEVEL_TRIGGERED ? 0 : 1; 1059 irq.Polarity 1060 = descriptor.polarity == B_HIGH_ACTIVE_POLARITY ? 0 : 1; 1061 irq.Shareable = descriptor.shareable ? 0 : 1; 1062 irq.InterruptCount = 1; 1063 irq.Interrupts[0] = descriptor.irq; 1064 1065 irqWritten = true; 1066 break; 1067 } 1068 1069 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 1070 { 1071 acpi_resource_extended_irq& irq = resource->Data.ExtendedIrq; 1072 if (irq.InterruptCount < 1) { 1073 dprintf("acpi extended irq resource with no interrupts\n"); 1074 break; 1075 } 1076 1077 irq.Triggering 1078 = descriptor.trigger_mode == B_LEVEL_TRIGGERED ? 0 : 1; 1079 irq.Polarity 1080 = descriptor.polarity == B_HIGH_ACTIVE_POLARITY ? 0 : 1; 1081 irq.Shareable = descriptor.shareable ? 0 : 1; 1082 irq.InterruptCount = 1; 1083 irq.Interrupts[0] = descriptor.irq; 1084 1085 irqWritten = true; 1086 break; 1087 } 1088 } 1089 1090 if (irqWritten) 1091 break; 1092 1093 resource = (acpi_resource*)((uint8*)resource + resource->Length); 1094 } 1095 1096 if (irqWritten) { 1097 status = acpi->set_current_resources(device, &buffer); 1098 if (status != B_OK) 1099 dprintf("failed to set irq resources\n"); 1100 } else { 1101 dprintf("failed to write requested irq into resources\n"); 1102 status = B_ERROR; 1103 } 1104 1105 free(buffer.pointer); 1106 return status; 1107 } 1108