Skip to content

Commit 1a7dbbc

Browse files
committed
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
2 parents 6c64614 + 5b4d1db commit 1a7dbbc

File tree

2 files changed

+66
-9
lines changed

2 files changed

+66
-9
lines changed

Documentation/kernel-parameters.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
774774
disable= [IPV6]
775775
See Documentation/networking/ipv6.txt.
776776

777+
disable_cpu_apicid= [X86,APIC,SMP]
778+
Format: <int>
779+
The number of initial APIC ID for the
780+
corresponding CPU to be disabled at boot,
781+
mostly used for the kdump 2nd kernel to
782+
disable BSP to wake up multiple CPUs without
783+
causing system reset or hang due to sending
784+
INIT from AP to BSP.
785+
777786
disable_ddw [PPC/PSERIES]
778787
Disable Dynamic DMA Window support. Use this if
779788
to workaround buggy firmware.

arch/x86/kernel/apic/apic.c

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ unsigned int max_physical_apicid;
7474
*/
7575
physid_mask_t phys_cpu_present_map;
7676

77+
/*
78+
* Processor to be disabled specified by kernel parameter
79+
* disable_cpu_apicid=<int>, mostly used for the kdump 2nd kernel to
80+
* avoid undefined behaviour caused by sending INIT from AP to BSP.
81+
*/
82+
static unsigned int disabled_cpu_apicid __read_mostly = BAD_APICID;
83+
7784
/*
7885
* Map cpu index to physical APIC ID
7986
*/
@@ -1968,7 +1975,7 @@ __visible void smp_trace_spurious_interrupt(struct pt_regs *regs)
19681975
*/
19691976
static inline void __smp_error_interrupt(struct pt_regs *regs)
19701977
{
1971-
u32 v0, v1;
1978+
u32 v;
19721979
u32 i = 0;
19731980
static const char * const error_interrupt_reason[] = {
19741981
"Send CS error", /* APIC Error Bit 0 */
@@ -1982,21 +1989,20 @@ static inline void __smp_error_interrupt(struct pt_regs *regs)
19821989
};
19831990

19841991
/* First tickle the hardware, only then report what went on. -- REW */
1985-
v0 = apic_read(APIC_ESR);
19861992
apic_write(APIC_ESR, 0);
1987-
v1 = apic_read(APIC_ESR);
1993+
v = apic_read(APIC_ESR);
19881994
ack_APIC_irq();
19891995
atomic_inc(&irq_err_count);
19901996

1991-
apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x(%02x)",
1992-
smp_processor_id(), v0 , v1);
1997+
apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x",
1998+
smp_processor_id(), v);
19931999

1994-
v1 = v1 & 0xff;
1995-
while (v1) {
1996-
if (v1 & 0x1)
2000+
v &= 0xff;
2001+
while (v) {
2002+
if (v & 0x1)
19972003
apic_printk(APIC_DEBUG, KERN_CONT " : %s", error_interrupt_reason[i]);
19982004
i++;
1999-
v1 >>= 1;
2005+
v >>= 1;
20002006
}
20012007

20022008
apic_printk(APIC_DEBUG, KERN_CONT "\n");
@@ -2114,6 +2120,39 @@ int generic_processor_info(int apicid, int version)
21142120
bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid,
21152121
phys_cpu_present_map);
21162122

2123+
/*
2124+
* boot_cpu_physical_apicid is designed to have the apicid
2125+
* returned by read_apic_id(), i.e, the apicid of the
2126+
* currently booting-up processor. However, on some platforms,
2127+
* it is temporarily modified by the apicid reported as BSP
2128+
* through MP table. Concretely:
2129+
*
2130+
* - arch/x86/kernel/mpparse.c: MP_processor_info()
2131+
* - arch/x86/mm/amdtopology.c: amd_numa_init()
2132+
* - arch/x86/platform/visws/visws_quirks.c: MP_processor_info()
2133+
*
2134+
* This function is executed with the modified
2135+
* boot_cpu_physical_apicid. So, disabled_cpu_apicid kernel
2136+
* parameter doesn't work to disable APs on kdump 2nd kernel.
2137+
*
2138+
* Since fixing handling of boot_cpu_physical_apicid requires
2139+
* another discussion and tests on each platform, we leave it
2140+
* for now and here we use read_apic_id() directly in this
2141+
* function, generic_processor_info().
2142+
*/
2143+
if (disabled_cpu_apicid != BAD_APICID &&
2144+
disabled_cpu_apicid != read_apic_id() &&
2145+
disabled_cpu_apicid == apicid) {
2146+
int thiscpu = num_processors + disabled_cpus;
2147+
2148+
pr_warning("APIC: Disabling requested cpu."
2149+
" Processor %d/0x%x ignored.\n",
2150+
thiscpu, apicid);
2151+
2152+
disabled_cpus++;
2153+
return -ENODEV;
2154+
}
2155+
21172156
/*
21182157
* If boot cpu has not been detected yet, then only allow upto
21192158
* nr_cpu_ids - 1 processors and keep one slot free for boot cpu
@@ -2592,3 +2631,12 @@ static int __init lapic_insert_resource(void)
25922631
* that is using request_resource
25932632
*/
25942633
late_initcall(lapic_insert_resource);
2634+
2635+
static int __init apic_set_disabled_cpu_apicid(char *arg)
2636+
{
2637+
if (!arg || !get_option(&arg, &disabled_cpu_apicid))
2638+
return -EINVAL;
2639+
2640+
return 0;
2641+
}
2642+
early_param("disable_cpu_apicid", apic_set_disabled_cpu_apicid);

0 commit comments

Comments
 (0)