lkml.org 
[lkml]   [2003]   [Jul]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH] ACPI patch which fixes all my IRQ problems on nforce2 -- linux-2.6.0-test2-acpi-irqparams-final5.patch
    Date
    On Monday 28 July 2003 16:30, Alexander Rau wrote:
    > Andrew de Quincey wrote:
    > > This is version final4 of the patch now. Improvement over version final3
    > > is a fix to IRQ allocation.. previously all PCI IRQs were allocated to
    > > IRQ11 on my Thinkpad.
    > >
    > > This _may_ break ACPI IRQ routing on the Toshiba 5005-S504 (I hope I
    > > have managed to support it though). Can someone check please? Quote from
    > > pci_link.c:
    > > * Note that we don't validate that the current IRQ (_CRS) exists
    > > * within the possible IRQs (_PRS): we blindly assume that
    > > whatever * IRQ a boot-enabled Link device is set to is the correct one. *
    > > (Required to support systems such as the Toshiba 5005-S504.)
    >
    > I tried to apply the patch to 2.6.0-test2 in hope that this resolves my
    > oops during boottime on my thinkpad t40p.
    >
    > Unfortunatly the compilation of the kernel fails with:

    Ah, hi, found the problem... you must be compiling with ACPI debug on. Thanks for pointing it out. New patch attached

    ---CUT HERE---
    --- linux-2.6.0-test2.orig/arch/i386/kernel/io_apic.c 2003-07-27 18:00:21.000000000 +0100
    +++ linux-2.6.0-test2/arch/i386/kernel/io_apic.c 2003-07-27 22:24:11.000000000 +0100
    @@ -1559,6 +1559,142 @@
    printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
    }

    +int io_apic_irq_read_proc (char *page, char **start, off_t off,
    + int count, int *eof, void *data)
    +{
    + int apic, i;
    + union IO_APIC_reg_00 reg_00;
    + union IO_APIC_reg_01 reg_01;
    + union IO_APIC_reg_02 reg_02;
    + union IO_APIC_reg_03 reg_03;
    + unsigned long flags;
    + char* start_page;
    +
    + start_page = page;
    + page += sprintf(page, "number of MP IRQ sources: %d.\n", mp_irq_entries);
    + for (i = 0; i < nr_ioapics; i++)
    + page += sprintf(page, "number of IO-APIC #%d registers: %d.\n",
    + mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]);
    +
    + for (apic = 0; apic < nr_ioapics; apic++) {
    +
    + spin_lock_irqsave(&ioapic_lock, flags);
    + reg_00.raw = io_apic_read(apic, 0);
    + reg_01.raw = io_apic_read(apic, 1);
    + if (reg_01.bits.version >= 0x10)
    + reg_02.raw = io_apic_read(apic, 2);
    + if (reg_01.bits.version >= 0x20)
    + reg_03.raw = io_apic_read(apic, 3);
    + spin_unlock_irqrestore(&ioapic_lock, flags);
    +
    + page += sprintf(page, "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
    + page += sprintf(page, ".... register #00: %08X\n", reg_00.raw);
    + page += sprintf(page, "....... : physical APIC id: %02X\n", reg_00.bits.ID);
    + page += sprintf(page, "....... : Delivery Type: %X\n", reg_00.bits.delivery_type);
    + page += sprintf(page, "....... : LTS : %X\n", reg_00.bits.LTS);
    + if (reg_00.bits.ID >= APIC_BROADCAST_ID)
    + page += sprintf(page, "UNEXPECTED_IO_APIC\n");
    + if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2)
    + page += sprintf(page, "UNEXPECTED_IO_APIC\n");
    +
    + page += sprintf(page, ".... register #01: %08X\n", reg_01.raw);
    + page += sprintf(page, "....... : max redirection entries: %04X\n", reg_01.bits.entries);
    + if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */
    + (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */
    + (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */
    + (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */
    + (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */
    + (reg_01.bits.entries != 0x2E) &&
    + (reg_01.bits.entries != 0x3F)
    + )
    + page += sprintf(page, "UNEXPECTED_IO_APIC\n");
    +
    + page += sprintf(page, "....... : PRQ implemented: %X\n", reg_01.bits.PRQ);
    + page += sprintf(page, "....... : IO APIC version: %04X\n", reg_01.bits.version);
    + if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */
    + (reg_01.bits.version != 0x10) && /* oldest IO-APICs */
    + (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */
    + (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */
    + (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */
    + )
    + page += sprintf(page, "UNEXPECTED_IO_APIC\n");
    + if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2)
    + page += sprintf(page, "UNEXPECTED_IO_APIC\n");
    +
    + /*
    + * Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02,
    + * but the value of reg_02 is read as the previous read register
    + * value, so ignore it if reg_02 == reg_01.
    + */
    + if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) {
    + page += sprintf(page, ".... register #02: %08X\n", reg_02.raw);
    + page += sprintf(page, "....... : arbitration: %02X\n", reg_02.bits.arbitration);
    + if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2)
    + page += sprintf(page, "UNEXPECTED_IO_APIC\n");
    + }
    +
    + /*
    + * Some Intel chipsets with IO APIC VERSION of 0x2? don't have reg_02
    + * or reg_03, but the value of reg_0[23] is read as the previous read
    + * register value, so ignore it if reg_03 == reg_0[12].
    + */
    + if (reg_01.bits.version >= 0x20 && reg_03.raw != reg_02.raw &&
    + reg_03.raw != reg_01.raw) {
    + page += sprintf(page, ".... register #03: %08X\n", reg_03.raw);
    + page += sprintf(page, "....... : Boot DT : %X\n", reg_03.bits.boot_DT);
    + if (reg_03.bits.__reserved_1)
    + page += sprintf(page, "UNEXPECTED_IO_APIC\n");
    + }
    +
    + page += sprintf(page, ".... IRQ redirection table:\n");
    +
    + page += sprintf(page, " NR Log Phy Mask Trig IRR Pol"
    + " Stat Dest Deli Vect: \n");
    +
    + for (i = 0; i <= reg_01.bits.entries; i++) {
    + struct IO_APIC_route_entry entry;
    +
    + spin_lock_irqsave(&ioapic_lock, flags);
    + *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
    + *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
    + spin_unlock_irqrestore(&ioapic_lock, flags);
    +
    + page += sprintf(page, " %02x %03X %02X ",
    + i,
    + entry.dest.logical.logical_dest,
    + entry.dest.physical.physical_dest
    + );
    +
    + page += sprintf(page, "%1d %1d %1d %1d %1d %1d %1d %02X\n",
    + entry.mask,
    + entry.trigger,
    + entry.irr,
    + entry.polarity,
    + entry.delivery_status,
    + entry.dest_mode,
    + entry.delivery_mode,
    + entry.vector
    + );
    + }
    + }
    + page += sprintf(page, "IRQ to pin mappings:\n");
    + for (i = 0; i < NR_IRQS; i++) {
    + struct irq_pin_list *entry = irq_2_pin + i;
    + if (entry->pin < 0)
    + continue;
    + page += sprintf(page, "IRQ%d ", i);
    + for (;;) {
    + page += sprintf(page, "-> %d:0x%x", entry->apic, entry->pin);
    + if (!entry->next)
    + break;
    + entry = irq_2_pin + entry->next;
    + }
    + page += sprintf(page, "\n");
    + }
    +
    + return page - start_page;
    +}
    +
    static void __init enable_IO_APIC(void)
    {
    union IO_APIC_reg_01 reg_01;
    @@ -2328,7 +2464,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;
    @@ -2350,19 +2486,23 @@
    entry.delivery_mode = INT_DELIVERY_MODE;
    entry.dest_mode = INT_DEST_MODE;
    entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
    - entry.mask = 1; /* Disabled (masked) */
    - entry.trigger = 1; /* Level sensitive */
    - entry.polarity = 1; /* Low active */
    + entry.trigger = edge_level;
    + entry.polarity = active_high_low;
    + entry.mask = 1;

    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]);

    --- linux-2.6.0-test2.orig/arch/i386/kernel/mpparse.c 2003-07-27 17:59:51.000000000 +0100
    +++ linux-2.6.0-test2/arch/i386/kernel/mpparse.c 2003-07-27 22:24:11.000000000 +0100
    @@ -1065,7 +1065,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, edge triggered
    }

    #endif /*CONFIG_ACPI_HT_ONLY*/
    @@ -1080,6 +1080,8 @@
    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
    @@ -1090,12 +1092,16 @@

    /* 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
    + 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)
    @@ -1130,7 +1136,7 @@

    mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);

    - if (!io_apic_set_pci_routing(ioapic, ioapic_pin, irq))
    + if (!io_apic_set_pci_routing(ioapic, ioapic_pin, irq, edge_level, active_high_low))
    entry->irq = irq;

    printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n",
    @@ -1140,6 +1146,9 @@
    entry->irq);
    }

    +
    +
    +
    return;
    }

    --- linux-2.6.0-test2.orig/arch/i386/kernel/irq.c 2003-07-27 17:57:11.000000000 +0100
    +++ linux-2.6.0-test2/arch/i386/kernel/irq.c 2003-07-27 22:24:11.000000000 +0100
    @@ -1028,6 +1028,13 @@

    unsigned long prof_cpu_mask = -1;

    +#ifdef CONFIG_X86_IO_APIC
    +static struct proc_dir_entry * io_apic_irq_entry;
    +
    +extern int io_apic_irq_read_proc (char *page, char **start, off_t off,
    + int count, int *eof, void *data);
    +#endif
    +
    void init_irq_proc (void)
    {
    struct proc_dir_entry *entry;
    @@ -1052,5 +1059,24 @@
    */
    for (i = 0; i < NR_IRQS; i++)
    register_irq_proc(i);
    +
    +#ifdef CONFIG_X86_IO_APIC
    + if (smp_found_config) {
    + if (!skip_ioapic_setup && nr_ioapics) {
    + struct proc_dir_entry* entry;
    +
    + /* create /proc/irq/io_apic */
    + entry = create_proc_entry("io_apic", 0400, root_irq_dir);
    +
    + if (entry) {
    + entry->nlink = 1;
    + entry->read_proc = io_apic_irq_read_proc;
    + }
    +
    + io_apic_irq_entry = entry;
    + }
    +
    + }
    +#endif
    }

    --- linux-2.6.0-test2.orig/drivers/acpi/pci_irq.c 2003-07-27 18:01:22.000000000 +0100
    +++ linux-2.6.0-test2/drivers/acpi/pci_irq.c 2003-07-27 22:24:11.000000000 +0100
    @@ -249,7 +249,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);
    @@ -389,7 +389,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. */
    --- linux-2.6.0-test2.orig/drivers/acpi/pci_link.c 2003-07-27 17:57:17.000000000 +0100
    +++ linux-2.6.0-test2/drivers/acpi/pci_link.c 2003-07-28 17:42:07.000000000 +0100
    @@ -69,6 +69,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];
    };
    @@ -118,6 +121,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:
    @@ -136,6 +141,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:
    @@ -264,7 +271,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));
    @@ -294,6 +300,8 @@
    if (!link || !irq)
    return_VALUE(-EINVAL);

    + /* We don't check irqs the first time round */
    + if (link->irq.setonboot) {
    /* See if we're already at the target IRQ. */
    if (irq == link->irq.active)
    return_VALUE(0);
    @@ -307,16 +315,18 @@
    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;
    }
    @@ -324,15 +334,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"));
    @@ -355,11 +365,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);
    }

    @@ -407,7 +419,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) {

    @@ -428,23 +440,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
    @@ -455,16 +467,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);
    }

    @@ -472,7 +488,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;
    @@ -498,11 +516,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);
    }

    --- linux-2.6.0-test2.orig/include/acpi/acpi_drivers.h 2003-07-27 18:06:07.000000000 +0100
    +++ linux-2.6.0-test2/include/acpi/acpi_drivers.h 2003-07-27 22:24:11.000000000 +0100
    @@ -60,7 +60,7 @@
    /* ACPI PCI Interrupt Link (pci_link.c) */

    int acpi_pci_link_check (void);
    -int acpi_pci_link_get_irq (acpi_handle handle, int index);
    +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) */

    --- linux-2.6.0-test2.orig/include/asm-i386/io_apic.h 2003-07-27 18:04:51.000000000 +0100
    +++ linux-2.6.0-test2/include/asm-i386/io_apic.h 2003-07-27 22:24:11.000000000 +0100
    @@ -170,7 +170,7 @@
    extern int io_apic_get_unique_id (int ioapic, int apic_id);
    extern int io_apic_get_version (int ioapic);
    extern int io_apic_get_redir_entries (int ioapic);
    -extern int io_apic_set_pci_routing (int ioapic, int pin, int irq);
    +extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low);
    #endif /*CONFIG_ACPI_BOOT*/

    #else /* !CONFIG_X86_IO_APIC */
    ---CUT HERE---

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 13:47    [W:0.049 / U:90.932 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site