x86: fix wakeup_cpu with numaq/es7000, v2
Impact: fix secondary-CPU wakeup/init path with numaq and es7000 While looking at wakeup_secondary_cpu for WAKE_SECONDARY_VIA_NMI: |#ifdef WAKE_SECONDARY_VIA_NMI |/* | * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal | * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this | * won't ... remember to clear down the APIC, etc later. | */ |static int __devinit |wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) |{ | unsigned long send_status, accept_status = 0; | int maxlvt; |... | if (APIC_INTEGRATED(apic_version[phys_apicid])) { | maxlvt = lapic_get_maxlvt(); I noticed that there is no warning about undefined phys_apicid... because WAKE_SECONDARY_VIA_NMI and WAKE_SECONDARY_VIA_INIT can not be defined at the same time. So NUMAQ is using wrong wakeup_secondary_cpu. WAKE_SECONDARY_VIA_NMI, WAKE_SECONDARY_VIA_INIT and WAKE_SECONDARY_VIA_MIP are variants of a weird and fragile preprocessor-driven "HAL" mechanisms to specify the kind of secondary-CPU wakeup strategy a given x86 kernel will use. The vast majority of systems want to use INIT for secondary wakeup - NUMAQ uses an NMI, (old-style-) ES7000 uses 'MIP' (a firmware driven in-memory flag to let secondaries continue). So convert these mechanisms to x86_quirks and add a ->wakeup_secondary_cpu() method to specify the rare exception to the sane default. Extend genapic accordingly as well, for 32-bit. While looking further, I noticed that functions in wakecup.h for numaq and es7000 are different to the default in mach_wakecpu.h - but smpboot.c will only use default mach_wakecpu.h with smphook.h. So we need to add mach_wakecpu.h for mach_generic, to properly support numaq and es7000, and vectorize the following SMP init methods: int trampoline_phys_low; int trampoline_phys_high; void (*wait_for_init_deassert)(atomic_t *deassert); void (*smp_callin_clear_local_apic)(void); void (*store_NMI_vector)(unsigned short *high, unsigned short *low); void (*restore_NMI_vector)(unsigned short *high, unsigned short *low); void (*inquire_remote_apic)(int apicid); Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
@@ -40,6 +40,7 @@
|
||||
#include <asm/smp.h>
|
||||
#include <asm/apicdef.h>
|
||||
#include <mach_mpparse.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
/*
|
||||
* ES7000 chipsets
|
||||
@@ -161,6 +162,26 @@ es7000_rename_gsi(int ioapic, int gsi)
|
||||
return gsi;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ES7000_CLUSTERED_APIC
|
||||
static int wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip)
|
||||
{
|
||||
unsigned long vect = 0, psaival = 0;
|
||||
|
||||
if (psai == NULL)
|
||||
return -1;
|
||||
|
||||
vect = ((unsigned long)__pa(eip)/0x1000) << 16;
|
||||
psaival = (0x1000000 | vect | cpu);
|
||||
|
||||
while (*psai & 0x1000000)
|
||||
;
|
||||
|
||||
*psai = psaival;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void __init
|
||||
setup_unisys(void)
|
||||
{
|
||||
@@ -176,6 +197,9 @@ setup_unisys(void)
|
||||
else
|
||||
es7000_plat = ES7000_CLASSIC;
|
||||
ioapic_renumber_irq = es7000_rename_gsi;
|
||||
#ifdef CONFIG_ES7000_CLUSTERED_APIC
|
||||
x86_quirks->wakeup_secondary_cpu = wakeup_secondary_cpu_via_mip;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -324,26 +348,6 @@ es7000_mip_write(struct mip_reg *mip_reg)
|
||||
return status;
|
||||
}
|
||||
|
||||
int
|
||||
es7000_start_cpu(int cpu, unsigned long eip)
|
||||
{
|
||||
unsigned long vect = 0, psaival = 0;
|
||||
|
||||
if (psai == NULL)
|
||||
return -1;
|
||||
|
||||
vect = ((unsigned long)__pa(eip)/0x1000) << 16;
|
||||
psaival = (0x1000000 | vect | cpu);
|
||||
|
||||
while (*psai & 0x1000000)
|
||||
;
|
||||
|
||||
*psai = psaival;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void __init
|
||||
es7000_sw_apic(void)
|
||||
{
|
||||
|
@@ -250,6 +250,7 @@ static struct x86_quirks numaq_x86_quirks __initdata = {
|
||||
.mpc_oem_pci_bus = mpc_oem_pci_bus,
|
||||
.smp_read_mpc_oem = smp_read_mpc_oem,
|
||||
.setup_ioapic_ids = numaq_setup_ioapic_ids,
|
||||
.wakeup_secondary_cpu = wakeup_secondary_cpu_via_nmi,
|
||||
};
|
||||
|
||||
void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
|
||||
|
@@ -62,6 +62,7 @@
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/vmi.h>
|
||||
#include <asm/genapic.h>
|
||||
#include <asm/setup.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
#include <mach_apic.h>
|
||||
@@ -536,7 +537,7 @@ static void impress_friends(void)
|
||||
pr_debug("Before bogocount - setting activated=1.\n");
|
||||
}
|
||||
|
||||
static inline void __inquire_remote_apic(int apicid)
|
||||
void __inquire_remote_apic(int apicid)
|
||||
{
|
||||
unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
|
||||
char *names[] = { "ID", "VERSION", "SPIV" };
|
||||
@@ -575,14 +576,13 @@ static inline void __inquire_remote_apic(int apicid)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WAKE_SECONDARY_VIA_NMI
|
||||
/*
|
||||
* Poke the other CPU in the eye via NMI to wake it up. Remember that the normal
|
||||
* INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
|
||||
* won't ... remember to clear down the APIC, etc later.
|
||||
*/
|
||||
static int __devinit
|
||||
wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
|
||||
int __devinit
|
||||
wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip)
|
||||
{
|
||||
unsigned long send_status, accept_status = 0;
|
||||
int maxlvt;
|
||||
@@ -599,7 +599,7 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
|
||||
* Give the other CPU some time to accept the IPI.
|
||||
*/
|
||||
udelay(200);
|
||||
if (APIC_INTEGRATED(apic_version[phys_apicid])) {
|
||||
if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
|
||||
maxlvt = lapic_get_maxlvt();
|
||||
if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
|
||||
apic_write(APIC_ESR, 0);
|
||||
@@ -614,11 +614,9 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
|
||||
|
||||
return (send_status | accept_status);
|
||||
}
|
||||
#endif /* WAKE_SECONDARY_VIA_NMI */
|
||||
|
||||
#ifdef WAKE_SECONDARY_VIA_INIT
|
||||
static int __devinit
|
||||
wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
|
||||
wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
|
||||
{
|
||||
unsigned long send_status, accept_status = 0;
|
||||
int maxlvt, num_starts, j;
|
||||
@@ -737,7 +735,15 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
|
||||
|
||||
return (send_status | accept_status);
|
||||
}
|
||||
#endif /* WAKE_SECONDARY_VIA_INIT */
|
||||
|
||||
static int __devinit
|
||||
wakeup_secondary_cpu(int apicid, unsigned long start_eip)
|
||||
{
|
||||
if (x86_quirks->wakeup_secondary_cpu)
|
||||
return x86_quirks->wakeup_secondary_cpu(apicid, start_eip);
|
||||
|
||||
return wakeup_secondary_cpu_via_init(apicid, start_eip);
|
||||
}
|
||||
|
||||
struct create_idle {
|
||||
struct work_struct work;
|
||||
|
Reference in New Issue
Block a user