Merge branch 'for-2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu
[linux-2.6.git] / arch / x86 / kernel / apic / apic.c
index 8accfe3..79e6baa 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/dmi.h>
-#include <linux/nmi.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
 
@@ -432,17 +431,18 @@ int setup_APIC_eilvt(u8 offset, u8 vector, u8 msg_type, u8 mask)
        reserved = reserve_eilvt_offset(offset, new);
 
        if (reserved != new) {
-               pr_err(FW_BUG "cpu %d, try to setup vector 0x%x, but "
-                      "vector 0x%x was already reserved by another core, "
-                      "APIC%lX=0x%x\n",
-                      smp_processor_id(), new, reserved, reg, old);
+               pr_err(FW_BUG "cpu %d, try to use APIC%lX (LVT offset %d) for "
+                      "vector 0x%x, but the register is already in use for "
+                      "vector 0x%x on another cpu\n",
+                      smp_processor_id(), reg, offset, new, reserved);
                return -EINVAL;
        }
 
        if (!eilvt_entry_is_changeable(old, new)) {
-               pr_err(FW_BUG "cpu %d, try to setup vector 0x%x but "
-                      "register already in use, APIC%lX=0x%x\n",
-                      smp_processor_id(), new, reg, old);
+               pr_err(FW_BUG "cpu %d, try to use APIC%lX (LVT offset %d) for "
+                      "vector 0x%x, but the register is already in use for "
+                      "vector 0x%x on this cpu\n",
+                      smp_processor_id(), reg, offset, new, old);
                return -EBUSY;
        }
 
@@ -799,11 +799,7 @@ void __init setup_boot_APIC_clock(void)
         * PIT/HPET going.  Otherwise register lapic as a dummy
         * device.
         */
-       if (nmi_watchdog != NMI_IO_APIC)
-               lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
-       else
-               pr_warning("APIC timer registered as dummy,"
-                       " due to nmi_watchdog=%d!\n", nmi_watchdog);
+       lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
 
        /* Setup the lapic or request the broadcast */
        setup_APIC_timer();
@@ -1195,12 +1191,15 @@ static void __cpuinit lapic_setup_esr(void)
                        oldvalue, value);
 }
 
-
 /**
  * setup_local_APIC - setup the local APIC
+ *
+ * Used to setup local APIC while initializing BSP or bringin up APs.
+ * Always called with preemption disabled.
  */
 void __cpuinit setup_local_APIC(void)
 {
+       int cpu = smp_processor_id();
        unsigned int value, queued;
        int i, j, acked = 0;
        unsigned long long tsc = 0, ntsc;
@@ -1225,8 +1224,6 @@ void __cpuinit setup_local_APIC(void)
 #endif
        perf_events_lapic_init();
 
-       preempt_disable();
-
        /*
         * Double-check whether this APIC is really registered.
         * This is meaningless in clustered apic mode, so we skip it.
@@ -1342,21 +1339,19 @@ void __cpuinit 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 (!smp_processor_id() && (pic_mode || !value)) {
+       if (!cpu && (pic_mode || !value)) {
                value = APIC_DM_EXTINT;
-               apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n",
-                               smp_processor_id());
+               apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", cpu);
        } else {
                value = APIC_DM_EXTINT | APIC_LVT_MASKED;
-               apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n",
-                               smp_processor_id());
+               apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", cpu);
        }
        apic_write(APIC_LVT0, value);
 
        /*
         * only the BP should see the LINT1 NMI signal, obviously.
         */
-       if (!smp_processor_id())
+       if (!cpu)
                value = APIC_DM_NMI;
        else
                value = APIC_DM_NMI | APIC_LVT_MASKED;
@@ -1364,11 +1359,9 @@ void __cpuinit setup_local_APIC(void)
                value |= APIC_LVT_LEVEL_TRIGGER;
        apic_write(APIC_LVT1, value);
 
-       preempt_enable();
-
 #ifdef CONFIG_X86_MCE_INTEL
        /* Recheck CMCI information after local APIC is up on CPU #0 */
-       if (smp_processor_id() == 0)
+       if (!cpu)
                cmci_recheck();
 #endif
 }
@@ -1387,8 +1380,15 @@ void __cpuinit end_local_APIC_setup(void)
        }
 #endif
 
-       setup_apic_nmi_watchdog(NULL);
        apic_pm_activate();
+
+       /*
+        * Now that local APIC setup is completed for BP, configure the fault
+        * handling for interrupt remapping.
+        */
+       if (!smp_processor_id() && intr_remapping_enabled)
+               enable_drhd_fault_handling();
+
 }
 
 #ifdef CONFIG_X86_X2APIC
@@ -1530,13 +1530,60 @@ static int __init detect_init_APIC(void)
        return 0;
 }
 #else
