diff options
Diffstat (limited to 'arch/i386/kernel/apic.c')
-rw-r--r-- | arch/i386/kernel/apic.c | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index f39e09ef64ec..6273bf74c203 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <asm/i8253.h> | 38 | #include <asm/i8253.h> |
39 | 39 | ||
40 | #include <mach_apic.h> | 40 | #include <mach_apic.h> |
41 | #include <mach_apicdef.h> | ||
41 | #include <mach_ipi.h> | 42 | #include <mach_ipi.h> |
42 | 43 | ||
43 | #include "io_ports.h" | 44 | #include "io_ports.h" |
@@ -414,6 +415,7 @@ void __init init_bsp_APIC(void) | |||
414 | void __devinit setup_local_APIC(void) | 415 | void __devinit setup_local_APIC(void) |
415 | { | 416 | { |
416 | unsigned long oldvalue, value, ver, maxlvt; | 417 | unsigned long oldvalue, value, ver, maxlvt; |
418 | int i, j; | ||
417 | 419 | ||
418 | /* 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 */ |
419 | if (esr_disable) { | 421 | if (esr_disable) { |
@@ -451,6 +453,25 @@ void __devinit setup_local_APIC(void) | |||
451 | apic_write_around(APIC_TASKPRI, value); | 453 | apic_write_around(APIC_TASKPRI, value); |
452 | 454 | ||
453 | /* | 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 | /* | ||
454 | * Now that we are all set up, enable the APIC | 475 | * Now that we are all set up, enable the APIC |
455 | */ | 476 | */ |
456 | value = apic_read(APIC_SPIV); | 477 | value = apic_read(APIC_SPIV); |
@@ -570,16 +591,18 @@ void __devinit setup_local_APIC(void) | |||
570 | */ | 591 | */ |
571 | void lapic_shutdown(void) | 592 | void lapic_shutdown(void) |
572 | { | 593 | { |
594 | unsigned long flags; | ||
595 | |||
573 | if (!cpu_has_apic) | 596 | if (!cpu_has_apic) |
574 | return; | 597 | return; |
575 | 598 | ||
576 | local_irq_disable(); | 599 | local_irq_save(flags); |
577 | clear_local_APIC(); | 600 | clear_local_APIC(); |
578 | 601 | ||
579 | if (enabled_via_apicbase) | 602 | if (enabled_via_apicbase) |
580 | disable_local_APIC(); | 603 | disable_local_APIC(); |
581 | 604 | ||
582 | local_irq_enable(); | 605 | local_irq_restore(flags); |
583 | } | 606 | } |
584 | 607 | ||
585 | #ifdef CONFIG_PM | 608 | #ifdef CONFIG_PM |
@@ -729,7 +752,7 @@ static int __init apic_set_verbosity(char *str) | |||
729 | printk(KERN_WARNING "APIC Verbosity level %s not recognised" | 752 | printk(KERN_WARNING "APIC Verbosity level %s not recognised" |
730 | " use apic=verbose or apic=debug\n", str); | 753 | " use apic=verbose or apic=debug\n", str); |
731 | 754 | ||
732 | return 0; | 755 | return 1; |
733 | } | 756 | } |
734 | 757 | ||
735 | __setup("apic=", apic_set_verbosity); | 758 | __setup("apic=", apic_set_verbosity); |