Merge branches 'pm-cpufreq', 'pm-cpuidle', 'pm-devfreq', 'pm-opp' and 'pm-tools'
[linux-drm-fsl-dcu.git] / arch / x86 / kernel / apic / apic.c
index 29b5b18afa27dca80d384fade47906299a581e8f..b665d241efaddc6e34880897db45b8de669ed2e0 100644 (file)
@@ -134,9 +134,6 @@ static inline void imcr_apic_to_pic(void)
  */
 static int force_enable_local_apic __initdata;
 
-/* Control whether x2APIC mode is enabled or not */
-static bool nox2apic __initdata;
-
 /*
  * APIC command line parameters
  */
@@ -161,33 +158,6 @@ static __init int setup_apicpmtimer(char *s)
 __setup("apicpmtimer", setup_apicpmtimer);
 #endif
 
-int x2apic_mode;
-#ifdef CONFIG_X86_X2APIC
-/* x2apic enabled before OS handover */
-int x2apic_preenabled;
-static int x2apic_disabled;
-static int __init setup_nox2apic(char *str)
-{
-       if (x2apic_enabled()) {
-               int apicid = native_apic_msr_read(APIC_ID);
-
-               if (apicid >= 255) {
-                       pr_warning("Apicid: %08x, cannot enforce nox2apic\n",
-                                  apicid);
-                       return 0;
-               }
-
-               pr_warning("x2apic already enabled. will disable it\n");
-       } else
-               setup_clear_cpu_cap(X86_FEATURE_X2APIC);
-
-       nox2apic = true;
-
-       return 0;
-}
-early_param("nox2apic", setup_nox2apic);
-#endif
-
 unsigned long mp_lapic_addr;
 int disable_apic;
 /* Disable local APIC timer from the kernel commandline or via dmi quirk */
@@ -1475,7 +1445,7 @@ void setup_local_APIC(void)
 #endif
 }
 
-void end_local_APIC_setup(void)
+static void end_local_APIC_setup(void)
 {
        lapic_setup_esr();
 
@@ -1492,116 +1462,184 @@ void end_local_APIC_setup(void)
        apic_pm_activate();
 }
 
-void __init bsp_end_local_APIC_setup(void)
+/*
+ * APIC setup function for application processors. Called from smpboot.c
+ */
+void apic_ap_setup(void)
 {
+       setup_local_APIC();
        end_local_APIC_setup();
-
-       /*
-        * Now that local APIC setup is completed for BP, configure the fault
-        * handling for interrupt remapping.
-        */
-       irq_remap_enable_fault_handling();
-
 }
 
 #ifdef CONFIG_X86_X2APIC
-/*
- * Need to disable xapic and x2apic at the same time and then enable xapic mode
- */
-static inline void __disable_x2apic(u64 msr)
-{
-       wrmsrl(MSR_IA32_APICBASE,
-              msr & ~(X2APIC_ENABLE | XAPIC_ENABLE));
-       wrmsrl(MSR_IA32_APICBASE, msr & ~X2APIC_ENABLE);
-}
+int x2apic_mode;
 
-static __init void disable_x2apic(void)
+enum {
+       X2APIC_OFF,
+       X2APIC_ON,
+       X2APIC_DISABLED,
+};
+static int x2apic_state;
+
+static inline void __x2apic_disable(void)
 {
        u64 msr;
 
-       if (!cpu_has_x2apic)
+       if (cpu_has_apic)
                return;
 
        rdmsrl(MSR_IA32_APICBASE, msr);
-       if (msr & X2APIC_ENABLE) {
-               u32 x2apic_id = read_apic_id();
-
-               if (x2apic_id >= 255)
-                       panic("Cannot disable x2apic, id: %08x\n", x2apic_id);
+       if (!(msr & X2APIC_ENABLE))
+               return;
+       /* Disable xapic and x2apic first and then reenable xapic mode */
+       wrmsrl(MSR_IA32_APICBASE, msr & ~(X2APIC_ENABLE | XAPIC_ENABLE));
+       wrmsrl(MSR_IA32_APICBASE, msr & ~X2APIC_ENABLE);
+       printk_once(KERN_INFO "x2apic disabled\n");
+}
 
-               pr_info("Disabling x2apic\n");
-               __disable_x2apic(msr);
+static inline void __x2apic_enable(void)
+{
+       u64 msr;
 
-               if (nox2apic) {
-                       clear_cpu_cap(&cpu_data(0), X86_FEATURE_X2APIC);
-                       setup_clear_cpu_cap(X86_FEATURE_X2APIC);
-               }
+       rdmsrl(MSR_IA32_APICBASE, msr);
+       if (msr & X2APIC_ENABLE)
+               return;
+       wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE);
+       printk_once(KERN_INFO "x2apic enabled\n");
+}
 
