[haiku-commits] r41400 - haiku/trunk/src/system/kernel/arch/x86

  • From: mmlr@xxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 9 May 2011 17:38:19 +0200 (CEST)

Author: mmlr
Date: 2011-05-09 17:38:18 +0200 (Mon, 09 May 2011)
New Revision: 41400
Changeset: https://dev.haiku-os.org/changeset/41400

Modified:
   haiku/trunk/src/system/kernel/arch/x86/arch_int.cpp
   haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.cpp
   haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.h
Log:
* Seperated out reading and enabling IRQ routing. Reading will only read the
  configuration that doesn't require any link device changes and will only
  prepare for updating the pci_info. Enabling then does the link device setup
  and updates the pci_info with the new IRQ values.
* Configuring link devices now takes into account that multiple devices may
  share a single link device, meaning that the sharing PCI devices can't be
  configured independently.

We still only blindly configure the first possible IRQ on the link devices, but
now we actually have all the information to change that. Working on that next.


Modified: haiku/trunk/src/system/kernel/arch/x86/arch_int.cpp
===================================================================
--- haiku/trunk/src/system/kernel/arch/x86/arch_int.cpp 2011-05-09 13:26:41 UTC 
(rev 41399)
+++ haiku/trunk/src/system/kernel/arch/x86/arch_int.cpp 2011-05-09 15:38:18 UTC 
(rev 41400)
@@ -664,6 +664,14 @@
                return;
        }
 
+       status = enable_irq_routing(acpiModule, table);
+       if (status != B_OK) {
+               panic("failed to enable IRQ routing");
+               // if it failed early on it might still work in PIC mode
+               acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC);
+               return;
+       }
+
        sLevelTriggeredInterrupts = 0;
        sIOAPICMaxRedirectionEntry
                = ((version >> IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT)

Modified: haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.cpp
===================================================================
--- haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.cpp        
2011-05-09 13:26:41 UTC (rev 41399)
+++ haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.cpp        
2011-05-09 15:38:18 UTC (rev 41400)
@@ -162,23 +162,92 @@
 
 
 static status_t
-configure_link_device(acpi_module_info* acpi, acpi_handle handle,
-       irq_descriptor& result)
+configure_link_devices(acpi_module_info* acpi, IRQRoutingTable& routingTable)
 {
-       status_t status = read_possible_irq(acpi, handle, &result);
-       if (status != B_OK) {
-               dprintf("failed to read possible IRQ configuration of link 
device\n");
+       /*
+               Before configuring the link devices we have to take a few 
things into
+               consideration:
+               * Multiple PCI devices / functions may link to the same PCI link
+                 device, so we must ensure that we don't try to configure 
different
+                 IRQs for each device, overwriting the previous config of the
+                 respective link device.
+               * If we can't use non-ISA IRQs then we must ensure that we don't
+                 configure any IRQs that overlaps with ISA devices (as they use
+                 different triggering modes and polarity they aren't 
compatible).
+                 Since the ISA bus isn't enumerable we don't have any clues as 
to
+                 where an ISA device might be connected. The only safe 
assumption
+                 therefore is to only use IRQs that are known to be usable for 
PCI
+                 devices. In our case we can use all the previously assigned 
PCI
+                 interrupt_line IRQs as stored in the bios_irq field.
+       */
 
-               // We could try returning the current config as a fallback, but 
it most
-               // probably is invalid as it points to the legacy config the 
BIOS has
-               // done in PIC mode.
-               return status;
+       // find all unique link devices and resolve their possible IRQs
+       Vector<link_device*> links;
+       for (int i = 0; i < routingTable.Count(); i++) {
+               irq_routing_entry& irqEntry = routingTable.ElementAt(i);
+               if (irqEntry.source == NULL)
+                       continue;
+
+               link_device* link = NULL;
+               for (int j = 0; j < links.Count(); j++) {
+                       link_device* existing = links.ElementAt(j);
+                       if (existing->handle == irqEntry.source) {
+                               link = existing;
+                               break;
+                       }
+               }
+
+               if (link != NULL) {
+                       link->used_by.PushBack(&irqEntry);
+                       continue;
+               }
+
+               // A new link device, read possible IRQs and fill them in.
+               link = new(std::nothrow) link_device;
+               if (link == NULL) {
+                       panic("ran out of memory while configuring irq link 
devices");
+                       return B_NO_MEMORY;
+               }
+
+               link->handle = irqEntry.source;
+               status_t status = read_possible_irqs(acpi, link->handle,
+                       link->possible_irqs);
+               if (status != B_OK) {
+                       panic("failed to read possible irqs of link device");
+                       return status;
+               }
+
+               link->used_by.PushBack(&irqEntry);
+               links.PushBack(link);
        }
 
        // TODO: Blindly set the first possible configuration (obviously not 
what we
        // want to do as it will most probably result in a "everything to single
        // IRQ" config; anyway just to get things going...)
-       return set_current_irq(acpi, handle, &result);
+       for (int i = 0; i < links.Count(); i++) {
+               link_device* link = links.ElementAt(i);
+
+               link->chosen_irq_index = 0;
+               irq_descriptor& irqDescriptor
+                       = link->possible_irqs.ElementAt(link->chosen_irq_index);
+
+               status_t status = set_current_irq(acpi, link->handle, 
&irqDescriptor);
+               if (status != B_OK) {
+                       panic("failed to set irq on link device");
+                       return status;
+               }
+
+               for (int j = 0; j < link->used_by.Count(); j++) {
+                       irq_routing_entry* irqEntry = 
link->used_by.ElementAt(j);
+                       irqEntry->irq = irqDescriptor.irq;
+                       irqEntry->polarity = irqDescriptor.polarity;
+                       irqEntry->trigger_mode = irqDescriptor.trigger_mode;
+               }
+
+               delete link;
+       }
+
+       return B_OK;
 }
 
 
@@ -247,34 +316,14 @@
                return status;
        }
 
-       // resolve any link device so we get a straight GSI in all cases
        if (noSource) {
-               // fixed GSI already
+               // fill in the GSI and config; link based entries will be 
resolved at
+               // link configuration time
                irqEntry.irq = irqEntry.source_index;
                irqEntry.polarity = B_LOW_ACTIVE_POLARITY;
                irqEntry.trigger_mode = B_LEVEL_TRIGGERED;
-       } else {
-               irq_descriptor irqDescriptor;
-               status = configure_link_device(acpi, source, irqDescriptor);
-               if (status != B_OK) {
-                       dprintf("failed to configure link device\n");
-                       return status;
-               }
-
-               irqEntry.irq = irqDescriptor.irq;
-               irqEntry.polarity = irqDescriptor.polarity;
-               irqEntry.trigger_mode = irqDescriptor.trigger_mode;
        }
 
-       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
-               return status;
-       }
-
        return B_OK;
 }
 
@@ -413,9 +462,47 @@
 }
 
 