+
+static int apic_verify(void)
+{
+       u32 features, h, l;
+
+       /*
+        * The APIC feature bit should now be enabled
+        * in `cpuid'
+        */
+       features = cpuid_edx(1);
+       if (!(features & (1 << X86_FEATURE_APIC))) {
+               pr_warning("Could not enable APIC!\n");
+               return -1;
+       }
+       set_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC);
+       mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+
+       /* The BIOS may have set up the APIC at some other address */
+       rdmsr(MSR_IA32_APICBASE, l, h);
+       if (l & MSR_IA32_APICBASE_ENABLE)
+               mp_lapic_addr = l & MSR_IA32_APICBASE_BASE;
+
+       pr_info("Found and enabled local APIC!\n");
+       return 0;
+}
+
+int apic_force_enable(void)
+{
+       u32 h, l;
+
+       if (disable_apic)
+               return -1;
+
+       /*
+        * Some BIOSes disable the local APIC in the APIC_BASE
+        * MSR. This can only be done in software for Intel P6 or later
+        * and AMD K7 (Model > 1) or later.
+        */
+       rdmsr(MSR_IA32_APICBASE, l, h);
+       if (!(l & MSR_IA32_APICBASE_ENABLE)) {
+               pr_info("Local APIC disabled by BIOS -- reenabling.\n");
+               l &= ~MSR_IA32_APICBASE_BASE;
+               l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
+               wrmsr(MSR_IA32_APICBASE, l, h);
+               enabled_via_apicbase = 1;
+       }
+       return apic_verify();
+}
+
 /*
  * Detect and initialize APIC
  */
 static int __init detect_init_APIC(void)
 {
-       u32 h, l, features;
-
        /* Disabled by kernel option? */
        if (disable_apic)
                return -1;
@@ -1566,38 +1613,12 @@ static int __init detect_init_APIC(void)
                                "you can enable it with \"lapic\"\n");
                        return -1;
                }
-               /*
-                * Some BIOSes disable the local APIC in the APIC_BASE
-                * MSR. This can only be done in software for Intel P6 or later
-                * and AMD K7 (Model > 1) or later.
-                */
-               rdmsr(MSR_IA32_APICBASE, l, h);
-               if (!(l & MSR_IA32_APICBASE_ENABLE)) {
-                       pr_info("Local APIC disabled by BIOS -- reenabling.\n");
-                       l &= ~MSR_IA32_APICBASE_BASE;
-                       l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
-                       wrmsr(MSR_IA32_APICBASE, l, h);
-                       enabled_via_apicbase = 1;
-               }
-       }
-       /*
-        * The APIC feature bit should now be enabled
-        * in `cpuid'
-        */
-       features = cpuid_edx(1);
-       if (!(features & (1 << X86_FEATURE_APIC))) {
-               pr_warning("Could not enable APIC!\n");
-               return -1;
+               if (apic_force_enable())
+                       return -1;
+       } else {
+               if (apic_verify())
+                       return -1;
        }
-       set_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC);
-       mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-
-       /* The BIOS may have set up the APIC at some other address */
-       rdmsr(MSR_IA32_APICBASE, l, h);
-       if (l & MSR_IA32_APICBASE_ENABLE)
-               mp_lapic_addr = l & MSR_IA32_APICBASE_BASE;
-
-       pr_info("Found and enabled local APIC!\n");
 
        apic_pm_activate();
 
@@ -1609,28 +1630,6 @@ no_apic:
 }
 #endif
 
-#ifdef CONFIG_X86_64
-void __init early_init_lapic_mapping(void)
-{
-       /*
-        * If no local APIC can be found then go out
-        * : it means there is no mpatable and MADT
-        */
-       if (!smp_found_config)
-               return;
-
-       set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
-       apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n",
-                   APIC_BASE, mp_lapic_addr);
-
-       /*
-        * Fetch the APIC ID of the BSP in case we have a
-        * default configuration (or the MP table is broken).
-        */
-       boot_cpu_physical_apicid = read_apic_id();
-}
-#endif
-
 /**
  * init_apic_mappings - initialize APIC mappings
  */
@@ -1656,10 +1655,7 @@ void __init init_apic_mappings(void)
                 * acpi_register_lapic_address()
                 */
                if (!acpi_lapic && !smp_found_config)
-                       set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
-
-               apic_printk(APIC_VERBOSE, "mapped APIC to %08lx (%08lx)\n",
-                                       APIC_BASE, apic_phys);
+                       register_lapic_address(apic_phys);
        }
 
        /*
@@ -1681,11 +1677,27 @@ void __init init_apic_mappings(void)
        }
 }
 
+void __init register_lapic_address(unsigned long address)
+{
+       mp_lapic_addr = address;
+
+       if (!x2apic_mode) {
+               set_fixmap_nocache(FIX_APIC_BASE, address);
+               apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n",
+                           APIC_BASE, mp_lapic_addr);
+       }
+       if (boot_cpu_physical_apicid == -1U) {
+               boot_cpu_physical_apicid  = read_apic_id();
+               apic_version[boot_cpu_physical_apicid] =
+                        GET_APIC_VERSION(apic_read(APIC_LVR));
+       }
+}
+
 /*
  * This initializes the IO-APIC and APIC hardware if this is
  * a UP kernel.
  */
-int apic_version[MAX_APICS];
+int apic_version[MAX_LOCAL_APIC];
 
 int __init APIC_init_uniprocessor(void)
 {
@@ -1750,17 +1762,10 @@ int __init APIC_init_uniprocessor(void)
                setup_IO_APIC();
        else {
                nr_ioapics = 0;
-               localise_nmi_watchdog();
        }
-#else
-       localise_nmi_watchdog();
 #endif
 
        x86_init.timers.setup_percpu_clockev();
-#ifdef CONFIG_X86_64
-       check_nmi_watchdog();
-#endif
-
        return 0;
 }