diff -ur /build/orig/linux-2.4.21-20.1.2024.2.1.nptl/arch/i386/kernel/io_apic.c linux-2.4.21-20.1.2024.2.1.nptl/arch/i386/kernel/io_apic.c --- /build/orig/linux-2.4.21-20.1.2024.2.1.nptl/arch/i386/kernel/io_apic.c 2003-07-11 02:55:37.000000000 -0700 +++ linux-2.4.21-20.1.2024.2.1.nptl/arch/i386/kernel/io_apic.c 2003-08-21 11:01:17.000000000 -0700 @@ -1897,7 +1897,7 @@ } -int io_apic_set_pci_routing (int ioapic, int pin, int irq) +int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low) { struct IO_APIC_route_entry entry; unsigned long flags; @@ -1919,19 +1919,23 @@ entry.delivery_mode = dest_LowestPrio; entry.dest_mode = INT_DELIVERY_MODE; entry.dest.logical.logical_dest = target_cpus(); + entry.trigger = edge_level; + entry.polarity = active_high_low; entry.mask = 1; /* Disabled (masked) */ - entry.trigger = 1; /* Level sensitive */ - entry.polarity = 1; /* Low active */ add_pin_to_irq(irq, ioapic, pin); entry.vector = assign_irq_vector(irq); printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " - "IRQ %d)\n", ioapic, - mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq); + "IRQ %d Mode:%i Active:%i)\n", ioapic, + mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); + if (edge_level) { irq_desc[irq].handler = &ioapic_level_irq_type; + } else { + irq_desc[irq].handler = &ioapic_edge_irq_type; + } set_intr_gate(entry.vector, interrupt[irq]); diff -ur /build/orig/linux-2.4.21-20.1.2024.2.1.nptl/arch/i386/kernel/mpparse.c linux-2.4.21-20.1.2024.2.1.nptl/arch/i386/kernel/mpparse.c --- /build/orig/linux-2.4.21-20.1.2024.2.1.nptl/arch/i386/kernel/mpparse.c 2003-07-11 02:55:20.000000000 -0700 +++ linux-2.4.21-20.1.2024.2.1.nptl/arch/i386/kernel/mpparse.c 2003-08-21 11:06:36.000000000 -0700 @@ -1256,7 +1256,7 @@ ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start; - io_apic_set_pci_routing(ioapic, ioapic_pin, irq); + io_apic_set_pci_routing(ioapic, ioapic_pin, irq, 1, 1); /* Active low, level triggered */ } #ifdef CONFIG_ACPI_PCI @@ -1269,6 +1269,9 @@ int ioapic_pin = 0; int irq = 0; int idx, bit = 0; + int edge_level = 0; + int active_high_low = 0; + /* * Parsing through the PCI Interrupt Routing Table (PRT) and program @@ -1279,12 +1282,17 @@ /* Need to get irq for dynamic entry */ if (entry->link.handle) { - irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index); + irq = acpi_pci_link_get_irq(entry->link.handle, + entry->link.index, &edge_level, &active_high_low); if (!irq) continue; } - else - irq = entry->link.index; + else { + /* Hardwired IRQ. Assume PCI standard settings */ + irq = entry->link.index; + edge_level = 1; + active_high_low = 1; + } /* Don't set up the ACPI SCI because it's already set up */ if (acpi_fadt.sci_int == irq) @@ -1317,7 +1325,8 @@ mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<irq = irq; printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n", diff -ur /build/orig/linux-2.4.21-20.1.2024.2.1.nptl/drivers/acpi/pci_irq.c linux-2.4.21-20.1.2024.2.1.nptl/drivers/acpi/pci_irq.c --- /build/orig/linux-2.4.21-20.1.2024.2.1.nptl/drivers/acpi/pci_irq.c 2003-07-11 02:55:06.000000000 -0700 +++ linux-2.4.21-20.1.2024.2.1.nptl/drivers/acpi/pci_irq.c 2003-08-21 11:12:02.000000000 -0700 @@ -24,6 +24,8 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include + #include #include #include @@ -36,6 +38,9 @@ #ifdef CONFIG_X86_IO_APIC #include #endif +#ifdef CONFIG_IOSAPIC +# include +#endif #include #include @@ -253,7 +258,7 @@ } if (!entry->irq && entry->link.handle) { - entry->irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index); + entry->irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, NULL, NULL); if (!entry->irq) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n")); return_VALUE(0); @@ -373,6 +378,10 @@ eisa_set_level_irq(dev->irq); } #endif +#ifdef CONFIG_IOSAPIC + if (acpi_irq_model == ACPI_IRQ_MODEL_IOSAPIC) + iosapic_enable_intr(dev->irq); +#endif return_VALUE(dev->irq); } @@ -392,7 +401,9 @@ } /* Make sure all link devices have a valid IRQ. */ - acpi_pci_link_check(); + if (acpi_pci_link_check()) { + return_VALUE(-ENODEV); + } #ifdef CONFIG_X86_IO_APIC /* Program IOAPICs using data from PRT entries. */ diff -ur /build/orig/linux-2.4.21-20.1.2024.2.1.nptl/drivers/acpi/pci_link.c linux-2.4.21-20.1.2024.2.1.nptl/drivers/acpi/pci_link.c --- /build/orig/linux-2.4.21-20.1.2024.2.1.nptl/drivers/acpi/pci_link.c 2003-07-11 02:55:06.000000000 -0700 +++ linux-2.4.21-20.1.2024.2.1.nptl/drivers/acpi/pci_link.c 2003-08-21 11:17:13.000000000 -0700 @@ -65,6 +65,9 @@ struct acpi_pci_link_irq { u8 active; /* Current IRQ */ + u8 edge_level; /* All IRQs */ + u8 active_high_low; /* All IRQs */ + u8 setonboot; u8 possible_count; u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; }; @@ -114,6 +117,8 @@ link->irq.possible[i] = p->interrupts[i]; link->irq.possible_count++; } + link->irq.edge_level = p->edge_level; + link->irq.active_high_low = p->active_high_low; break; } case ACPI_RSTYPE_EXT_IRQ: @@ -132,6 +137,8 @@ link->irq.possible[i] = p->interrupts[i]; link->irq.possible_count++; } + link->irq.edge_level = p->edge_level; + link->irq.active_high_low = p->active_high_low; break; } default: @@ -260,7 +267,6 @@ * IRQ a boot-enabled Link device is set to is the correct one. * (Required to support systems such as the Toshiba 5005-S504.) */ - link->irq.active = irq; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active)); @@ -290,29 +296,33 @@ if (!link || !irq) return_VALUE(-EINVAL); - /* See if we're already at the target IRQ. */ - if (irq == link->irq.active) - return_VALUE(0); - - /* Make sure the target IRQ in the list of possible IRQs. */ - for (i=0; iirq.possible_count; i++) { - if (irq == link->irq.possible[i]) - valid = 1; - } - if (!valid) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Target IRQ %d invalid\n", irq)); - return_VALUE(-EINVAL); + /* We don't check irqs the first time around */ + if (link->irq.setonboot) { + /* See if we're already at the target IRQ. */ + if (irq == link->irq.active) + return_VALUE(0); + + /* Make sure the target IRQ in the list of possible IRQs. */ + for (i=0; iirq.possible_count; i++) { + if (irq == link->irq.possible[i]) + valid = 1; + } + if (!valid) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Target IRQ %d invalid\n", irq)); + return_VALUE(-EINVAL); + } } memset(&resource, 0, sizeof(resource)); - /* NOTE: PCI interrupts are always level / active_low / shared. */ + /* NOTE: PCI interrupts are always level / active_low / shared. But not all + interrupts > 15 are PCI interrupts. Rely on the ACPI IRQ definition for + parameters */ if (irq <= 15) { resource.res.id = ACPI_RSTYPE_IRQ; resource.res.length = sizeof(struct acpi_resource); - resource.res.data.irq.edge_level = ACPI_LEVEL_SENSITIVE; - resource.res.data.irq.active_high_low = ACPI_ACTIVE_LOW; - resource.res.data.irq.shared_exclusive = ACPI_SHARED; + resource.res.data.irq.edge_level = link->irq.edge_level; + resource.res.data.irq.active_high_low = link->irq.active_high_low; resource.res.data.irq.number_of_interrupts = 1; resource.res.data.irq.interrupts[0] = irq; } @@ -320,15 +330,15 @@ resource.res.id = ACPI_RSTYPE_EXT_IRQ; resource.res.length = sizeof(struct acpi_resource); resource.res.data.extended_irq.producer_consumer = ACPI_CONSUMER; - resource.res.data.extended_irq.edge_level = ACPI_LEVEL_SENSITIVE; - resource.res.data.extended_irq.active_high_low = ACPI_ACTIVE_LOW; - resource.res.data.extended_irq.shared_exclusive = ACPI_SHARED; + resource.res.data.extended_irq.edge_level = link->irq.edge_level; + resource.res.data.extended_irq.active_high_low = link->irq.active_high_low; resource.res.data.extended_irq.number_of_interrupts = 1; resource.res.data.extended_irq.interrupts[0] = irq; /* ignore resource_source, it's optional */ } resource.end.id = ACPI_RSTYPE_END_TAG; + /* Attempt to set the resource */ status = acpi_set_current_resources(link->handle, &buffer); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n")); @@ -351,11 +361,13 @@ if (result) { return_VALUE(result); } + if (link->irq.active != irq) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Attempt to enable at IRQ %d resulted in IRQ %d\n", irq, link->irq.active)); link->irq.active = 0; + acpi_ut_evaluate_object (link->handle, "_DIS", 0, NULL); return_VALUE(-ENODEV); } @@ -403,7 +415,7 @@ ACPI_FUNCTION_TRACE("acpi_pci_link_check"); /* - * Pass #1: Update penalties to facilitate IRQ balancing. + * Update penalties to facilitate IRQ balancing. */ list_for_each(node, &acpi_link.entries) { @@ -424,23 +436,23 @@ } } - /* - * Pass #2: Enable boot-disabled Links at 'best' IRQ. - */ - list_for_each(node, &acpi_link.entries) { - int irq = 0; - int i = 0; + return_VALUE(0); +} - link = list_entry(node, struct acpi_pci_link, node); - if (!link || !link->irq.possible_count) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); - continue; - } +static int acpi_pci_link_allocate(struct acpi_pci_link* link) { + int irq; + int i; - if (link->irq.active) - continue; + ACPI_FUNCTION_TRACE("acpi_pci_link_allocate"); + + if (link->irq.setonboot) + return_VALUE(0); + if (link->irq.active) { + irq = link->irq.active; + } else { irq = link->irq.possible[0]; + } /* * Select the best IRQ. This is done in reverse to promote @@ -451,16 +463,20 @@ irq = link->irq.possible[i]; } - /* Enable the link device at this IRQ. */ - acpi_pci_link_set(link, irq); - + /* Attempt to enable the link device at this IRQ. */ + if (acpi_pci_link_set(link, irq)) { + printk(PREFIX "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS). Aborting ACPI-based IRQ routing. Try pci=noacpi or acpi=off\n", + acpi_device_name(link->device), + acpi_device_bid(link->device)); + return_VALUE(-ENODEV); + } else { acpi_irq_penalty[link->irq.active] += 100; - printk(PREFIX "%s [%s] enabled at IRQ %d\n", acpi_device_name(link->device), acpi_device_bid(link->device), link->irq.active); } + link->irq.setonboot = 1; return_VALUE(0); } @@ -468,7 +484,9 @@ int acpi_pci_link_get_irq ( acpi_handle handle, - int index) + int index, + int* edge_level, + int* active_high_low) { int result = 0; struct acpi_device *device = NULL; @@ -494,11 +512,17 @@ return_VALUE(0); } + if (acpi_pci_link_allocate(link)) { + return -ENODEV; + } + if (!link->irq.active) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link disabled\n")); return_VALUE(0); } + if (edge_level) *edge_level = link->irq.edge_level; + if (active_high_low) *active_high_low = link->irq.active_high_low; return_VALUE(link->irq.active); } @@ -588,8 +612,7 @@ } -int __init -acpi_pci_link_init (void) +int __init acpi_pci_link_init (void) { ACPI_FUNCTION_TRACE("acpi_pci_link_init"); diff -ur /build/orig/linux-2.4.21-20.1.2024.2.1.nptl/include/acpi/acpi_drivers.h linux-2.4.21-20.1.2024.2.1.nptl/include/acpi/acpi_drivers.h --- /build/orig/linux-2.4.21-20.1.2024.2.1.nptl/include/acpi/acpi_drivers.h 2003-07-11 02:55:15.000000000 -0700 +++ linux-2.4.21-20.1.2024.2.1.nptl/include/acpi/acpi_drivers.h 2003-08-21 11:08:23.000000000 -0700 @@ -174,9 +174,7 @@ #define ACPI_PCI_LINK_FILE_STATUS "state" int acpi_pci_link_check (void); -int acpi_pci_link_get_irq (acpi_handle handle, int index); -int acpi_pci_link_init (void); -void acpi_pci_link_exit (void); +int acpi_pci_link_get_irq (acpi_handle handle, int index, int* edge_level, int* active_high_low); /* ACPI PCI Interrupt Routing (pci_irq.c) */