|
@@ -81,6 +81,12 @@ physid_mask_t phys_cpu_present_map;
|
|
|
*/
|
|
|
static unsigned int disabled_cpu_apicid __read_mostly = BAD_APICID;
|
|
|
|
|
|
+/*
|
|
|
+ * This variable controls which CPUs receive external NMIs. By default,
|
|
|
+ * external NMIs are delivered only to the BSP.
|
|
|
+ */
|
|
|
+static int apic_extnmi = APIC_EXTNMI_BSP;
|
|
|
+
|
|
|
/*
|
|
|
* Map cpu index to physical APIC ID
|
|
|
*/
|
|
@@ -1161,6 +1167,8 @@ void __init init_bsp_APIC(void)
|
|
|
value = APIC_DM_NMI;
|
|
|
if (!lapic_is_integrated()) /* 82489DX */
|
|
|
value |= APIC_LVT_LEVEL_TRIGGER;
|
|
|
+ if (apic_extnmi == APIC_EXTNMI_NONE)
|
|
|
+ value |= APIC_LVT_MASKED;
|
|
|
apic_write(APIC_LVT1, value);
|
|
|
}
|
|
|
|
|
@@ -1378,9 +1386,11 @@ void setup_local_APIC(void)
|
|
|
apic_write(APIC_LVT0, value);
|
|
|
|
|
|
/*
|
|
|
- * only the BP should see the LINT1 NMI signal, obviously.
|
|
|
+ * Only the BSP sees the LINT1 NMI signal by default. This can be
|
|
|
+ * modified by apic_extnmi= boot option.
|
|
|
*/
|
|
|
- if (!cpu)
|
|
|
+ if ((!cpu && apic_extnmi != APIC_EXTNMI_NONE) ||
|
|
|
+ apic_extnmi == APIC_EXTNMI_ALL)
|
|
|
value = APIC_DM_NMI;
|
|
|
else
|
|
|
value = APIC_DM_NMI | APIC_LVT_MASKED;
|
|
@@ -2270,6 +2280,7 @@ static struct {
|
|
|
unsigned int apic_tmict;
|
|
|
unsigned int apic_tdcr;
|
|
|
unsigned int apic_thmr;
|
|
|
+ unsigned int apic_cmci;
|
|
|
} apic_pm_state;
|
|
|
|
|
|
static int lapic_suspend(void)
|
|
@@ -2299,6 +2310,10 @@ static int lapic_suspend(void)
|
|
|
if (maxlvt >= 5)
|
|
|
apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
|
|
|
#endif
|
|
|
+#ifdef CONFIG_X86_MCE_INTEL
|
|
|
+ if (maxlvt >= 6)
|
|
|
+ apic_pm_state.apic_cmci = apic_read(APIC_LVTCMCI);
|
|
|
+#endif
|
|
|
|
|
|
local_irq_save(flags);
|
|
|
disable_local_APIC();
|
|
@@ -2355,9 +2370,13 @@ static void lapic_resume(void)
|
|
|
apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
|
|
|
apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
|
|
|
apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
|
|
|
-#if defined(CONFIG_X86_MCE_INTEL)
|
|
|
+#ifdef CONFIG_X86_THERMAL_VECTOR
|
|
|
if (maxlvt >= 5)
|
|
|
apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_X86_MCE_INTEL
|
|
|
+ if (maxlvt >= 6)
|
|
|
+ apic_write(APIC_LVTCMCI, apic_pm_state.apic_cmci);
|
|
|
#endif
|
|
|
if (maxlvt >= 4)
|
|
|
apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
|
|
@@ -2548,3 +2567,23 @@ static int __init apic_set_disabled_cpu_apicid(char *arg)
|
|
|
return 0;
|
|
|
}
|
|
|
early_param("disable_cpu_apicid", apic_set_disabled_cpu_apicid);
|
|
|
+
|
|
|
+static int __init apic_set_extnmi(char *arg)
|
|
|
+{
|
|
|
+ if (!arg)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!strncmp("all", arg, 3))
|
|
|
+ apic_extnmi = APIC_EXTNMI_ALL;
|
|
|
+ else if (!strncmp("none", arg, 4))
|
|
|
+ apic_extnmi = APIC_EXTNMI_NONE;
|
|
|
+ else if (!strncmp("bsp", arg, 3))
|
|
|
+ apic_extnmi = APIC_EXTNMI_BSP;
|
|
|
+ else {
|
|
|
+ pr_warn("Unknown external NMI delivery mode `%s' ignored\n", arg);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+early_param("apic_extnmi", apic_set_extnmi);
|