Skip to contentSkip to conversation

x86: Arbitrary CPU hot(un)plug support

PATCH Superseded Fenghua Yu 3 participants 19 messages Aug 24, 2012

Subsystems (3)

v7 of 10 Superseded Latest is v10 →

lore
Share & tools
lore

Fenghua Yu

author
#0 lore raw

v7 cover x86: Arbitrary CPU hot(un)plug support

From: Fenghua Yu <[email protected]>

CPU0 or BSP (Bootstrap Processor) has been the last processor that can not be hot removed on x86. This patch set implements CPU0 or BSP online and offline and removes this obstacle to CPU hotplug.

RAS needs the feature. If socket0 needs to be hotplugged for any reason (any thread on socket0 is bad, shared cache issue, uncore issue, etc), CPU0 is required to be offline or hot replaced to keep the system run. For example, starting with Core Duo, if you have a system that is reporting cache problems via the "yellow" status in the MCi_STATUS msr, then there is benefit in simply soft off-lining the cores that share that cache - assuming that leaves you at least one online core. A single socket system with L3 cache troubles is not helped - but problems in L1/L2 cache, or on multi-socket systems can be avoided. They are already being avoided for the cases where CPU0 is not involved. This patchset can help L1/L2 cache problem in CPU0 or L3 cache problem on the socket with CPU0 in a multi-socket system.

v7: Change smp_store_cpu_info() to allow store cpuinfo for CPU0 when online. Change PIC irq detection in native_cpu_disable().

v6: If CPU0 is offlined during boot time in CPU0 hotplug debug mode, put CPU0 online again before resuming from hibernation and disable x2apic and xapic.Don't set __CPUINIT for start_cpu0() in head_32.S. Clean up CPU0 wake up nmi handler after callin and callout sync. In a period (3 seconds), check if CPU0 wake up NMI is handled after offlined CPU0 exits from mwait.

v5: Add CONFIG_BOOTPARAM_HOTPLUG_CPU0 and CONFIG_DEBUG_HOTPLUG_CPU0. Simplify duplicate xstate_size init check. Wakeup CPU0 via nmi instead INITs. Add mcheck_cpu_init when CPU0 online. Change variable bsp_hotpluggable to cpu0_hotpluggable with __initdata qualifier.

v4: Add __read_mostly for internal bsp_hotpluggable variable. Add my email address in cpu-hotplug.txt document. A wording change in comment.

v3: Register a pm notifier to check if CPU0 is online before hibernate/suspend. Small wording changes in document and print info.

v2: Add locking changes between cpu hotplug and hibernate/suspend. Change PIC irq bound to CPU0 detection.

Fenghua Yu (12):
Documentations/cpu-hotplug.tx, kernel-parameters.txt: Add x86 CPU0
online/offline feature
x86/Kconfig: Add config switch for CPU0 hotplug x86/topology.c: Support functions for CPU0 online/offline Don't offline CPU0 if any PIC irq can not be migrated out of it. Because x86 BIOS requires CPU0 to resume from sleep, suspend or
hibernate can't be executed if CPU0 is detected offline. To make suspend or hibernate and further resume succeed, CPU0 must be online.
start_cpu0() is defined in head_64.S for 64-bit. The function sets up
stack and jumps to start_secondary() for CPU0 wake up.
start_cpu0() is defined in head_32.S for 32-bit. The function sets up
stack and jumps to start_secondary() for CPU0 wake up.
Instead of waiting for STARTUP after INITs, BSP will execute the BIOS
boot-strap code which is not a desired behavior for waking up BSP. To avoid the boot-strap code, wake up CPU0 by NMI instead.
During CPU0 online, enable x2apic, set_numa_node.
Ask the first online CPU to save mtrr instead of asking BSP. BSP
could be offline when mtrr_save_state() is called.
x86/i387.c: Thread xstate is initialized only on CPU0 once x86/topology.c: debug CPU0 hotplug

 Documentation/cpu-hotplug.txt       |   24 ++++++
 Documentation/kernel-parameters.txt |   14 ++++
 arch/x86/Kconfig                    |   44 +++++++++++
 arch/x86/include/asm/cpu.h          |    4 +
 arch/x86/include/asm/smp.h          |    2 +-
 arch/x86/kernel/cpu/common.c        |    5 +-
 arch/x86/kernel/cpu/mtrr/main.c     |    9 ++-
 arch/x86/kernel/head_32.S           |   12 +++
 arch/x86/kernel/head_64.S           |   15 ++++
 arch/x86/kernel/i387.c              |    6 +-
 arch/x86/kernel/smpboot.c           |  144 ++++++++++++++++++++++++++++-------
 arch/x86/kernel/topology.c          |   92 ++++++++++++++++++++--
 arch/x86/power/cpu.c                |   82 ++++++++++++++++++++
 13 files changed, 412 insertions(+), 41 deletions(-)
Signature · 1 line
1.7.2
author
#1 lore raw

PATCH v7 1/12 Documentations/cpu-hotplug.tx, kernel-parameters.txt: Add x86 CPU0 online/offline feature

From: Fenghua Yu <[email protected]>

If CONFIG_BOOTPARAM_HOTPLUG_CPU0 is turned on, CPU0 is hotpluggable. Otherwise, by default CPU0 is not hotpluggable and kernel parameter cpu0_hotplug enables CPU0 online/offline feature.

The documentations point out two known CPU0 dependencies. First, resume from hibernate or suspend always starts from CPU0. So hibernate and suspend are prevented if CPU0 is offline. Another dependency is PIC interrupts always go to CPU0.

It's said that some machines may depend on CPU0 to poweroff/reboot. But I haven't seen such dependency on a few tested machines.

Please let me know if you see any CPU0 dependencies on your machine.

---
 Documentation/cpu-hotplug.txt       |   24 ++++++++++++++++++++++++
 Documentation/kernel-parameters.txt |   14 ++++++++++++++
 2 files changed, 38 insertions(+), 0 deletions(-)
Documentation/cpu-hotplug.txt +24 -0
index 66ef8f3..9f40135 100644
@@ -207,6 +207,30 @@ by making it not-removable.
 
 In such cases you will also notice that the online file is missing under cpu0.
 
+Q: Is CPU0 removable on X86?
+A: Yes. If kernel is compiled with CONFIG_BOOTPARAM_HOTPLUG_CPU0=y, CPU0 is
+removable by default. Otherwise, CPU0 is also removable by kernel option
+cpu0_hotplug.
+
+But some features depend on CPU0. Two known dependencies are:
+
+1. Resume from hibernate/suspend depends on CPU0. Hibernate/suspend will fail if
+CPU0 is offline and you need to online CPU0 before hibernate/suspend can
+continue.
+2. PIC interrupts also depend on CPU0. CPU0 can't be removed if a PIC interrupt
+is detected.
+
+It's said poweroff/reboot may depend on CPU0 on some machines although I haven't
+seen any poweroff/reboot failure so far after CPU0 is offline on a few tested
+machines.
+
+Please let me know if you know or see any other dependencies of CPU0.
+
+If the dependencies are under your control, you can turn on CPU0 hotplug feature
+either by CONFIG_BOOTPARAM_HOTPLUG_CPU0 or by kernel parameter cpu0_hotplug.
+
+--Fenghua Yu <[email protected]>
+
 Q: How do i find out if a particular CPU is not removable?
 A: Depending on the implementation, some architectures may show this by the
 absence of the "online" file. This is done if it can be determined ahead of
Documentation/kernel-parameters.txt +14 -0
index 7aef334..f8b38f4 100644
@@ -1952,6 +1952,20 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
 	nox2apic	[X86-64,APIC] Do not enable x2APIC mode.
 
+	cpu0_hotplug	[X86] Turn on CPU0 hotplug feature when
+			CONFIG_BOOTPARAM_HOTPLUG_CPU0 is off.
+			Some features depend on CPU0. Known dependencies are:
+			1. Resume from suspend/hibernate depends on CPU0.
+			Suspend/hibernate will fail if CPU0 is offline and you
+			need to online CPU0 before suspend/hibernate.
+			2. PIC interrupts also depend on CPU0. CPU0 can't be
+			removed if a PIC interrupt is detected.
+			It's said poweroff/reboot may depend on CPU0 on some
+			machines although I haven't seen such issues so far
+			after CPU0 is offline on a few tested machines.
+			If the dependencies are under your control, you can
+			turn on cpu0_hotplug.
+
 	nptcg=		[IA-64] Override max number of concurrent global TLB
 			purges which is reported from either PAL_VM_SUMMARY or
 			SAL PALO.
Signature · 1 line
1.7.2
author
#2 lore raw

PATCH v7 2/12 x86/Kconfig: Add config switch for CPU0 hotplug

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

New config switch CONFIG_BOOTPARAM_HOTPLUG_CPU0 sets default state of whether the CPU0 hotplug is on or off.

If the switch is off, CPU0 is not hotpluggable by default. But the CPU0 hotplug feature can still be turned on by kernel parameter cpu0_hotplug at boot.

If the switch is on, CPU0 is always hotpluggable. The default value of the switch is off.

---
 arch/x86/Kconfig |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)
arch/x86/Kconfig +29 -0
index 1d91dac..31c8b89 100644
@@ -1711,6 +1711,35 @@ config HOTPLUG_CPU
 	    automatically on SMP systems. )
 	  Say N if you want to disable CPU hotplug.
 
+config BOOTPARAM_HOTPLUG_CPU0
+	bool "Set default setting of cpu0_hotpluggable"
+	default n
+	depends on HOTPLUG_CPU && EXPERIMENTAL
+	---help---
+	  Set whether default state of cpu0_hotpluggable is on or off.
+
+	  Say Y here to enable CPU0 hotplug by default. If this switch
+	  is turned on, there is no need to give cpu0_hotplug kernel
+	  parameter and the CPU0 hotplug feature is enabled by default.
+
+	  Please note: there are two known CPU0 dependencies if you want
+	  to enable the CPU0 hotplug feature either by this switch or by
+	  cpu0_hotplug kernel parameter.
+
+	  First, resume from hibernate or suspend always starts from CPU0.
+	  So hibernate and suspend are prevented if CPU0 is offline.
+
+	  Second dependency is PIC interrupts always go to CPU0. CPU0 can not
+	  offline if any interrupt can not migrate out of CPU0. There may
+	  be other CPU0 dependencies.
+
+	  Please make sure the dependencies are under your control before
+	  you enable this feature.
+
+	  Say N if you don't want to enable CPU0 hotplug feature by default.
+	  You still can enable the CPU0 hotplug feature at boot by kernel
+	  parameter cpu0_hotplug.
+
 config COMPAT_VDSO
 	def_bool y
 	prompt "Compat VDSO support"
Signature · 1 line
1.7.2
maintainer
#3 lore raw

