[haiku-commits] r41759 - haiku/branches/releases/r1alpha3/src/system/kernel/arch/x86

  • From: mmlr@xxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 26 May 2011 14:59:19 +0200 (CEST)

Author: mmlr
Date: 2011-05-26 14:59:18 +0200 (Thu, 26 May 2011)
New Revision: 41759
Changeset: https://dev.haiku-os.org/changeset/41759

Modified:
   
haiku/branches/releases/r1alpha3/src/system/kernel/arch/x86/irq_routing_table.cpp
Log:
* Merge r41726 from trunk as it fixes some missing interrupt routing when using
  the IO-APIC.
* Merge r41758 from trunk as well, but with disabled panics in the fallback
  cases. It is needed to complete the routing when the IO-APIC is enabled.
  This also prevents the IO-APIC from being used if the routing can't be fully
  established. With the disabled panics it will simply print the reason and fall
  back to PIC mode.


Modified: 
haiku/branches/releases/r1alpha3/src/system/kernel/arch/x86/irq_routing_table.cpp
===================================================================
--- 
haiku/branches/releases/r1alpha3/src/system/kernel/arch/x86/irq_routing_table.cpp
   2011-05-26 12:35:02 UTC (rev 41758)
+++ 
haiku/branches/releases/r1alpha3/src/system/kernel/arch/x86/irq_routing_table.cpp
   2011-05-26 12:59:18 UTC (rev 41759)
@@ -32,6 +32,8 @@
 
 // TODO: as per PCI 3.0, the PCI module hardcodes it in various places as well.
 static const uint8 kMaxPCIFunctionCount = 8;
+static const uint8 kMaxPCIDeviceCount = 32;
+       // TODO: actually this is mechanism dependent
 static const uint8 kMaxISAInterrupts = 16;
 
 irq_descriptor::irq_descriptor()
@@ -111,17 +113,9 @@
        // check the base device at function 0
        uint8 headerType = pci->read_pci_config(entry.pci_bus, 
entry.pci_device, 0,
                PCI_header_type, 1);