+status_t
+enable_irq_routing(acpi_module_info* acpi, IRQRoutingTable& routingTable)
+{
+       // configure the link devices; also resolves GSIs for link based entries
+       status_t status = configure_link_devices(acpi, routingTable);
+       if (status != B_OK) {
+               panic("failed to configure link devices");
+               return status;
+       }
+
+       pci_module_info* pci;
+       status = get_module(B_PCI_MODULE_NAME, (module_info**)&pci);
+       if (status != B_OK) {
+               // shouldn't happen, since the PCI module is a dependency of the
+               // ACPI module and we shouldn't be here at all if it wasn't 
loaded
+               dprintf("failed to get PCI module!\n");
+               return status;
+       }
+
+       // update the PCI info now that all GSIs are known
+       for (int i = 0; i < routingTable.Count(); i++) {
+               irq_routing_entry& irqEntry = routingTable.ElementAt(i);
+
+               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
+               }
+       }
+
+       put_module(B_PCI_MODULE_NAME);
+       return B_OK;
+}
+
+
 static status_t
 read_irq_descriptor(acpi_module_info* acpi, acpi_handle device,
-       bool readCurrent, irq_descriptor* descriptor)
+       bool readCurrent, irq_descriptor* _descriptor,
+       irq_descriptor_list* descriptorList)
 {
        acpi_data buffer;
        buffer.pointer = NULL;
@@ -434,7 +521,9 @@
                return status;
        }
 
-       descriptor->irq = 0;
+       irq_descriptor descriptor;
+       descriptor.irq = 255;
+
        acpi_resource* resource = (acpi_resource*)buffer.pointer;
        while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) {
                switch (resource->Type) {
@@ -446,13 +535,21 @@
                                        break;
                                }
 
-                               descriptor->irq = irq.Interrupts[0];
-                               descriptor->shareable = irq.Sharable != 0;
-                               descriptor->trigger_mode = irq.Triggering == 0
+                               descriptor.shareable = irq.Sharable != 0;
+                               descriptor.trigger_mode = irq.Triggering == 0
                                        ? B_LEVEL_TRIGGERED : B_EDGE_TRIGGERED;
-                               descriptor->polarity = irq.Polarity == 0
+                               descriptor.polarity = irq.Polarity == 0
                                        ? B_HIGH_ACTIVE_POLARITY : 
B_LOW_ACTIVE_POLARITY;
 
+                               if (readCurrent)
+                                       descriptor.irq = irq.Interrupts[0];
+                               else {
+                                       for (uint16 i = 0; i < 
irq.InterruptCount; i++) {
+                                               descriptor.irq = 
irq.Interrupts[i];
+                                               
descriptorList->PushBack(descriptor);
+                                       }
+                               }
+
 #ifdef TRACE_PRT
                                dprintf("acpi irq resource (%s):\n",
                                        readCurrent ? "current" : "possible");
@@ -480,13 +577,21 @@
                                        break;
                                }
 
