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 {
* 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.
*/
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;
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)
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) \
\
{ \
......@@ -1533,6 +1553,10 @@ static inline void check_timer(void)
setup_ExtINT_IRQ0_pin(pin2, vector);
if (timer_irq_works()) {
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) {
setup_nmi();
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