-               x2apic_disabled = 1;
-               x2apic_mode = 0;
+static int __init setup_nox2apic(char *str)
+{
+       if (x2apic_enabled()) {
+               int apicid = native_apic_msr_read(APIC_ID);
 
-               register_lapic_address(mp_lapic_addr);
+               if (apicid >= 255) {
+                       pr_warning("Apicid: %08x, cannot enforce nox2apic\n",
+                                  apicid);
+                       return 0;
+               }
+               pr_warning("x2apic already enabled.\n");
+               __x2apic_disable();
        }
+       setup_clear_cpu_cap(X86_FEATURE_X2APIC);
+       x2apic_state = X2APIC_DISABLED;
+       x2apic_mode = 0;
+       return 0;
 }
+early_param("nox2apic", setup_nox2apic);
 
-void check_x2apic(void)
+/* Called from cpu_init() to enable x2apic on (secondary) cpus */
+void x2apic_setup(void)
 {
-       if (x2apic_enabled()) {
-               pr_info("x2apic enabled by BIOS, switching to x2apic ops\n");
-               x2apic_preenabled = x2apic_mode = 1;
+       /*
+        * If x2apic is not in ON state, disable it if already enabled
+        * from BIOS.
+        */
+       if (x2apic_state != X2APIC_ON) {
+               __x2apic_disable();
+               return;
        }
+       __x2apic_enable();
 }
 
-void enable_x2apic(void)
+static __init void x2apic_disable(void)
 {
-       u64 msr;
+       u32 x2apic_id;
 
-       rdmsrl(MSR_IA32_APICBASE, msr);
-       if (x2apic_disabled) {
-               __disable_x2apic(msr);
+       if (x2apic_state != X2APIC_ON)
+               goto out;
+
+       x2apic_id = read_apic_id();
+       if (x2apic_id >= 255)
+               panic("Cannot disable x2apic, id: %08x\n", x2apic_id);
+
+       __x2apic_disable();
+       register_lapic_address(mp_lapic_addr);
+out:
+       x2apic_state = X2APIC_DISABLED;
+       x2apic_mode = 0;
+}
+
+static __init void x2apic_enable(void)
+{
+       if (x2apic_state != X2APIC_OFF)
                return;
-       }
 
-       if (!x2apic_mode)
+       x2apic_mode = 1;
+       x2apic_state = X2APIC_ON;
+       __x2apic_enable();
+}
+
+static __init void try_to_enable_x2apic(int remap_mode)
+{
+       if (x2apic_state == X2APIC_DISABLED)
                return;
 
-       if (!(msr & X2APIC_ENABLE)) {
-               printk_once(KERN_INFO "Enabling x2apic\n");
-               wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE);
+       if (remap_mode != IRQ_REMAP_X2APIC_MODE) {
+               /* IR is required if there is APIC ID > 255 even when running
+                * under KVM
+                */
+               if (max_physical_apicid > 255 ||
+                   (IS_ENABLED(CONFIG_HYPERVISOR_GUEST) &&
+                    !hypervisor_x2apic_available())) {
+                       pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n");
+                       x2apic_disable();
+                       return;
+               }
+
+               /*
+                * without IR all CPUs can be addressed by IOAPIC/MSI
+                * only in physical mode
+                */
+               x2apic_phys = 1;
        }
+       x2apic_enable();
 }
-#endif /* CONFIG_X86_X2APIC */
 
-int __init enable_IR(void)
+void __init check_x2apic(void)
 {
-#ifdef CONFIG_IRQ_REMAP
-       if (!irq_remapping_supported()) {
-               pr_debug("intr-remapping not supported\n");
-               return -1;
+       if (x2apic_enabled()) {
+               pr_info("x2apic: enabled by BIOS, switching to x2apic ops\n");
+               x2apic_mode = 1;
+               x2apic_state = X2APIC_ON;
+       } else if (!cpu_has_x2apic) {
+               x2apic_state = X2APIC_DISABLED;
        }
+}
+#else /* CONFIG_X86_X2APIC */
+static int __init validate_x2apic(void)
+{
+       if (!apic_is_x2apic_enabled())
+               return 0;
+       /*
+        * Checkme: Can we simply turn off x2apic here instead of panic?
+        */
+       panic("BIOS has enabled x2apic but kernel doesn't support x2apic, please disable x2apic in BIOS.\n");
+}
+early_initcall(validate_x2apic);
 
-       if (!x2apic_preenabled && skip_ioapic_setup) {
-               pr_info("Skipped enabling intr-remap because of skipping "
-                       "io-apic setup\n");
+static inline void try_to_enable_x2apic(int remap_mode) { }
+static inline void __x2apic_enable(void) { }
+#endif /* !CONFIG_X86_X2APIC */
+
+static int __init try_to_enable_IR(void)
+{
+#ifdef CONFIG_X86_IO_APIC
+       if (!x2apic_enabled() && skip_ioapic_setup) {
+               pr_info("Not enabling interrupt remapping due to skipped IO-APIC setup\n");
                return -1;
        }
-
-       return irq_remapping_enable();
 #endif
-       return -1;
+       return irq_remapping_enable();
 }
 
 void __init enable_IR_x2apic(void)
 {
        unsigned long flags;
-       int ret, x2apic_enabled = 0;
-       int hardware_init_ret;
-
-       /* Make sure irq_remap_ops are initialized */
-       setup_irq_remapping_ops();
+       int ret, ir_stat;
 
-       hardware_init_ret = irq_remapping_prepare();
-       if (hardware_init_ret && !x2apic_supported())
+       ir_stat = irq_remapping_prepare();
+       if (ir_stat < 0 && !x2apic_supported())
                return;
 
        ret = save_ioapic_entries();
@@ -1614,49 +1652,13 @@ void __init enable_IR_x2apic(void)
        legacy_pic->mask_all();
        mask_ioapic_entries();
 
-       if (x2apic_preenabled && nox2apic)
-               disable_x2apic();
-
-       if (hardware_init_ret)
-               ret = -1;
-       else
-               ret = enable_IR();
-
-       if (!x2apic_supported())
-               goto skip_x2apic;
+       /* If irq_remapping_prepare() succeded, try to enable it */
+       if (ir_stat >= 0)
+               ir_stat = try_to_enable_IR();
+       /* ir_stat contains the remap mode or an error code */
+       try_to_enable_x2apic(ir_stat);
 
-       if (ret < 0) {
-               /* IR is required if there is APIC ID > 255 even when running
-                * under KVM
-                */
-               if (max_physical_apicid > 255 ||
-                   !hypervisor_x2apic_available()) {
-                       if (x2apic_preenabled)
-                               disable_x2apic();
-                       goto skip_x2apic;
-               }
-               /*
-                * without IR all CPUs can be addressed by IOAPIC/MSI
-                * only in physical mode
-                */
-               x2apic_force_phys();
-       }
-
-       if (ret == IRQ_REMAP_XAPIC_MODE) {
-               pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n");
-               goto skip_x2apic;
-       }
-
-       x2apic_enabled = 1;
-
-       if (x2apic_supported() && !x2apic_mode) {
-               x2apic_mode = 1;
-               enable_x2apic();
-               pr_info("Enabled x2apic\n");
-       }
-
-skip_x2apic:
-       if (ret < 0) /* IR enabling failed */
+       if (ir_stat < 0)
                restore_ioapic_entries();
        legacy_pic->restore_mask();
        local_irq_restore(flags);
@@ -1847,82 +1849,8 @@ void __init register_lapic_address(unsigned long address)
        }
 }
 
-/*
- * This initializes the IO-APIC and APIC hardware if this is
- * a UP kernel.
- */
 int apic_version[MAX_LOCAL_APIC];
 
-int __init APIC_init_uniprocessor(void)
-{
-       if (disable_apic) {
-               pr_info("Apic disabled\n");
-               return -1;
-       }
-#ifdef CONFIG_X86_64
-       if (!cpu_has_apic) {
-               disable_apic = 1;
-               pr_info("Apic disabled by BIOS\n");
-               return -1;
-       }
-#else
-       if (!smp_found_config && !cpu_has_apic)
-               return -1;
-
-       /*
-        * Complain if the BIOS pretends there is one.
-        */
-       if (!cpu_has_apic &&
-           APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
-               pr_err("BIOS bug, local APIC 0x%x not detected!...\n",
-                       boot_cpu_physical_apicid);
-               return -1;
-       }
-#endif
-
-       default_setup_apic_routing();
-
-       verify_local_APIC();
-       connect_bsp_APIC();
-
-#ifdef CONFIG_X86_64
-       apic_write(APIC_ID, SET_APIC_ID(boot_cpu_physical_apicid));
-#else
-       /*
-        * Hack: In case of kdump, after a crash, kernel might be booting
-        * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid
-        * might be zero if read from MP tables. Get it from LAPIC.
-        */
-# ifdef CONFIG_CRASH_DUMP
-       boot_cpu_physical_apicid = read_apic_id();
-# endif
-#endif
-       physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
-       setup_local_APIC();
-
-#ifdef CONFIG_X86_IO_APIC
-       /*
-        * Now enable IO-APICs, actually call clear_IO_APIC
-        * We need clear_IO_APIC before enabling error vector
-        */
-       if (!skip_ioapic_setup && nr_ioapics)
-               enable_IO_APIC();
-#endif
-
-       bsp_end_local_APIC_setup();
-
-#ifdef CONFIG_X86_IO_APIC
-       if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
-               setup_IO_APIC();
-       else {
-               nr_ioapics = 0;
-       }
-#endif
-
-       x86_init.timers.setup_percpu_clockev();
-       return 0;
-}
-
 /*
  * Local APIC interrupts
  */
@@ -2027,7 +1955,7 @@ __visible void smp_trace_error_interrupt(struct pt_regs *regs)
 /**
  * connect_bsp_APIC - attach the APIC to the interrupt system
  */
-void __init connect_bsp_APIC(void)
+static void __init connect_bsp_APIC(void)
 {
 #ifdef CONFIG_X86_32
        if (pic_mode) {
@@ -2274,6 +2202,100 @@ void __init apic_set_eoi_write(void (*eoi_write)(u32 reg, u32 v))
        }
 }
 
+static void __init apic_bsp_up_setup(void)
+{
+#ifdef CONFIG_X86_64
+       apic_write(APIC_ID, SET_APIC_ID(boot_cpu_physical_apicid));
+#else
+       /*
+        * Hack: In case of kdump, after a crash, kernel might be booting
+        * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid
+        * might be zero if read from MP tables. Get it from LAPIC.
+        */
+# ifdef CONFIG_CRASH_DUMP
+       boot_cpu_physical_apicid = read_apic_id();
+# endif
+#endif
+       physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
+}
+
+/**
+ * apic_bsp_setup - Setup function for local apic and io-apic
+ * @upmode:            Force UP mode (for APIC_init_uniprocessor)
+ *
+ * Returns:
+ * apic_id of BSP APIC
+ */
+int __init apic_bsp_setup(bool upmode)
+{
+       int id;
+
+       connect_bsp_APIC();
+       if (upmode)
+               apic_bsp_up_setup();
+       setup_local_APIC();
+
+       if (x2apic_mode)
+               id = apic_read(APIC_LDR);
+       else
+               id = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
+
+       enable_IO_APIC();
+       end_local_APIC_setup();
+       irq_remap_enable_fault_handling();
+       setup_IO_APIC();
+       /* Setup local timer */
+       x86_init.timers.setup_percpu_clockev();
+       return id;
+}
+
+/*
+ * This initializes the IO-APIC and APIC hardware if this is
+ * a UP kernel.
+ */
+int __init APIC_init_uniprocessor(void)
+{
+       if (disable_apic) {
+               pr_info("Apic disabled\n");
+               return -1;
+       }
+#ifdef CONFIG_X86_64
+       if (!cpu_has_apic) {
+               disable_apic = 1;
+               pr_info("Apic disabled by BIOS\n");
+               return -1;
+       }
+#else
+       if (!smp_found_config && !cpu_has_apic)
+               return -1;
+
+       /*
+        * Complain if the BIOS pretends there is one.
+        */
+       if (!cpu_has_apic &&
+           APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
+               pr_err("BIOS bug, local APIC 0x%x not detected!...\n",
+                       boot_cpu_physical_apicid);
+               return -1;
+       }
+#endif
+
+       if (!smp_found_config)
+               disable_ioapic_support();
+
+       default_setup_apic_routing();
+       verify_local_APIC();
+       apic_bsp_setup(true);
+       return 0;
+}
+
+#ifdef CONFIG_UP_LATE_INIT
+void __init up_late_init(void)
+{
+       APIC_init_uniprocessor();
+}
+#endif
+
 /*
  * Power management
  */
@@ -2359,9 +2381,9 @@ static void lapic_resume(void)
        mask_ioapic_entries();
        legacy_pic->mask_all();
 
-       if (x2apic_mode)
-               enable_x2apic();
-       else {
+       if (x2apic_mode) {
+               __x2apic_enable();
+       else {
                /*
                 * Make sure the APICBASE points to the right address
                 *