-                               descriptor->irq = irq.Interrupts[0];
-                               descriptor->shareable = irq.Sharable != 0;
-                               descriptor->trigger_mode = irq.Triggering == 0
+                               descriptor.shareable = irq.Sharable != 0;
+                               descriptor.trigger_mode = irq.Triggering == 0
                                        ? B_LEVEL_TRIGGERED : B_EDGE_TRIGGERED;
-                               descriptor->polarity = irq.Polarity == 0
+                               descriptor.polarity = irq.Polarity == 0
                                        ? B_HIGH_ACTIVE_POLARITY : 
B_LOW_ACTIVE_POLARITY;
 
+                               if (readCurrent)
+                                       descriptor.irq = irq.Interrupts[0];
+                               else {
+                                       for (uint16 i = 0; i < 
irq.InterruptCount; i++) {
+                                               descriptor.irq = 
irq.Interrupts[i];
+                                               
descriptorList->PushBack(descriptor);
+                                       }
+                               }
+
 #ifdef TRACE_PRT
                                dprintf("acpi extended irq resource (%s):\n",
                                        readCurrent ? "current" : "possible");
@@ -509,14 +614,21 @@
                        }
                }
 
-               if (descriptor->irq != 0)
+               if (descriptor.irq != 255)
                        break;
 
                resource = (acpi_resource*)((uint8*)resource + 
resource->Length);
        }
 
        free(buffer.pointer);
-       return descriptor->irq != 0 ? B_OK : B_ERROR;
+
+       if (descriptor.irq == 255)
+               return B_ERROR;
+
+       if (readCurrent)
+               *_descriptor = descriptor;
+
+       return B_OK;
 }
 
 
@@ -524,15 +636,15 @@
 read_current_irq(acpi_module_info* acpi, acpi_handle device,
        irq_descriptor* descriptor)
 {
-       return read_irq_descriptor(acpi, device, true, descriptor);
+       return read_irq_descriptor(acpi, device, true, descriptor, NULL);
 }
 
 
 status_t
-read_possible_irq(acpi_module_info* acpi, acpi_handle device,
-       irq_descriptor* descriptor)
+read_possible_irqs(acpi_module_info* acpi, acpi_handle device,
+       irq_descriptor_list& descriptorList)
 {
-       return read_irq_descriptor(acpi, device, false, descriptor);
+       return read_irq_descriptor(acpi, device, false, NULL, &descriptorList);
 }
 
 

Modified: haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.h
===================================================================
--- haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.h  2011-05-09 
13:26:41 UTC (rev 41399)
+++ haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.h  2011-05-09 
15:38:18 UTC (rev 41400)
@@ -48,6 +48,9 @@
 };
 
 
+typedef Vector<irq_descriptor> irq_descriptor_list;
+
+
 struct pci_address {
        uint8   segment;
        uint8   bus;
@@ -56,16 +59,26 @@
 };
 
 
+struct link_device {
+       acpi_handle                                     handle;
+       uint32                                          chosen_irq_index;
+       Vector<irq_descriptor>          possible_irqs;
+       Vector<irq_routing_entry*>      used_by;
+};
+
+
 void print_irq_descriptor(irq_descriptor* descriptor);
 void print_irq_routing_table(IRQRoutingTable* table);
 
 
 status_t read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable* 
table);
+status_t enable_irq_routing(acpi_module_info* acpi,
+                       IRQRoutingTable& routingTable);
 
 status_t read_current_irq(acpi_module_info* acpi, acpi_handle device,
                        irq_descriptor* descriptor);
-status_t read_possible_irq(acpi_module_info* acpi, acpi_handle device,
-                       irq_descriptor* descriptor);
+status_t read_possible_irqs(acpi_module_info* acpi, acpi_handle device,
+                       irq_descriptor_list& descriptorList);
 
 status_t set_current_irq(acpi_module_info* acpi, acpi_handle device,
                        const irq_descriptor* descriptor);


Other related posts: