Skip to contentSkip to conversation

x86: Arbitrary CPU hot(un)plug support

PATCH Superseded Fenghua Yu 5 participants 33 messages Oct 12, 2012 – Oct 19, 2012

Subsystems (3)

v9 of 10 Superseded Latest is v10 →

lore
Share & tools
lore

Fenghua Yu

author
#0 lore raw

v9 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 patchset 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.

v9: Add Intel vendor check to support the feature on Intel platforms only.

v8: Add smp_store_boot_cpu_info() and change smp_store_cpu_info() back to avoid a compilation error. Fix a few messy subject issues.

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):
doc: Add x86 CPU0 online/offline feature
x86, Kconfig: Add config switch for CPU0 hotplug
x86, topology: Don't offline CPU0 if any PIC irq can not be migrated
out of it
x86, hotplug: Support functions for CPU0 online/offline x86, hotplug, suspend: Online CPU0 for suspend or hibernate x86-64, hotplug: Add start_cpu0() entry point to head_64.S x86-32, hotplug: Add start_cpu0() entry point to head_32.S x86, hotplug: Wake up CPU0 via NMI instead of INIT, SIPI, SIPI x86, hotplug: During CPU0 online, enable x2apic, set_numa_node. x86, hotplug: The first online processor saves the MTRR state x86/i387.c: Initialize thread xstate only on CPU0 only once x86, topology: Debug CPU00 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          |    1 +
 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           |  150 +++++++++++++++++++++++++++++------
 arch/x86/kernel/topology.c          |  101 ++++++++++++++++++++++--
 arch/x86/power/cpu.c                |   82 +++++++++++++++++++
 13 files changed, 428 insertions(+), 39 deletions(-)
Signature · 1 line
1.7.2
author
#1 lore raw

PATCH v9 1/12 doc: 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 df43807..20d7956 100644
@@ -1962,6 +1962,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 v9 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 56e7a25..cf53f0f 100644
@@ -1726,6 +1726,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
author
#3 lore raw

PATCH v9 3/12 x86, topology: 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]>

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.

Currently the feature is supported on Intel platforms only.

---
 arch/x86/kernel/topology.c |   50 +++++++++++++++++++++++++++++++++++++------
 1 files changed, 43 insertions(+), 7 deletions(-)
arch/x86/kernel/topology.c +43 -7
index 76ee977..0e7b4a7 100644
@@ -30,23 +30,59 @@
 #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)
 {
+	struct cpuinfo_x86 *c = &cpu_data(num);
+
+	/*
+	 * Currently CPU0 is only hotpluggable on Intel platforms. Other
+	 * vendors can add hotplug support later.
+	 */
+	if (c->x86_vendor != X86_VENDOR_INTEL)
+		cpu0_hotpluggable = 0;
+
 	/*
-	 * 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
maintainer
#4 lore raw

Re: [PATCH v9 03/12] x86, topology: Don't offline CPU0 if any PIC irq can not be migrated out of it

Quoted 9 lines · 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.

Quoted 5 lines

Currently the feature is supported on Intel platforms only.

---
 arch/x86/kernel/topology.c |   50 +++++++++++++++++++++++++++++++++++++------

It is just me or is this whole change better suited for

arch/x86/kernel/cpu/topology.c

where cpu-specific stuff lives anyway?

Thanks.

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

RE: [PATCH v9 03/12] x86, topology: Don't offline CPU0 if any PIC irq can not be migrated out of it

Quoted 18 lines · Fenghua Yu
Quoted 3 lines

From: Fenghua Yu <[email protected]>

If CONFIG_BOOTPARAM_HOTPLUG_CPU is turned on, CPU0 hotplug feature is

enabled

Quoted 3 lines

by default.

If CONFIG_BOOTPARAM_HOTPLUG_CPU is not turned on, CPU0 hotplug

feature is not

Quoted 1 line

enabled by default. The kernel parameter cpu0_hotplug can enable CPU0

hotplug

Quoted 7 lines

feature at boot.

Currently the feature is supported on Intel platforms only.

---
 arch/x86/kernel/topology.c |   50
Quoted 7 lines

+++++++++++++++++++++++++++++++++++++------

It is just me or is this whole change better suited for

arch/x86/kernel/cpu/topology.c

where cpu-specific stuff lives anyway?

arch/x86/kernel/cpu/topology.c doesn't contain CPU hotplug hooks. To place the BSP patchset in this file, other existing CPU hotplug code should be moved to this file as well. Apparently that's not this patchset's task.

Thanks.

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

maintainer
#6 lore raw

Re: [PATCH v9 03/12] x86, topology: Don't offline CPU0 if any PIC irq can not be migrated out of it

Quoted 4 lines · Fenghua

arch/x86/kernel/cpu/topology.c doesn't contain CPU hotplug hooks. To place the BSP patchset in this file, other existing CPU hotplug code should be moved to this file as well. Apparently that's not this patchset's task.

Right, ok.

But looking at this a bit more, we (someone :)) should probably merge those two files together since both deal with the cpu aspect of topology...

Oh well.

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

PATCH v9 4/12 x86, hotplug: Support functions for CPU0 online/offline

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

Add smp_store_boot_cpu_info() to store cpu info for BSP during boot time.

Now smp_store_cpu_info() stores cpu info for bringing up BSP or AP after it's offline.

Continue to online CPU0 in native_cpu_up().

Continue to offline CPU0 in native_cpu_disable().

---
 arch/x86/include/asm/smp.h |    1 +
 arch/x86/kernel/smpboot.c  |   38 ++++++++++++++++++--------------------
 2 files changed, 19 insertions(+), 20 deletions(-)
arch/x86/include/asm/smp.h +1 -0
index 4f19a15..b073aae 100644
@@ -166,6 +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_boot_cpu_info(void);
 void smp_store_cpu_info(int id);
 #define cpu_physical_id(cpu)	per_cpu(x86_cpu_to_apicid, cpu)
 
arch/x86/kernel/smpboot.c +18 -20
index c80a33b..c297907 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)
 {
@@ -279,19 +279,30 @@ notrace static void __cpuinit start_secondary(void *unused)
 	cpu_idle();
 }
 
+void __init smp_store_boot_cpu_info(void)
+{
+	int id = 0; /* CPU 0 */
+	struct cpuinfo_x86 *c = &cpu_data(id);
+
+	*c = boot_cpu_data;
+	c->cpu_index = id;
+}
+
 /*
  * The bootstrap kernel entry code has set these up. Save them for
  * a given CPU
  */
