|
@@ -74,6 +74,13 @@ unsigned int max_physical_apicid;
|
|
|
*/
|
|
|
physid_mask_t phys_cpu_present_map;
|
|
|
|
|
|
+/*
|
|
|
+ * Processor to be disabled specified by kernel parameter
|
|
|
+ * disable_cpu_apicid=<int>, mostly used for the kdump 2nd kernel to
|
|
|
+ * avoid undefined behaviour caused by sending INIT from AP to BSP.
|
|
|
+ */
|
|
|
+static unsigned int disabled_cpu_apicid __read_mostly = BAD_APICID;
|
|
|
+
|
|
|
/*
|
|
|
* Map cpu index to physical APIC ID
|
|
|
*/
|
|
@@ -1968,7 +1975,7 @@ __visible void smp_trace_spurious_interrupt(struct pt_regs *regs)
|
|
|
*/
|
|
|
static inline void __smp_error_interrupt(struct pt_regs *regs)
|
|
|
{
|
|
|
- u32 v0, v1;
|
|
|
+ u32 v;
|
|
|
u32 i = 0;
|
|
|
static const char * const error_interrupt_reason[] = {
|
|
|
"Send CS error", /* APIC Error Bit 0 */
|
|
@@ -1982,21 +1989,20 @@ static inline void __smp_error_interrupt(struct pt_regs *regs)
|
|
|
};
|
|
|
|
|
|
/* First tickle the hardware, only then report what went on. -- REW */
|
|
|
- v0 = apic_read(APIC_ESR);
|
|
|
apic_write(APIC_ESR, 0);
|
|
|
- v1 = apic_read(APIC_ESR);
|
|
|
+ v = apic_read(APIC_ESR);
|
|
|
ack_APIC_irq();
|
|
|
atomic_inc(&irq_err_count);
|
|
|
|
|
|
- apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x(%02x)",
|
|
|
- smp_processor_id(), v0 , v1);
|
|
|
+ apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x",
|
|
|
+ smp_processor_id(), v);
|
|
|
|
|
|
- v1 = v1 & 0xff;
|
|
|
- while (v1) {
|
|
|
- if (v1 & 0x1)
|
|
|
+ v &= 0xff;
|
|
|
+ while (v) {
|
|
|
+ if (v & 0x1)
|
|
|
apic_printk(APIC_DEBUG, KERN_CONT " : %s", error_interrupt_reason[i]);
|
|
|
i++;
|
|
|
- v1 >>= 1;
|
|
|
+ v >>= 1;
|
|
|
}
|
|
|
|
|
|
apic_printk(APIC_DEBUG, KERN_CONT "\n");
|
|
@@ -2114,6 +2120,39 @@ int generic_processor_info(int apicid, int version)
|
|
|
bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid,
|
|
|
phys_cpu_present_map);
|
|
|
|
|
|
+ /*
|
|
|
+ * boot_cpu_physical_apicid is designed to have the apicid
|
|
|
+ * returned by read_apic_id(), i.e, the apicid of the
|
|
|
+ * currently booting-up processor. However, on some platforms,
|
|
|
+ * it is temporarily modified by the apicid reported as BSP
|
|
|
+ * through MP table. Concretely:
|
|
|
+ *
|
|
|
+ * - arch/x86/kernel/mpparse.c: MP_processor_info()
|
|
|
+ * - arch/x86/mm/amdtopology.c: amd_numa_init()
|
|
|
+ * - arch/x86/platform/visws/visws_quirks.c: MP_processor_info()
|
|
|
+ *
|
|
|
+ * This function is executed with the modified
|
|
|
+ * boot_cpu_physical_apicid. So, disabled_cpu_apicid kernel
|
|
|
+ * parameter doesn't work to disable APs on kdump 2nd kernel.
|
|
|
+ *
|
|
|
+ * Since fixing handling of boot_cpu_physical_apicid requires
|
|
|
+ * another discussion and tests on each platform, we leave it
|
|
|
+ * for now and here we use read_apic_id() directly in this
|
|
|
+ * function, generic_processor_info().
|
|
|
+ */
|
|
|
+ if (disabled_cpu_apicid != BAD_APICID &&
|
|
|
+ disabled_cpu_apicid != read_apic_id() &&
|
|
|
+ disabled_cpu_apicid == apicid) {
|
|
|
+ int thiscpu = num_processors + disabled_cpus;
|
|
|
+
|
|
|
+ pr_warning("APIC: Disabling requested cpu."
|
|
|
+ " Processor %d/0x%x ignored.\n",
|
|
|
+ thiscpu, apicid);
|
|
|
+
|
|
|
+ disabled_cpus++;
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* If boot cpu has not been detected yet, then only allow upto
|
|
|
* nr_cpu_ids - 1 processors and keep one slot free for boot cpu
|
|
@@ -2592,3 +2631,12 @@ static int __init lapic_insert_resource(void)
|
|
|
* that is using request_resource
|
|
|
*/
|
|
|
late_initcall(lapic_insert_resource);
|
|
|
+
|
|
|
+static int __init apic_set_disabled_cpu_apicid(char *arg)
|
|
|
+{
|
|
|
+ if (!arg || !get_option(&arg, &disabled_cpu_apicid))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+early_param("disable_cpu_apicid", apic_set_disabled_cpu_apicid);
|