aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Weinberger <richard@nod.at>2016-07-13 13:17:01 -0400
committerIngo Molnar <mingo@kernel.org>2016-07-15 04:41:43 -0400
commit31487f8328f20fdb302430b020a5d6e8446c1971 (patch)
tree73d62b623424d059cd36633bcdf54de2e7d12240
parent6b2c28471de550308784560206c3365e5179d42f (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.h2
-rw-r--r--include/linux/smp.h5
-rw-r--r--kernel/cpu.c9
-rw-r--r--kernel/smp.c79
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
197void smp_setup_processor_id(void); 197void smp_setup_processor_id(void);
198 198
199/* SMP core functions */
200int smpcfd_prepare_cpu(unsigned int cpu);
201int smpcfd_dead_cpu(unsigned int cpu);
202int 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
34static void flush_smp_call_function_queue(bool warn_cpu_offline); 34static void flush_smp_call_function_queue(bool warn_cpu_offline);
35 35
36static int 36int smpcfd_prepare_cpu(unsigned int cpu)
37hotplug_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 52int 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
85static struct notifier_block hotplug_cfd_notifier = { 61int 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
89void __init call_function_init(void) 76void __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/*