aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorYinghai Lu <yhlu.kernel@gmail.com>2008-08-19 23:50:48 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-16 10:52:56 -0400
commit3eb2cce84beae8fd41de950569cafd5bca7edd5d (patch)
tree42bd7ff48555893b0c07b68f64af1d94864d0c20 /arch/x86
parent4e738e2f307113feaedebae147c3e0d072e39648 (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/x86')
-rw-r--r--arch/x86/kernel/io_apic.c73
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
393static bool io_apic_level_ack_pending(unsigned int irq) 392static 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
424union entry_union { 422union 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
2400atomic_t irq_mis_count;
2401#endif
2402
2402static void ack_apic_level(unsigned int irq) 2403static 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
2455atomic_t irq_mis_count;
2456static 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
2498static struct irq_chip ioapic_chip __read_mostly = { 2495static struct irq_chip ioapic_chip __read_mostly = {
2499 .name = "IO-APIC", 2496 .name = "IO-APIC",