diff options
author | Richard Weinberger <richard@nod.at> | 2016-07-13 13:17:01 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-07-15 04:41:43 -0400 |
commit | 31487f8328f20fdb302430b020a5d6e8446c1971 (patch) | |
tree | 73d62b623424d059cd36633bcdf54de2e7d12240 | |
parent | 6b2c28471de550308784560206c3365e5179d42f (diff) |
smp/cfd: Convert core to hotplug state machine
Install the callbacks via the state machine. They are installed at runtime so
smpcfd_prepare_cpu() needs to be invoked by the boot-CPU.
Signed-off-by: Richard Weinberger <richard@nod.at>
[ Added the dropped CPU dying case back in. ]
Signed-off-by: Richard Cochran <rcochran@linutronix.de>
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Davidlohr Bueso <dave@stgolabs>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: rt@linutronix.de
Link: http://lkml.kernel.org/r/20160713153337.818376366@linutronix.de
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | include/linux/cpuhotplug.h | 2 | ||||
-rw-r--r-- | include/linux/smp.h | 5 | ||||
-rw-r--r-- | kernel/cpu.c | 9 | ||||
-rw-r--r-- | kernel/smp.c | 79 |
4 files changed, 48 insertions, 47 deletions
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 78170827a776..b5cf01ace71b 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h | |||
@@ -18,6 +18,7 @@ enum cpuhp_state { | |||
18 | CPUHP_HRTIMERS_PREPARE, | 18 | CPUHP_HRTIMERS_PREPARE, |
19 | CPUHP_PROFILE_PREPARE, | 19 | CPUHP_PROFILE_PREPARE, |
20 | CPUHP_X2APIC_PREPARE, | 20 | CPUHP_X2APIC_PREPARE, |
21 | CPUHP_SMPCFD_PREPARE, | ||
21 | CPUHP_TIMERS_DEAD, | 22 | CPUHP_TIMERS_DEAD, |
22 | CPUHP_NOTIFY_PREPARE, | 23 | CPUHP_NOTIFY_PREPARE, |
23 | CPUHP_BRINGUP_CPU, | 24 | CPUHP_BRINGUP_CPU, |
@@ -57,6 +58,7 @@ enum cpuhp_state { | |||
57 | CPUHP_AP_ARM_CORESIGHT4_STARTING, | 58 | CPUHP_AP_ARM_CORESIGHT4_STARTING, |
58 | CPUHP_AP_ARM64_ISNDEP_STARTING, | 59 | CPUHP_AP_ARM64_ISNDEP_STARTING, |
59 | CPUHP_AP_LEDTRIG_STARTING, | 60 | CPUHP_AP_LEDTRIG_STARTING, |
61 | CPUHP_AP_SMPCFD_DYING, | ||
60 | CPUHP_AP_X86_TBOOT_DYING, | 62 | CPUHP_AP_X86_TBOOT_DYING, |
61 | CPUHP_AP_NOTIFY_STARTING, | 63 | CPUHP_AP_NOTIFY_STARTING, |
62 | CPUHP_AP_ONLINE, | 64 | CPUHP_AP_ONLINE, |
diff --git a/include/linux/smp.h b/include/linux/smp.h index c4414074bd88..eccae4690f41 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h | |||
@@ -196,4 +196,9 @@ extern void arch_enable_nonboot_cpus_end(void); | |||
196 | 196 | ||
197 | void smp_setup_processor_id(void); | 197 | void smp_setup_processor_id(void); |
198 | 198 | ||
199 | /* SMP core functions */ | ||
200 | int smpcfd_prepare_cpu(unsigned int cpu); | ||
201 | int smpcfd_dead_cpu(unsigned int cpu); | ||
202 | int smpcfd_dying_cpu(unsigned int cpu); | ||
203 | |||
199 | #endif /* __LINUX_SMP_H */ | 204 | #endif /* __LINUX_SMP_H */ |
diff --git a/kernel/cpu.c b/kernel/cpu.c index e1017d92d308..008e2fd40cb1 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -1195,6 +1195,11 @@ static struct cpuhp_step cpuhp_bp_states[] = { | |||
1195 | .startup = hrtimers_prepare_cpu, | 1195 | .startup = hrtimers_prepare_cpu, |
1196 | .teardown = hrtimers_dead_cpu, | 1196 | .teardown = hrtimers_dead_cpu, |
1197 | }, | 1197 | }, |
1198 | [CPUHP_SMPCFD_PREPARE] = { | ||
1199 | .name = "SMPCFD prepare", | ||
1200 | .startup = smpcfd_prepare_cpu, | ||
1201 | .teardown = smpcfd_dead_cpu, | ||
1202 | }, | ||
1198 | [CPUHP_TIMERS_DEAD] = { | 1203 | [CPUHP_TIMERS_DEAD] = { |
1199 | .name = "timers dead", | 1204 | .name = "timers dead", |
1200 | .startup = NULL, | 1205 | .startup = NULL, |
@@ -1218,6 +1223,10 @@ static struct cpuhp_step cpuhp_bp_states[] = { | |||
1218 | .teardown = NULL, | 1223 | .teardown = NULL, |
1219 | .cant_stop = true, | 1224 | .cant_stop = true, |
1220 | }, | 1225 | }, |
1226 | [CPUHP_AP_SMPCFD_DYING] = { | ||
1227 | .startup = NULL, | ||
1228 | .teardown = smpcfd_dying_cpu, | ||
1229 | }, | ||
1221 | /* | 1230 | /* |
1222 | * Handled on controll processor until the plugged processor manages | 1231 | * Handled on controll processor until the plugged processor manages |
1223 | * this itself. | 1232 | * this itself. |
diff --git a/kernel/smp.c b/kernel/smp.c index 74165443c240..7180491c9678 100644 --- a/kernel/smp.c +++ b/kernel/smp.c | |||
@@ -33,69 +33,54 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(struct llist_head, call_single_queue); | |||
33 | 33 | ||
34 | static void flush_smp_call_function_queue(bool warn_cpu_offline); | 34 | static void flush_smp_call_function_queue(bool warn_cpu_offline); |
35 | 35 | ||
36 | static int | 36 | int smpcfd_prepare_cpu(unsigned int cpu) |
37 | hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu) | ||
38 | { | 37 | { |
39 | long cpu = (long)hcpu; | ||
40 | struct call_function_data *cfd = &per_cpu(cfd_data, cpu); | 38 | struct call_function_data *cfd = &per_cpu(cfd_data, cpu); |
41 | 39 | ||
42 | switch (action) { | 40 | if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL, |
43 | case CPU_UP_PREPARE: | 41 | cpu_to_node(cpu))) |
44 | case CPU_UP_PREPARE_FROZEN: | 42 | return -ENOMEM; |
45 | if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL, | 43 | cfd->csd = alloc_percpu(struct call_single_data); |
46 | cpu_to_node(cpu))) | 44 | if (!cfd->csd) { |
47 | return notifier_from_errno(-ENOMEM); | ||
48 | cfd->csd = alloc_percpu(struct call_single_data); | ||
49 | if (!cfd->csd) { | ||
50 | free_cpumask_var(cfd->cpumask); | ||
51 | return notifier_from_errno(-ENOMEM); | ||
52 | } | ||
53 | break; | ||
54 | |||
55 | #ifdef CONFIG_HOTPLUG_CPU | ||
56 | case CPU_UP_CANCELED: | ||
57 | case CPU_UP_CANCELED_FROZEN: | ||
58 | /* Fall-through to the CPU_DEAD[_FROZEN] case. */ | ||
59 | |||
60 | case CPU_DEAD: | ||
61 | case CPU_DEAD_FROZEN: | ||
62 | free_cpumask_var(cfd->cpumask); | 45 | free_cpumask_var(cfd->cpumask); |
63 | free_percpu(cfd->csd); | 46 | return -ENOMEM; |
64 | break; | 47 | } |
65 | 48 | ||
66 | case CPU_DYING: | 49 | return 0; |
67 | case CPU_DYING_FROZEN: | 50 | } |
68 | /* | 51 | |
69 | * The IPIs for the smp-call-function callbacks queued by other | 52 | int smpcfd_dead_cpu(unsigned int cpu) |
70 | * CPUs might arrive late, either due to hardware latencies or | 53 | { |
71 | * because this CPU disabled interrupts (inside stop-machine) | 54 | struct call_function_data *cfd = &per_cpu(cfd_data, cpu); |
72 | * before the IPIs were sent. So flush out any pending callbacks | ||
73 | * explicitly (without waiting for the IPIs to arrive), to | ||
74 | * ensure that the outgoing CPU doesn't go offline with work | ||
75 | * still pending. | ||
76 | */ | ||
77 | flush_smp_call_function_queue(false); | ||
78 | break; | ||
79 | #endif | ||
80 | }; | ||
81 | 55 | ||
82 | return NOTIFY_OK; | 56 | free_cpumask_var(cfd->cpumask); |
57 | free_percpu(cfd->csd); | ||
58 | return 0; | ||
83 | } | 59 | } |
84 | 60 | ||
85 | static struct notifier_block hotplug_cfd_notifier = { | 61 | int smpcfd_dying_cpu(unsigned int cpu) |
86 | .notifier_call = hotplug_cfd, | 62 | { |
87 | }; | 63 | /* |
64 | * The IPIs for the smp-call-function callbacks queued by other | ||
65 | * CPUs might arrive late, either due to hardware latencies or | ||
66 | * because this CPU disabled interrupts (inside stop-machine) | ||
67 | * before the IPIs were sent. So flush out any pending callbacks | ||
68 | * explicitly (without waiting for the IPIs to arrive), to | ||
69 | * ensure that the outgoing CPU doesn't go offline with work | ||
70 | * still pending. | ||
71 | */ | ||
72 | flush_smp_call_function_queue(false); | ||
73 | return 0; | ||
74 | } | ||
88 | 75 | ||
89 | void __init call_function_init(void) | 76 | void __init call_function_init(void) |
90 | { | 77 | { |
91 | void *cpu = (void *)(long)smp_processor_id(); | ||
92 | int i; | 78 | int i; |
93 | 79 | ||
94 | for_each_possible_cpu(i) | 80 | for_each_possible_cpu(i) |
95 | init_llist_head(&per_cpu(call_single_queue, i)); | 81 | init_llist_head(&per_cpu(call_single_queue, i)); |
96 | 82 | ||
97 | hotplug_cfd(&hotplug_cfd_notifier, CPU_UP_PREPARE, cpu); | 83 | smpcfd_prepare_cpu(smp_processor_id()); |
98 | register_cpu_notifier(&hotplug_cfd_notifier); | ||
99 | } | 84 | } |
100 | 85 | ||
101 | /* | 86 | /* |