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: "An xAPIC CPU hotplug race fix, plus cleanups and minor fixes" * 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/apic: Plug racy xAPIC access of CPU hotplug code x86/apic: Always define nox2apic and define it as initdata x86/apic: Remove unused function prototypes x86/apic: Switch wait_for_init_deassert() to a bool flag x86/apic: Only use default_wait_for_init_deassert()
This commit is contained in:
commit
6ed7705167
|
@ -93,9 +93,6 @@ static inline int is_vsmp_box(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
extern void xapic_wait_icr_idle(void);
|
|
||||||
extern u32 safe_xapic_wait_icr_idle(void);
|
|
||||||
extern void xapic_icr_write(u32, u32);
|
|
||||||
extern int setup_profiling_timer(unsigned int);
|
extern int setup_profiling_timer(unsigned int);
|
||||||
|
|
||||||
static inline void native_apic_mem_write(u32 reg, u32 v)
|
static inline void native_apic_mem_write(u32 reg, u32 v)
|
||||||
|
@ -184,7 +181,6 @@ extern int x2apic_phys;
|
||||||
extern int x2apic_preenabled;
|
extern int x2apic_preenabled;
|
||||||
extern void check_x2apic(void);
|
extern void check_x2apic(void);
|
||||||
extern void enable_x2apic(void);
|
extern void enable_x2apic(void);
|
||||||
extern void x2apic_icr_write(u32 low, u32 id);
|
|
||||||
static inline int x2apic_enabled(void)
|
static inline int x2apic_enabled(void)
|
||||||
{
|
{
|
||||||
u64 msr;
|
u64 msr;
|
||||||
|
@ -221,7 +217,6 @@ static inline void x2apic_force_phys(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#define nox2apic 0
|
|
||||||
#define x2apic_preenabled 0
|
#define x2apic_preenabled 0
|
||||||
#define x2apic_supported() 0
|
#define x2apic_supported() 0
|
||||||
#endif
|
#endif
|
||||||
|
@ -351,7 +346,7 @@ struct apic {
|
||||||
int trampoline_phys_low;
|
int trampoline_phys_low;
|
||||||
int trampoline_phys_high;
|
int trampoline_phys_high;
|
||||||
|
|
||||||
void (*wait_for_init_deassert)(atomic_t *deassert);
|
bool wait_for_init_deassert;
|
||||||
void (*smp_callin_clear_local_apic)(void);
|
void (*smp_callin_clear_local_apic)(void);
|
||||||
void (*inquire_remote_apic)(int apicid);
|
void (*inquire_remote_apic)(int apicid);
|
||||||
|
|
||||||
|
@ -517,13 +512,6 @@ extern int default_cpu_present_to_apicid(int mps_cpu);
|
||||||
extern int default_check_phys_apicid_present(int phys_apicid);
|
extern int default_check_phys_apicid_present(int phys_apicid);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void default_wait_for_init_deassert(atomic_t *deassert)
|
|
||||||
{
|
|
||||||
while (!atomic_read(deassert))
|
|
||||||
cpu_relax();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void generic_bigsmp_probe(void);
|
extern void generic_bigsmp_probe(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,10 @@ static inline void imcr_apic_to_pic(void)
|
||||||
* +1=force-enable
|
* +1=force-enable
|
||||||
*/
|
*/
|
||||||
static int force_enable_local_apic __initdata;
|
static int force_enable_local_apic __initdata;
|
||||||
|
|
||||||
|
/* Control whether x2APIC mode is enabled or not */
|
||||||
|
static bool nox2apic __initdata;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* APIC command line parameters
|
* APIC command line parameters
|
||||||
*/
|
*/
|
||||||
|
@ -162,8 +166,7 @@ int x2apic_mode;
|
||||||
/* x2apic enabled before OS handover */
|
/* x2apic enabled before OS handover */
|
||||||
int x2apic_preenabled;
|
int x2apic_preenabled;
|
||||||
static int x2apic_disabled;
|
static int x2apic_disabled;
|
||||||
static int nox2apic;
|
static int __init setup_nox2apic(char *str)
|
||||||
static __init int setup_nox2apic(char *str)
|
|
||||||
{
|
{
|
||||||
if (x2apic_enabled()) {
|
if (x2apic_enabled()) {
|
||||||
int apicid = native_apic_msr_read(APIC_ID);
|
int apicid = native_apic_msr_read(APIC_ID);
|
||||||
|
@ -178,7 +181,7 @@ static __init int setup_nox2apic(char *str)
|
||||||
} else
|
} else
|
||||||
setup_clear_cpu_cap(X86_FEATURE_X2APIC);
|
setup_clear_cpu_cap(X86_FEATURE_X2APIC);
|
||||||
|
|
||||||
nox2apic = 1;
|
nox2apic = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -283,8 +286,12 @@ u32 native_safe_apic_wait_icr_idle(void)
|
||||||
|
|
||||||
void native_apic_icr_write(u32 low, u32 id)
|
void native_apic_icr_write(u32 low, u32 id)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
local_irq_save(flags);
|
||||||
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id));
|
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id));
|
||||||
apic_write(APIC_ICR, low);
|
apic_write(APIC_ICR, low);
|
||||||
|
local_irq_restore(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 native_apic_icr_read(void)
|
u64 native_apic_icr_read(void)
|
||||||
|
|
|
@ -198,7 +198,7 @@ static struct apic apic_flat = {
|
||||||
|
|
||||||
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
||||||
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
||||||
.wait_for_init_deassert = NULL,
|
.wait_for_init_deassert = false,
|
||||||
.smp_callin_clear_local_apic = NULL,
|
.smp_callin_clear_local_apic = NULL,
|
||||||
.inquire_remote_apic = default_inquire_remote_apic,
|
.inquire_remote_apic = default_inquire_remote_apic,
|
||||||
|
|
||||||
|
@ -314,7 +314,7 @@ static struct apic apic_physflat = {
|
||||||
|
|
||||||
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
||||||
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
||||||
.wait_for_init_deassert = NULL,
|
.wait_for_init_deassert = false,
|
||||||
.smp_callin_clear_local_apic = NULL,
|
.smp_callin_clear_local_apic = NULL,
|
||||||
.inquire_remote_apic = default_inquire_remote_apic,
|
.inquire_remote_apic = default_inquire_remote_apic,
|
||||||
|
|
||||||
|
|
|
@ -172,8 +172,7 @@ struct apic apic_noop = {
|
||||||
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
||||||
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
||||||
|
|
||||||
.wait_for_init_deassert = NULL,
|
.wait_for_init_deassert = false,
|
||||||
|
|
||||||
.smp_callin_clear_local_apic = NULL,
|
.smp_callin_clear_local_apic = NULL,
|
||||||
.inquire_remote_apic = NULL,
|
.inquire_remote_apic = NULL,
|
||||||
|
|
||||||
|
|
|
@ -248,7 +248,7 @@ static const struct apic apic_numachip __refconst = {
|
||||||
.wakeup_secondary_cpu = numachip_wakeup_secondary,
|
.wakeup_secondary_cpu = numachip_wakeup_secondary,
|
||||||
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
||||||
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
||||||
.wait_for_init_deassert = NULL,
|
.wait_for_init_deassert = false,
|
||||||
.smp_callin_clear_local_apic = NULL,
|
.smp_callin_clear_local_apic = NULL,
|
||||||
.inquire_remote_apic = NULL, /* REMRD not supported */
|
.inquire_remote_apic = NULL, /* REMRD not supported */
|
||||||
|
|
||||||
|
|
|
@ -199,8 +199,7 @@ static struct apic apic_bigsmp = {
|
||||||
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
||||||
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
||||||
|
|
||||||
.wait_for_init_deassert = default_wait_for_init_deassert,
|
.wait_for_init_deassert = true,
|
||||||
|
|
||||||
.smp_callin_clear_local_apic = NULL,
|
.smp_callin_clear_local_apic = NULL,
|
||||||
.inquire_remote_apic = default_inquire_remote_apic,
|
.inquire_remote_apic = default_inquire_remote_apic,
|
||||||
|
|
||||||
|
|
|
@ -394,12 +394,6 @@ static void es7000_enable_apic_mode(void)
|
||||||
WARN(1, "Command failed, status = %x\n", mip_status);
|
WARN(1, "Command failed, status = %x\n", mip_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void es7000_wait_for_init_deassert(atomic_t *deassert)
|
|
||||||
{
|
|
||||||
while (!atomic_read(deassert))
|
|
||||||
cpu_relax();
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int es7000_get_apic_id(unsigned long x)
|
static unsigned int es7000_get_apic_id(unsigned long x)
|
||||||
{
|
{
|
||||||
return (x >> 24) & 0xFF;
|
return (x >> 24) & 0xFF;
|
||||||
|
@ -658,8 +652,7 @@ static struct apic __refdata apic_es7000_cluster = {
|
||||||
.trampoline_phys_low = 0x467,
|
.trampoline_phys_low = 0x467,
|
||||||
.trampoline_phys_high = 0x469,
|
.trampoline_phys_high = 0x469,
|
||||||
|
|
||||||
.wait_for_init_deassert = NULL,
|
.wait_for_init_deassert = false,
|
||||||
|
|
||||||
/* Nothing to do for most platforms, since cleared by the INIT cycle: */
|
/* Nothing to do for most platforms, since cleared by the INIT cycle: */
|
||||||
.smp_callin_clear_local_apic = NULL,
|
.smp_callin_clear_local_apic = NULL,
|
||||||
.inquire_remote_apic = default_inquire_remote_apic,
|
.inquire_remote_apic = default_inquire_remote_apic,
|
||||||
|
@ -722,8 +715,7 @@ static struct apic __refdata apic_es7000 = {
|
||||||
.trampoline_phys_low = 0x467,
|
.trampoline_phys_low = 0x467,
|
||||||
.trampoline_phys_high = 0x469,
|
.trampoline_phys_high = 0x469,
|
||||||
|
|
||||||
.wait_for_init_deassert = es7000_wait_for_init_deassert,
|
.wait_for_init_deassert = true,
|
||||||
|
|
||||||
/* Nothing to do for most platforms, since cleared by the INIT cycle: */
|
/* Nothing to do for most platforms, since cleared by the INIT cycle: */
|
||||||
.smp_callin_clear_local_apic = NULL,
|
.smp_callin_clear_local_apic = NULL,
|
||||||
.inquire_remote_apic = default_inquire_remote_apic,
|
.inquire_remote_apic = default_inquire_remote_apic,
|
||||||
|
|
|
@ -505,8 +505,7 @@ static struct apic __refdata apic_numaq = {
|
||||||
.trampoline_phys_high = NUMAQ_TRAMPOLINE_PHYS_HIGH,
|
.trampoline_phys_high = NUMAQ_TRAMPOLINE_PHYS_HIGH,
|
||||||
|
|
||||||
/* We don't do anything here because we use NMI's to boot instead */
|
/* We don't do anything here because we use NMI's to boot instead */
|
||||||
.wait_for_init_deassert = NULL,
|
.wait_for_init_deassert = false,
|
||||||
|
|
||||||
.smp_callin_clear_local_apic = numaq_smp_callin_clear_local_apic,
|
.smp_callin_clear_local_apic = numaq_smp_callin_clear_local_apic,
|
||||||
.inquire_remote_apic = NULL,
|
.inquire_remote_apic = NULL,
|
||||||
|
|
||||||
|
|
|
@ -119,8 +119,7 @@ static struct apic apic_default = {
|
||||||
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
||||||
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
||||||
|
|
||||||
.wait_for_init_deassert = default_wait_for_init_deassert,
|
.wait_for_init_deassert = true,
|
||||||
|
|
||||||
.smp_callin_clear_local_apic = NULL,
|
.smp_callin_clear_local_apic = NULL,
|
||||||
.inquire_remote_apic = default_inquire_remote_apic,
|
.inquire_remote_apic = default_inquire_remote_apic,
|
||||||
|
|
||||||
|
|
|
@ -532,8 +532,7 @@ static struct apic apic_summit = {
|
||||||
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
||||||
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
||||||
|
|
||||||
.wait_for_init_deassert = default_wait_for_init_deassert,
|
.wait_for_init_deassert = true,
|
||||||
|
|
||||||
.smp_callin_clear_local_apic = NULL,
|
.smp_callin_clear_local_apic = NULL,
|
||||||
.inquire_remote_apic = default_inquire_remote_apic,
|
.inquire_remote_apic = default_inquire_remote_apic,
|
||||||
|
|
||||||
|
|
|
@ -279,7 +279,7 @@ static struct apic apic_x2apic_cluster = {
|
||||||
|
|
||||||
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
||||||
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
||||||
.wait_for_init_deassert = NULL,
|
.wait_for_init_deassert = false,
|
||||||
.smp_callin_clear_local_apic = NULL,
|
.smp_callin_clear_local_apic = NULL,
|
||||||
.inquire_remote_apic = NULL,
|
.inquire_remote_apic = NULL,
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,7 @@ static struct apic apic_x2apic_phys = {
|
||||||
|
|
||||||
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
||||||
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
||||||
.wait_for_init_deassert = NULL,
|
.wait_for_init_deassert = false,
|
||||||
.smp_callin_clear_local_apic = NULL,
|
.smp_callin_clear_local_apic = NULL,
|
||||||
.inquire_remote_apic = NULL,
|
.inquire_remote_apic = NULL,
|
||||||
|
|
||||||
|
|
|
@ -396,7 +396,7 @@ static struct apic __refdata apic_x2apic_uv_x = {
|
||||||
.wakeup_secondary_cpu = uv_wakeup_secondary,
|
.wakeup_secondary_cpu = uv_wakeup_secondary,
|
||||||
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
.trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
|
||||||
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
.trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
|
||||||
.wait_for_init_deassert = NULL,
|
.wait_for_init_deassert = false,
|
||||||
.smp_callin_clear_local_apic = NULL,
|
.smp_callin_clear_local_apic = NULL,
|
||||||
.inquire_remote_apic = NULL,
|
.inquire_remote_apic = NULL,
|
||||||
|
|
||||||
|
|
|
@ -122,8 +122,9 @@ static void smp_callin(void)
|
||||||
* Since CPU0 is not wakened up by INIT, it doesn't wait for the IPI.
|
* Since CPU0 is not wakened up by INIT, it doesn't wait for the IPI.
|
||||||
*/
|
*/
|
||||||
cpuid = smp_processor_id();
|
cpuid = smp_processor_id();
|
||||||
if (apic->wait_for_init_deassert && cpuid != 0)
|
if (apic->wait_for_init_deassert && cpuid)
|
||||||
apic->wait_for_init_deassert(&init_deasserted);
|
while (!atomic_read(&init_deasserted))
|
||||||
|
cpu_relax();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (This works even if the APIC is not enabled.)
|
* (This works even if the APIC is not enabled.)
|
||||||
|
@ -701,11 +702,15 @@ wakeup_cpu_via_init_nmi(int cpu, unsigned long start_ip, int apicid,
|
||||||
int id;
|
int id;
|
||||||
int boot_error;
|
int boot_error;
|
||||||
|
|
||||||
|
preempt_disable();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wake up AP by INIT, INIT, STARTUP sequence.
|
* Wake up AP by INIT, INIT, STARTUP sequence.
|
||||||
*/
|
*/
|
||||||
if (cpu)
|
if (cpu) {
|
||||||
return wakeup_secondary_cpu_via_init(apicid, start_ip);
|
boot_error = wakeup_secondary_cpu_via_init(apicid, start_ip);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wake up BSP by nmi.
|
* Wake up BSP by nmi.
|
||||||
|
@ -725,6 +730,9 @@ wakeup_cpu_via_init_nmi(int cpu, unsigned long start_ip, int apicid,
|
||||||
boot_error = wakeup_secondary_cpu_via_nmi(id, start_ip);
|
boot_error = wakeup_secondary_cpu_via_nmi(id, start_ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
preempt_enable();
|
||||||
|
|
||||||
return boot_error;
|
return boot_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue