Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 569712b2 authored by Yinghai Lu's avatar Yinghai Lu Committed by Ingo Molnar
Browse files

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: default avatarYinghai Lu <yinghai@kernel.org>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent e14c8bf8
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -24,8 +24,6 @@ static inline cpumask_t target_cpus(void)
#define INT_DELIVERY_MODE	(dest_Fixed)
#define INT_DEST_MODE		(0)    /* phys delivery to target proc */
#define NO_BALANCE_IRQ		(0)
#define WAKE_SECONDARY_VIA_INIT


static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
{
+0 −3
Original line number Diff line number Diff line
@@ -23,8 +23,6 @@ static inline cpumask_t target_cpus(void)
#define INT_DELIVERY_MODE	(dest_LowestPrio)
#define INT_DEST_MODE		(1)    /* logical delivery broadcast to all procs */
#define NO_BALANCE_IRQ		(1)
#undef  WAKE_SECONDARY_VIA_INIT
#define WAKE_SECONDARY_VIA_MIP
#else
#define APIC_DFR_VALUE		(APIC_DFR_FLAT)
#define INT_DELIVERY_MODE	(dest_Fixed)
@@ -32,7 +30,6 @@ static inline cpumask_t target_cpus(void)
#define NO_BALANCE_IRQ		(0)
#undef  APIC_DEST_LOGICAL
#define APIC_DEST_LOGICAL	0x0
#define WAKE_SECONDARY_VIA_INIT
#endif

static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
+10 −31
Original line number Diff line number Diff line
#ifndef __ASM_ES7000_WAKECPU_H
#define __ASM_ES7000_WAKECPU_H

/*
 * This file copes with machines that wakeup secondary CPUs by the
 * INIT, INIT, STARTUP sequence.
 */

#ifdef CONFIG_ES7000_CLUSTERED_APIC
#define WAKE_SECONDARY_VIA_MIP
#else
#define WAKE_SECONDARY_VIA_INIT
#endif

#ifdef WAKE_SECONDARY_VIA_MIP
extern int es7000_start_cpu(int cpu, unsigned long eip);
static inline int
wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
{
	int boot_error = 0;
	boot_error = es7000_start_cpu(phys_apicid, start_eip);
	return boot_error;
}
#endif

#define TRAMPOLINE_LOW phys_to_virt(0x467)
#define TRAMPOLINE_HIGH phys_to_virt(0x469)

#define boot_cpu_apicid boot_cpu_physical_apicid
#define TRAMPOLINE_PHYS_LOW	0x467
#define TRAMPOLINE_PHYS_HIGH	0x469

static inline void wait_for_init_deassert(atomic_t *deassert)
{
#ifdef WAKE_SECONDARY_VIA_INIT
#ifndef CONFIG_ES7000_CLUSTERED_APIC
	while (!atomic_read(deassert))
		cpu_relax();
#endif
@@ -50,9 +26,12 @@ static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
{
}

#define inquire_remote_apic(apicid) do {		\
		if (apic_verbosity >= APIC_DEBUG)	\
			__inquire_remote_apic(apicid);	\
	} while (0)
extern void __inquire_remote_apic(int apicid);

static inline void inquire_remote_apic(int apicid)
{
	if (apic_verbosity >= APIC_DEBUG)
		__inquire_remote_apic(apicid);
}

#endif /* __ASM_MACH_WAKECPU_H */
+16 −1
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
#define _ASM_X86_GENAPIC_32_H

#include <asm/mpspec.h>
#include <asm/atomic.h>

/*
 * Generic APIC driver interface.
@@ -65,6 +66,13 @@ struct genapic {
	void (*send_IPI_allbutself)(int vector);
	void (*send_IPI_all)(int vector);
#endif
	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);
};

#define APICFUNC(x) .x = x,
@@ -112,6 +120,13 @@ struct genapic {
	IPIFUNC(send_IPI_all)				\
	APICFUNC(enable_apic_mode)			\
	APICFUNC(phys_pkg_id)				\
	.trampoline_phys_low = TRAMPOLINE_PHYS_LOW,		\
	.trampoline_phys_high = TRAMPOLINE_PHYS_HIGH,		\
	APICFUNC(wait_for_init_deassert)		\
	APICFUNC(smp_callin_clear_local_apic)		\
	APICFUNC(store_NMI_vector)			\
	APICFUNC(restore_NMI_vector)			\
	APICFUNC(inquire_remote_apic)			\
}

extern struct genapic *genapic;
+9 −15
Original line number Diff line number Diff line
#ifndef _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H
#define _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H

/* 
 * This file copes with machines that wakeup secondary CPUs by the
 * INIT, INIT, STARTUP sequence.
 */

#define WAKE_SECONDARY_VIA_INIT

#define TRAMPOLINE_LOW phys_to_virt(0x467)
#define TRAMPOLINE_HIGH phys_to_virt(0x469)

#define boot_cpu_apicid boot_cpu_physical_apicid
#define TRAMPOLINE_PHYS_LOW (0x467)
#define TRAMPOLINE_PHYS_HIGH (0x469)

static inline void wait_for_init_deassert(atomic_t *deassert)
{
@@ -33,9 +24,12 @@ static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
{
}

#define inquire_remote_apic(apicid) do {		\
		if (apic_verbosity >= APIC_DEBUG)	\
			__inquire_remote_apic(apicid);	\
	} while (0)
extern void __inquire_remote_apic(int apicid);

static inline void inquire_remote_apic(int apicid)
{
	if (apic_verbosity >= APIC_DEBUG)
		__inquire_remote_apic(apicid);
}

#endif /* _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H */
Loading