From 80c4e0ced06167a20dc11bfeb80f4cb671a86805 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Mon, 9 May 2011 16:46:18 +0000 Subject: [PATCH] * Balance the IRQs amongst the possible ones. A simple usage counter, filled by hardwired GSIs and updated on configuring the link devices, is used for that. This doesn't guarantee optimal results as some link devices may not be configurable to some IRQs and we might fill up their slots this way. Most of the time this should be good enough though. * Take the BIOS assigned IRQ white list into account when assigning IRQs in the ISA range and avoid assigning to non white listed IRQs. Quite probably it'd be ok to use all of the IRQs present in the possible IRQ list, but let's play it safe... * Also white listed are the IRQs that were set on the link device before reconfiguration. * Some cleanup, use references instead of pointers where applicable. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41401 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/arch/x86/arch_int.cpp | 17 ++-- .../kernel/arch/x86/irq_routing_table.cpp | 88 ++++++++++++++----- .../kernel/arch/x86/irq_routing_table.h | 8 +- 3 files changed, 79 insertions(+), 34 deletions(-) diff --git a/src/system/kernel/arch/x86/arch_int.cpp b/src/system/kernel/arch/x86/arch_int.cpp index 11032535e5..29126d6f9c 100644 --- a/src/system/kernel/arch/x86/arch_int.cpp +++ b/src/system/kernel/arch/x86/arch_int.cpp @@ -664,14 +664,6 @@ ioapic_init(kernel_args* args) 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) @@ -679,6 +671,15 @@ ioapic_init(kernel_args* args) TRACE(("ioapic has %lu entries\n", sIOAPICMaxRedirectionEntry + 1)); + status = enable_irq_routing(acpiModule, table, + sIOAPICMaxRedirectionEntry + 1); + 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; + } + // use the boot CPU as the target for all interrupts uint64 targetAPIC = args->arch_args.cpu_apic_id[0]; diff --git a/src/system/kernel/arch/x86/irq_routing_table.cpp b/src/system/kernel/arch/x86/irq_routing_table.cpp index a9073282a0..575fa8122a 100644 --- a/src/system/kernel/arch/x86/irq_routing_table.cpp +++ b/src/system/kernel/arch/x86/irq_routing_table.cpp @@ -32,6 +32,7 @@ const char* kACPIPciExpressRootName = "PNP0A08"; // TODO: as per PCI 3.0, the PCI module hardcodes it in various places as well. static const uint8 kMaxPCIFunctionCount = 8; +static const uint8 kMaxISAInterrupts = 16; irq_descriptor::irq_descriptor() : @@ -162,7 +163,8 @@ fill_pci_info_for_entry(pci_module_info* pci, irq_routing_entry& entry) static status_t -configure_link_devices(acpi_module_info* acpi, IRQRoutingTable& routingTable) +configure_link_devices(acpi_module_info* acpi, IRQRoutingTable& routingTable, + uint32 maxIRQCount) { /* Before configuring the link devices we have to take a few things into @@ -181,12 +183,27 @@ configure_link_devices(acpi_module_info* acpi, IRQRoutingTable& routingTable) interrupt_line IRQs as stored in the bios_irq field. */ + uint16 validForPCI = 0; // only applies to the ISA IRQs + uint16 irqUsage[maxIRQCount]; + memset(irqUsage, 0, sizeof(irqUsage)); + // find all unique link devices and resolve their possible IRQs Vector links; for (int i = 0; i < routingTable.Count(); i++) { irq_routing_entry& irqEntry = routingTable.ElementAt(i); - if (irqEntry.source == NULL) + + if (irqEntry.bios_irq != 0 && irqEntry.bios_irq != 255) { + if (irqEntry.bios_irq < kMaxISAInterrupts) + validForPCI |= (1 << irqEntry.bios_irq); + } + + if (irqEntry.source == NULL) { + // populate all hardwired GSI entries into our map + irqUsage[irqEntry.irq]++; + if (irqEntry.irq < kMaxISAInterrupts) + validForPCI |= (1 << irqEntry.irq); continue; + } link_device* link = NULL; for (int j = 0; j < links.Count(); j++) { @@ -217,6 +234,15 @@ configure_link_devices(acpi_module_info* acpi, IRQRoutingTable& routingTable) return status; } + status = read_current_irq(acpi, link->handle, link->current_irq); + if (status != B_OK) { + panic("failed to read current irq of link device"); + return status; + } + + if (link->current_irq.irq < kMaxISAInterrupts) + validForPCI |= (1 << link->current_irq.irq); + link->used_by.PushBack(&irqEntry); links.PushBack(link); } @@ -227,11 +253,28 @@ configure_link_devices(acpi_module_info* acpi, IRQRoutingTable& routingTable) 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); + int bestIRQIndex = 0; + uint16 bestIRQUsage = UINT16_MAX; + for (int j = 0; j < link->possible_irqs.Count(); j++) { + irq_descriptor& possibleIRQ = link->possible_irqs.ElementAt(j); + if (possibleIRQ.irq < kMaxISAInterrupts + && (validForPCI & (1 << possibleIRQ.irq)) == 0) { + // better avoid that if possible + continue; + } - status_t status = set_current_irq(acpi, link->handle, &irqDescriptor); + if (irqUsage[possibleIRQ.irq] < bestIRQUsage) { + bestIRQIndex = j; + bestIRQUsage = irqUsage[possibleIRQ.irq]; + } + } + + // pick that one and update the counts + irq_descriptor& chosenDescriptor + = link->possible_irqs.ElementAt(bestIRQIndex); + irqUsage[chosenDescriptor.irq]++; + + status_t status = set_current_irq(acpi, link->handle, chosenDescriptor); if (status != B_OK) { panic("failed to set irq on link device"); return status; @@ -239,9 +282,9 @@ configure_link_devices(acpi_module_info* acpi, IRQRoutingTable& routingTable) 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; + irqEntry->irq = chosenDescriptor.irq; + irqEntry->polarity = chosenDescriptor.polarity; + irqEntry->trigger_mode = chosenDescriptor.trigger_mode; } delete link; @@ -463,10 +506,11 @@ read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable* table) status_t -enable_irq_routing(acpi_module_info* acpi, IRQRoutingTable& routingTable) +enable_irq_routing(acpi_module_info* acpi, IRQRoutingTable& routingTable, + uint32 maxIRQCount) { // configure the link devices; also resolves GSIs for link based entries - status_t status = configure_link_devices(acpi, routingTable); + status_t status = configure_link_devices(acpi, routingTable, maxIRQCount); if (status != B_OK) { panic("failed to configure link devices"); return status; @@ -634,9 +678,9 @@ read_irq_descriptor(acpi_module_info* acpi, acpi_handle device, status_t read_current_irq(acpi_module_info* acpi, acpi_handle device, - irq_descriptor* descriptor) + irq_descriptor& descriptor) { - return read_irq_descriptor(acpi, device, true, descriptor, NULL); + return read_irq_descriptor(acpi, device, true, &descriptor, NULL); } @@ -650,7 +694,7 @@ read_possible_irqs(acpi_module_info* acpi, acpi_handle device, status_t set_current_irq(acpi_module_info* acpi, acpi_handle device, - const irq_descriptor* descriptor) + const irq_descriptor& descriptor) { acpi_data buffer; buffer.pointer = NULL; @@ -675,12 +719,12 @@ set_current_irq(acpi_module_info* acpi, acpi_handle device, } irq.Triggering - = descriptor->trigger_mode == B_LEVEL_TRIGGERED ? 0 : 1; + = descriptor.trigger_mode == B_LEVEL_TRIGGERED ? 0 : 1; irq.Polarity - = descriptor->polarity == B_HIGH_ACTIVE_POLARITY ? 0 : 1; - irq.Sharable = descriptor->shareable ? 0 : 1; + = descriptor.polarity == B_HIGH_ACTIVE_POLARITY ? 0 : 1; + irq.Sharable = descriptor.shareable ? 0 : 1; irq.InterruptCount = 1; - irq.Interrupts[0] = descriptor->irq; + irq.Interrupts[0] = descriptor.irq; irqWritten = true; break; @@ -695,12 +739,12 @@ set_current_irq(acpi_module_info* acpi, acpi_handle device, } irq.Triggering - = descriptor->trigger_mode == B_LEVEL_TRIGGERED ? 0 : 1; + = descriptor.trigger_mode == B_LEVEL_TRIGGERED ? 0 : 1; irq.Polarity - = descriptor->polarity == B_HIGH_ACTIVE_POLARITY ? 0 : 1; - irq.Sharable = descriptor->shareable ? 0 : 1; + = descriptor.polarity == B_HIGH_ACTIVE_POLARITY ? 0 : 1; + irq.Sharable = descriptor.shareable ? 0 : 1; irq.InterruptCount = 1; - irq.Interrupts[0] = descriptor->irq; + irq.Interrupts[0] = descriptor.irq; irqWritten = true; break; diff --git a/src/system/kernel/arch/x86/irq_routing_table.h b/src/system/kernel/arch/x86/irq_routing_table.h index 91c9959b80..71b8b6e64b 100644 --- a/src/system/kernel/arch/x86/irq_routing_table.h +++ b/src/system/kernel/arch/x86/irq_routing_table.h @@ -61,7 +61,7 @@ struct pci_address { struct link_device { acpi_handle handle; - uint32 chosen_irq_index; + irq_descriptor current_irq; Vector possible_irqs; Vector used_by; }; @@ -73,14 +73,14 @@ 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); + IRQRoutingTable& routingTable, uint32 maxIRQCount); status_t read_current_irq(acpi_module_info* acpi, acpi_handle device, - irq_descriptor* descriptor); + 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); + const irq_descriptor& descriptor); #endif // IRQ_ROUTING_TABLE_H