Re: [PATCH v7 02/12] x86/Kconfig: Add config switch for CPU0 hotplug

Quoted 21 lines · Fenghua Yu

From: Fenghua Yu <[email protected]>

New config switch CONFIG_BOOTPARAM_HOTPLUG_CPU0 sets default state of whether the CPU0 hotplug is on or off.

If the switch is off, CPU0 is not hotpluggable by default. But the CPU0 hotplug feature can still be turned on by kernel parameter cpu0_hotplug at boot.

If the switch is on, CPU0 is always hotpluggable. The default value of the switch is off.

---
 arch/x86/Kconfig |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)
arch/x86/Kconfig +0 -0
index 1d91dac..31c8b89 100644

arch/x86/Kconfig config HOTPLUG_CPU · line 1715

Quoted 5 lines
arch/x86/Kconfig +2 -0
@@ -1711,6 +1711,35 @@ config HOTPLUG_CPU
 	    automatically on SMP systems. )
 	  Say N if you want to disable CPU hotplug.
 
+config BOOTPARAM_HOTPLUG_CPU0
+	bool "Set default setting of cpu0_hotpluggable"

Why not change this boot option into something more understandable like

bool "BSP hotpluggable by default"

or similar?

And, btw, maybe I didn't catch this earlier, but why is in all user-visible options the thing called "cpu0_*"? Wouldn't it be better to call it "bsp_*"?

Thanks.

Signature · 2 lines
Regards/Gruss,
    Boris.
#4 lore raw

RE: [PATCH v7 02/12] x86/Kconfig: Add config switch for CPU0 hotplug

Quoted 4 lines

And, btw, maybe I didn't catch this earlier, but why is in all user-visible options the thing called "cpu0_*"? Wouldn't it be better to
call it "bsp_*"?

The kernel parameter was called bsp_hotplug before. It was changed to cpu0_hotplug in v5 to keep uniform cpu0/CPU0 names.

Thanks.