-
 void __cpuinit smp_store_cpu_info(int id)
 {
 	struct cpuinfo_x86 *c = &cpu_data(id);
 
 	*c = boot_cpu_data;
 	c->cpu_index = id;
-	if (id != 0)
-		identify_secondary_cpu(c);
+	/*
+	 * During boot time, CPU0 has this setup already. Save the info when
+	 * bringing up AP or offlined CPU0.
+	 */
+	identify_secondary_cpu(c);
 }
 
 static bool __cpuinit
@@ -795,7 +806,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 +1001,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_boot_cpu_info(); /* Final full version of the data */
 	cpumask_copy(cpu_callin_mask, cpumask_of(0));
 	mb();
 
@@ -1214,19 +1225,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
author
#8 lore raw

PATCH v9 5/12 x86, hotplug, suspend: Online CPU0 for suspend or hibernate

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

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.

---
 arch/x86/power/cpu.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 44 insertions(+), 0 deletions(-)
arch/x86/power/cpu.c +44 -0
index 218cdb1..adde775 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) {
+		pr_warn("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
#9 lore raw

Re: [PATCH v9 05/12] x86, hotplug, suspend: Online CPU0 for suspend or hibernate

Quoted 41 lines · On Friday 12 of October 2012 09:09:42 Fenghua Yu wrote:

From: Fenghua Yu <[email protected]>

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.

---
 arch/x86/power/cpu.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 44 insertions(+), 0 deletions(-)
arch/x86/power/cpu.c +22 -0
index 218cdb1..adde775 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) {
+		pr_warn("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) {

arch/x86/power/cpu.c void restore_processor_state(void) · line 271

Quoted 10 lines
arch/x86/power/cpu.c +10 -0
+	case PM_SUSPEND_PREPARE:
+	case PM_HIBERNATION_PREPARE:
+		ret = bsp_check();
+		break;
+	default:
+		break;
+	}
+	return notifier_from_errno(ret);
+}
+

I wonder if there's anything preventing CPU0 from becoming offline after you've done this check and before user space is frozen?

Rafael

Quoted 13 lines
arch/x86/power/cpu.c +12 -0
+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 · 2 lines
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
#10 lore raw

Re: [PATCH v9 05/12] x86, hotplug, suspend: Online CPU0 for suspend or hibernate

Quoted 47 lines · Rafael J. Wysocki
Quoted 46 lines · On Friday 12 of October 2012 09:09:42 Fenghua Yu wrote:

From: Fenghua Yu <[email protected]>

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.

---
 arch/x86/power/cpu.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 44 insertions(+), 0 deletions(-)
arch/x86/power/cpu.c +27 -0
index 218cdb1..adde775 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) {
+		pr_warn("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:
Quoted 9 lines

arch/x86/power/cpu.c void restore_processor_state(void) · line 271

Quoted 5 lines
arch/x86/power/cpu.c +5 -0
+		break;
+	}
+	return notifier_from_errno(ret);
+}
+

I wonder if there's anything preventing CPU0 from becoming offline after you've done this check and before user space is frozen?

Hi Rafael,

bsp_pm_callback runs as a low priority notifier callback, specifically with lower priority than the cpu_hotplug_pm_callback (as mentioned in the comment below). And cpu_hotplug_pm_callback disables regular CPU hotplug (till the suspend/resume sequence is complete).. So there is no chance for CPU0 to become offline after that.

Or, are you thinking of some other scenario where CPU0 can go offline?

Regards,
Srivatsa S. Bhat

Quoted 15 lines
Quoted 15 lines
arch/x86/power/cpu.c +12 -0
+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);
#11 lore raw

Re: [PATCH v9 05/12] x86, hotplug, suspend: Online CPU0 for suspend or hibernate

Quoted 58 lines · On Tuesday 16 of October 2012 11:05:18 Srivatsa S. Bhat wrote:
Quoted 47 lines · Rafael J. Wysocki
Quoted 46 lines · On Friday 12 of October 2012 09:09:42 Fenghua Yu wrote:

From: Fenghua Yu <[email protected]>

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.

---
 arch/x86/power/cpu.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 44 insertions(+), 0 deletions(-)
arch/x86/power/cpu.c +27 -0
index 218cdb1..adde775 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) {
+		pr_warn("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:
Quoted 9 lines

arch/x86/power/cpu.c void restore_processor_state(void) · line 271

Quoted 5 lines
arch/x86/power/cpu.c +5 -0
+		break;
+	}
+	return notifier_from_errno(ret);
+}
+

I wonder if there's anything preventing CPU0 from becoming offline after you've done this check and before user space is frozen?

Quoted 8 lines

Hi Rafael,

bsp_pm_callback runs as a low priority notifier callback, specifically with lower priority than the cpu_hotplug_pm_callback (as mentioned in the comment below). And cpu_hotplug_pm_callback disables regular CPU hotplug (till the suspend/resume sequence is complete).. So there is no chance for CPU0 to become offline after that.

Or, are you thinking of some other scenario where CPU0 can go offline?

No, that should be fine technically, but designs relying on notifier priority for correctness are kind of fragile.

