|
@@ -1531,13 +1531,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;
|
|
@@ -1567,38 +1614,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();
|
|
|
|