mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
d3f138106b
commit
1e75b31d63
|
@ -593,10 +593,56 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
|
|||
entry = ioapic_read_entry(apic, pin);
|
||||
if (entry.delivery_mode == dest_SMI)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Disable it in the IO-APIC irq-routing table:
|
||||
* Make sure the entry is masked and re-read the contents to check
|
||||
* if it is a level triggered pin and if the remote-IRR is set.
|
||||
*/
|
||||
if (!entry.mask) {
|
||||
entry.mask = 1;
|
||||
ioapic_write_entry(apic, pin, entry);
|
||||
entry = ioapic_read_entry(apic, pin);
|
||||
}
|
||||
|
||||
if (entry.irr) {
|
||||
/*
|
||||
* Make sure the trigger mode is set to level. Explicit EOI
|
||||
* doesn't clear the remote-IRR if the trigger mode is not
|
||||
* set to level.
|
||||
*/
|
||||
if (!entry.trigger) {
|
||||
entry.trigger = IOAPIC_LEVEL;
|
||||
ioapic_write_entry(apic, pin, entry);
|
||||
}
|
||||
|
||||
if (mpc_ioapic_ver(apic) >= 0x20) {
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&ioapic_lock, flags);
|
||||
io_apic_eoi(apic, entry.vector);
|
||||
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
|
||||
} else {
|
||||
/*
|
||||
* Mechanism by which we clear remote-IRR in this
|
||||
* case is by changing the trigger mode to edge and
|
||||
* back to level.
|
||||
*/
|
||||
entry.trigger = IOAPIC_EDGE;
|
||||
ioapic_write_entry(apic, pin, entry);
|
||||
entry.trigger = IOAPIC_LEVEL;
|
||||
ioapic_write_entry(apic, pin, entry);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the rest of the bits in the IO-APIC RTE except for the mask
|
||||
* bit.
|
||||
*/
|
||||
ioapic_mask_entry(apic, pin);
|
||||
entry = ioapic_read_entry(apic, pin);
|
||||
if (entry.irr)
|
||||
printk(KERN_ERR "Unable to reset IRR for apic: %d, pin :%d\n",
|
||||
mpc_ioapic_id(apic), pin);
|
||||
}
|
||||
|
||||
static void clear_IO_APIC (void)
|
||||
|
|
Loading…
Reference in New Issue