Would it be possible to make cpu_hotplug_pm_callback() do the BSP online check?

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
arch/x86/power/cpu.c +4 -0
+static int __init bsp_pm_check_init(void)
+{
+	/*
+	 * Set this bsp_pm_callback as lower priority than
Quoted 8 lines
Quoted 8 lines

arch/x86/power/cpu.c void restore_processor_state(void) · line 283

Quoted 8 lines
arch/x86/power/cpu.c +8 -0
+	 * 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);

Thanks,
Rafael

Signature · 2 lines
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
#12 lore raw

Re: [PATCH v9 05/12] x86, hotplug, suspend: Online CPU0 for suspend or hibernate

Quoted 49 lines · Rafael J. Wysocki
Quoted 48 lines · On Tuesday 16 of October 2012 11:05:18 Srivatsa S. Bhat wrote:
Quoted 30 lines · Rafael J. Wysocki
Quoted 29 lines · On Friday 12 of October 2012 09:09:42 Fenghua Yu wrote:

From: Fenghua Yu <[email protected]>

arch/x86/power/cpu.c +27 -0
+
+/*
+ * 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) {
+		pr_warn("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:
Quoted 9 lines

arch/x86/power/cpu.c void restore_processor_state(void) · line 271

Quoted 5 lines
arch/x86/power/cpu.c +5 -0
+		break;
+	}
+	return notifier_from_errno(ret);
+}
+

I wonder if there's anything preventing CPU0 from becoming offline after you've done this check and before user space is frozen?

Hi Rafael,

bsp_pm_callback runs as a low priority notifier callback, specifically with lower priority than the cpu_hotplug_pm_callback (as mentioned in the comment below). And cpu_hotplug_pm_callback disables regular CPU hotplug (till the suspend/resume sequence is complete).. So there is no chance for CPU0 to become offline after that.

Quoted 5 lines
Quoted 1 line

Or, are you thinking of some other scenario where CPU0 can go offline?

No, that should be fine technically, but designs relying on notifier priority for correctness are kind of fragile.

Hmm.. I agree.

Quoted 2 lines

Would it be possible to make cpu_hotplug_pm_callback() do the BSP online check?

Good idea! I think that could be done quite easily. And while doing that, it would be good to rethink what to do in patch 12/12 (Debug CPU0 hotplug) to fix the bug I pointed out in my other mail.

Regards,
Srivatsa S. Bhat

Quoted 13 lines
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
arch/x86/power/cpu.c +12 -0
+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);
#13 lore raw

RE: [PATCH v9 05/12] x86, hotplug, suspend: Online CPU0 for suspend or hibernate

Quoted 69 lines · Rafael J. Wysocki
Quoted 8 lines · On Tuesday 16 of October 2012 11:05:18 Srivatsa S. Bhat wrote:
Quoted 7 lines · Rafael J. Wysocki
Quoted 6 lines · On Friday 12 of October 2012 09:09:42 Fenghua Yu wrote:

arch/x86/power/cpu.c void restore_processor_state(void)

Quoted 5 lines

From: Fenghua Yu <[email protected]>

arch/x86/power/cpu.c +3 -0
+
+/*
+ * When bsp_check() is called in hibernate and suspend, cpu

hotplug

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

+ * is disabled already. So it's unnessary to handle race

condition between

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

+ * cpumask query and cpu hotplug.
+ */

arch/x86/power/cpu.c +3 -0
+static int bsp_check(void)
+{
+	if (cpumask_first(cpu_online_mask) != 0) {
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

arch/x86/power/cpu.c void restore_processor_state(void)

Quoted 8 lines
arch/x86/power/cpu.c +8 -0
+		pr_warn("CPU0 is offline.\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int bsp_pm_callback(struct notifier_block *nb, unsigned

long action,

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
arch/x86/power/cpu.c +9 -0
+			   void *ptr)
+{
+	int ret = 0;
+
+	switch (action) {
+	case PM_SUSPEND_PREPARE:
+	case PM_HIBERNATION_PREPARE:
+		ret = bsp_check();
+		break;
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

arch/x86/power/cpu.c void restore_processor_state(void) · line 271

Quoted 6 lines
arch/x86/power/cpu.c +6 -0
+	default:
+		break;
+	}
+	return notifier_from_errno(ret);
+}
+

I wonder if there's anything preventing CPU0 from becoming offline

after you've

Quoted 6 lines
Quoted 6 lines
Quoted 2 lines

done this check and before user space is frozen?

Hi Rafael,

bsp_pm_callback runs as a low priority notifier callback,

specifically with lower

Quoted 1 line
Quoted 1 line

priority than the cpu_hotplug_pm_callback (as mentioned in the

comment below).

Quoted 1 line
Quoted 1 line

And cpu_hotplug_pm_callback disables regular CPU hotplug (till the

suspend/resume

Quoted 1 line
Quoted 1 line

sequence is complete).. So there is no chance for CPU0 to become

offline after that.

Quoted 2 lines
Quoted 2 lines

Or, are you thinking of some other scenario where CPU0 can go

offline?

Quoted 2 lines

No, that should be fine technically, but designs relying on notifier

priority

Quoted 2 lines

for correctness are kind of fragile.

Hmm.. I agree.

Quoted 1 line

Would it be possible to make cpu_hotplug_pm_callback() do the BSP

Quoted 8 lines

online check?

Quoted 1 line

Good idea! I think that could be done quite easily. And while doing that, it would
be good to rethink what to do in patch 12/12 (Debug CPU0 hotplug) to fix the bug I
pointed out in my other mail.

Why is this design relying on notifier priority fragile? I don't get it.

The priority in pm_notifier() is in a well designed API. This code just follows the API to assign lower priority for bsp_pm_callback than cpu_hotplug_pm_callback. Unless your justification is that the API of pm_notifier() is fragile, I think this patch should be ok.

It's not a good idea to move bsp_pm_callback() into cpu_hotplug_pm_callback(). There is no architecture specific hook to call x86 bsp specific hotplug in cpu_hotplug_pm_callback(). Moving bsp_pm_callback() into cpu_hotplug_pm_callback() is hacking while this patch follows well defined API and has better coding.

Thanks.

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

#14 lore raw

Re: [PATCH v9 05/12] x86, hotplug, suspend: Online CPU0 for suspend or hibernate

Quoted 72 lines · Fenghua
Quoted 72 lines · Rafael J. Wysocki
Quoted 8 lines · On Tuesday 16 of October 2012 11:05:18 Srivatsa S. Bhat wrote:
Quoted 7 lines · Rafael J. Wysocki
Quoted 6 lines · On Friday 12 of October 2012 09:09:42 Fenghua Yu wrote:

arch/x86/power/cpu.c void restore_processor_state(void)

Quoted 5 lines

From: Fenghua Yu <[email protected]>

arch/x86/power/cpu.c +3 -0
+
+/*
+ * When bsp_check() is called in hibernate and suspend, cpu

hotplug

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

+ * is disabled already. So it's unnessary to handle race

condition between

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

+ * cpumask query and cpu hotplug.
+ */

arch/x86/power/cpu.c +3 -0
+static int bsp_check(void)
+{
+	if (cpumask_first(cpu_online_mask) != 0) {
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

arch/x86/power/cpu.c void restore_processor_state(void)

Quoted 8 lines
arch/x86/power/cpu.c +8 -0
+		pr_warn("CPU0 is offline.\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int bsp_pm_callback(struct notifier_block *nb, unsigned

long action,

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
arch/x86/power/cpu.c +9 -0
+			   void *ptr)
+{
+	int ret = 0;
+
+	switch (action) {
+	case PM_SUSPEND_PREPARE:
+	case PM_HIBERNATION_PREPARE:
+		ret = bsp_check();
+		break;
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

arch/x86/power/cpu.c void restore_processor_state(void) · line 271

Quoted 6 lines
arch/x86/power/cpu.c +6 -0
+	default:
+		break;
+	}
+	return notifier_from_errno(ret);
+}
+

I wonder if there's anything preventing CPU0 from becoming offline

after you've

Quoted 6 lines
Quoted 6 lines
Quoted 2 lines

done this check and before user space is frozen?

Hi Rafael,

bsp_pm_callback runs as a low priority notifier callback,

specifically with lower

Quoted 1 line
Quoted 1 line

priority than the cpu_hotplug_pm_callback (as mentioned in the

comment below).

Quoted 1 line
Quoted 1 line

And cpu_hotplug_pm_callback disables regular CPU hotplug (till the

suspend/resume

Quoted 1 line
Quoted 1 line

sequence is complete).. So there is no chance for CPU0 to become

offline after that.

Quoted 2 lines
Quoted 2 lines

Or, are you thinking of some other scenario where CPU0 can go

offline?

Quoted 2 lines

No, that should be fine technically, but designs relying on notifier

priority

Quoted 2 lines

for correctness are kind of fragile.

Hmm.. I agree.

Quoted 1 line

Would it be possible to make cpu_hotplug_pm_callback() do the BSP

online check?

Quoted 1 line
Quoted 7 lines
Quoted 5 lines

Good idea! I think that could be done quite easily. And while doing that, it would
be good to rethink what to do in patch 12/12 (Debug CPU0 hotplug) to fix the bug I
pointed out in my other mail.

Why is this design relying on notifier priority fragile? I don't get it.

Because things like this are often overlooked by people trying to optimize stuff and the fact that you have to add a comment explaining that dependency only means that it is not exactly straightforward.

Moreover, you should also add a corresponding comment in the other notifier indicating that its priority should be higher than the priority of the new thing and explaining why.

Quoted 4 lines

The priority in pm_notifier() is in a well designed API. This code just follows the API to assign lower priority for bsp_pm_callback than cpu_hotplug_pm_callback. Unless your justification is that the API of pm_notifier() is fragile, I think this patch should be ok.

I really think that notifiers are fragile in general and this particular one is no exception.

Quoted 5 lines

It's not a good idea to move bsp_pm_callback() into cpu_hotplug_pm_callback(). There is no architecture specific hook to call x86 bsp specific hotplug in cpu_hotplug_pm_callback(). Moving bsp_pm_callback() into cpu_hotplug_pm_callback() is hacking while this patch follows well defined API and has better coding.

I'm not sure it is better coding. You really want one piece of code to always follow another piece of code and the best way to ensure that is to execute them both explicitly in sequence.

Thanks,
Rafael

Signature · 2 lines
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
#15 lore raw

RE: [PATCH v9 05/12] x86, hotplug, suspend: Online CPU0 for suspend or hibernate

Quoted 6 lines
Quoted 1 line
Quoted 1 line · Rafael J. Wysocki
Quoted 4 lines · Fenghua
Quoted 4 lines · Rafael J. Wysocki
Quoted 3 lines · On Tuesday 16 of October 2012 11:05:18 Srivatsa S. Bhat wrote:
Quoted 2 lines · Rafael J. Wysocki
Quoted 1 line · On Friday 12 of October 2012 09:09:42 Fenghua Yu wrote:
Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

From: Fenghua Yu <[email protected]>

fix the bug I
pointed out in my other mail.

Because things like this are often overlooked by people trying to optimize
stuff and the fact that you have to add a comment explaining that dependency
only means that it is not exactly straightforward.

If people try to optimize pm notifier, they really need to know pm_notifier() API and its priority. If they ignore the priority, they will screw up kernel no matter how many comments in it.

Quoted 5 lines

Moreover, you should also add a corresponding comment in the other notifier
indicating that its priority should be higher than the priority of the new thing and explaining why.

The comment in the patch explains this very clearly. I don't think it's necessary to add comments in other notifiers.

If adding comments in other notifiers each time when you add a new notifier, will you add 10 more comments in all other notifiers if you add 10 new notifiers?

I would think when people try to change notifier priority, they should know what they are going to do and search the notifiers and see the comments.

BTW, the other notifier is in generic code. Adding a paranoid comment in it doesn't seem to be worth. The comment in this patch code is very clear already.

Quoted 4 lines

I really think that notifiers are fragile in general and this particular
one is no exception.

If we think pm_notifier API is fragile, we need to fix the API instead of leaving it there and not allowing people to use it because it's suspected fragile.

It's simply not realistic to tell people not to use the API each time in code review while in the meantime the API and its priority are staying in kernel to allow people to use it.

Quoted 10 lines
Quoted 6 lines

It's not a good idea to move bsp_pm_callback() into cpu_hotplug_pm_callback(). There is no architecture specific hook to call x86 bsp specific hotplug in cpu_hotplug_pm_callback(). Moving bsp_pm_callback() into cpu_hotplug_pm_callback() is hacking while this patch follows well defined API and has better coding.

I'm not sure it is better coding. You really want one piece of code to always follow another piece of code and the best way to ensure that is to execute them both explicitly in sequence.

Besides notifiers, there are other places relying on priority (e.g. initcall). Again, if we think the priority in notifiers and other APIs are fragile, why don't we fix the APIs?

The problem of calling bsp_pm_callback() in cpu_hotplug_pm_callback() is that cpu_hotplug_pm_callback() is defined in generic kernel/cpu.c. This bsp hotplug patchset is x86 arch specific code so far. Changing kernel/cpu.c to hook arch specific code is more like hacking kernel compared to the systematic way to do so in the patch.

Thanks.

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

#16 lore raw

Re: [PATCH v9 05/12] x86, hotplug, suspend: Online CPU0 for suspend or hibernate

Quoted 25 lines · Fenghua
Quoted 6 lines
Quoted 1 line
Quoted 1 line · Rafael J. Wysocki
Quoted 4 lines · Fenghua
Quoted 4 lines · Rafael J. Wysocki
Quoted 3 lines · On Tuesday 16 of October 2012 11:05:18 Srivatsa S. Bhat wrote:
Quoted 2 lines · Rafael J. Wysocki
Quoted 1 line · On Friday 12 of October 2012 09:09:42 Fenghua Yu wrote:
Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

From: Fenghua Yu <[email protected]>

fix the bug I
pointed out in my other mail.

Because things like this are often overlooked by people trying to optimize
stuff and the fact that you have to add a comment explaining that dependency
only means that it is not exactly straightforward.

If people try to optimize pm notifier, they really need to know pm_notifier() API and its priority. If they ignore the priority, they will screw up kernel no matter how many comments in it.

Quoted 5 lines

Moreover, you should also add a corresponding comment in the other notifier
indicating that its priority should be higher than the priority of the new thing and explaining why.

Quoted 5 lines

The comment in the patch explains this very clearly. I don't think it's necessary to add comments in other notifiers.

If adding comments in other notifiers each time when you add a new notifier, will you add 10 more comments in all other notifiers if you add 10 new notifiers?

Well, if there are strict ordering requirements regarding them, then those requirements should be documented in both places. Otherwise, if somebody looks at cpu_hotplug_pm_callback() alone, for example, he/she may not even realize that it has to be strictly ordered with respect to bsp_pm_callback().

Of course, you can argue that people should know what they are doing, but then reality is that it's quite easy to overlook things like that.

Quoted 6 lines

I would think when people try to change notifier priority, they should know what they are going to do and search the notifiers and see the comments.

BTW, the other notifier is in generic code. Adding a paranoid comment in it doesn't seem to be worth. The comment in this patch code is very clear already.

The problem is that it is generally difficult to find all subsystems that have registered notifiers in a given chain and figuring out dependencies between them is highly problematic. That's why I'm saying this is a fragile design - because it is so easy to break accidentally (and that's already happened in CPU hotplug, so I'm not making that up).

Quoted 7 lines
Quoted 3 lines

I really think that notifiers are fragile in general and this particular
one is no exception.

If we think pm_notifier API is fragile, we need to fix the API instead of leaving it there and not allowing people to use it because it's suspected fragile.

Because it is use by the existing code which generally works and may be broken while attempting to "fix" the API.

Quoted 3 lines

It's simply not realistic to tell people not to use the API each time in code review while in the meantime the API and its priority are staying in kernel to allow people to use it.

I don't quite agree. It sometimes is not worth changing code that's been around for a while already, because it's been tested in multiple configurations and changing it may cause things to break, although we may not like the APIs used by that code. That doesn't necessarily mean, however, that adding new code using those APIs is always a good idea.

In this particular case I just wondered if we could avoid adding more code that would use an API having known problems. The answer seems to be that it would cost some additional complexity that might not be worth it. This is a good answer, but you might have given it to me directly. :-)

Thanks,
Rafael

Signature · 2 lines
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
#17 lore raw

Re: [PATCH v9 05/12] x86, hotplug, suspend: Online CPU0 for suspend or hibernate

Quoted 29 lines · Rafael J. Wysocki
Quoted 28 lines · Fenghua
Quoted 6 lines
Quoted 1 line
Quoted 1 line · Rafael J. Wysocki
Quoted 4 lines · Fenghua
Quoted 4 lines · Rafael J. Wysocki
Quoted 3 lines · On Tuesday 16 of October 2012 11:05:18 Srivatsa S. Bhat wrote:
Quoted 2 lines · Rafael J. Wysocki
Quoted 1 line · On Friday 12 of October 2012 09:09:42 Fenghua Yu wrote:
Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

From: Fenghua Yu <[email protected]>

fix the bug I
pointed out in my other mail.

Because things like this are often overlooked by people trying to optimize
stuff and the fact that you have to add a comment explaining that dependency
only means that it is not exactly straightforward.

If people try to optimize pm notifier, they really need to know pm_notifier() API and its priority. If they ignore the priority, they will screw up kernel no matter how many comments in it.

Quoted 5 lines

Moreover, you should also add a corresponding comment in the other notifier
indicating that its priority should be higher than the priority of the new thing and explaining why.

The comment in the patch explains this very clearly. I don't think it's necessary to add comments in other notifiers.

Quoted 8 lines
Quoted 2 lines

If adding comments in other notifiers each time when you add a new notifier, will you add 10 more comments in all other notifiers if you add 10 new notifiers?

Well, if there are strict ordering requirements regarding them, then those requirements should be documented in both places. Otherwise, if somebody looks at cpu_hotplug_pm_callback() alone, for example, he/she may not even realize that it has to be strictly ordered with respect to bsp_pm_callback().

Right, either we could put comments at both places or set up #defines for their priorities in a common header file or some such and comment about it there, like what is done in include/linux/cpu.h for example. But atleast one of these *has* to be done; just commenting at one place is too risky for code-maintenance.

Quoted 3 lines

Of course, you can argue that people should know what they are doing, but then reality is that it's quite easy to overlook things like that.

Yep.

Quoted 7 lines
Quoted 6 lines

I would think when people try to change notifier priority, they should know what they are going to do and search the notifiers and see the comments.

BTW, the other notifier is in generic code. Adding a paranoid comment in it doesn't seem to be worth. The comment in this patch code is very clear already.

Quoted 5 lines

The problem is that it is generally difficult to find all subsystems that have registered notifiers in a given chain and figuring out dependencies between them is highly problematic. That's why I'm saying this is a fragile design - because it is so easy to break accidentally (and that's already happened in CPU hotplug, so I'm not making that up).

True..

Regards,
Srivatsa S. Bhat

Quoted 27 lines
Quoted 8 lines
Quoted 4 lines

I really think that notifiers are fragile in general and this particular
one is no exception.

If we think pm_notifier API is fragile, we need to fix the API instead of leaving it there and not allowing people to use it because it's suspected fragile.

Because it is use by the existing code which generally works and may be broken while attempting to "fix" the API.

Quoted 3 lines

It's simply not realistic to tell people not to use the API each time in code review while in the meantime the API and its priority are staying in kernel to allow people to use it.

I don't quite agree. It sometimes is not worth changing code that's been around for a while already, because it's been tested in multiple configurations and changing it may cause things to break, although we may not like the APIs used by that code. That doesn't necessarily mean, however, that adding new code using those APIs is always a good idea.

In this particular case I just wondered if we could avoid adding more code that would use an API having known problems. The answer seems to be that it would cost some additional complexity that might not be worth it. This is a good answer, but you might have given it to me directly. :-)

#18 lore raw

RE: [PATCH v9 05/12] x86, hotplug, suspend: Online CPU0 for suspend or hibernate

In reply to Srivatsa S. Bhat
Quoted 67 lines

From: Srivatsa S. Bhat [mailto:[email protected]]

Quoted 4 lines · Rafael J. Wysocki
Quoted 3 lines · On Friday 12 of October 2012 09:09:42 Fenghua Yu wrote:

From: Fenghua Yu <[email protected]>

Because x86 BIOS requires CPU0 to resume from sleep, suspend or

hibernate can't

Quoted 1 line
Quoted 1 line

be executed if CPU0 is detected offline. To make suspend or

hibernate and

Quoted 5 lines
Quoted 5 lines

further resume succeed, CPU0 must be online.

---
 arch/x86/power/cpu.c |   44

++++++++++++++++++++++++++++++++++++++++++++

Quoted 14 lines
Quoted 7 lines
 1 files changed, 44 insertions(+), 0 deletions(-)
arch/x86/power/cpu.c +0 -0
index 218cdb1..adde775 100644

arch/x86/power/cpu.c void restore_processor_state(void) · line 243

Quoted 7 lines
arch/x86/power/cpu.c +4 -0
@@ -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

Quoted 5 lines
Quoted 5 lines
arch/x86/power/cpu.c +5 -0
+ * cpumask query and cpu hotplug.
+ */
+static int bsp_check(void)
+{
+	if (cpumask_first(cpu_online_mask) != 0) {
Quoted 8 lines

arch/x86/power/cpu.c void restore_processor_state(void)

Quoted 8 lines
arch/x86/power/cpu.c +8 -0
+		pr_warn("CPU0 is offline.\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int bsp_pm_callback(struct notifier_block *nb, unsigned long

action,

Quoted 9 lines
Quoted 9 lines
arch/x86/power/cpu.c +9 -0
+			   void *ptr)
+{
+	int ret = 0;
+
+	switch (action) {
+	case PM_SUSPEND_PREPARE:
+	case PM_HIBERNATION_PREPARE:
+		ret = bsp_check();
+		break;
Quoted 8 lines

arch/x86/power/cpu.c void restore_processor_state(void) · line 271

Quoted 6 lines
arch/x86/power/cpu.c +6 -0
+	default:
+		break;
+	}
+	return notifier_from_errno(ret);
+}
+

I wonder if there's anything preventing CPU0 from becoming offline

after you've

Quoted 2 lines

done this check and before user space is frozen?

Hi Rafael,

Quoted 8 lines

bsp_pm_callback runs as a low priority notifier callback, specifically with lower
priority than the cpu_hotplug_pm_callback (as mentioned in the comment below).
And cpu_hotplug_pm_callback disables regular CPU hotplug (till the suspend/resume
sequence is complete).. So there is no chance for CPU0 to become offline after that.

Bhat is right here. There is no functionality issue here.

bsp_check() is protected by cpu_hotplug_disable which is set before bsp_pm_callback and cleared after it. There is no chance for CPU0 to be offline after that.

Thanks.

-Fenghua

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

author
#19 lore raw

PATCH v9 6/12 x86-64, hotplug: Add start_cpu0() entry point to head_64.S

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

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.

---
 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
maintainer
#20 lore raw

Re: [PATCH v9 06/12] x86-64, hotplug: Add start_cpu0() entry point to head_64.S

Quoted 21 lines · Fenghua Yu

From: Fenghua Yu <[email protected]>

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.

---
 arch/x86/kernel/head_64.S |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)
arch/x86/kernel/head_64.S +3 -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

arch/x86/kernel/head_64.S ENTRY(secondary_startup_64) · line 267

Quoted 10 lines
arch/x86/kernel/head_64.S +10 -0
+ * 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

ENDPROC(start_cpu0) maybe?

Ditto for head_32.S in the next patch.

Thanks.

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

PATCH v9 7/12 x86-32, hotplug: Add start_cpu0() entry point to head_32.S

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

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.

---
 arch/x86/kernel/head_32.S |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
arch/x86/kernel/head_32.S +12 -0
index 957a47a..207abd4 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
author
#22 lore raw

PATCH v9 8/12 x86, hotplug: Wake up CPU0 via NMI instead of INIT, SIPI, SIPI

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

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.

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, SIPI, SIPI 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
#23 lore raw

Re: [PATCH v9 08/12] x86, hotplug: Wake up CPU0 via NMI instead of INIT, SIPI, SIPI

From: Fenghua Yu <[email protected]>
Subject: [PATCH v9 08/12] x86, hotplug: Wake up CPU0 via NMI instead of INIT, SIPI, SIPI
Date: Fri, 12 Oct 2012 09:09:45 -0700

<cut>

arch/x86/kernel/smpboot.c void __init native_smp_prepare_cpus(unsigned int max_cpus) · line 1105

Quoted 6 lines
arch/x86/kernel/smpboot.c +2 -0
@@ -1037,6 +1101,8 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 	 */
 	setup_local_APIC();
 
+	cpu0_logical_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
+

In x2apic mode, logical apicid occupies a whole 32-bit length of LDR, but GET_APIC_LOGICAL_ID returns high 31-24 bits only, and this is only for xapic mode.

Thanks.
HATAYAMA, Daisuke

maintainer
#24 lore raw

Re: [PATCH v9 08/12] x86, hotplug: Wake up CPU0 via NMI instead of INIT, SIPI, SIPI

In reply to Fenghua Yu
Quoted 18 lines · Fenghua Yu

From: Fenghua Yu <[email protected]>

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.

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, SIPI, SIPI sequence.

---
 arch/x86/include/asm/cpu.h |    1 +
 arch/x86/kernel/smpboot.c  |  112 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 107 insertions(+), 6 deletions(-)

[ … ]

Quoted 35 lines
arch/x86/kernel/smpboot.c +29 -2
@@ -727,8 +745,47 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
 	 */
 	if (apic->wakeup_secondary_cpu)
 		boot_error = apic->wakeup_secondary_cpu(apicid, start_ip);
-	else
-		boot_error = wakeup_secondary_cpu_via_init(apicid, start_ip);
+	else {
+		if (cpu)
+			/*
+			 * Wake up AP by INIT, INIT, STARTUP sequence.
+			 */
+			boot_error = wakeup_secondary_cpu_via_init(apicid,
+								   start_ip);
+		else {
+			/*
+			 * 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.
+			 *
+			 * 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.
+			 */
+			int id;
+
+			enable_start_cpu0 = 1;
+			/*
+			 * Register a NMI handler to help wake up CPU0.
+			 */
+			boot_error = register_nmi_handler(NMI_LOCAL,
+					 wakeup_cpu0_nmi, 0, "wake_cpu0");

arch/x86/kernel/smpboot.c static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle) · line 786

Quoted 10 lines
arch/x86/kernel/smpboot.c +10 -0
+
+			if (!boot_error) {
+				cpu0_nmi_registered = 1;
+				if (apic->dest_logical == APIC_DEST_LOGICAL)
+					id = cpu0_logical_apicid;
+				else
+					id = apicid;
+				boot_error = wakeup_secondary_cpu_via_nmi(id,
+								start_ip);
+			}

This whole else-part for cpu 0 could be carved out into a separate function so that you can save yourself the awkward code indentation and make this a lot more readable.

Thanks.

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

PATCH v9 9/12 x86, hotplug: During CPU0 online, enable x2apic, set_numa_node.

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

Previously these functions were not run on the BSP (CPU 0, the boot processor) since the boot processor init would only be executed before this functionality was initialized.

---
 arch/x86/kernel/cpu/common.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/common.c +2 -3
index 7505f7b..ca165ac 100644
@@ -1237,7 +1237,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
@@ -1269,8 +1269,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
#26 lore raw

PATCH v9 10/12 x86, hotplug: The first online processor saves the MTRR state

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

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

---
 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
#27 lore raw

PATCH v9 11/12 x86/i387.c: Initialize thread xstate only on CPU0 only 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 675a050..245a71d 100644
@@ -175,7 +175,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
#28 lore raw

PATCH v9 12/12 x86, topology: Debug CPU00 hotplug

In reply to Fenghua Yu

From: Fenghua Yu <[email protected]>

CONFIG_DEBUG_HOTPLUG_CPU0 is for debugging 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.

Please note that some applications or drivers, e.g. some versions of udevd, during boot time may put CPU0 online again in this CPU0 hotplug debug mode.

In this debug mode, setup_local_APIC() may report a warning on max_loops<=0 when CPU0 is onlined back after boot time. This is because pending interrupt in IRR can not move to ISR. The warning is not CPU0 specfic and it can happen on other CPUs as well. It is harmless except the first CPU0 online takes a bit longer time. And so this debug mode is useful to expose this issue. I'll send a seperate patch to fix this generic warning issue.

---
 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 cf53f0f..1abcae4 100644
@@ -1755,6 +1755,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 adde775..120cee1 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
#29 lore raw

Re: [PATCH v9 12/12] x86, topology: Debug CPU00 hotplug

Quoted 6 lines · Fenghua Yu

From: Fenghua Yu <[email protected]>

arch/x86/Kconfig +4 -0
+config DEBUG_HOTPLUG_CPU0
+	def_bool n
+	prompt "Debug CPU0 hotplug"
+	depends on HOTPLUG_CPU && EXPERIMENTAL

arch/x86/Kconfig config BOOTPARAM_HOTPLUG_CPU0 · line 1771

Quoted 10 lines
arch/x86/Kconfig +10 -0
+	---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.

s/unuser/unsure

Quoted 69 lines
arch/x86/kernel/topology.c +51 -0
+#ifdef CONFIG_DEBUG_HOTPLUG_CPU0
+/*
+ * This function offlines a CPU as early as possible and allows userspace to
+ * boot up without the CPU. The CPU can be onlined back by user after boot.
+ *
+ * This is only called for debugging CPU offline/online feature.
+ */
+int __ref _debug_hotplug_cpu(int cpu, int action)
+{
+	struct device *dev = get_cpu_device(cpu);
+	int ret;
+
+	if (!cpu_is_hotpluggable(cpu))
+		return -EINVAL;
+
+	cpu_hotplug_driver_lock();
+
+	switch (action) {
+	case 0:
+		ret = cpu_down(cpu);
+		if (!ret) {
+			pr_info("CPU %u is now offline\n", cpu);
+			kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
+		} else
+			pr_debug("Can't offline CPU%d.\n", cpu);
+		break;
+	case 1:
+		ret = cpu_up(cpu);
+		if (!ret)
+			kobject_uevent(&dev->kobj, KOBJ_ONLINE);
+		else
+			pr_debug("Can't online CPU%d.\n", cpu);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	cpu_hotplug_driver_unlock();
+
+	return ret;
+}
+
+static int __init debug_hotplug_cpu(void)
+{
+	_debug_hotplug_cpu(0, 0);
+	return 0;
+}
+
+late_initcall_sync(debug_hotplug_cpu);
+#endif /* CONFIG_DEBUG_HOTPLUG_CPU0 */
+
 int __ref arch_register_cpu(int num)
 {
 	struct cpuinfo_x86 *c = &cpu_data(num);
arch/x86/power/cpu.c +1 -0
index adde775..120cee1 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();

arch/x86/power/cpu.c static int bsp_pm_callback(struct notifier_block *nb, unsigned long action, · line 275

Quoted 10 lines
arch/x86/power/cpu.c +9 -0
 		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);

This won't work. CPU hotplug is disabled by cpu_hotplug_pm_callback() during PM_HIBERNATION_PREPARE and is enabled back only during PM_POST_HIBERNATION.

So calls to cpu_up() or cpu_down() will fail in the meantime.

Regards,
Srivatsa S. Bhat

Quoted 32 lines
arch/x86/power/cpu.c +28 -0
+		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;
 	}
#30 lore raw

RE: [PATCH v9 12/12] x86, topology: Debug CPU00 hotplug

Quoted 16 lines
Quoted 1 line

+#ifdef CONFIG_DEBUG_HOTPLUG_CPU0

arch/x86/power/cpu.c +1 -0
+	case PM_RESTORE_PREPARE:

Review

Quoted 2 lines
(quoted diff) +2 -0
+		/*
+		 * When system resumes from hibernation, online CPU0

because

arch/x86/power/cpu.c static int bsp_pm_callback(struct notifier_block *nb, unsigned long action, · line 275

Quoted 5 lines
arch/x86/power/cpu.c +5 -0
+		 * 1. it's required for resume and
+		 * 2. the CPU was online before hibernation
+		 */
+		if (!cpu_online(0))
+			_debug_hotplug_cpu(0, 1);

This won't work. CPU hotplug is disabled by cpu_hotplug_pm_callback() during
PM_HIBERNATION_PREPARE and is enabled back only during PM_POST_HIBERNATION.

Quoted 1 line

So calls to cpu_up() or cpu_down() will fail in the meantime.

The code works just fine.

You are talking about hibernation/suspend phase. This piece of code is all about restore phase. Of course you can call cpu_up() and cpu_down() during restore phase.

So there is no problem here.

Thanks.

-Fenghua

#31 lore raw

Re: [PATCH v9 12/12] x86, topology: Debug CPU00 hotplug

Quoted 18 lines · Fenghua
Quoted 16 lines
Quoted 1 line

+#ifdef CONFIG_DEBUG_HOTPLUG_CPU0

arch/x86/power/cpu.c +1 -0
+	case PM_RESTORE_PREPARE:

Review

Quoted 2 lines
(quoted diff) +2 -0
+		/*
+		 * When system resumes from hibernation, online CPU0

because

arch/x86/power/cpu.c static int bsp_pm_callback(struct notifier_block *nb, unsigned long action, · line 275

Quoted 5 lines
arch/x86/power/cpu.c +5 -0
+		 * 1. it's required for resume and
+		 * 2. the CPU was online before hibernation
+		 */
+		if (!cpu_online(0))
+			_debug_hotplug_cpu(0, 1);

This won't work. CPU hotplug is disabled by cpu_hotplug_pm_callback() during
PM_HIBERNATION_PREPARE and is enabled back only during PM_POST_HIBERNATION.

Quoted 1 line

So calls to cpu_up() or cpu_down() will fail in the meantime.

Quoted 8 lines

The code works just fine.

You are talking about hibernation/suspend phase. This piece of code is all about restore phase. Of course you can call cpu_up() and cpu_down() during restore phase.

So there is no problem here.

I looked into it again, and actually you are right, it'll work fine; but the reason *why* it will work fine is quite subtle.

Note that there is a difference between calling cpu_up() or cpu_down() vs calling _cpu_up() or _cpu_down(). The former set of calls will return -EBUSY if the 'cpu_hotplug_disabled' flag is set. The latter set of calls don't care about that flag and hence proceed irrespective of the state of that flag. The former set of calls are used when you echo 0/1 to the online file from userspace. Whereas the latter set of calls are used by the disable/enable_nonboot_cpus() functions. This is how you can disable cpu hotplug by userspace, but continue to do cpu hotplug yourself from within the kernel in the suspend/hibernation/restore phases.

Now, coming to the notifications part, earlier, I was referring to the entire hibernate->restore phase, not just the hibernate phase. The relevant notifications that are sent out during this entire (successful) sequence are:

-> PM_HIBERNATION_PREPARE
-> PM_RESTORE_PREPARE
-> PM_POST_HIBERNATION

cpu_hotplug_pm_callback() will set the cpu_hotplug_disabled flag during PM_HIBERNATION_PREPARE and clears it only during PM_POST_HIBERNATION. So in-between, if you invoke cpu_up() or cpu_down(), it should return -EBUSY.

Then how is it that this patch can work fine? The answer is, during the restore phase, you are not yet in the kernel-to-be-restored. IOW, that cpu_hotplug_disabled flag is clear in that kernel. That's why cpu_up() and cpu_down() will continue to work at that point. But once you resume execution from the saved hibernation image, you won't be able to do cpu_up() and cpu_down() until that flag is cleared by cpu_hotplug_pm_callback() during PM_POST_HIBERNATION.

All in all, its tricky, and luckily this patch uses cpu_up()/cpu_down() at the right moment...

I don't actually see why cpu_hotplug_pm_callback() should not clear the cpu_hotplug_disabled flag during PM_RESTORE_PREPARE itself.. if we do that, we don't have to be *this* careful about -when- we can invoke -which- function..

Regards,
Srivatsa S. Bhat

#32 lore raw

RE: [PATCH v9 12/12] x86, topology: Debug CPU00 hotplug

Quoted 73 lines

From: Srivatsa S. Bhat [mailto:[email protected]]
Sent: Wednesday, October 17, 2012 11:43 PM

Quoted 18 lines · Fenghua
Quoted 16 lines
Quoted 1 line

+#ifdef CONFIG_DEBUG_HOTPLUG_CPU0

arch/x86/power/cpu.c +1 -0
+	case PM_RESTORE_PREPARE:

Review

Quoted 2 lines
(quoted diff) +2 -0
+		/*
+		 * When system resumes from hibernation, online CPU0

because

arch/x86/power/cpu.c static int bsp_pm_callback(struct notifier_block *nb, unsigned long action, · line 275

Quoted 5 lines
arch/x86/power/cpu.c +5 -0
+		 * 1. it's required for resume and
+		 * 2. the CPU was online before hibernation
+		 */
+		if (!cpu_online(0))
+			_debug_hotplug_cpu(0, 1);

This won't work. CPU hotplug is disabled by cpu_hotplug_pm_callback() during
PM_HIBERNATION_PREPARE and is enabled back only during PM_POST_HIBERNATION.

Quoted 1 line

So calls to cpu_up() or cpu_down() will fail in the meantime.

Quoted 8 lines

The code works just fine.

You are talking about hibernation/suspend phase. This piece of code is all about restore phase. Of course you can call cpu_up() and cpu_down() during restore phase.

So there is no problem here.

I looked into it again, and actually you are right, it'll work fine; but the reason *why* it will work fine is quite subtle.

Note that there is a difference between calling cpu_up() or cpu_down() vs calling _cpu_up() or _cpu_down(). The former set of calls will return
-EBUSY if the 'cpu_hotplug_disabled' flag is set. The latter set of calls
don't care about that flag and hence proceed irrespective of the state of
that flag. The former set of calls are used when you echo 0/1 to the online
file from userspace. Whereas the latter set of calls are used by the disable/enable_nonboot_cpus() functions. This is how you can disable cpu hotplug by userspace, but continue to do cpu hotplug yourself from within the kernel in the suspend/hibernation/restore phases.

Now, coming to the notifications part, earlier, I was referring to the entire hibernate->restore phase, not just the hibernate phase. The relevant
notifications that are sent out during this entire (successful) sequence are:

-> PM_HIBERNATION_PREPARE
-> PM_RESTORE_PREPARE
-> PM_POST_HIBERNATION

cpu_hotplug_pm_callback() will set the cpu_hotplug_disabled flag during PM_HIBERNATION_PREPARE and clears it only during PM_POST_HIBERNATION. So in-between, if you invoke cpu_up() or cpu_down(), it should return - EBUSY.

Then how is it that this patch can work fine? The answer is, during the restore phase, you are not yet in the kernel-to-be-restored. IOW, that cpu_hotplug_disabled flag is clear in that kernel. That's why cpu_up() and
cpu_down() will continue to work at that point. But once you resume execution
from the saved hibernation image, you won't be able to do cpu_up() and cpu_down() until that flag is cleared by cpu_hotplug_pm_callback() during
PM_POST_HIBERNATION.

Quoted 8 lines

All in all, its tricky, and luckily this patch uses cpu_up()/cpu_down() at the right moment...

I don't actually see why cpu_hotplug_pm_callback() should not clear the cpu_hotplug_disabled flag during PM_RESTORE_PREPARE itself.. if we do that,
we don't have to be *this* careful about -when- we can invoke -which- function..

Yes, this is tricky because we have to offline CPU0 in debug mode and online CPU0 in resume. So we need to do online and offline in this short period of boot and resume.

I explained this tick in the comment:
+ * 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.
......

Thanks.

-Fenghua