diff options
author | Yinghai Lu <yhlu.kernel@gmail.com> | 2008-08-19 23:50:48 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-16 10:52:56 -0400 |
commit | 3eb2cce84beae8fd41de950569cafd5bca7edd5d (patch) | |
tree | 42bd7ff48555893b0c07b68f64af1d94864d0c20 /arch | |
parent | 4e738e2f307113feaedebae147c3e0d072e39648 (diff) |
x86: unify ack_apic_edge
use code in 64 to replace
move_native_irq(irq, desc);
in 32 bit
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/io_apic.c | 73 |
1 files changed, 35 insertions, 38 deletions
diff --git a/arch/x86/kernel/io_apic.c b/arch/x86/kernel/io_apic.c index 099696109ca8..a466b04ad5a4 100644 --- a/arch/x86/kernel/io_apic.c +++ b/arch/x86/kernel/io_apic.c | |||
@@ -389,7 +389,6 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned | |||
389 | writel(value, &io_apic->data); | 389 | writel(value, &io_apic->data); |
390 | } | 390 | } |
391 | 391 | ||
392 | #ifdef CONFIG_X86_64 | ||
393 | static bool io_apic_level_ack_pending(unsigned int irq) | 392 | static bool io_apic_level_ack_pending(unsigned int irq) |
394 | { | 393 | { |
395 | struct irq_pin_list *entry; | 394 | struct irq_pin_list *entry; |
@@ -419,7 +418,6 @@ static bool io_apic_level_ack_pending(unsigned int irq) | |||
419 | 418 | ||
420 | return false; | 419 | return false; |
421 | } | 420 | } |
422 | #endif | ||
423 | 421 | ||
424 | union entry_union { | 422 | union entry_union { |
425 | struct { u32 w1, w2; }; | 423 | struct { u32 w1, w2; }; |
@@ -2398,9 +2396,16 @@ static void ack_apic_edge(unsigned int irq) | |||
2398 | ack_APIC_irq(); | 2396 | ack_APIC_irq(); |
2399 | } | 2397 | } |
2400 | 2398 | ||
2401 | #ifdef CONFIG_X86_64 | 2399 | #ifdef CONFIG_X86_32 |
2400 | atomic_t irq_mis_count; | ||
2401 | #endif | ||
2402 | |||
2402 | static void ack_apic_level(unsigned int irq) | 2403 | static void ack_apic_level(unsigned int irq) |
2403 | { | 2404 | { |
2405 | #ifdef CONFIG_X86_32 | ||
2406 | unsigned long v; | ||
2407 | int i; | ||
2408 | #endif | ||
2404 | int do_unmask_irq = 0; | 2409 | int do_unmask_irq = 0; |
2405 | 2410 | ||
2406 | irq_complete_move(irq); | 2411 | irq_complete_move(irq); |
@@ -2412,6 +2417,31 @@ static void ack_apic_level(unsigned int irq) | |||
2412 | } | 2417 | } |
2413 | #endif | 2418 | #endif |
2414 | 2419 | ||
2420 | #ifdef CONFIG_X86_32 | ||
2421 | /* | ||
2422 | * It appears there is an erratum which affects at least version 0x11 | ||
2423 | * of I/O APIC (that's the 82093AA and cores integrated into various | ||
2424 | * chipsets). Under certain conditions a level-triggered interrupt is | ||
2425 | * erroneously delivered as edge-triggered one but the respective IRR | ||
2426 | * bit gets set nevertheless. As a result the I/O unit expects an EOI | ||
2427 | * message but it will never arrive and further interrupts are blocked | ||
2428 | * from the source. The exact reason is so far unknown, but the | ||
2429 | * phenomenon was observed when two consecutive interrupt requests | ||
2430 | * from a given source get delivered to the same CPU and the source is | ||
2431 | * temporarily disabled in between. | ||
2432 | * | ||
2433 | * A workaround is to simulate an EOI message manually. We achieve it | ||
2434 | * by setting the trigger mode to edge and then to level when the edge | ||
2435 | * trigger mode gets detected in the TMR of a local APIC for a | ||
2436 | * level-triggered interrupt. We mask the source for the time of the | ||
2437 | * operation to prevent an edge-triggered interrupt escaping meanwhile. | ||
2438 | * The idea is from Manfred Spraul. --macro | ||
2439 | */ | ||
2440 | i = irq_cfg(irq)->vector; | ||
2441 | |||
2442 | v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); | ||
2443 | #endif | ||
2444 | |||
2415 | /* | 2445 | /* |
2416 | * We must acknowledge the irq before we move it or the acknowledge will | 2446 | * We must acknowledge the irq before we move it or the acknowledge will |
2417 | * not propagate properly. | 2447 | * not propagate properly. |
@@ -2450,41 +2480,8 @@ static void ack_apic_level(unsigned int irq) | |||
2450 | move_masked_irq(irq); | 2480 | move_masked_irq(irq); |
2451 | unmask_IO_APIC_irq(irq); | 2481 | unmask_IO_APIC_irq(irq); |
2452 | } | 2482 | } |
2453 | } | ||
2454 | #else | ||
2455 | atomic_t irq_mis_count; | ||
2456 | static void ack_apic_level(unsigned int irq) | ||
2457 | { | ||
2458 | unsigned long v; | ||
2459 | int i; | ||
2460 | |||
2461 | irq_complete_move(irq); | ||
2462 | move_native_irq(irq); | ||
2463 | /* | ||
2464 | * It appears there is an erratum which affects at least version 0x11 | ||
2465 | * of I/O APIC (that's the 82093AA and cores integrated into various | ||
2466 | * chipsets). Under certain conditions a level-triggered interrupt is | ||
2467 | * erroneously delivered as edge-triggered one but the respective IRR | ||
2468 | * bit gets set nevertheless. As a result the I/O unit expects an EOI | ||
2469 | * message but it will never arrive and further interrupts are blocked | ||
2470 | * from the source. The exact reason is so far unknown, but the | ||
2471 | * phenomenon was observed when two consecutive interrupt requests | ||
2472 | * from a given source get delivered to the same CPU and the source is | ||
2473 | * temporarily disabled in between. | ||
2474 | * | ||
2475 | * A workaround is to simulate an EOI message manually. We achieve it | ||
2476 | * by setting the trigger mode to edge and then to level when the edge | ||
2477 | * trigger mode gets detected in the TMR of a local APIC for a | ||
2478 | * level-triggered interrupt. We mask the source for the time of the | ||
2479 | * operation to prevent an edge-triggered interrupt escaping meanwhile. | ||
2480 | * The idea is from Manfred Spraul. --macro | ||
2481 | */ | ||
2482 | i = irq_cfg(irq)->vector; | ||
2483 | |||
2484 | v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); | ||
2485 | |||
2486 | ack_APIC_irq(); | ||
2487 | 2483 | ||
2484 | #ifdef CONFIG_X86_32 | ||
2488 | if (!(v & (1 << (i & 0x1f)))) { | 2485 | if (!(v & (1 << (i & 0x1f)))) { |
2489 | atomic_inc(&irq_mis_count); | 2486 | atomic_inc(&irq_mis_count); |
2490 | spin_lock(&ioapic_lock); | 2487 | spin_lock(&ioapic_lock); |
@@ -2492,8 +2489,8 @@ static void ack_apic_level(unsigned int irq) | |||
2492 | __unmask_and_level_IO_APIC_irq(irq); | 2489 | __unmask_and_level_IO_APIC_irq(irq); |
2493 | spin_unlock(&ioapic_lock); | 2490 | spin_unlock(&ioapic_lock); |
2494 | } | 2491 | } |
2495 | } | ||
2496 | #endif | 2492 | #endif |
2493 | } | ||
2497 | 2494 | ||
2498 | static struct irq_chip ioapic_chip __read_mostly = { | 2495 | static struct irq_chip ioapic_chip __read_mostly = { |
2499 | .name = "IO-APIC", | 2496 | .name = "IO-APIC", |