Commit 1a7dbbcc authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86/apic changes from Ingo Molnar:
 "Two main changes:

   - improve local APIC Error Status Register reporting robustness

   - add the 'disable_cpu_apicid=x' boot parameter for kexec booting"

* 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86, apic: Make disabled_cpu_apicid static read_mostly, fix typos
  x86, apic, kexec: Add disable_cpu_apicid kernel parameter
  x86/apic: Read Error Status Register correctly
parents 6c646143 5b4d1dbc
...@@ -774,6 +774,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -774,6 +774,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
disable= [IPV6] disable= [IPV6]
See Documentation/networking/ipv6.txt. See Documentation/networking/ipv6.txt.
disable_cpu_apicid= [X86,APIC,SMP]
Format: <int>
The number of initial APIC ID for the
corresponding CPU to be disabled at boot,
mostly used for the kdump 2nd kernel to
disable BSP to wake up multiple CPUs without
causing system reset or hang due to sending
INIT from AP to BSP.
disable_ddw [PPC/PSERIES] disable_ddw [PPC/PSERIES]
Disable Dynamic DMA Window support. Use this if Disable Dynamic DMA Window support. Use this if
to workaround buggy firmware. to workaround buggy firmware.
......
...@@ -74,6 +74,13 @@ unsigned int max_physical_apicid; ...@@ -74,6 +74,13 @@ unsigned int max_physical_apicid;
*/ */
physid_mask_t phys_cpu_present_map; 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 * Map cpu index to physical APIC ID
*/ */
...@@ -1968,7 +1975,7 @@ __visible void smp_trace_spurious_interrupt(struct pt_regs *regs) ...@@ -1968,7 +1975,7 @@ __visible void smp_trace_spurious_interrupt(struct pt_regs *regs)
*/ */
static inline void __smp_error_interrupt(struct pt_regs *regs) static inline void __smp_error_interrupt(struct pt_regs *regs)
{ {
u32 v0, v1; u32 v;
u32 i = 0; u32 i = 0;
static const char * const error_interrupt_reason[] = { static const char * const error_interrupt_reason[] = {
"Send CS error", /* APIC Error Bit 0 */ "Send CS error", /* APIC Error Bit 0 */
...@@ -1982,21 +1989,20 @@ static inline void __smp_error_interrupt(struct pt_regs *regs) ...@@ -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 */ /* First tickle the hardware, only then report what went on. -- REW */
v0 = apic_read(APIC_ESR);
apic_write(APIC_ESR, 0); apic_write(APIC_ESR, 0);
v1 = apic_read(APIC_ESR); v = apic_read(APIC_ESR);
ack_APIC_irq(); ack_APIC_irq();
atomic_inc(&irq_err_count); atomic_inc(&irq_err_count);
apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x(%02x)", apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x",
smp_processor_id(), v0 , v1); smp_processor_id(), v);
v1 = v1 & 0xff; v &= 0xff;
while (v1) { while (v) {
if (v1 & 0x1) if (v & 0x1)
apic_printk(APIC_DEBUG, KERN_CONT " : %s", error_interrupt_reason[i]); apic_printk(APIC_DEBUG, KERN_CONT " : %s", error_interrupt_reason[i]);
i++; i++;
v1 >>= 1; v >>= 1;
} }
apic_printk(APIC_DEBUG, KERN_CONT "\n"); apic_printk(APIC_DEBUG, KERN_CONT "\n");
...@@ -2114,6 +2120,39 @@ int generic_processor_info(int apicid, int version) ...@@ -2114,6 +2120,39 @@ int generic_processor_info(int apicid, int version)
bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid, bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid,
phys_cpu_present_map); 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 * 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 * nr_cpu_ids - 1 processors and keep one slot free for boot cpu
...@@ -2592,3 +2631,12 @@ static int __init lapic_insert_resource(void) ...@@ -2592,3 +2631,12 @@ static int __init lapic_insert_resource(void)
* that is using request_resource * that is using request_resource
*/ */
late_initcall(lapic_insert_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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment