aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/apic.c
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@in.ibm.com>2006-03-31 05:30:05 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-31 15:18:50 -0500
commit1a75a3f0680d9c4bc4761512658b6fd664032e18 (patch)
tree8d3d7fe266740f58961b43ecf144503f36e88dc4 /arch/i386/kernel/apic.c
parent3ccfb81e871b45e4af6ebb3282f3cfa0f98f1b80 (diff)
[PATCH] i386 kdump timer vector lockup fix
Porting the patch I posted for x86_64 to i386. http://marc.theaimsgroup.com/?l=linux-kernel&m=114178139610707&w=2 o While using kdump, after a system crash when second kernel boots, timer vector gets (0x31) locked and CPU does not see timer interrupts travelling from IOAPIC to APIC. Currently it does not lead to boot failure in second kernel as timer interrupts continues to come as ExtInt through LAPIC directly, but fixing it is good in case some boards do not support the other mode. o After a system crash, it is not safe to service interrupts any more, hence interrupts are disabled. This leads to pending interrupts at LAPIC. LAPIC sends these interrupts to the CPU during early boot of second kernel. Other pending interrupts are discarded saying unexpected trap but timer interrupt is serviced and CPU does not issue an LAPIC EOI because it think this interrupt came from i8259 and sends ack to 8259. This leads to vector 0x31 locking as LAPIC does not clear respective ISR and keeps on waiting for EOI. o This patch issues extra EOI for the pending interrupts who have ISR set. o Though today only timer seems to be the special case because in early boot it thinks interrupts are coming from i8259 and uses mask_and_ack_8259A() as ack handler and does not issue LAPIC EOI. But probably doing it in generic manner for all vectors makes sense. Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Andi Kleen <ak@muc.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel/apic.c')
-rw-r--r--arch/i386/kernel/apic.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index eb5279d23b7f..3fff3c62d57a 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -415,6 +415,7 @@ void __init init_bsp_APIC(void)
415void __devinit setup_local_APIC(void) 415void __devinit setup_local_APIC(void)
416{ 416{
417 unsigned long oldvalue, value, ver, maxlvt; 417 unsigned long oldvalue, value, ver, maxlvt;
418 int i, j;
418 419
419 /* Pound the ESR really hard over the head with a big hammer - mbligh */ 420 /* Pound the ESR really hard over the head with a big hammer - mbligh */
420 if (esr_disable) { 421 if (esr_disable) {
@@ -452,6 +453,25 @@ void __devinit setup_local_APIC(void)
452 apic_write_around(APIC_TASKPRI, value); 453 apic_write_around(APIC_TASKPRI, value);
453 454
454 /* 455 /*
456 * After a crash, we no longer service the interrupts and a pending
457 * interrupt from previous kernel might still have ISR bit set.
458 *
459 * Most probably by now CPU has serviced that pending interrupt and
460 * it might not have done the ack_APIC_irq() because it thought,
461 * interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it
462 * does not clear the ISR bit and cpu thinks it has already serivced
463 * the interrupt. Hence a vector might get locked. It was noticed
464 * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
465 */
466 for (i = APIC_ISR_NR - 1; i >= 0; i--) {
467 value = apic_read(APIC_ISR + i*0x10);
468 for (j = 31; j >= 0; j--) {
469 if (value & (1<<j))
470 ack_APIC_irq();
471 }
472 }
473
474 /*
455 * Now that we are all set up, enable the APIC 475 * Now that we are all set up, enable the APIC
456 */ 476 */
457 value = apic_read(APIC_SPIV); 477 value = apic_read(APIC_SPIV);