-Fenghua ���{.n�+�������+%�����ݶ��w��{.n�+����{��G�����{ay�ʇڙ�,j��f���h��������z_�(�階�ݢj"���m������G������?����&���~��iO��z��v�^�m���� ������?�I�

author
#5 lore raw

PATCH v7 3/12 x86/topology.c: Support functions for CPU0 online/offline

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

If CONFIG_BOOTPARAM_HOTPLUG_CPU is turned on, CPU0 hotplug feature is enabled by default.

If CONFIG_BOOTPARAM_HOTPLUG_CPU is not turned on, CPU0 hotplug feature is not enabled by default. The kernel parameter cpu0_hotplug can enable CPU0 hotplug feature at boot.

---
 arch/x86/kernel/topology.c |   41 ++++++++++++++++++++++++++++++++++-------
 1 files changed, 34 insertions(+), 7 deletions(-)
arch/x86/kernel/topology.c +34 -7
index 76ee977..fa87fd6 100644
@@ -30,23 +30,50 @@
 #include <linux/mmzone.h>
 #include <linux/init.h>
 #include <linux/smp.h>
+#include <linux/irq.h>
 #include <asm/cpu.h>
 
 static DEFINE_PER_CPU(struct x86_cpu, cpu_devices);
 
 #ifdef CONFIG_HOTPLUG_CPU
+
+#ifdef CONFIG_BOOTPARAM_HOTPLUG_CPU0
+static int cpu0_hotpluggable = 1;
+#else
+static int cpu0_hotpluggable;
+static int __init enable_cpu0_hotplug(char *str)
+{
+	cpu0_hotpluggable = 1;
+	return 1;
+}
+
+__setup("cpu0_hotplug", enable_cpu0_hotplug);
+#endif
+
 int __ref arch_register_cpu(int num)
 {
 	/*
-	 * CPU0 cannot be offlined due to several
-	 * restrictions and assumptions in kernel. This basically
-	 * doesn't add a control file, one cannot attempt to offline
-	 * BSP.
+	 * Two known BSP/CPU0 dependencies: Resume from suspend/hibernate
+	 * depends on BSP. PIC interrupts depend on BSP.
 	 *
-	 * Also certain PCI quirks require not to enable hotplug control
-	 * for all CPU's.
+	 * If the BSP depencies are under control, one can tell kernel to
+	 * enable BSP hotplug. This basically adds a control file and
+	 * one can attempt to offline BSP.
 	 */
-	if (num)
+	if (num == 0 && cpu0_hotpluggable) {
+		unsigned int irq;
+		/*
+		 * We won't take down the boot processor on i386 if some
+		 * interrupts only are able to be serviced by the BSP in PIC.
+		 */
+		for_each_active_irq(irq) {
+			if (!IO_APIC_IRQ(irq) && irq_has_action(irq)) {
+				cpu0_hotpluggable = 0;
+				break;
+			}
+		}
+	}
+	if (num || cpu0_hotpluggable)
 		per_cpu(cpu_devices, num).cpu.hotpluggable = 1;
 
 	return register_cpu(&per_cpu(cpu_devices, num).cpu, num);
Signature · 1 line
1.7.2
author
#6 lore raw

PATCH v7 4/12 Don't offline CPU0 if any PIC irq can not be migrated out of it.

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

Change smp_store_cpu_info() to store cpu info for a CPU when it's brought up. This includes bringing up CPU0 or AP after it's offline. But don't store cpu info when BSP first boots during boot time.

Continue to online CPU0 in native_cpu_up().

---
 arch/x86/include/asm/smp.h |    2 +-
 arch/x86/kernel/smpboot.c  |   32 +++++++++++---------------------
 2 files changed, 12 insertions(+), 22 deletions(-)
arch/x86/include/asm/smp.h +1 -1
index 4f19a15..0be0b29 100644
@@ -166,7 +166,7 @@ void native_send_call_func_ipi(const struct cpumask *mask);
 void native_send_call_func_single_ipi(int cpu);
 void x86_idle_thread_init(unsigned int cpu, struct task_struct *idle);
 
-void smp_store_cpu_info(int id);
+void smp_store_cpu_info(int id, int store);
 #define cpu_physical_id(cpu)	per_cpu(x86_cpu_to_apicid, cpu)
 
 #else /* !CONFIG_SMP */
arch/x86/kernel/smpboot.c +11 -21
index c80a33b..8d0b4ff 100644
@@ -125,8 +125,8 @@ EXPORT_PER_CPU_SYMBOL(cpu_info);
 atomic_t init_deasserted;
 
 /*
- * Report back to the Boot Processor.
- * Running on AP.
+ * Report back to the Boot Processor during boot time or to the caller processor
+ * during CPU online.
  */
 static void __cpuinit smp_callin(void)
 {
@@ -201,7 +201,7 @@ static void __cpuinit smp_callin(void)
 	 * Save our processor parameters. Note: this information
 	 * is needed for clock calibration.
 	 */
-	smp_store_cpu_info(cpuid);
+	smp_store_cpu_info(cpuid, 1);
 
 	/*
 	 * Get our bogomips.
@@ -283,14 +283,17 @@ notrace static void __cpuinit start_secondary(void *unused)
  * The bootstrap kernel entry code has set these up. Save them for
  * a given CPU
  */
-
-void __cpuinit smp_store_cpu_info(int id)
+void __cpuinit smp_store_cpu_info(int id, int store)
 {
 	struct cpuinfo_x86 *c = &cpu_data(id);
 
 	*c = boot_cpu_data;
 	c->cpu_index = id;
-	if (id != 0)
+	/*
+	 * During boot time, CPU0 has this setup already. Save the info when
+	 * bringing up AP or offlined CPU0.
+	 */
+	if (store)
 		identify_secondary_cpu(c);
 }
 
@@ -795,7 +798,7 @@ int __cpuinit native_cpu_up(unsigned int cpu, struct task_struct *tidle)
 
 	pr_debug("++++++++++++++++++++=_---CPU UP  %u\n", cpu);
 
-	if (apicid == BAD_APICID || apicid == boot_cpu_physical_apicid ||
+	if (apicid == BAD_APICID ||
 	    !physid_isset(apicid, phys_cpu_present_map) ||
 	    !apic->apic_id_valid(apicid)) {
 		pr_err("%s: bad cpu %d\n", __func__, cpu);
@@ -990,7 +993,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 	/*
 	 * Setup boot CPU information
 	 */
-	smp_store_cpu_info(0); /* Final full version of the data */
+	smp_store_cpu_info(0, 0); /* Final full version of the data */
 	cpumask_copy(cpu_callin_mask, cpumask_of(0));
 	mb();
 
@@ -1214,19 +1217,6 @@ void cpu_disable_common(void)
 
 int native_cpu_disable(void)
 {
-	int cpu = smp_processor_id();
-
-	/*
-	 * Perhaps use cpufreq to drop frequency, but that could go
-	 * into generic code.
-	 *
-	 * We won't take down the boot processor on i386 due to some
-	 * interrupts only being able to be serviced by the BSP.
-	 * Especially so if we're not using an IOAPIC	-zwane
-	 */
-	if (cpu == 0)
-		return -EBUSY;
-
 	clear_local_APIC();
 
 	cpu_disable_common();
Signature · 1 line
1.7.2
maintainer
#7 lore raw

Re: [PATCH v7 04/12] Don't offline CPU0 if any PIC irq can not be migrated out of it.

Quoted 52 lines · Fenghua Yu

From: Fenghua Yu <[email protected]>

Change smp_store_cpu_info() to store cpu info for a CPU when it's brought up. This includes bringing up CPU0 or AP after it's offline. But don't store cpu info when BSP first boots during boot time.

Continue to online CPU0 in native_cpu_up().

---
 arch/x86/include/asm/smp.h |    2 +-
 arch/x86/kernel/smpboot.c  |   32 +++++++++++---------------------
 2 files changed, 12 insertions(+), 22 deletions(-)
arch/x86/include/asm/smp.h +1 -1
index 4f19a15..0be0b29 100644
@@ -166,7 +166,7 @@ void native_send_call_func_ipi(const struct cpumask *mask);
 void native_send_call_func_single_ipi(int cpu);
 void x86_idle_thread_init(unsigned int cpu, struct task_struct *idle);
 
-void smp_store_cpu_info(int id);
+void smp_store_cpu_info(int id, int store);
 #define cpu_physical_id(cpu)	per_cpu(x86_cpu_to_apicid, cpu)
 
 #else /* !CONFIG_SMP */
arch/x86/kernel/smpboot.c +3 -3
index c80a33b..8d0b4ff 100644
@@ -125,8 +125,8 @@ EXPORT_PER_CPU_SYMBOL(cpu_info);
 atomic_t init_deasserted;
 
 /*
- * Report back to the Boot Processor.
- * Running on AP.
+ * Report back to the Boot Processor during boot time or to the caller processor
+ * during CPU online.
  */
 static void __cpuinit smp_callin(void)
 {
@@ -201,7 +201,7 @@ static void __cpuinit smp_callin(void)
 	 * Save our processor parameters. Note: this information
 	 * is needed for clock calibration.
 	 */
-	smp_store_cpu_info(cpuid);
+	smp_store_cpu_info(cpuid, 1);
 
 	/*
 	 * Get our bogomips.

arch/x86/kernel/smpboot.c notrace static void __cpuinit start_secondary(void *unused) · line 286

Quoted 6 lines
arch/x86/kernel/smpboot.c +1 -2
@@ -283,14 +283,17 @@ notrace static void __cpuinit start_secondary(void *unused)
  * The bootstrap kernel entry code has set these up. Save them for
  * a given CPU
  */
-
-void __cpuinit smp_store_cpu_info(int id)
+void __cpuinit smp_store_cpu_info(int id, int store)

This usage begs for "bool store".

Quoted 15 lines
arch/x86/kernel/smpboot.c +5 -1
 {
 	struct cpuinfo_x86 *c = &cpu_data(id);
 
 	*c = boot_cpu_data;
 	c usage->cpu_index = id;
-	if (id != 0)
+	/*
+	 * During boot time, CPU0 has this setup already. Save the info when
+	 * bringing up AP or offlined CPU0.
+	 */
+	if (store)
 		identify_secondary_cpu(c);
 }
 

arch/x86/kernel/smpboot.c int __cpuinit native_cpu_up(unsigned int cpu, struct task_struct *tidle) · line 803

Quoted 7 lines
arch/x86/kernel/smpboot.c +1 -1
@@ -795,7 +798,7 @@ int __cpuinit native_cpu_up(unsigned int cpu, struct task_struct *tidle)
 
 	pr_debug("++++++++++++++++++++=_---CPU UP  %u\n", cpu);
 
-	if (apicid == BAD_APICID || apicid == boot_cpu_physical_apicid ||
+	if (apicid == BAD_APICID ||
 	    !physid_isset(apicid, phys_cpu_present_map) ||
 	    !apic->apic_id_valid(apicid)) {

Nothing in the commit message explains this change...

Quoted 38 lines
arch/x86/kernel/smpboot.c +1 -14
 		pr_err("%s: bad cpu %d\n", __func__, cpu);
@@ -990,7 +993,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 	/*
 	 * Setup boot CPU information
 	 */
-	smp_store_cpu_info(0); /* Final full version of the data */
+	smp_store_cpu_info(0, 0); /* Final full version of the data */
 	cpumask_copy(cpu_callin_mask, cpumask_of(0));
 	mb();
 
@@ -1214,19 +1217,6 @@ void cpu_disable_common(void)
 
 int native_cpu_disable(void)
 {
-	int cpu = smp_processor_id();
-
-	/*
-	 * Perhaps use cpufreq to drop frequency, but that could go
-	 * into generic code.
-	 *
-	 * We won't take down the boot processor on i386 due to some
-	 * interrupts only being able to be serviced by the BSP.
-	 * Especially so if we're not using an IOAPIC	-zwane
-	 */
-	if (cpu == 0)
-		return -EBUSY;
-
 	clear_local_APIC();
 
 	cpu_disable_common();
Signature · 7 lines
1.7.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Signature · 2 lines
Regards/Gruss,
    Boris.
author
#8 lore raw

PATCH v7 5/12 Because x86 BIOS requires CPU0 to resume from sleep, suspend or hibernate can't be executed if CPU0 is detected offline. To make suspend or hibernate and further resume succeed, CPU0 must be online.

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

---
 arch/x86/power/cpu.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 44 insertions(+), 0 deletions(-)
arch/x86/power/cpu.c +44 -0
index 218cdb1..3338609 100644
@@ -237,3 +237,47 @@ void restore_processor_state(void)
 #ifdef CONFIG_X86_32
 EXPORT_SYMBOL(restore_processor_state);
 #endif
+
+/*
+ * When bsp_check() is called in hibernate and suspend, cpu hotplug
+ * is disabled already. So it's unnessary to handle race condition between
+ * cpumask query and cpu hotplug.
+ */
+static int bsp_check(void)
+{
+	if (cpumask_first(cpu_online_mask) != 0) {
+		printk(KERN_WARNING "CPU0 is offline.\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int bsp_pm_callback(struct notifier_block *nb, unsigned long action,
+			   void *ptr)
+{
+	int ret = 0;
+
+	switch (action) {
+	case PM_SUSPEND_PREPARE:
+	case PM_HIBERNATION_PREPARE:
+		ret = bsp_check();
+		break;
+	default:
+		break;
+	}
+	return notifier_from_errno(ret);
+}
+
+static int __init bsp_pm_check_init(void)
+{
+	/*
+	 * Set this bsp_pm_callback as lower priority than
+	 * cpu_hotplug_pm_callback. So cpu_hotplug_pm_callback will be called
+	 * earlier to disable cpu hotplug before bsp online check.
+	 */
+	pm_notifier(bsp_pm_callback, -INT_MAX);
+	return 0;
+}
+
+core_initcall(bsp_pm_check_init);
Signature · 1 line
1.7.2
maintainer
#9 lore raw

Re: [PATCH v7 05/12] Because x86 BIOS requires CPU0 to resume from sleep, suspend or hibernate can't be executed if CPU0 is detected offline. To make suspend or hibernate and further resume succeed, CPU0 must be online.

Quoted 2 lines · Fenghua Yu

From: Fenghua Yu <[email protected]>

Ditto for too long Subject line and missing commit message.

Quoted 65 lines
---
 arch/x86/power/cpu.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 44 insertions(+), 0 deletions(-)
arch/x86/power/cpu.c +44 -0
index 218cdb1..3338609 100644
@@ -237,3 +237,47 @@ void restore_processor_state(void)
 #ifdef CONFIG_X86_32
 EXPORT_SYMBOL(restore_processor_state);
 #endif
+
+/*
+ * When bsp_check() is called in hibernate and suspend, cpu hotplug
+ * is disabled already. So it's unnessary to handle race condition between
+ * cpumask query and cpu hotplug.
+ */
+static int bsp_check(void)
+{
+	if (cpumask_first(cpu_online_mask) != 0) {
+		printk(KERN_WARNING "CPU0 is offline.\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int bsp_pm_callback(struct notifier_block *nb, unsigned long action,
+			   void *ptr)
+{
+	int ret = 0;
+
+	switch (action) {
+	case PM_SUSPEND_PREPARE:
+	case PM_HIBERNATION_PREPARE:
+		ret = bsp_check();
+		break;
+	default:
+		break;
+	}
+	return notifier_from_errno(ret);
+}
+
+static int __init bsp_pm_check_init(void)
+{
+	/*
+	 * Set this bsp_pm_callback as lower priority than
+	 * cpu_hotplug_pm_callback. So cpu_hotplug_pm_callback will be called
+	 * earlier to disable cpu hotplug before bsp online check.
+	 */
+	pm_notifier(bsp_pm_callback, -INT_MAX);
+	return 0;
+}
+
+core_initcall(bsp_pm_check_init);
Signature · 7 lines
1.7.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Signature · 2 lines
Regards/Gruss,
    Boris.
author
#10 lore raw

PATCH v7 6/12 start_cpu0() is defined in head_64.S for 64-bit. The function sets up stack and jumps to start_secondary() for CPU0 wake up.

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

---
 arch/x86/kernel/head_64.S |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)
arch/x86/kernel/head_64.S +15 -0
index 94bf9cc..3faac8a 100644
@@ -252,6 +252,21 @@ ENTRY(secondary_startup_64)
 	pushq	%rax		# target address in negative space
 	lretq
 
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * Boot CPU0 entry point. It's called from play_dead(). Everything has been set
+ * up already except stack. We just set up stack here. Then call
+ * start_secondary().
+ */
+ENTRY(start_cpu0)
+	movq stack_start(%rip),%rsp
+	movq	initial_code(%rip),%rax
+	pushq	$0		# fake return address to stop unwinder
+	pushq	$__KERNEL_CS	# set correct cs
+	pushq	%rax		# target address in negative space
+	lretq
+#endif
+
 	/* SMP bootup changes these two */
 	__REFDATA
 	.align	8
Signature · 1 line
1.7.2
author
#11 lore raw

PATCH v7 7/12 start_cpu0() is defined in head_32.S for 32-bit. The function sets up stack and jumps to start_secondary() for CPU0 wake up.

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

---
 arch/x86/kernel/head_32.S |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
arch/x86/kernel/head_32.S +12 -0
index d42ab17..964f87a 100644
@@ -266,6 +266,18 @@ num_subarch_entries = (. - subarch_entries) / 4
 	jmp default_entry
 #endif /* CONFIG_PARAVIRT */
 
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * Boot CPU0 entry point. It's called from play_dead(). Everything has been set
+ * up already except stack. We just set up stack here. Then call
+ * start_secondary().
+ */
+ENTRY(start_cpu0)
+	movl stack_start, %ecx
+	movl %ecx, %esp
+	jmp  *(initial_code)
+#endif
+
 /*
  * Non-boot CPU entry point; entered from trampoline.S
  * We can't lgdt here, because lgdt itself uses a data segment, but
Signature · 1 line
1.7.2
maintainer
#12 lore raw

Re: [PATCH v7 07/12] start_cpu0() is defined in head_32.S for 32-bit. The function sets up stack and jumps to start_secondary() for CPU0 wake up.

Quoted 2 lines · Fenghua Yu

From: Fenghua Yu <[email protected]>

Looks like the extra-long Subject line belongs in here where the commit message should be.

Quoted 36 lines
---
 arch/x86/kernel/head_32.S |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
arch/x86/kernel/head_32.S +12 -0
index d42ab17..964f87a 100644
@@ -266,6 +266,18 @@ num_subarch_entries = (. - subarch_entries) / 4
 	jmp default_entry
 #endif /* CONFIG_PARAVIRT */
 
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * Boot CPU0 entry point. It's called from play_dead(). Everything has been set
+ * up already except stack. We just set up stack here. Then call
+ * start_secondary().
+ */
+ENTRY(start_cpu0)
+	movl stack_start, %ecx
+	movl %ecx, %esp
+	jmp  *(initial_code)
+#endif
+
 /*
  * Non-boot CPU entry point; entered from trampoline.S
  * We can't lgdt here, because lgdt itself uses a data segment, but
Signature · 7 lines
1.7.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Signature · 2 lines
Regards/Gruss,
    Boris.
author
#13 lore raw

PATCH v7 8/12 Instead of waiting for STARTUP after INITs, BSP will execute the BIOS boot-strap code which is not a desired behavior for waking up BSP. To avoid the boot-strap code, wake up CPU0 by NMI instead.

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

This works to wake up soft offlined CPU0 only. If CPU0 is hard offlined (i.e. physically hot removed and then hot added), NMI won't wake it up. We'll change this code in the future to wake up hard offlined CPU0 if real platform and request are available.

AP is still waken up as before by INIT, INIT, STARTUP sequence.

---
 arch/x86/include/asm/cpu.h |    1 +
 arch/x86/kernel/smpboot.c  |  112 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 107 insertions(+), 6 deletions(-)
arch/x86/include/asm/cpu.h +1 -0
index 4564c8e..a119572 100644
@@ -28,6 +28,7 @@ struct x86_cpu {
 #ifdef CONFIG_HOTPLUG_CPU
 extern int arch_register_cpu(int num);
 extern void arch_unregister_cpu(int);
+extern void __cpuinit start_cpu0(void);
 #endif
 
 DECLARE_PER_CPU(int, cpu_state);
arch/x86/kernel/smpboot.c +106 -6

197 lines not on this page · raw message

Signature · 1 line
1.7.2
author
#14 lore raw

PATCH v7 9/12 During CPU0 online, enable x2apic, set_numa_node.

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

---
 arch/x86/kernel/cpu/common.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/common.c +2 -3
index 2ea24da..ce8b772 100644
@@ -1223,7 +1223,7 @@ void __cpuinit cpu_init(void)
 	oist = &per_cpu(orig_ist, cpu);
 
 #ifdef CONFIG_NUMA
-	if (cpu != 0 && this_cpu_read(numa_node) == 0 &&
+	if (this_cpu_read(numa_node) == 0 &&
 	    early_cpu_to_node(cpu) != NUMA_NO_NODE)
 		set_numa_node(early_cpu_to_node(cpu));
 #endif
@@ -1255,8 +1255,7 @@ void __cpuinit cpu_init(void)
 	barrier();
 
 	x86_configure_nx();
-	if (cpu != 0)
-		enable_x2apic();
+	enable_x2apic();
 
 	/*
 	 * set up and load the per-CPU TSS
Signature · 1 line
1.7.2
author
#15 lore raw

PATCH v7 10/12 Ask the first online CPU to save mtrr instead of asking BSP. BSP could be offline when mtrr_save_state() is called.

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

---
 arch/x86/kernel/cpu/mtrr/main.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)
arch/x86/kernel/cpu/mtrr/main.c +7 -2
index 6b96110..e4c1a41 100644
@@ -695,11 +695,16 @@ void mtrr_ap_init(void)
 }
 
 /**
- * Save current fixed-range MTRR state of the BSP
+ * Save current fixed-range MTRR state of the first cpu in cpu_online_mask.
  */
 void mtrr_save_state(void)
 {
-	smp_call_function_single(0, mtrr_save_fixed_ranges, NULL, 1);
+	int first_cpu;
+
+	get_online_cpus();
+	first_cpu = cpumask_first(cpu_online_mask);
+	smp_call_function_single(first_cpu, mtrr_save_fixed_ranges, NULL, 1);
+	put_online_cpus();
 }
 
 void set_mtrr_aps_delayed_init(void)
Signature · 1 line
1.7.2
author
#16 lore raw

PATCH v7 11/12 x86/i387.c: Thread xstate is initialized only on CPU0 once

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

init_thread_xstate() is only called once to avoid overriding xstate_size during boot time or during CPU hotplug.

---
 arch/x86/kernel/i387.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)
arch/x86/kernel/i387.c +5 -1
index f250431..e4c3a21 100644
@@ -188,7 +188,11 @@ void __cpuinit fpu_init(void)
 		cr0 |= X86_CR0_EM;
 	write_cr0(cr0);
 
-	if (!smp_processor_id())
+	/*
+	 * init_thread_xstate is only called once to avoid overriding
+	 * xstate_size during boot time or during CPU hotplug.
+	 */
+	if (xstate_size == 0)
 		init_thread_xstate();
 
 	mxcsr_feature_mask_init();
Signature · 1 line
1.7.2
author
#17 lore raw

PATCH v7 12/12 x86/topology.c: debug CPU0 hotplug

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

CONFIG_DEBUG_HOTPLUG_CPU0 is for debuging the CPU0 hotplug feature. The switch offlines CPU0 as soon as possible and boots userspace up with CPU0 offlined. User can online CPU0 back after boot time. The default value of the switch is off.

To debug CPU0 hotplug, you need to enable CPU0 offline/online feature by either turning on CONFIG_BOOTPARAM_HOTPLUG_CPU0 during compilation or giving cpu0_hotplug kernel parameter at boot.

It's safe and early place to take down CPU0 after all hotplug notifiers are installed and SMP is booted.

---
 arch/x86/Kconfig           |   15 +++++++++++++
 arch/x86/include/asm/cpu.h |    3 ++
 arch/x86/kernel/topology.c |   51 ++++++++++++++++++++++++++++++++++++++++++++
 arch/x86/power/cpu.c       |   38 ++++++++++++++++++++++++++++++++
 4 files changed, 107 insertions(+), 0 deletions(-)
arch/x86/Kconfig +15 -0
index 31c8b89..6795c8a 100644
@@ -1740,6 +1740,21 @@ config BOOTPARAM_HOTPLUG_CPU0
 	  You still can enable the CPU0 hotplug feature at boot by kernel
 	  parameter cpu0_hotplug.
 
+config DEBUG_HOTPLUG_CPU0
+	def_bool n
+	prompt "Debug CPU0 hotplug"
+	depends on HOTPLUG_CPU && EXPERIMENTAL
+	---help---
+	  Enabling this option offlines CPU0 (if CPU0 can be offlined) as
+	  soon as possible and boots up userspace with CPU0 offlined. User
+	  can online CPU0 back after boot time.
+
+	  To debug CPU0 hotplug, you need to enable CPU0 offline/online
+	  feature by either turning on CONFIG_BOOTPARAM_HOTPLUG_CPU0 during
+	  compilation or giving cpu0_hotplug kernel parameter at boot.
+
+	  If unuser, say N.
+
 config COMPAT_VDSO
 	def_bool y
 	prompt "Compat VDSO support"
arch/x86/include/asm/cpu.h +3 -0
index a119572..5f9a124 100644
@@ -29,6 +29,9 @@ struct x86_cpu {
 extern int arch_register_cpu(int num);
 extern void arch_unregister_cpu(int);
 extern void __cpuinit start_cpu0(void);
+#ifdef CONFIG_DEBUG_HOTPLUG_CPU0
+extern int _debug_hotplug_cpu(int cpu, int action);
+#endif
 #endif
 
 DECLARE_PER_CPU(int, cpu_state);
arch/x86/kernel/topology.c +51 -0

57 lines not on this page · raw message

arch/x86/power/cpu.c +38 -0
index 3338609..abc748a 100644
@@ -21,6 +21,7 @@
 #include <asm/suspend.h>
 #include <asm/debugreg.h>
 #include <asm/fpu-internal.h> /* pcntxt_mask */
+#include <asm/cpu.h>
 
 #ifdef CONFIG_X86_32
 static struct saved_context saved_context;
@@ -263,6 +264,43 @@ static int bsp_pm_callback(struct notifier_block *nb, unsigned long action,
 	case PM_HIBERNATION_PREPARE:
 		ret = bsp_check();
 		break;
+#ifdef CONFIG_DEBUG_HOTPLUG_CPU0
+	case PM_RESTORE_PREPARE:
+		/*
+		 * When system resumes from hibernation, online CPU0 because
+		 * 1. it's required for resume and
+		 * 2. the CPU was online before hibernation
+		 */
+		if (!cpu_online(0))
+			_debug_hotplug_cpu(0, 1);
+		break;
+	case PM_POST_RESTORE:
+		/*
+		 * When a resume really happens, this code won't be called.
+		 *
+		 * This code is called only when user space hibernation software
+		 * prepares for snapshot device during boot time. So we just
+		 * call _debug_hotplug_cpu() to restore to CPU0's state prior to
+		 * preparing the snapshot device.
+		 *
+		 * This works for normal boot case in our CPU0 hotplug debug
+		 * mode, i.e. CPU0 is offline and user mode hibernation
+		 * software initializes during boot time.
+		 *
+		 * If CPU0 is online and user application accesses snapshot
+		 * device after boot time, this will offline CPU0 and user may
+		 * see different CPU0 state before and after accessing
+		 * the snapshot device. But hopefully this is not a case when
+		 * user debugging CPU0 hotplug. Even if users hit this case,
+		 * they can easily online CPU0 back.
+		 *
+		 * To simplify this debug code, we only consider normal boot
+		 * case. Otherwise we need to remember CPU0's state and restore
+		 * to that state and resolve racy conditions etc.
+		 */
+		_debug_hotplug_cpu(0, 0);
+		break;
+#endif
 	default:
 		break;
 	}
Signature · 1 line
1.7.2
#18 lore raw
In reply to Fenghua Yu

Hi Fenghua,

This patchset breaks compiling with Xen enabled on 64 bits:

/home/hpa/kernel/tip.x86-hotplug/arch/x86/xen/smp.c: In function ‘cpu_bringup’:
/home/hpa/kernel/tip.x86-hotplug/arch/x86/xen/smp.c:75:2: error: too few arguments to function ‘smp_store_cpu_info’ In file included from /home/hpa/kernel/tip.x86-hotplug/include/linux/smp.h:38:0,
from
/home/hpa/kernel/tip.x86-hotplug/include/linux/sched.h:70,
from
/home/hpa/kernel/tip.x86-hotplug/arch/x86/xen/smp.c:15:
/home/hpa/kernel/tip.x86-hotplug/arch/x86/include/asm/smp.h:169:6: note: declared here /home/hpa/kernel/tip.x86-hotplug/arch/x86/xen/smp.c: In function ‘xen_smp_prepare_cpus’:
/home/hpa/kernel/tip.x86-hotplug/arch/x86/xen/smp.c:257:2: error: too few arguments to function ‘smp_store_cpu_info’ In file included from /home/hpa/kernel/tip.x86-hotplug/include/linux/smp.h:38:0,
from
/home/hpa/kernel/tip.x86-hotplug/include/linux/sched.h:70,
from
/home/hpa/kernel/tip.x86-hotplug/arch/x86/xen/smp.c:15:
/home/hpa/kernel/tip.x86-hotplug/arch/x86/include/asm/smp.h:169:6: note: declared here
make[4]: *** [arch/x86/xen/smp.o] Error 1
make[3]: *** [arch/x86/xen] Error 2
make[2]: *** [arch/x86] Error 2
make[1]: *** [sub-make] Error 2
make[1]: Leaving directory `/home/hpa/kernel/tip.x86-hotplug'

Could you fix that?

-hpa