-       switch (headerType & PCI_header_type_mask) {
-               case PCI_header_type_generic:
-               case PCI_header_type_PCI_to_PCI_bridge:
-                       // We don't really care about bridges as we won't 
install
-                       // interrupt handlers for them, but we can still map 
them and
-                       // update their info for completeness.
-                       break;
-
-               default:
-                       // either an unsupported or a non-present device (0xff)
-                       return B_ENTRY_NOT_FOUND;
+       if (headerType == 0xff) {
+               // the device is not present
+               return B_ENTRY_NOT_FOUND;
        }
 
        // we have a device, check how many functions we need to iterate
@@ -358,7 +352,7 @@
 
 static status_t
 handle_routing_table_entry(acpi_module_info* acpi, pci_module_info* pci,
-       const acpi_pci_routing_table* acpiTable, const pci_address& pciAddress,
+       const acpi_pci_routing_table* acpiTable, uint8 currentBus,
        irq_routing_entry& irqEntry)
 {
        bool noSource = acpiTable->Source[0] == '\0';
@@ -383,7 +377,7 @@
        irqEntry.pin = acpiTable->Pin;
        irqEntry.source = noSource ? NULL : source;
        irqEntry.source_index = acpiTable->SourceIndex;
-       irqEntry.pci_bus = pciAddress.bus;
+       irqEntry.pci_bus = currentBus;
        irqEntry.pci_device = (uint8)(acpiTable->Address >> 16);
 
        status = fill_pci_info_for_entry(pci, irqEntry);
@@ -393,10 +387,14 @@
                // used to describe the full actual wireing regardless of the 
presence
                // of devices, in which case many entries won't have a match.
 #ifdef TRACE_PRT
-               dprintf("didn't find a matching PCI device for irq entry:\n");
+               dprintf("no matching PCI device for irq entry: ");
                print_irq_routing_entry(irqEntry);
 #endif
-               return status;
+       } else {
+#ifdef TRACE_PRT
+               dprintf("found matching PCI device for irq entry: ");
+               print_irq_routing_entry(irqEntry);
+#endif
        }
 
        if (noSource) {
@@ -411,77 +409,250 @@
 }
 
 
+irq_routing_entry*
+find_routing_table_entry(IRQRoutingTable& table, uint8 bus, uint8 device,
+       uint8 pin)
+{
+       for (int i = 0; i < table.Count(); i++) {
+               irq_routing_entry& irqEntry = table.ElementAt(i);
+               if (irqEntry.pci_bus != bus || irqEntry.pci_device != device)
+                       continue;
+
+               if (irqEntry.pin + 1 == pin)
+                       return &irqEntry;
+       }
+
+       return NULL;
+}
+
+
 static status_t
+ensure_all_functions_matched(pci_module_info* pci, uint8 bus,
+       IRQRoutingTable& matchedTable, IRQRoutingTable& unmatchedTable,
+       Vector<pci_address>& parents)
+{
+       for (uint8 device = 0; device < kMaxPCIDeviceCount; device++) {
+               if (pci->read_pci_config(bus, device, 0, PCI_vendor_id, 2) == 
0xffff) {
+                       // not present
+                       continue;
+               }
+
+               uint8 headerType = pci->read_pci_config(bus, device, 0,
+                       PCI_header_type, 1);
+
+               uint8 functionCount = 1;
+               if ((headerType & PCI_multifunction) != 0)
+                       functionCount = kMaxPCIFunctionCount;
+
+               for (uint8 function = 0; function < functionCount; function++) {
+                       // check for device presence by looking for a valid 
vendor
+                       if (pci->read_pci_config(bus, device, function, 
PCI_vendor_id, 2)
+                               == 0xffff) {
+                               // not present
+                               continue;
+                       }
+
+                       if (function > 0) {
+                               headerType = pci->read_pci_config(bus, device, 
function,
+                                       PCI_header_type, 1);
+                       }
+
+                       // if this is a bridge, recurse down
+                       if ((headerType & PCI_header_type_mask)
+                               == PCI_header_type_PCI_to_PCI_bridge) {
+
+                               pci_address pciAddress;
+                               pciAddress.bus = bus;
+                               pciAddress.device = device;
+                               pciAddress.function = function;
+
+                               parents.PushBack(pciAddress);
+
+                               uint8 secondaryBus = pci->read_pci_config(bus, 
device, function,
+                                       PCI_secondary_bus, 1);
+                               if (secondaryBus != 0xff) {
+                                       ensure_all_functions_matched(pci, 
secondaryBus,
+                                               matchedTable, unmatchedTable, 
parents);
+                               }
+
+                               parents.PopBack();
+                       }
+
+                       uint8 interruptPin = pci->read_pci_config(bus, device, 
function,
+                               PCI_interrupt_pin, 1);
+                       if (interruptPin == 0 || interruptPin > 4) {
+                               // not routed
+                               continue;
+                       }
+
+                       irq_routing_entry* irqEntry = 
find_routing_table_entry(matchedTable,
+                               bus, device, interruptPin);
+                       if (irqEntry != NULL) {
+                               // we already have a matching entry for that 
device/pin, make
+                               // sure the function mask includes us
+                               irqEntry->pci_function_mask |= 1 << function;
+                               continue;
+                       }
+
+                       // This function has no matching routing table entry 
yet. Try to
+                       // figure one out in the parent, based on the device 
number and
+                       // interrupt pin.
+                       bool matched = false;
+                       uint8 parentPin = ((device + interruptPin - 1) % 4) + 1;
+                       for (int i = parents.Count() - 1; i >= 0; i--) {
+                               pci_address& parent = parents.ElementAt(i);
+                               irqEntry = 
find_routing_table_entry(matchedTable, parent.bus,
+                                       parent.device, parentPin);
+                               if (irqEntry == NULL) {
+                                       // try the unmatched table as well
+                                       irqEntry = 
find_routing_table_entry(unmatchedTable,
+                                               parent.bus, parent.device, 
parentPin);
+                               }
+
+                               if (irqEntry == NULL) {
+                                       // no match in that parent, go further 
up
+                                       parentPin = ((parent.device + parentPin 
- 1) % 4) + 1;
+                                       continue;
+                               }
+
+                               // found a match, make a copy and add it to the 
table
+                               irq_routing_entry newEntry = *irqEntry;
+                               newEntry.device_address = (device << 16) | 
0xffff;
+                               newEntry.pin = interruptPin - 1;
+                               newEntry.pci_bus = bus;
+                               newEntry.pci_device = device;
+                               newEntry.pci_function_mask = 1 << function;
+
+                               uint8 biosIRQ = pci->read_pci_config(bus, 
device, function,
+                                       PCI_interrupt_line, 1);
+                               if (biosIRQ != 0 && biosIRQ != 255) {
+                                       if (newEntry.bios_irq != 0 && 
newEntry.bios_irq != 255
+                                               && newEntry.bios_irq != 
biosIRQ) {
+                                               // If the function was actually 
routed to that pin,
+                                               // the two bios irqs should 
match. If they don't
+                                               // that means we're not correct 
in our routing
+                                               // assumption.
+                                               dprintf("calculated irq routing 
doesn't match bios for "
+                                                       "PCI %u:%u:%u\n", bus, 
device, function);
+                                               return B_ERROR;
+                                       }
+
+                                       newEntry.bios_irq = biosIRQ;
+                               }
+
+                               dprintf("calculated irq routing entry: ");
+                               print_irq_routing_entry(newEntry);
+
+                               matchedTable.PushBack(newEntry);
+                               matched = true;
+                               break;
+                       }
+
+                       if (!matched) {
+                               dprintf("unable to find irq routing for PCI 
%u:%u:%u\n", bus,
+                                       device, function);
+                               return B_ERROR;
+                       }
+               }
+       }
+
+       return B_OK;
+}
+
+
+static status_t
 read_irq_routing_table_recursive(acpi_module_info* acpi, pci_module_info* pci,
-       acpi_handle device, const pci_address& parentAddress,
-       IRQRoutingTable& table, bool rootBridge,
+       acpi_handle device, uint8 currentBus, IRQRoutingTable& table,
+       IRQRoutingTable& unmatchedTable, bool rootBridge,
        interrupt_available_check_function checkFunction)
 {
-       acpi_data buffer;
-       buffer.pointer = NULL;
-       buffer.length = ACPI_ALLOCATE_BUFFER;
-       status_t status = acpi->get_irq_routing_table(device, &buffer);
-       if (status != B_OK) {
-               // simply not a bridge
-               return B_OK;
-       }
+       if (!rootBridge) {
+               // check if this actually is a bridge
+               uint64 value;
+               pci_address pciAddress;
+               pciAddress.bus = currentBus;
+               if (evaluate_integer(acpi, device, "_ADR", value) == B_OK) {
+                       pciAddress.device = (uint8)(value >> 16);
+                       pciAddress.function = (uint8)value;
+               } else {
+                       pciAddress.device = 0;
+                       pciAddress.function = 0;
+               }
 
-       TRACE("found irq routing table\n");
+               uint8 headerType = pci->read_pci_config(pciAddress.bus,
+                       pciAddress.device, pciAddress.function, 
PCI_header_type, 1);
 
-       uint64 value;
-       pci_address pciAddress = parentAddress;
-       if (evaluate_integer(acpi, device, "_ADR", value) == B_OK) {
-               pciAddress.device = (uint8)(value >> 16);
-               pciAddress.function = (uint8)value;
-       } else {
-               pciAddress.device = 0;
-               pciAddress.function = 0;
-       }
+               switch (headerType & PCI_header_type_mask) {
+                       case PCI_header_type_PCI_to_PCI_bridge:
+                       case PCI_header_type_cardbus:
+                               TRACE("found a PCI bridge (0x%02x)\n", 
headerType);
+                               break;
 
-       if (!rootBridge) {
+                       default:
+                               // Simply not a bridge or not present at all.
+                               TRACE("not a PCI bridge (0x%02x)\n", 
headerType);
+                               return B_OK;
+               }
+
                // Find the secondary bus number (the "downstream" bus number 
for the
                // attached devices) in the bridge configuration.
                uint8 secondaryBus = pci->read_pci_config(pciAddress.bus,
                        pciAddress.device, pciAddress.function, 
PCI_secondary_bus, 1);
                if (secondaryBus == 255) {
                        // The bus below this bridge is inactive, nothing to do.
+                       TRACE("secondary bus is inactive\n");
                        return B_OK;
                }
 
                // The secondary bus cannot be the same as the current one.
-               if (secondaryBus == parentAddress.bus) {
+               if (secondaryBus == currentBus) {
                        dprintf("invalid secondary bus %u on primary bus %u,"
                                " can't configure irq routing of devices 
below\n",
-                               secondaryBus, parentAddress.bus);
+                               secondaryBus, currentBus);
                        return B_ERROR;
                }
 
                // Everything below is now on the secondary bus.
-               pciAddress.bus = secondaryBus;
+               TRACE("now scanning bus %u\n", secondaryBus);
+               currentBus = secondaryBus;
        }
 
-       acpi_pci_routing_table* acpiTable = 
(acpi_pci_routing_table*)buffer.pointer;
-       while (acpiTable->Length) {
-               irq_routing_entry irqEntry;
-               status = handle_routing_table_entry(acpi, pci, acpiTable, 
pciAddress,
-                       irqEntry);
-               if (status == B_OK) {
-                       if (irqEntry.source == NULL && 
!checkFunction(irqEntry.irq)) {
-                               dprintf("hardwired irq %u not addressable\n", 
irqEntry.irq);
-                               free(buffer.pointer);
-                               return B_ERROR;
+       acpi_data buffer;
+       buffer.pointer = NULL;
+       buffer.length = ACPI_ALLOCATE_BUFFER;
+       status_t status = acpi->get_irq_routing_table(device, &buffer);
+       if (status == B_OK) {
+               TRACE("found irq routing table\n");
+
+               acpi_pci_routing_table* acpiTable
+                       = (acpi_pci_routing_table*)buffer.pointer;
+               while (acpiTable->Length) {
+                       irq_routing_entry irqEntry;
+                       status = handle_routing_table_entry(acpi, pci, 
acpiTable,
+                               currentBus, irqEntry);
+                       if (status == B_OK) {
+                               if (irqEntry.source == NULL && 
!checkFunction(irqEntry.irq)) {
+                                       dprintf("hardwired irq %u not 
addressable\n", irqEntry.irq);
+                                       free(buffer.pointer);
+                                       return B_ERROR;
+                               }
+
+                               if (irqEntry.pci_function_mask != 0)
+                                       table.PushBack(irqEntry);
+                               else
+                                       unmatchedTable.PushBack(irqEntry);
                        }
 
-                       table.PushBack(irqEntry);
+                       acpiTable = (acpi_pci_routing_table*)((uint8*)acpiTable
+                               + acpiTable->Length);
                }
 
-               acpiTable = (acpi_pci_routing_table*)((uint8*)acpiTable
-                       + acpiTable->Length);
+               free(buffer.pointer);
+       } else {
+               TRACE("no irq routing table present\n");
        }
 
-       free(buffer.pointer);
-
-       // recurse down to the child devices
+       // recurse down the ACPI child devices
        acpi_data pathBuffer;
        pathBuffer.pointer = NULL;
        pathBuffer.length = ACPI_ALLOCATE_BUFFER;
@@ -505,7 +676,7 @@
 
                TRACE("recursing down to child \"%s\"\n", childName);
                status = read_irq_routing_table_recursive(acpi, pci, 
childHandle,
-                       pciAddress, table, false, checkFunction);
+                       currentBus, table, unmatchedTable, false, 
checkFunction);
                if (status != B_OK)
                        break;
        }
@@ -530,16 +701,19 @@
        if (status != B_OK)
                return status;
 
-       // We reset the structure to 0 here. Any failed evaluation means default
+       // We reset the root bus to 0 here. Any failed evaluation means default
        // values, so we don't have to do anything in the error case.
-       pci_address rootPciAddress;
-       memset(&rootPciAddress, 0, sizeof(pci_address));
+       uint8 rootBus = 0;
 
        uint64 value;
+       if (evaluate_integer(acpi, rootPciHandle, "_BBN", value) == B_OK)
+               rootBus = (uint8)value;
+
+#if 0
+       // TODO: handle
        if (evaluate_integer(acpi, rootPciHandle, "_SEG", value) == B_OK)
                rootPciAddress.segment = (uint8)value;
-       if (evaluate_integer(acpi, rootPciHandle, "_BBN", value) == B_OK)
-               rootPciAddress.bus = (uint8)value;
+#endif
 
        pci_module_info* pci;
        status = get_module(B_PCI_MODULE_NAME, (module_info**)&pci);
@@ -550,15 +724,30 @@
                return status;
        }
 
-       status = read_irq_routing_table_recursive(acpi, pci, rootPciHandle,
-               rootPciAddress, table, true, checkFunction);
+       IRQRoutingTable unmatchedTable;
+       status = read_irq_routing_table_recursive(acpi, pci, rootPciHandle, 
rootBus,
+               table, unmatchedTable, true, checkFunction);
+       if (status != B_OK) {
+               put_module(B_PCI_MODULE_NAME);
+               return status;
+       }
 
-       put_module(B_PCI_MODULE_NAME);
+       if (table.Count() == 0) {
+               put_module(B_PCI_MODULE_NAME);
+               return B_ERROR;
+       }
 
-       if (status != B_OK)
-               return status;
+       // Now go through all the PCI devices and verify that they have a 
routing
+       // table entry. For the devices without a match, we calculate their pins
+       // on the bridges and try to match these in the parent routing table. We
+       // do this recursively going up the tree until we find a match or arrive
+       // at the top.
+       Vector<pci_address> parents;
+       status = ensure_all_functions_matched(pci, rootBus, table, 
unmatchedTable,
+               parents);
 
-       return table.Count() > 0 ? B_OK : B_ERROR;
+       put_module(B_PCI_MODULE_NAME);
+       return status;
 }
 
 
@@ -600,10 +789,9 @@
 
                status = update_pci_info_for_entry(pci, irqEntry);
                if (status != B_OK) {
-#ifdef TRACE_PRT
-                       dprintf("failed to update interrupt_line info for 
entry:\n");
-                       print_irq_routing_entry(irqEntry);
-#endif
+                       dprintf("failed to update interrupt_line for PCI %u:%u 
mask %lx\n",
+                               irqEntry.pci_bus, irqEntry.pci_device,
+                               irqEntry.pci_function_mask);
                }
        }
 


Other related posts:

  • » [haiku-commits] r41759 - haiku/branches/releases/r1alpha3/src/system/kernel/arch/x86 - mmlr