Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / arch / x86 / kernel / apic / apic.c
index b203af0..2aabd4c 100644 (file)
@@ -1408,22 +1408,69 @@ static void lapic_setup_esr(void)
                        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 queued;
+       unsigned long value;
+       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_each_set_bit(j, &value, 32) {
+                               ack_APIC_irq();
+                               acked++;
+                       }
+               }
+               if (acked > 256) {
+                       pr_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
  *
  * Used to setup local APIC while initializing BSP or bringing up APs.
  * Always called with preemption disabled.
  */
-void setup_local_APIC(void)
+static void setup_local_APIC(void)
 {
        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 logical_apicid, ldr_apicid;
+#endif
 
-       if (boot_cpu_has(X86_FEATURE_TSC))
-               tsc = rdtsc();
 
        if (disable_apic) {
                disable_ioapic_support();
@@ -1460,11 +1507,11 @@ void setup_local_APIC(void)
         * initialized during get_smp_config(), make sure it matches the
         * actual value.
         */
-       i = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
-       WARN_ON(i != BAD_APICID && i != logical_smp_processor_id());
+       logical_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
+       ldr_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
+       WARN_ON(logical_apicid != BAD_APICID && logical_apicid != ldr_apicid);
        /* always use the value from LDR */
-       early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
-               logical_smp_processor_id();
+       early_per_cpu(x86_cpu_to_logical_apicid, cpu) = ldr_apicid;
 #endif
 
        /*
@@ -1475,45 +1522,7 @@ void setup_local_APIC(void)
        value &= ~APIC_TPRI_MASK;
        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
@@ -1570,7 +1579,7 @@ void setup_local_APIC(void)
         * TODO: set up through-local-APIC from through-I/O-APIC? --macro
         */
        value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
-       if (!cpu && (pic_mode || !value)) {
+       if (!cpu && (pic_mode || !value || skip_ioapic_setup)) {
                value = APIC_DM_EXTINT;
                apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", cpu);
        } else {