diff options
-rw-r--r-- | arch/x86/Kconfig | 15 | ||||
-rw-r--r-- | arch/x86/include/asm/cpu.h | 3 | ||||
-rw-r--r-- | arch/x86/kernel/topology.c | 51 | ||||
-rw-r--r-- | arch/x86/power/cpu.c | 38 |
4 files changed, 107 insertions, 0 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 036e89ab470c..b6cfa5f62529 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -1727,6 +1727,21 @@ config BOOTPARAM_HOTPLUG_CPU0 | |||
1727 | You still can enable the CPU0 hotplug feature at boot by kernel | 1727 | You still can enable the CPU0 hotplug feature at boot by kernel |
1728 | parameter cpu0_hotplug. | 1728 | parameter cpu0_hotplug. |
1729 | 1729 | ||
1730 | config DEBUG_HOTPLUG_CPU0 | ||
1731 | def_bool n | ||
1732 | prompt "Debug CPU0 hotplug" | ||
1733 | depends on HOTPLUG_CPU && EXPERIMENTAL | ||
1734 | ---help--- | ||
1735 | Enabling this option offlines CPU0 (if CPU0 can be offlined) as | ||
1736 | soon as possible and boots up userspace with CPU0 offlined. User | ||
1737 | can online CPU0 back after boot time. | ||
1738 | |||
1739 | To debug CPU0 hotplug, you need to enable CPU0 offline/online | ||
1740 | feature by either turning on CONFIG_BOOTPARAM_HOTPLUG_CPU0 during | ||
1741 | compilation or giving cpu0_hotplug kernel parameter at boot. | ||
1742 | |||
1743 | If unsure, say N. | ||
1744 | |||
1730 | config COMPAT_VDSO | 1745 | config COMPAT_VDSO |
1731 | def_bool y | 1746 | def_bool y |
1732 | prompt "Compat VDSO support" | 1747 | prompt "Compat VDSO support" |
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index a1195726e8c2..5f9a1243190e 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h | |||
@@ -29,6 +29,9 @@ struct x86_cpu { | |||
29 | extern int arch_register_cpu(int num); | 29 | extern int arch_register_cpu(int num); |
30 | extern void arch_unregister_cpu(int); | 30 | extern void arch_unregister_cpu(int); |
31 | extern void __cpuinit start_cpu0(void); | 31 | extern void __cpuinit start_cpu0(void); |
32 | #ifdef CONFIG_DEBUG_HOTPLUG_CPU0 | ||
33 | extern int _debug_hotplug_cpu(int cpu, int action); | ||
34 | #endif | ||
32 | #endif | 35 | #endif |
33 | 36 | ||
34 | DECLARE_PER_CPU(int, cpu_state); | 37 | DECLARE_PER_CPU(int, cpu_state); |
diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c index 0e7b4a7a7fb8..6e60b5fe2244 100644 --- a/arch/x86/kernel/topology.c +++ b/arch/x86/kernel/topology.c | |||
@@ -50,6 +50,57 @@ static int __init enable_cpu0_hotplug(char *str) | |||
50 | __setup("cpu0_hotplug", enable_cpu0_hotplug); | 50 | __setup("cpu0_hotplug", enable_cpu0_hotplug); |
51 | #endif | 51 | #endif |
52 | 52 | ||
53 | #ifdef CONFIG_DEBUG_HOTPLUG_CPU0 | ||
54 | /* | ||
55 | * This function offlines a CPU as early as possible and allows userspace to | ||
56 | * boot up without the CPU. The CPU can be onlined back by user after boot. | ||
57 | * | ||
58 | * This is only called for debugging CPU offline/online feature. | ||
59 | */ | ||
60 | int __ref _debug_hotplug_cpu(int cpu, int action) | ||
61 | { | ||
62 | struct device *dev = get_cpu_device(cpu); | ||
63 | int ret; | ||
64 | |||
65 | if (!cpu_is_hotpluggable(cpu)) | ||
66 | return -EINVAL; | ||
67 | |||
68 | cpu_hotplug_driver_lock(); | ||
69 | |||
70 | switch (action) { | ||
71 | case 0: | ||
72 | ret = cpu_down(cpu); | ||
73 | if (!ret) { | ||
74 | pr_info("CPU %u is now offline\n", cpu); | ||
75 | kobject_uevent(&dev->kobj, KOBJ_OFFLINE); | ||
76 | } else | ||
77 | pr_debug("Can't offline CPU%d.\n", cpu); | ||
78 | break; | ||
79 | case 1: | ||
80 | ret = cpu_up(cpu); | ||
81 | if (!ret) | ||
82 | kobject_uevent(&dev->kobj, KOBJ_ONLINE); | ||
83 | else | ||
84 | pr_debug("Can't online CPU%d.\n", cpu); | ||
85 | break; | ||
86 | default: | ||
87 | ret = -EINVAL; | ||
88 | } | ||
89 | |||
90 | cpu_hotplug_driver_unlock(); | ||
91 | |||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | static int __init debug_hotplug_cpu(void) | ||
96 | { | ||
97 | _debug_hotplug_cpu(0, 0); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | late_initcall_sync(debug_hotplug_cpu); | ||
102 | #endif /* CONFIG_DEBUG_HOTPLUG_CPU0 */ | ||
103 | |||
53 | int __ref arch_register_cpu(int num) | 104 | int __ref arch_register_cpu(int num) |
54 | { | 105 | { |
55 | struct cpuinfo_x86 *c = &cpu_data(num); | 106 | struct cpuinfo_x86 *c = &cpu_data(num); |
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c index adde77588e25..120cee1c3f8d 100644 --- a/arch/x86/power/cpu.c +++ b/arch/x86/power/cpu.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/suspend.h> | 21 | #include <asm/suspend.h> |
22 | #include <asm/debugreg.h> | 22 | #include <asm/debugreg.h> |
23 | #include <asm/fpu-internal.h> /* pcntxt_mask */ | 23 | #include <asm/fpu-internal.h> /* pcntxt_mask */ |
24 | #include <asm/cpu.h> | ||
24 | 25 | ||
25 | #ifdef CONFIG_X86_32 | 26 | #ifdef CONFIG_X86_32 |
26 | static struct saved_context saved_context; | 27 | static struct saved_context saved_context; |
@@ -263,6 +264,43 @@ static int bsp_pm_callback(struct notifier_block *nb, unsigned long action, | |||
263 | case PM_HIBERNATION_PREPARE: | 264 | case PM_HIBERNATION_PREPARE: |
264 | ret = bsp_check(); | 265 | ret = bsp_check(); |
265 | break; | 266 | break; |
267 | #ifdef CONFIG_DEBUG_HOTPLUG_CPU0 | ||
268 | case PM_RESTORE_PREPARE: | ||
269 | /* | ||
270 | * When system resumes from hibernation, online CPU0 because | ||
271 | * 1. it's required for resume and | ||
272 | * 2. the CPU was online before hibernation | ||
273 | */ | ||
274 | if (!cpu_online(0)) | ||
275 | _debug_hotplug_cpu(0, 1); | ||
276 | break; | ||
277 | case PM_POST_RESTORE: | ||
278 | /* | ||
279 | * When a resume really happens, this code won't be called. | ||
280 | * | ||
281 | * This code is called only when user space hibernation software | ||
282 | * prepares for snapshot device during boot time. So we just | ||
283 | * call _debug_hotplug_cpu() to restore to CPU0's state prior to | ||
284 | * preparing the snapshot device. | ||
285 | * | ||
286 | * This works for normal boot case in our CPU0 hotplug debug | ||
287 | * mode, i.e. CPU0 is offline and user mode hibernation | ||
288 | * software initializes during boot time. | ||
289 | * | ||
290 | * If CPU0 is online and user application accesses snapshot | ||
291 | * device after boot time, this will offline CPU0 and user may | ||
292 | * see different CPU0 state before and after accessing | ||
293 | * the snapshot device. But hopefully this is not a case when | ||
294 | * user debugging CPU0 hotplug. Even if users hit this case, | ||
295 | * they can easily online CPU0 back. | ||
296 | * | ||
297 | * To simplify this debug code, we only consider normal boot | ||
298 | * case. Otherwise we need to remember CPU0's state and restore | ||
299 | * to that state and resolve racy conditions etc. | ||
300 | */ | ||
301 | _debug_hotplug_cpu(0, 0); | ||
302 | break; | ||
303 | #endif | ||
266 | default: | 304 | default: |
267 | break; | 305 | break; |
268 | } | 306 | } |