diff options
author | Maciej W. Rozycki <macro@linux-mips.org> | 2008-05-27 16:19:51 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-08 03:13:07 -0400 |
commit | 691874fa96d6349a8b60f8ea9c2bae52ece79941 (patch) | |
tree | a705c041eb25329632eab0491244b4544218273b /arch | |
parent | 03be750559b2fe20d85dd968e08d5fe1c3accf83 (diff) |
x86: I/O APIC: timer through 8259A second-chance
Some systems incorrectly report the ExtINTA pin of the I/O APIC as the
genuine target of the timer interrupt. Here is a change that copies timer
pin information found to the other pin if one has been found only. This
way both a direct and a through-8259A route is tested with the pin letting
these problematic systems work well enough. If no timer pin information
has been found for the I/O APIC, then local APIC variations are tried
only, similarly to what is done without the change (except without the
misleading messages).
Obviously if we try the first-chance path without being told by the BIOS
to do so, we should not complain either, so do not print the message in
this case.
The 64-bit variation should be updated with a call to
replace_pin_at_irq() which can be done with the upcoming merge. Since
add_pin_to_irq() is now always called in the first-chance path, the
condition to require it in the second-chance path no longer happens.
Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/io_apic_32.c | 38 | ||||
-rw-r--r-- | arch/x86/kernel/io_apic_64.c | 36 |
2 files changed, 57 insertions, 17 deletions
diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c index 63a2f64c765b..a69a59d19e18 100644 --- a/arch/x86/kernel/io_apic_32.c +++ b/arch/x86/kernel/io_apic_32.c | |||
@@ -2122,6 +2122,7 @@ static inline void __init unlock_ExtINT_logic(void) | |||
2122 | static inline void __init check_timer(void) | 2122 | static inline void __init check_timer(void) |
2123 | { | 2123 | { |
2124 | int apic1, pin1, apic2, pin2; | 2124 | int apic1, pin1, apic2, pin2; |
2125 | int no_pin1 = 0; | ||
2125 | int vector; | 2126 | int vector; |
2126 | unsigned int ver; | 2127 | unsigned int ver; |
2127 | unsigned long flags; | 2128 | unsigned long flags; |
@@ -2159,10 +2160,30 @@ static inline void __init check_timer(void) | |||
2159 | printk(KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", | 2160 | printk(KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", |
2160 | vector, apic1, pin1, apic2, pin2); | 2161 | vector, apic1, pin1, apic2, pin2); |
2161 | 2162 | ||
2163 | /* | ||
2164 | * Some BIOS writers are clueless and report the ExtINTA | ||
2165 | * I/O APIC input from the cascaded 8259A as the timer | ||
2166 | * interrupt input. So just in case, if only one pin | ||
2167 | * was found above, try it both directly and through the | ||
2168 | * 8259A. | ||
2169 | */ | ||
2170 | if (pin1 == -1) { | ||
2171 | pin1 = pin2; | ||
2172 | apic1 = apic2; | ||
2173 | no_pin1 = 1; | ||
2174 | } else if (pin2 == -1) { | ||
2175 | pin2 = pin1; | ||
2176 | apic2 = apic1; | ||
2177 | } | ||
2178 | |||
2162 | if (pin1 != -1) { | 2179 | if (pin1 != -1) { |
2163 | /* | 2180 | /* |
2164 | * Ok, does IRQ0 through the IOAPIC work? | 2181 | * Ok, does IRQ0 through the IOAPIC work? |
2165 | */ | 2182 | */ |
2183 | if (no_pin1) { | ||
2184 | add_pin_to_irq(0, apic1, pin1); | ||
2185 | setup_timer_IRQ0_pin(apic1, pin1, vector); | ||
2186 | } | ||
2166 | unmask_IO_APIC_irq(0); | 2187 | unmask_IO_APIC_irq(0); |
2167 | if (timer_irq_works()) { | 2188 | if (timer_irq_works()) { |
2168 | if (nmi_watchdog == NMI_IO_APIC) { | 2189 | if (nmi_watchdog == NMI_IO_APIC) { |
@@ -2174,26 +2195,23 @@ static inline void __init check_timer(void) | |||
2174 | goto out; | 2195 | goto out; |
2175 | } | 2196 | } |
2176 | clear_IO_APIC_pin(apic1, pin1); | 2197 | clear_IO_APIC_pin(apic1, pin1); |
2177 | printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to " | 2198 | if (!no_pin1) |
2178 | "IO-APIC\n"); | 2199 | printk(KERN_ERR "..MP-BIOS bug: " |
2179 | } | 2200 | "8254 timer not connected to IO-APIC\n"); |
2180 | 2201 | ||
2181 | printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... "); | 2202 | printk(KERN_INFO "...trying to set up timer (IRQ0) " |
2182 | if (pin2 != -1) { | 2203 | "through the 8259A ... "); |
2183 | printk("\n..... (found pin %d) ...", pin2); | 2204 | printk("\n..... (found pin %d) ...", pin2); |
2184 | /* | 2205 | /* |
2185 | * legacy devices should be connected to IO APIC #0 | 2206 | * legacy devices should be connected to IO APIC #0 |
2186 | */ | 2207 | */ |
2208 | replace_pin_at_irq(0, apic1, pin1, apic2, pin2); | ||
2187 | setup_timer_IRQ0_pin(apic2, pin2, vector); | 2209 | setup_timer_IRQ0_pin(apic2, pin2, vector); |
2188 | unmask_IO_APIC_irq(0); | 2210 | unmask_IO_APIC_irq(0); |
2189 | enable_8259A_irq(0); | 2211 | enable_8259A_irq(0); |
2190 | if (timer_irq_works()) { | 2212 | if (timer_irq_works()) { |
2191 | printk("works.\n"); | 2213 | printk("works.\n"); |
2192 | timer_through_8259 = 1; | 2214 | timer_through_8259 = 1; |
2193 | if (pin1 != -1) | ||
2194 | replace_pin_at_irq(0, apic1, pin1, apic2, pin2); | ||
2195 | else | ||
2196 | add_pin_to_irq(0, apic2, pin2); | ||
2197 | if (nmi_watchdog == NMI_IO_APIC) { | 2215 | if (nmi_watchdog == NMI_IO_APIC) { |
2198 | disable_8259A_irq(0); | 2216 | disable_8259A_irq(0); |
2199 | setup_nmi(); | 2217 | setup_nmi(); |
@@ -2206,8 +2224,8 @@ static inline void __init check_timer(void) | |||
2206 | */ | 2224 | */ |
2207 | disable_8259A_irq(0); | 2225 | disable_8259A_irq(0); |
2208 | clear_IO_APIC_pin(apic2, pin2); | 2226 | clear_IO_APIC_pin(apic2, pin2); |
2227 | printk(" failed.\n"); | ||
2209 | } | 2228 | } |
2210 | printk(" failed.\n"); | ||
2211 | 2229 | ||
2212 | if (nmi_watchdog == NMI_IO_APIC) { | 2230 | if (nmi_watchdog == NMI_IO_APIC) { |
2213 | printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n"); | 2231 | printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n"); |
diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c index ae0ac990574f..9a54b779abd4 100644 --- a/arch/x86/kernel/io_apic_64.c +++ b/arch/x86/kernel/io_apic_64.c | |||
@@ -1638,6 +1638,7 @@ static inline void __init check_timer(void) | |||
1638 | struct irq_cfg *cfg = irq_cfg + 0; | 1638 | struct irq_cfg *cfg = irq_cfg + 0; |
1639 | int apic1, pin1, apic2, pin2; | 1639 | int apic1, pin1, apic2, pin2; |
1640 | unsigned long flags; | 1640 | unsigned long flags; |
1641 | int no_pin1 = 0; | ||
1641 | 1642 | ||
1642 | local_irq_save(flags); | 1643 | local_irq_save(flags); |
1643 | 1644 | ||
@@ -1662,10 +1663,30 @@ static inline void __init check_timer(void) | |||
1662 | apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", | 1663 | apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", |
1663 | cfg->vector, apic1, pin1, apic2, pin2); | 1664 | cfg->vector, apic1, pin1, apic2, pin2); |
1664 | 1665 | ||
1666 | /* | ||
1667 | * Some BIOS writers are clueless and report the ExtINTA | ||
1668 | * I/O APIC input from the cascaded 8259A as the timer | ||
1669 | * interrupt input. So just in case, if only one pin | ||
1670 | * was found above, try it both directly and through the | ||
1671 | * 8259A. | ||
1672 | */ | ||
1673 | if (pin1 == -1) { | ||
1674 | pin1 = pin2; | ||
1675 | apic1 = apic2; | ||
1676 | no_pin1 = 1; | ||
1677 | } else if (pin2 == -1) { | ||
1678 | pin2 = pin1; | ||
1679 | apic2 = apic1; | ||
1680 | } | ||
1681 | |||
1665 | if (pin1 != -1) { | 1682 | if (pin1 != -1) { |
1666 | /* | 1683 | /* |
1667 | * Ok, does IRQ0 through the IOAPIC work? | 1684 | * Ok, does IRQ0 through the IOAPIC work? |
1668 | */ | 1685 | */ |
1686 | if (no_pin1) { | ||
1687 | add_pin_to_irq(0, apic1, pin1); | ||
1688 | setup_timer_IRQ0_pin(apic1, pin1, vector); | ||
1689 | } | ||
1669 | unmask_IO_APIC_irq(0); | 1690 | unmask_IO_APIC_irq(0); |
1670 | if (!no_timer_check && timer_irq_works()) { | 1691 | if (!no_timer_check && timer_irq_works()) { |
1671 | nmi_watchdog_default(); | 1692 | nmi_watchdog_default(); |
@@ -1678,18 +1699,19 @@ static inline void __init check_timer(void) | |||
1678 | goto out; | 1699 | goto out; |
1679 | } | 1700 | } |
1680 | clear_IO_APIC_pin(apic1, pin1); | 1701 | clear_IO_APIC_pin(apic1, pin1); |
1681 | apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not " | 1702 | if (!no_pin1) |
1682 | "connected to IO-APIC\n"); | 1703 | apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: " |
1683 | } | 1704 | "8254 timer not connected to IO-APIC\n"); |
1684 | 1705 | ||
1685 | apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) " | 1706 | apic_printk(APIC_VERBOSE,KERN_INFO |
1686 | "through the 8259A ... "); | 1707 | "...trying to set up timer (IRQ0) " |
1687 | if (pin2 != -1) { | 1708 | "through the 8259A ... "); |
1688 | apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...", | 1709 | apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...", |
1689 | apic2, pin2); | 1710 | apic2, pin2); |
1690 | /* | 1711 | /* |
1691 | * legacy devices should be connected to IO APIC #0 | 1712 | * legacy devices should be connected to IO APIC #0 |
1692 | */ | 1713 | */ |
1714 | /* replace_pin_at_irq(0, apic1, pin1, apic2, pin2); */ | ||
1693 | setup_timer_IRQ0_pin(apic2, pin2, cfg->vector); | 1715 | setup_timer_IRQ0_pin(apic2, pin2, cfg->vector); |
1694 | unmask_IO_APIC_irq(0); | 1716 | unmask_IO_APIC_irq(0); |
1695 | enable_8259A_irq(0); | 1717 | enable_8259A_irq(0); |
@@ -1709,8 +1731,8 @@ static inline void __init check_timer(void) | |||
1709 | */ | 1731 | */ |
1710 | disable_8259A_irq(0); | 1732 | disable_8259A_irq(0); |
1711 | clear_IO_APIC_pin(apic2, pin2); | 1733 | clear_IO_APIC_pin(apic2, pin2); |
1734 | apic_printk(APIC_VERBOSE," failed.\n"); | ||
1712 | } | 1735 | } |
1713 | apic_printk(APIC_VERBOSE," failed.\n"); | ||
1714 | 1736 | ||
1715 | if (nmi_watchdog == NMI_IO_APIC) { | 1737 | if (nmi_watchdog == NMI_IO_APIC) { |
1716 | printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n"); | 1738 | printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n"); |