Ticket #7520: pci_route_fallback.diff

File pci_route_fallback.diff, 7.9 KB (added by mmlr, 13 years ago)

Infer PCI irq routing from parent pins.

  • src/system/kernel/arch/x86/irq_routing_table.cpp

     
    1616#include <PCI.h>
    1717
    1818
    19 //#define TRACE_PRT
     19#define TRACE_PRT
    2020#ifdef TRACE_PRT
    2121#   define TRACE(x...) dprintf("IRQRoutingTable: "x)
    2222#else
     
    3232
    3333// TODO: as per PCI 3.0, the PCI module hardcodes it in various places as well.
    3434static const uint8 kMaxPCIFunctionCount = 8;
     35static const uint8 kMaxPCIDeviceCount = 32;
     36    // TODO: actually this is mechanism dependent
    3537static const uint8 kMaxISAInterrupts = 16;
    3638
    3739irq_descriptor::irq_descriptor()
     
    388390        dprintf("no matching PCI device for irq entry: ");
    389391        print_irq_routing_entry(irqEntry);
    390392#endif
    391         return status;
    392393    } else {
    393394#ifdef TRACE_PRT
    394395        dprintf("found matching PCI device for irq entry: ");
     
    408409}
    409410
    410411
     412irq_routing_entry*
     413find_routing_table_entry(IRQRoutingTable& table, uint8 bus, uint8 device,
     414    uint8 pin)
     415{
     416    for (int i = 0; i < table.Count(); i++) {
     417        irq_routing_entry& irqEntry = table.ElementAt(i);
     418        if (irqEntry.pci_bus != bus || irqEntry.pci_device != device)
     419            continue;
     420
     421        if (irqEntry.pin + 1 == pin)
     422            return &irqEntry;
     423    }
     424
     425    return NULL;
     426}
     427
     428
    411429static status_t
     430ensure_all_functions_matched(pci_module_info* pci, uint8 bus,
     431    IRQRoutingTable& matchedTable, IRQRoutingTable& unmatchedTable,
     432    Vector<pci_address>& parents)
     433{
     434    for (uint8 device = 0; device < kMaxPCIDeviceCount; device++) {
     435        if (pci->read_pci_config(bus, device, 0, PCI_vendor_id, 2) == 0xffff) {
     436            // not present
     437            continue;
     438        }
     439
     440        uint8 headerType = pci->read_pci_config(bus, device, 0,
     441            PCI_header_type, 1);
     442
     443        uint8 functionCount = 1;
     444        if ((headerType & PCI_multifunction) != 0)
     445            functionCount = kMaxPCIFunctionCount;
     446
     447        for (uint8 function = 0; function < functionCount; function++) {
     448            // check for device presence by looking for a valid vendor
     449            if (pci->read_pci_config(bus, device, function, PCI_vendor_id, 2)
     450                == 0xffff) {
     451                // not present
     452                continue;
     453            }
     454
     455            if (function > 0) {
     456                headerType = pci->read_pci_config(bus, device, function,
     457                    PCI_header_type, 1);
     458            }
     459
     460            // if this is a bridge, recurse down
     461            if ((headerType & PCI_header_type_mask)
     462                == PCI_header_type_PCI_to_PCI_bridge) {
     463
     464                pci_address pciAddress;
     465                pciAddress.bus = bus;
     466                pciAddress.device = device;
     467                pciAddress.function = function;
     468
     469                parents.PushBack(pciAddress);
     470
     471                uint8 secondaryBus = pci->read_pci_config(bus, device, function,
     472                    PCI_secondary_bus, 1);
     473                if (secondaryBus != 0xff) {
     474                    ensure_all_functions_matched(pci, secondaryBus,
     475                        matchedTable, unmatchedTable, parents);
     476                }
     477
     478                parents.PopBack();
     479            }
     480
     481            uint8 interruptPin = pci->read_pci_config(bus, device, function,
     482                PCI_interrupt_pin, 1);
     483            if (interruptPin == 0 || interruptPin > 4) {
     484                // not routed
     485                continue;
     486            }
     487
     488            irq_routing_entry* irqEntry = find_routing_table_entry(matchedTable,
     489                bus, device, interruptPin);
     490            if (irqEntry != NULL) {
     491                // we already have a matching entry for that device/pin, make
     492                // sure the function mask includes us
     493                irqEntry->pci_function_mask |= 1 << function;
     494                continue;
     495            }
     496
     497            // This function has no matching routing table entry yet. Try to
     498            // figure one out in the parent, based on the device number and
     499            // interrupt pin.
     500            bool matched = false;
     501            uint8 parentPin = ((device + interruptPin - 1) % 4) + 1;
     502            for (int i = parents.Count() - 1; i >= 0; i--) {
     503                pci_address& parent = parents.ElementAt(i);
     504                irqEntry = find_routing_table_entry(matchedTable, parent.bus,
     505                    parent.device, parentPin);
     506                if (irqEntry == NULL) {
     507                    // try the unmatched table as well
     508                    irqEntry = find_routing_table_entry(unmatchedTable,
     509                        parent.bus, parent.device, parentPin);
     510                }
     511
     512                if (irqEntry == NULL) {
     513                    // no match in that parent, go further up
     514                    parentPin = ((parent.device + parentPin - 1) % 4) + 1;
     515                    continue;
     516                }
     517
     518                // found a match, make a copy and add it to the table
     519                irq_routing_entry newEntry = *irqEntry;
     520                newEntry.device_address = (device << 16) | 0xffff;
     521                newEntry.pin = interruptPin - 1;
     522                newEntry.pci_bus = bus;
     523                newEntry.pci_device = device;
     524                newEntry.pci_function_mask = 1 << function;
     525
     526                if (newEntry.bios_irq != 0 && newEntry.bios_irq != 255) {
     527                    uint8 biosIRQ = pci->read_pci_config(bus, device, function,
     528                        PCI_interrupt_line, 1);
     529                    if (biosIRQ != 0 && biosIRQ != 255
     530                        && newEntry.bios_irq != biosIRQ) {
     531                        // If the function was actually routed to that pin,
     532                        // the two bios irqs should match. If they don't
     533                        // that means we're not correct in our routing
     534                        // assumption.
     535                        panic("calculated irq routing doesn't match bios for "
     536                            "PCI %u:%u:%u", bus, device, function);
     537                        newEntry.bios_irq = biosIRQ;
     538                        return B_ERROR;
     539                    }
     540                }
     541
     542                dprintf("calculated irq routing entry: ");
     543                print_irq_routing_entry(newEntry);
     544
     545                matchedTable.PushBack(newEntry);
     546                matched = true;
     547                break;
     548            }
     549
     550            if (!matched) {
     551                panic("unable to find irq routing for PCI %u:%u:%u", bus,
     552                    device, function);
     553                return B_ERROR;
     554            }
     555        }
     556    }
     557
     558    return B_OK;
     559}
     560
     561
     562static status_t
    412563read_irq_routing_table_recursive(acpi_module_info* acpi, pci_module_info* pci,
    413564    acpi_handle device, uint8 currentBus, IRQRoutingTable& table,
    414     bool rootBridge, interrupt_available_check_function checkFunction)
     565    IRQRoutingTable& unmatchedTable, bool rootBridge,
     566    interrupt_available_check_function checkFunction)
    415567{
    416568    if (!rootBridge) {
    417569        // check if this actually is a bridge
     
    484636                    return B_ERROR;
    485637                }
    486638
    487                 table.PushBack(irqEntry);
     639                if (irqEntry.pci_function_mask != 0)
     640                    table.PushBack(irqEntry);
     641                else
     642                    unmatchedTable.PushBack(irqEntry);
    488643            }
    489644
    490645            acpiTable = (acpi_pci_routing_table*)((uint8*)acpiTable
     
    496651        TRACE("no irq routing table present\n");
    497652    }
    498653
    499     // recurse down to the child devices
     654    // recurse down the ACPI child devices
    500655    acpi_data pathBuffer;
    501656    pathBuffer.pointer = NULL;
    502657    pathBuffer.length = ACPI_ALLOCATE_BUFFER;
     
    520675
    521676        TRACE("recursing down to child \"%s\"\n", childName);
    522677        status = read_irq_routing_table_recursive(acpi, pci, childHandle,
    523             currentBus, table, false, checkFunction);
     678            currentBus, table, unmatchedTable, false, checkFunction);
    524679        if (status != B_OK)
    525680            break;
    526681    }
     
    568723        return status;
    569724    }
    570725
     726    IRQRoutingTable unmatchedTable;
    571727    status = read_irq_routing_table_recursive(acpi, pci, rootPciHandle, rootBus,
    572         table, true, checkFunction);
     728        table, unmatchedTable, true, checkFunction);
     729    if (status != B_OK) {
     730        put_module(B_PCI_MODULE_NAME);
     731        return status;
     732    }
    573733
    574     put_module(B_PCI_MODULE_NAME);
     734    if (table.Count() == 0) {
     735        put_module(B_PCI_MODULE_NAME);
     736        return B_ERROR;
     737    }
    575738
    576     if (status != B_OK)
    577         return status;
     739    // Now go through all the PCI devices and verify that they have a routing
     740    // table entry. For the devices without a match, we calculate their pins
     741    // on the bridges and try to match these in the parent routing table. We
     742    // do this recursively going up the tree until we find a match or arrive
     743    // at the top.
     744    Vector<pci_address> parents;
     745    status = ensure_all_functions_matched(pci, rootBus, table, unmatchedTable,
     746        parents);
    578747
    579     return table.Count() > 0 ? B_OK : B_ERROR;
     748    put_module(B_PCI_MODULE_NAME);
     749    return status;
    580750}
    581751
    582752
     
    618788
    619789        status = update_pci_info_for_entry(pci, irqEntry);
    620790        if (status != B_OK) {
    621 #ifdef TRACE_PRT
    622             dprintf("failed to update interrupt_line info for entry:\n");
    623             print_irq_routing_entry(irqEntry);
    624 #endif
     791            panic("failed to update interrupt_line for PCI %u:%u mask %lx",
     792                irqEntry.pci_bus, irqEntry.pci_device,
     793                irqEntry.pci_function_mask);
    625794        }
    626795    }
    627796