|
@@ -1408,6 +1408,56 @@ static void lapic_setup_esr(void)
|
|
oldvalue, value);
|
|
oldvalue, value);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void apic_pending_intr_clear(void)
|
|
|
|
+{
|
|
|
|
+ long long max_loops = cpu_khz ? cpu_khz : 1000000;
|
|
|
|
+ unsigned long long tsc = 0, ntsc;
|
|
|
|
+ unsigned int value, queued;
|
|
|
|
+ int i, j, acked = 0;
|
|
|
|
+
|
|
|
|
+ if (boot_cpu_has(X86_FEATURE_TSC))
|
|
|
|
+ tsc = rdtsc();
|
|
|
|
+ /*
|
|
|
|
+ * After a crash, we no longer service the interrupts and a pending
|
|
|
|
+ * interrupt from previous kernel might still have ISR bit set.
|
|
|
|
+ *
|
|
|
|
+ * Most probably by now CPU has serviced that pending interrupt and
|
|
|
|
+ * it might not have done the ack_APIC_irq() because it thought,
|
|
|
|
+ * interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it
|
|
|
|
+ * does not clear the ISR bit and cpu thinks it has already serivced
|
|
|
|
+ * the interrupt. Hence a vector might get locked. It was noticed
|
|
|
|
+ * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
|
|
|
|
+ */
|
|
|
|
+ do {
|
|
|
|
+ queued = 0;
|
|
|
|
+ for (i = APIC_ISR_NR - 1; i >= 0; i--)
|
|
|
|
+ queued |= apic_read(APIC_IRR + i*0x10);
|
|
|
|
+
|
|
|
|
+ for (i = APIC_ISR_NR - 1; i >= 0; i--) {
|
|
|
|
+ value = apic_read(APIC_ISR + i*0x10);
|
|
|
|
+ for (j = 31; j >= 0; j--) {
|
|
|
|
+ if (value & (1<<j)) {
|
|
|
|
+ ack_APIC_irq();
|
|
|
|
+ acked++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (acked > 256) {
|
|
|
|
+ printk(KERN_ERR "LAPIC pending interrupts after %d EOI\n",
|
|
|
|
+ acked);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (queued) {
|
|
|
|
+ if (boot_cpu_has(X86_FEATURE_TSC) && cpu_khz) {
|
|
|
|
+ ntsc = rdtsc();
|
|
|
|
+ max_loops = (cpu_khz << 10) - (ntsc - tsc);
|
|
|
|
+ } else
|
|
|
|
+ max_loops--;
|
|
|
|
+ }
|
|
|
|
+ } while (queued && max_loops > 0);
|
|
|
|
+ WARN_ON(max_loops <= 0);
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* setup_local_APIC - setup the local APIC
|
|
* setup_local_APIC - setup the local APIC
|
|
*
|
|
*
|
|
@@ -1417,13 +1467,11 @@ static void lapic_setup_esr(void)
|
|
static void setup_local_APIC(void)
|
|
static void setup_local_APIC(void)
|
|
{
|
|
{
|
|
int cpu = smp_processor_id();
|
|
int cpu = smp_processor_id();
|
|
- unsigned int value, queued;
|
|
|
|
- int i, j, acked = 0;
|
|
|
|
- unsigned long long tsc = 0, ntsc;
|
|
|
|
- long long max_loops = cpu_khz ? cpu_khz : 1000000;
|
|
|
|
|
|
+ unsigned int value;
|
|
|
|
+#ifdef CONFIG_X86_32
|
|
|
|
+ int i;
|
|
|
|
+#endif
|
|
|
|
|
|
- if (boot_cpu_has(X86_FEATURE_TSC))
|
|
|
|
- tsc = rdtsc();
|
|
|
|
|
|
|
|
if (disable_apic) {
|
|
if (disable_apic) {
|
|
disable_ioapic_support();
|
|
disable_ioapic_support();
|
|
@@ -1475,45 +1523,7 @@ static void setup_local_APIC(void)
|
|
value &= ~APIC_TPRI_MASK;
|
|
value &= ~APIC_TPRI_MASK;
|
|
apic_write(APIC_TASKPRI, value);
|
|
apic_write(APIC_TASKPRI, value);
|
|
|
|
|
|
- /*
|
|
|
|
- * After a crash, we no longer service the interrupts and a pending
|
|
|
|
- * interrupt from previous kernel might still have ISR bit set.
|
|
|
|
- *
|
|
|
|
- * Most probably by now CPU has serviced that pending interrupt and
|
|
|
|
- * it might not have done the ack_APIC_irq() because it thought,
|
|
|
|
- * interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it
|
|
|
|
- * does not clear the ISR bit and cpu thinks it has already serivced
|
|
|
|
- * the interrupt. Hence a vector might get locked. It was noticed
|
|
|
|
- * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
|
|
|
|
- */
|
|
|
|
- do {
|
|
|
|
- queued = 0;
|
|
|
|
- for (i = APIC_ISR_NR - 1; i >= 0; i--)
|
|
|
|
- queued |= apic_read(APIC_IRR + i*0x10);
|
|
|
|
-
|
|
|
|
- for (i = APIC_ISR_NR - 1; i >= 0; i--) {
|
|
|
|
- value = apic_read(APIC_ISR + i*0x10);
|
|
|
|
- for (j = 31; j >= 0; j--) {
|
|
|
|
- if (value & (1<<j)) {
|
|
|
|
- ack_APIC_irq();
|
|
|
|
- acked++;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (acked > 256) {
|
|
|
|
- printk(KERN_ERR "LAPIC pending interrupts after %d EOI\n",
|
|
|
|
- acked);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- if (queued) {
|
|
|
|
- if (boot_cpu_has(X86_FEATURE_TSC) && cpu_khz) {
|
|
|
|
- ntsc = rdtsc();
|
|
|
|
- max_loops = (cpu_khz << 10) - (ntsc - tsc);
|
|
|
|
- } else
|
|
|
|
- max_loops--;
|
|
|
|
- }
|
|
|
|
- } while (queued && max_loops > 0);
|
|
|
|
- WARN_ON(max_loops <= 0);
|
|
|
|
|
|
+ apic_pending_intr_clear();
|
|
|
|
|
|
/*
|
|
/*
|
|
* Now that we are all set up, enable the APIC
|
|
* Now that we are all set up, enable the APIC
|