1b2d54669SAndrew Jones // SPDX-License-Identifier: GPL-2.0-only
2b2d54669SAndrew Jones /*
3b2d54669SAndrew Jones * on_cpus() support based on cpumasks.
4b2d54669SAndrew Jones *
5b2d54669SAndrew Jones * Copyright (C) 2015, Red Hat Inc, Andrew Jones <drjones@redhat.com>
6b2d54669SAndrew Jones */
7b2d54669SAndrew Jones #include <libcflat.h>
8b2d54669SAndrew Jones #include <cpumask.h>
9b2d54669SAndrew Jones #include <on-cpus.h>
10b2d54669SAndrew Jones #include <asm/barrier.h>
11b2d54669SAndrew Jones #include <asm/smp.h>
120b27f391SAndrew Jones #include <asm/spinlock.h>
13b2d54669SAndrew Jones
14b2d54669SAndrew Jones bool cpu0_calls_idle;
15b2d54669SAndrew Jones
16b2d54669SAndrew Jones struct on_cpu_info {
17b2d54669SAndrew Jones void (*func)(void *data);
18b2d54669SAndrew Jones void *data;
19b2d54669SAndrew Jones cpumask_t waiters;
20b2d54669SAndrew Jones };
21b2d54669SAndrew Jones static struct on_cpu_info on_cpu_info[NR_CPUS];
220b27f391SAndrew Jones static struct spinlock lock;
23b2d54669SAndrew Jones
__deadlock_check(int cpu,const cpumask_t * waiters,bool * found)24b2d54669SAndrew Jones static void __deadlock_check(int cpu, const cpumask_t *waiters, bool *found)
25b2d54669SAndrew Jones {
26b2d54669SAndrew Jones int i;
27b2d54669SAndrew Jones
28b2d54669SAndrew Jones for_each_cpu(i, waiters) {
29b2d54669SAndrew Jones if (i == cpu) {
30b2d54669SAndrew Jones printf("CPU%d", cpu);
31b2d54669SAndrew Jones *found = true;
32b2d54669SAndrew Jones return;
33b2d54669SAndrew Jones }
34b2d54669SAndrew Jones __deadlock_check(cpu, &on_cpu_info[i].waiters, found);
35b2d54669SAndrew Jones if (*found) {
36b2d54669SAndrew Jones printf(" <=> CPU%d", i);
37b2d54669SAndrew Jones return;
38b2d54669SAndrew Jones }
39b2d54669SAndrew Jones }
40b2d54669SAndrew Jones }
41b2d54669SAndrew Jones
deadlock_check(int me,int cpu)42b2d54669SAndrew Jones static void deadlock_check(int me, int cpu)
43b2d54669SAndrew Jones {
44b2d54669SAndrew Jones bool found = false;
45b2d54669SAndrew Jones
46b2d54669SAndrew Jones __deadlock_check(cpu, &on_cpu_info[me].waiters, &found);
47b2d54669SAndrew Jones if (found) {
48b2d54669SAndrew Jones printf(" <=> CPU%d deadlock detectd\n", me);
49b2d54669SAndrew Jones assert(0);
50b2d54669SAndrew Jones }
51b2d54669SAndrew Jones }
52b2d54669SAndrew Jones
cpu_wait(int cpu)53b2d54669SAndrew Jones static void cpu_wait(int cpu)
54b2d54669SAndrew Jones {
55b2d54669SAndrew Jones int me = smp_processor_id();
56b2d54669SAndrew Jones
57b2d54669SAndrew Jones if (cpu == me)
58b2d54669SAndrew Jones return;
59b2d54669SAndrew Jones
60b2d54669SAndrew Jones cpumask_set_cpu(me, &on_cpu_info[cpu].waiters);
61b2d54669SAndrew Jones deadlock_check(me, cpu);
62b2d54669SAndrew Jones while (!cpu_idle(cpu))
63b2d54669SAndrew Jones smp_wait_for_event();
64b2d54669SAndrew Jones cpumask_clear_cpu(me, &on_cpu_info[cpu].waiters);
65b2d54669SAndrew Jones }
66b2d54669SAndrew Jones
do_idle(void)67b2d54669SAndrew Jones void do_idle(void)
68b2d54669SAndrew Jones {
69b2d54669SAndrew Jones int cpu = smp_processor_id();
70b2d54669SAndrew Jones
71b2d54669SAndrew Jones if (cpu == 0)
72b2d54669SAndrew Jones cpu0_calls_idle = true;
73b2d54669SAndrew Jones
740b27f391SAndrew Jones for (;;) {
75b2d54669SAndrew Jones set_cpu_idle(cpu, true);
76b2d54669SAndrew Jones smp_send_event();
77b2d54669SAndrew Jones
78b2d54669SAndrew Jones while (cpu_idle(cpu))
79b2d54669SAndrew Jones smp_wait_for_event();
80b2d54669SAndrew Jones smp_rmb();
81b2d54669SAndrew Jones on_cpu_info[cpu].func(on_cpu_info[cpu].data);
822491edacSAndrew Jones smp_wmb(); /* pairs with the smp_rmb() in on_cpu() and on_cpumask() */
83b2d54669SAndrew Jones }
84b2d54669SAndrew Jones }
85b2d54669SAndrew Jones
on_cpu_async(int cpu,void (* func)(void * data),void * data)86b2d54669SAndrew Jones void on_cpu_async(int cpu, void (*func)(void *data), void *data)
87b2d54669SAndrew Jones {
88b2d54669SAndrew Jones if (cpu == smp_processor_id()) {
89b2d54669SAndrew Jones func(data);
90b2d54669SAndrew Jones return;
91b2d54669SAndrew Jones }
92b2d54669SAndrew Jones
93b2d54669SAndrew Jones assert_msg(cpu != 0 || cpu0_calls_idle, "Waiting on CPU0, which is unlikely to idle. "
94b2d54669SAndrew Jones "If this is intended set cpu0_calls_idle=1");
95b2d54669SAndrew Jones
96b2d54669SAndrew Jones smp_boot_secondary_nofail(cpu, do_idle);
97b2d54669SAndrew Jones
98b2d54669SAndrew Jones for (;;) {
99b2d54669SAndrew Jones cpu_wait(cpu);
1000b27f391SAndrew Jones spin_lock(&lock);
1010b27f391SAndrew Jones if (cpu_idle(cpu))
102b2d54669SAndrew Jones break;
1030b27f391SAndrew Jones spin_unlock(&lock);
104b2d54669SAndrew Jones }
105b2d54669SAndrew Jones
106b2d54669SAndrew Jones on_cpu_info[cpu].func = func;
107b2d54669SAndrew Jones on_cpu_info[cpu].data = data;
1080b27f391SAndrew Jones smp_wmb();
109b2d54669SAndrew Jones set_cpu_idle(cpu, false);
1100b27f391SAndrew Jones spin_unlock(&lock);
111b2d54669SAndrew Jones smp_send_event();
112b2d54669SAndrew Jones }
113b2d54669SAndrew Jones
on_cpumask_async(const cpumask_t * mask,void (* func)(void * data),void * data)114d012cfd5SAndrew Jones void on_cpumask_async(const cpumask_t *mask, void (*func)(void *data), void *data)
115d012cfd5SAndrew Jones {
116d012cfd5SAndrew Jones int cpu, me = smp_processor_id();
117d012cfd5SAndrew Jones
118d012cfd5SAndrew Jones for_each_cpu(cpu, mask) {
119d012cfd5SAndrew Jones if (cpu == me)
120d012cfd5SAndrew Jones continue;
121d012cfd5SAndrew Jones on_cpu_async(cpu, func, data);
122d012cfd5SAndrew Jones }
123d012cfd5SAndrew Jones if (cpumask_test_cpu(me, mask))
124d012cfd5SAndrew Jones func(data);
125d012cfd5SAndrew Jones }
126d012cfd5SAndrew Jones
on_cpumask(const cpumask_t * mask,void (* func)(void * data),void * data)127d012cfd5SAndrew Jones void on_cpumask(const cpumask_t *mask, void (*func)(void *data), void *data)
128d012cfd5SAndrew Jones {
129d012cfd5SAndrew Jones int cpu, me = smp_processor_id();
130*9c86d8cdSAndrew Jones cpumask_t tmp;
131d012cfd5SAndrew Jones
132*9c86d8cdSAndrew Jones cpumask_copy(&tmp, mask);
133*9c86d8cdSAndrew Jones cpumask_clear_cpu(me, &tmp);
134*9c86d8cdSAndrew Jones
135*9c86d8cdSAndrew Jones for_each_cpu(cpu, &tmp)
136d012cfd5SAndrew Jones on_cpu_async(cpu, func, data);
137d012cfd5SAndrew Jones if (cpumask_test_cpu(me, mask))
138d012cfd5SAndrew Jones func(data);
139d012cfd5SAndrew Jones
140*9c86d8cdSAndrew Jones for_each_cpu(cpu, &tmp) {
141d012cfd5SAndrew Jones cpumask_set_cpu(me, &on_cpu_info[cpu].waiters);
142d012cfd5SAndrew Jones deadlock_check(me, cpu);
143d012cfd5SAndrew Jones }
144*9c86d8cdSAndrew Jones while (!cpumask_subset(&tmp, &cpu_idle_mask))
145d012cfd5SAndrew Jones smp_wait_for_event();
146*9c86d8cdSAndrew Jones for_each_cpu(cpu, &tmp)
147d012cfd5SAndrew Jones cpumask_clear_cpu(me, &on_cpu_info[cpu].waiters);
1482491edacSAndrew Jones smp_rmb(); /* pairs with the smp_wmb() in do_idle() */
149d012cfd5SAndrew Jones }
150d012cfd5SAndrew Jones
on_cpu(int cpu,void (* func)(void * data),void * data)151b2d54669SAndrew Jones void on_cpu(int cpu, void (*func)(void *data), void *data)
152b2d54669SAndrew Jones {
153b2d54669SAndrew Jones on_cpu_async(cpu, func, data);
154b2d54669SAndrew Jones cpu_wait(cpu);
1552491edacSAndrew Jones smp_rmb(); /* pairs with the smp_wmb() in do_idle() */
156b2d54669SAndrew Jones }
157b2d54669SAndrew Jones
on_cpus(void (* func)(void * data),void * data)158b2d54669SAndrew Jones void on_cpus(void (*func)(void *data), void *data)
159b2d54669SAndrew Jones {
160d012cfd5SAndrew Jones on_cpumask(&cpu_present_mask, func, data);
161b2d54669SAndrew Jones }
162