* [PATCH -rt] irq nobody cared workaround for i386 [not found] <4676CF81.2000205@redhat.com> @ 2007-06-19 13:18 ` Michal Schmidt 2007-06-20 13:59 ` Michal Schmidt 0 siblings, 1 reply; 5+ messages in thread From: Michal Schmidt @ 2007-06-19 13:18 UTC (permalink / raw) To: Steven Rostedt; +Cc: Thomas Gleixner, Ingo Molnar, linux-rt-users, linux-kernel Steven Rostedt wrote: > This is the final "design" for the nobody cared bug. For all IO-APICS > other than the first one (the chained IO-APICS) we use the PCIX version > of the mask and unmask interrupt routines. This changes the interrupt > from level to edge for mask and edge to level for unmask. This keeps the > PCI-E from thinking it's in legacy mode and assert an old fashion INT# > interrupt which might spread to other interrupts. > > Here's a port of the workaround to i386. I tested it successfully on IBM LS21. Notice I had to disable the quirk handling in ack_ioapic_quirk_irq. The code path was triggering on LS21 and because it plays with the Interrupt Mask bit, it produced the doubled interrupts again. I don't like it and I need to think about a solution which would handle both quirks correctly. Michal --- arch/i386/kernel/io_apic.c.orig 2007-06-19 08:40:05.000000000 -0400 +++ arch/i386/kernel/io_apic.c 2007-06-19 08:58:00.000000000 -0400 @@ -261,6 +261,18 @@ static void __unmask_IO_APIC_irq (unsign __modify_IO_APIC_irq(irq, 0, 0x00010000); } +/* trigger = 0 (edge mode) */ +static void __pcix_mask_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0, 0x00008000); +} + +/* mask = 0, trigger = 1 (level mode) */ +static void __pcix_unmask_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000); +} + static void mask_IO_APIC_irq (unsigned int irq) { unsigned long flags; @@ -279,6 +291,24 @@ static void unmask_IO_APIC_irq (unsigned spin_unlock_irqrestore(&ioapic_lock, flags); } +static void pcix_mask_IO_APIC_irq (unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); + __pcix_mask_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); +} + +static void pcix_unmask_IO_APIC_irq (unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); + __pcix_unmask_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); +} + static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; @@ -1257,22 +1287,27 @@ static int assign_irq_vector(int irq) return vector; } + static struct irq_chip ioapic_chip; +static struct irq_chip pcix_ioapic_chip; #define IOAPIC_AUTO -1 #define IOAPIC_EDGE 0 #define IOAPIC_LEVEL 1 -static void ioapic_register_intr(int irq, int vector, unsigned long trigger) +static void ioapic_register_intr(int irq, int vector, unsigned long trigger, + int pcix) { + struct irq_chip *chip = pcix ? &pcix_ioapic_chip : &ioapic_chip; + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || trigger == IOAPIC_LEVEL) - set_irq_chip_and_handler_name(irq, &ioapic_chip, - handle_fasteoi_irq, "fasteoi"); - else { - set_irq_chip_and_handler_name(irq, &ioapic_chip, - handle_edge_irq, "edge"); - } + set_irq_chip_and_handler_name(irq, chip, handle_fasteoi_irq, + pcix ? "pcix-fasteoi" : "fasteoi"); + else + set_irq_chip_and_handler_name(irq, chip, handle_edge_irq, + pcix ? "pcix-edge" : "edge"); + set_intr_gate(vector, interrupt[irq]); } @@ -1336,7 +1371,7 @@ static void __init setup_IO_APIC_irqs(vo if (IO_APIC_IRQ(irq)) { vector = assign_irq_vector(irq); entry.vector = vector; - ioapic_register_intr(irq, vector, IOAPIC_AUTO); + ioapic_register_intr(irq, vector, IOAPIC_AUTO, apic>0); if (!apic && (irq < 16)) disable_8259A_irq(irq); @@ -2027,6 +2062,7 @@ static void ack_ioapic_quirk_irq(unsigne ack_APIC_irq(); +#if 0 if (!(v & (1 << (i & 0x1f)))) { atomic_inc(&irq_mis_count); spin_lock(&ioapic_lock); @@ -2036,6 +2072,7 @@ static void ack_ioapic_quirk_irq(unsigne __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000); spin_unlock(&ioapic_lock); } +#endif } static int ioapic_retrigger_irq(unsigned int irq) @@ -2058,6 +2095,18 @@ static struct irq_chip ioapic_chip __rea .retrigger = ioapic_retrigger_irq, }; +static struct irq_chip pcix_ioapic_chip __read_mostly = { + .name = "IO-APIC", + .startup = startup_ioapic_irq, + .mask = pcix_mask_IO_APIC_irq, + .unmask = pcix_unmask_IO_APIC_irq, + .ack = ack_ioapic_irq, + .eoi = ack_ioapic_quirk_irq, +#ifdef CONFIG_SMP + .set_affinity = set_ioapic_affinity_irq, +#endif + .retrigger = ioapic_retrigger_irq, +}; static inline void init_IO_APIC_traps(void) { @@ -2858,7 +2907,7 @@ int io_apic_set_pci_routing (int ioapic, mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); - ioapic_register_intr(irq, entry.vector, edge_level); + ioapic_register_intr(irq, entry.vector, edge_level, ioapic>0); if (!ioapic && (irq < 16)) disable_8259A_irq(irq); ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH -rt] irq nobody cared workaround for i386 2007-06-19 13:18 ` [PATCH -rt] irq nobody cared workaround for i386 Michal Schmidt @ 2007-06-20 13:59 ` Michal Schmidt 2007-06-20 14:17 ` Steven Rostedt 0 siblings, 1 reply; 5+ messages in thread From: Michal Schmidt @ 2007-06-20 13:59 UTC (permalink / raw) To: Ingo Molnar; +Cc: Steven Rostedt, Thomas Gleixner, linux-rt-users, linux-kernel Michal Schmidt wrote: > Steven Rostedt wrote: > >> This is the final "design" for the nobody cared bug. For all IO-APICS >> other than the first one (the chained IO-APICS) we use the PCIX version >> of the mask and unmask interrupt routines. This changes the interrupt >> from level to edge for mask and edge to level for unmask. This keeps the >> PCI-E from thinking it's in legacy mode and assert an old fashion INT# >> interrupt which might spread to other interrupts. >> >> >> > > Here's a port of the workaround to i386. I tested it successfully on IBM > LS21. > Notice I had to disable the quirk handling in ack_ioapic_quirk_irq. The > code path was triggering on LS21 and because it plays with the Interrupt > Mask bit, it produced the doubled interrupts again. I don't like it and > I need to think about a solution which would handle both quirks correctly. > I came to the conclusion that the IO-APICs which need the fix for the nobody cared bug don't have the issue ack_ioapic_quirk_irq is designed to work-around. It should be safe simply to use the normal ack_ioapic_irq as the .eoi method in pcix_ioapic_chip. So this is the port of Steven's fix for the nobody cared bug to i386. It works fine on IBM LS21 I have access to. Signed-off-by: Michal Schmidt <mschmidt@redhat.com> --- arch/i386/kernel/io_apic.c.orig 2007-06-19 08:40:05.000000000 -0400 +++ arch/i386/kernel/io_apic.c 2007-06-20 09:03:55.000000000 -0400 @@ -261,6 +261,18 @@ static void __unmask_IO_APIC_irq (unsign __modify_IO_APIC_irq(irq, 0, 0x00010000); } +/* trigger = 0 (edge mode) */ +static void __pcix_mask_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0, 0x00008000); +} + +/* mask = 0, trigger = 1 (level mode) */ +static void __pcix_unmask_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000); +} + static void mask_IO_APIC_irq (unsigned int irq) { unsigned long flags; @@ -279,6 +291,24 @@ static void unmask_IO_APIC_irq (unsigned spin_unlock_irqrestore(&ioapic_lock, flags); } +static void pcix_mask_IO_APIC_irq (unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); + __pcix_mask_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); +} + +static void pcix_unmask_IO_APIC_irq (unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); + __pcix_unmask_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); +} + static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; @@ -1257,22 +1287,27 @@ static int assign_irq_vector(int irq) return vector; } + static struct irq_chip ioapic_chip; +static struct irq_chip pcix_ioapic_chip; #define IOAPIC_AUTO -1 #define IOAPIC_EDGE 0 #define IOAPIC_LEVEL 1 -static void ioapic_register_intr(int irq, int vector, unsigned long trigger) +static void ioapic_register_intr(int irq, int vector, unsigned long trigger, + int pcix) { + struct irq_chip *chip = pcix ? &pcix_ioapic_chip : &ioapic_chip; + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || trigger == IOAPIC_LEVEL) - set_irq_chip_and_handler_name(irq, &ioapic_chip, - handle_fasteoi_irq, "fasteoi"); - else { - set_irq_chip_and_handler_name(irq, &ioapic_chip, - handle_edge_irq, "edge"); - } + set_irq_chip_and_handler_name(irq, chip, handle_fasteoi_irq, + pcix ? "pcix-fasteoi" : "fasteoi"); + else + set_irq_chip_and_handler_name(irq, chip, handle_edge_irq, + pcix ? "pcix-edge" : "edge"); + set_intr_gate(vector, interrupt[irq]); } @@ -1336,7 +1371,7 @@ static void __init setup_IO_APIC_irqs(vo if (IO_APIC_IRQ(irq)) { vector = assign_irq_vector(irq); entry.vector = vector; - ioapic_register_intr(irq, vector, IOAPIC_AUTO); + ioapic_register_intr(irq, vector, IOAPIC_AUTO, apic>0); if (!apic && (irq < 16)) disable_8259A_irq(irq); @@ -2058,6 +2093,18 @@ static struct irq_chip ioapic_chip __rea .retrigger = ioapic_retrigger_irq, }; +static struct irq_chip pcix_ioapic_chip __read_mostly = { + .name = "IO-APIC", + .startup = startup_ioapic_irq, + .mask = pcix_mask_IO_APIC_irq, + .unmask = pcix_unmask_IO_APIC_irq, + .ack = ack_ioapic_irq, + .eoi = ack_ioapic_irq, +#ifdef CONFIG_SMP + .set_affinity = set_ioapic_affinity_irq, +#endif + .retrigger = ioapic_retrigger_irq, +}; static inline void init_IO_APIC_traps(void) { @@ -2858,7 +2905,7 @@ int io_apic_set_pci_routing (int ioapic, mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); - ioapic_register_intr(irq, entry.vector, edge_level); + ioapic_register_intr(irq, entry.vector, edge_level, ioapic>0); if (!ioapic && (irq < 16)) disable_8259A_irq(irq); ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH -rt] irq nobody cared workaround for i386 2007-06-20 13:59 ` Michal Schmidt @ 2007-06-20 14:17 ` Steven Rostedt 2007-06-21 11:31 ` Michal Schmidt 0 siblings, 1 reply; 5+ messages in thread From: Steven Rostedt @ 2007-06-20 14:17 UTC (permalink / raw) To: Michal Schmidt; +Cc: Ingo Molnar, Thomas Gleixner, linux-rt-users, linux-kernel Michal Schmidt wrote: > Michal Schmidt wrote: > I came to the conclusion that the IO-APICs which need the fix for the > nobody cared bug don't have the issue ack_ioapic_quirk_irq is designed > to work-around. It should be safe simply to use the normal > ack_ioapic_irq as the .eoi method in pcix_ioapic_chip. > So this is the port of Steven's fix for the nobody cared bug to i386. It > works fine on IBM LS21 I have access to. > Thanks Michal for doing this! > Signed-off-by: Michal Schmidt <mschmidt@redhat.com> > @@ -1336,7 +1371,7 @@ static void __init setup_IO_APIC_irqs(vo > if (IO_APIC_IRQ(irq)) { > vector = assign_irq_vector(irq); > entry.vector = vector; > - ioapic_register_intr(irq, vector, IOAPIC_AUTO); > + ioapic_register_intr(irq, vector, IOAPIC_AUTO, apic>0); You want to make that "apic > 0". Note the spacing. If it breaks 80 characters, then simply put it to a new line. > > if (!apic && (irq < 16)) > disable_8259A_irq(irq); > @@ -2058,6 +2093,18 @@ static struct irq_chip ioapic_chip __rea > .retrigger = ioapic_retrigger_irq, > }; > [...] > static inline void init_IO_APIC_traps(void) > { > @@ -2858,7 +2905,7 @@ int io_apic_set_pci_routing (int ioapic, > mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, > edge_level, active_high_low); > > - ioapic_register_intr(irq, entry.vector, edge_level); > + ioapic_register_intr(irq, entry.vector, edge_level, ioapic>0); Again, add the spaces. > > if (!ioapic && (irq < 16)) > disable_8259A_irq(irq); > > ACK -- Steve ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH -rt] irq nobody cared workaround for i386 2007-06-20 14:17 ` Steven Rostedt @ 2007-06-21 11:31 ` Michal Schmidt 2007-06-22 7:14 ` Thomas Gleixner 0 siblings, 1 reply; 5+ messages in thread From: Michal Schmidt @ 2007-06-21 11:31 UTC (permalink / raw) To: Steven Rostedt; +Cc: Ingo Molnar, Thomas Gleixner, linux-rt-users, linux-kernel Steven Rostedt wrote: > Michal Schmidt wrote: > >> I came to the conclusion that the IO-APICs which need the fix for the >> nobody cared bug don't have the issue ack_ioapic_quirk_irq is designed >> to work-around. It should be safe simply to use the normal >> ack_ioapic_irq as the .eoi method in pcix_ioapic_chip. >> So this is the port of Steven's fix for the nobody cared bug to i386. It >> works fine on IBM LS21 I have access to. >> >> > You want to make that "apic > 0". Note the spacing. If it breaks > 80 characters, then simply put it to a new line. > > [...] > ACK > > -- Steve > OK, I fixed the spacing in both occurences. Signed-off-by: Michal Schmidt <mschmidt@redhat.com> --- arch/i386/kernel/io_apic.c.orig 2007-06-19 08:40:05.000000000 -0400 +++ arch/i386/kernel/io_apic.c 2007-06-21 06:51:16.000000000 -0400 @@ -261,6 +261,18 @@ static void __unmask_IO_APIC_irq (unsign __modify_IO_APIC_irq(irq, 0, 0x00010000); } +/* trigger = 0 (edge mode) */ +static void __pcix_mask_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0, 0x00008000); +} + +/* mask = 0, trigger = 1 (level mode) */ +static void __pcix_unmask_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000); +} + static void mask_IO_APIC_irq (unsigned int irq) { unsigned long flags; @@ -279,6 +291,24 @@ static void unmask_IO_APIC_irq (unsigned spin_unlock_irqrestore(&ioapic_lock, flags); } +static void pcix_mask_IO_APIC_irq (unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); + __pcix_mask_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); +} + +static void pcix_unmask_IO_APIC_irq (unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); + __pcix_unmask_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); +} + static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; @@ -1257,22 +1287,27 @@ static int assign_irq_vector(int irq) return vector; } + static struct irq_chip ioapic_chip; +static struct irq_chip pcix_ioapic_chip; #define IOAPIC_AUTO -1 #define IOAPIC_EDGE 0 #define IOAPIC_LEVEL 1 -static void ioapic_register_intr(int irq, int vector, unsigned long trigger) +static void ioapic_register_intr(int irq, int vector, unsigned long trigger, + int pcix) { + struct irq_chip *chip = pcix ? &pcix_ioapic_chip : &ioapic_chip; + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || trigger == IOAPIC_LEVEL) - set_irq_chip_and_handler_name(irq, &ioapic_chip, - handle_fasteoi_irq, "fasteoi"); - else { - set_irq_chip_and_handler_name(irq, &ioapic_chip, - handle_edge_irq, "edge"); - } + set_irq_chip_and_handler_name(irq, chip, handle_fasteoi_irq, + pcix ? "pcix-fasteoi" : "fasteoi"); + else + set_irq_chip_and_handler_name(irq, chip, handle_edge_irq, + pcix ? "pcix-edge" : "edge"); + set_intr_gate(vector, interrupt[irq]); } @@ -1336,7 +1371,8 @@ static void __init setup_IO_APIC_irqs(vo if (IO_APIC_IRQ(irq)) { vector = assign_irq_vector(irq); entry.vector = vector; - ioapic_register_intr(irq, vector, IOAPIC_AUTO); + ioapic_register_intr(irq, vector, IOAPIC_AUTO, + apic > 0); if (!apic && (irq < 16)) disable_8259A_irq(irq); @@ -2058,6 +2094,18 @@ static struct irq_chip ioapic_chip __rea .retrigger = ioapic_retrigger_irq, }; +static struct irq_chip pcix_ioapic_chip __read_mostly = { + .name = "IO-APIC", + .startup = startup_ioapic_irq, + .mask = pcix_mask_IO_APIC_irq, + .unmask = pcix_unmask_IO_APIC_irq, + .ack = ack_ioapic_irq, + .eoi = ack_ioapic_irq, +#ifdef CONFIG_SMP + .set_affinity = set_ioapic_affinity_irq, +#endif + .retrigger = ioapic_retrigger_irq, +}; static inline void init_IO_APIC_traps(void) { @@ -2858,7 +2906,7 @@ int io_apic_set_pci_routing (int ioapic, mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); - ioapic_register_intr(irq, entry.vector, edge_level); + ioapic_register_intr(irq, entry.vector, edge_level, ioapic > 0); if (!ioapic && (irq < 16)) disable_8259A_irq(irq); ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH -rt] irq nobody cared workaround for i386 2007-06-21 11:31 ` Michal Schmidt @ 2007-06-22 7:14 ` Thomas Gleixner 0 siblings, 0 replies; 5+ messages in thread From: Thomas Gleixner @ 2007-06-22 7:14 UTC (permalink / raw) To: Michal Schmidt; +Cc: Steven Rostedt, Ingo Molnar, linux-rt-users, linux-kernel On Thu, 2007-06-21 at 13:31 +0200, Michal Schmidt wrote: > OK, I fixed the spacing in both occurences. > > Signed-off-by: Michal Schmidt <mschmidt@redhat.com> > > --- arch/i386/kernel/io_apic.c.orig 2007-06-19 08:40:05.000000000 -0400 > +++ arch/i386/kernel/io_apic.c 2007-06-21 06:51:16.000000000 -0400 Please create -p1 patches next time. Applied. Thanks, tglx ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2007-06-22 7:14 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <4676CF81.2000205@redhat.com>
2007-06-19 13:18 ` [PATCH -rt] irq nobody cared workaround for i386 Michal Schmidt
2007-06-20 13:59 ` Michal Schmidt
2007-06-20 14:17 ` Steven Rostedt
2007-06-21 11:31 ` Michal Schmidt
2007-06-22 7:14 ` Thomas Gleixner
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).