Commit 04a868aa authored by Maciej W. Rozycki's avatar Maciej W. Rozycki Committed by Linus Torvalds

[PATCH] 2.4.18, 2.5.5: I/O APIC through-8259A mode IRQ 0 routing

 There is a problem with the through-8259A mode for IRQ 0 on I/O APIC
systems.  Depending on correctness of an MP table, IRQ 0 routing is either
not registered at all or registered at a wrong pin.  As a result the 8254
timer IRQ only works by an accident (it's edge-triggered and never
disabled/enabled so it happens to survive this incorrect configuration).
A visible effect is you can't change the affinity for IRQ 0.

 Following is a patch that fixes both cases referred to above.  The code
looks obvious but it was additionally run-time tested just in case.  The
issue is serious -- please apply the patch ASAP.  As no changes were done
to io_apic.c since the development fork, the patch applies cleanly both to
2.4 and to 2.5.

 Credit goes to Joe for discovering the affinity problem and providing a
fix proposal (incorporated in the final one).

  Maciej
parent 28bb7028
...@@ -67,7 +67,7 @@ static struct irq_pin_list { ...@@ -67,7 +67,7 @@ static struct irq_pin_list {
* shared ISA-space IRQs, so we have to support them. We are super * shared ISA-space IRQs, so we have to support them. We are super
* fast in the common case, and fast for shared ISA-space IRQs. * fast in the common case, and fast for shared ISA-space IRQs.
*/ */
static void add_pin_to_irq(unsigned int irq, int apic, int pin) static void __init add_pin_to_irq(unsigned int irq, int apic, int pin)
{ {
static int first_free_entry = NR_IRQS; static int first_free_entry = NR_IRQS;
struct irq_pin_list *entry = irq_2_pin + irq; struct irq_pin_list *entry = irq_2_pin + irq;
...@@ -85,6 +85,26 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin) ...@@ -85,6 +85,26 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
entry->pin = pin; entry->pin = pin;
} }
/*
* Reroute an IRQ to a different pin.
*/
static void __init replace_pin_at_irq(unsigned int irq,
int oldapic, int oldpin,
int newapic, int newpin)
{
struct irq_pin_list *entry = irq_2_pin + irq;
while (1) {
if (entry->apic == oldapic && entry->pin == oldpin) {
entry->apic = newapic;
entry->pin = newpin;
}
if (!entry->next)
break;
entry = irq_2_pin + entry->next;
}
}
#define __DO_ACTION(R, ACTION, FINAL) \ #define __DO_ACTION(R, ACTION, FINAL) \
\ \
{ \ { \
...@@ -1533,6 +1553,10 @@ static inline void check_timer(void) ...@@ -1533,6 +1553,10 @@ static inline void check_timer(void)
setup_ExtINT_IRQ0_pin(pin2, vector); setup_ExtINT_IRQ0_pin(pin2, vector);
if (timer_irq_works()) { if (timer_irq_works()) {
printk("works.\n"); printk("works.\n");
if (pin1 != -1)
replace_pin_at_irq(0, 0, pin1, 0, pin2);
else
add_pin_to_irq(0, 0, pin2);
if (nmi_watchdog == NMI_IO_APIC) { if (nmi_watchdog == NMI_IO_APIC) {
setup_nmi(); setup_nmi();
check_nmi_watchdog(); check_nmi_watchdog();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment