diff options
author | Suresh Siddha <suresh.b.siddha@intel.com> | 2011-08-25 15:01:11 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-09-21 04:26:25 -0400 |
commit | 1e75b31d638d5242ca8e9771dfdcbd28a5f041df (patch) | |
tree | aa89a8dc78eae9f20c12aed485ca04ad1dc4301e /arch/x86/kernel | |
parent | d3f138106b4b40640dc667f0222fd9f137387b32 (diff) |
x86, kdump, ioapic: Reset remote-IRR in clear_IO_APIC
In the kdump scenario mentioned below, we can have a case where
the device using level triggered interrupt will not generate any
interrupts in the kdump kernel.
1. IO-APIC sends a level triggered interrupt to the CPU's local APIC.
2. Kernel crashed before the CPU services this interrupt, leaving
the remote-IRR in the IO-APIC set.
3. kdump kernel boot sequence does clear_IO_APIC() as part of IO-APIC
initialization. But this fails to reset remote-IRR bit of the
IO-APIC RTE as the remote-IRR bit is read-only.
4. Device using that level triggered entry can't generate any
more interrupts because of the remote-IRR bit.
In clear_IO_APIC_pin(), check if the remote-IRR bit is set and if
so do an explicit attempt to clear it (by doing EOI write on
modern io-apic's and changing trigger mode to edge/level on
older io-apic's). Also before doing the explicit EOI to the
io-apic, ensure that the trigger mode is indeed set to level.
This will enable the explicit EOI to the io-apic to reset the
remote-IRR bit.
Tested-by: Leonardo Chiquitto <lchiquitto@novell.com>
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Fixes: https://bugzilla.novell.com/show_bug.cgi?id=701686
Cc: Rafael Wysocki <rjw@novell.com>
Cc: Maciej W. Rozycki <macro@linux-mips.org>
Cc: Thomas Renninger <trenn@suse.de>
Cc: jbeulich@novell.com
Cc: yinghai@kernel.org
Link: http://lkml.kernel.org/r/20110825190657.157502602@sbsiddha-desk.sc.intel.com
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 48 |
1 files changed, 47 insertions, 1 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 620da6fed6b7..913d4bd2913a 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -593,10 +593,56 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) | |||
593 | entry = ioapic_read_entry(apic, pin); | 593 | entry = ioapic_read_entry(apic, pin); |
594 | if (entry.delivery_mode == dest_SMI) | 594 | if (entry.delivery_mode == dest_SMI) |
595 | return; | 595 | return; |
596 | |||
597 | /* | ||
598 | * Make sure the entry is masked and re-read the contents to check | ||
599 | * if it is a level triggered pin and if the remote-IRR is set. | ||
600 | */ | ||
601 | if (!entry.mask) { | ||
602 | entry.mask = 1; | ||
603 | ioapic_write_entry(apic, pin, entry); | ||
604 | entry = ioapic_read_entry(apic, pin); | ||
605 | } | ||
606 | |||
607 | if (entry.irr) { | ||
608 | /* | ||
609 | * Make sure the trigger mode is set to level. Explicit EOI | ||
610 | * doesn't clear the remote-IRR if the trigger mode is not | ||
611 | * set to level. | ||
612 | */ | ||
613 | if (!entry.trigger) { | ||
614 | entry.trigger = IOAPIC_LEVEL; | ||
615 | ioapic_write_entry(apic, pin, entry); | ||
616 | } | ||
617 | |||
618 | if (mpc_ioapic_ver(apic) >= 0x20) { | ||
619 | unsigned long flags; | ||
620 | |||
621 | raw_spin_lock_irqsave(&ioapic_lock, flags); | ||
622 | io_apic_eoi(apic, entry.vector); | ||
623 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); | ||
624 | } else { | ||
625 | /* | ||
626 | * Mechanism by which we clear remote-IRR in this | ||
627 | * case is by changing the trigger mode to edge and | ||
628 | * back to level. | ||
629 | */ | ||
630 | entry.trigger = IOAPIC_EDGE; | ||
631 | ioapic_write_entry(apic, pin, entry); | ||
632 | entry.trigger = IOAPIC_LEVEL; | ||
633 | ioapic_write_entry(apic, pin, entry); | ||
634 | } | ||
635 | } | ||
636 | |||
596 | /* | 637 | /* |
597 | * Disable it in the IO-APIC irq-routing table: | 638 | * Clear the rest of the bits in the IO-APIC RTE except for the mask |
639 | * bit. | ||
598 | */ | 640 | */ |
599 | ioapic_mask_entry(apic, pin); | 641 | ioapic_mask_entry(apic, pin); |
642 | entry = ioapic_read_entry(apic, pin); | ||
643 | if (entry.irr) | ||
644 | printk(KERN_ERR "Unable to reset IRR for apic: %d, pin :%d\n", | ||
645 | mpc_ioapic_id(apic), pin); | ||
600 | } | 646 | } |
601 | 647 | ||
602 | static void clear_IO_APIC (void) | 648 | static void clear_IO_APIC (void) |