xref: /kvm-unit-tests/lib/on-cpus.c (revision d012cfd5d309a6ec20176045eb367793b7692379)
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>
12b2d54669SAndrew Jones 
13b2d54669SAndrew Jones bool cpu0_calls_idle;
14b2d54669SAndrew Jones 
15b2d54669SAndrew Jones struct on_cpu_info {
16b2d54669SAndrew Jones 	void (*func)(void *data);
17b2d54669SAndrew Jones 	void *data;
18b2d54669SAndrew Jones 	cpumask_t waiters;
19b2d54669SAndrew Jones };
20b2d54669SAndrew Jones static struct on_cpu_info on_cpu_info[NR_CPUS];
21b2d54669SAndrew Jones static cpumask_t on_cpu_info_lock;
22b2d54669SAndrew Jones 
23b2d54669SAndrew Jones static bool get_on_cpu_info(int cpu)
24b2d54669SAndrew Jones {
25b2d54669SAndrew Jones 	return !cpumask_test_and_set_cpu(cpu, &on_cpu_info_lock);
26b2d54669SAndrew Jones }
27b2d54669SAndrew Jones 
28b2d54669SAndrew Jones static void put_on_cpu_info(int cpu)
29b2d54669SAndrew Jones {
30b2d54669SAndrew Jones 	int ret = cpumask_test_and_clear_cpu(cpu, &on_cpu_info_lock);
31b2d54669SAndrew Jones 	assert(ret);
32b2d54669SAndrew Jones }
33b2d54669SAndrew Jones 
34b2d54669SAndrew Jones static void __deadlock_check(int cpu, const cpumask_t *waiters, bool *found)
35b2d54669SAndrew Jones {
36b2d54669SAndrew Jones 	int i;
37b2d54669SAndrew Jones 
38b2d54669SAndrew Jones 	for_each_cpu(i, waiters) {
39b2d54669SAndrew Jones 		if (i == cpu) {
40b2d54669SAndrew Jones 			printf("CPU%d", cpu);
41b2d54669SAndrew Jones 			*found = true;
42b2d54669SAndrew Jones 			return;
43b2d54669SAndrew Jones 		}
44b2d54669SAndrew Jones 		__deadlock_check(cpu, &on_cpu_info[i].waiters, found);
45b2d54669SAndrew Jones 		if (*found) {
46b2d54669SAndrew Jones 			printf(" <=> CPU%d", i);
47b2d54669SAndrew Jones 			return;
48b2d54669SAndrew Jones 		}
49b2d54669SAndrew Jones 	}
50b2d54669SAndrew Jones }
51b2d54669SAndrew Jones 
52b2d54669SAndrew Jones static void deadlock_check(int me, int cpu)
53b2d54669SAndrew Jones {
54b2d54669SAndrew Jones 	bool found = false;
55b2d54669SAndrew Jones 
56b2d54669SAndrew Jones 	__deadlock_check(cpu, &on_cpu_info[me].waiters, &found);
57b2d54669SAndrew Jones 	if (found) {
58b2d54669SAndrew Jones 		printf(" <=> CPU%d deadlock detectd\n", me);
59b2d54669SAndrew Jones 		assert(0);
60b2d54669SAndrew Jones 	}
61b2d54669SAndrew Jones }
62b2d54669SAndrew Jones 
63b2d54669SAndrew Jones static void cpu_wait(int cpu)
64b2d54669SAndrew Jones {
65b2d54669SAndrew Jones 	int me = smp_processor_id();
66b2d54669SAndrew Jones 
67b2d54669SAndrew Jones 	if (cpu == me)
68b2d54669SAndrew Jones 		return;
69b2d54669SAndrew Jones 
70b2d54669SAndrew Jones 	cpumask_set_cpu(me, &on_cpu_info[cpu].waiters);
71b2d54669SAndrew Jones 	deadlock_check(me, cpu);
72b2d54669SAndrew Jones 	while (!cpu_idle(cpu))
73b2d54669SAndrew Jones 		smp_wait_for_event();
74b2d54669SAndrew Jones 	cpumask_clear_cpu(me, &on_cpu_info[cpu].waiters);
75b2d54669SAndrew Jones }
76b2d54669SAndrew Jones 
77b2d54669SAndrew Jones void do_idle(void)
78b2d54669SAndrew Jones {
79b2d54669SAndrew Jones 	int cpu = smp_processor_id();
80b2d54669SAndrew Jones 
81b2d54669SAndrew Jones 	if (cpu == 0)
82b2d54669SAndrew Jones 		cpu0_calls_idle = true;
83b2d54669SAndrew Jones 
84b2d54669SAndrew Jones 	set_cpu_idle(cpu, true);
85b2d54669SAndrew Jones 	smp_send_event();
86b2d54669SAndrew Jones 
87b2d54669SAndrew Jones 	for (;;) {
88b2d54669SAndrew Jones 		while (cpu_idle(cpu))
89b2d54669SAndrew Jones 			smp_wait_for_event();
90b2d54669SAndrew Jones 		smp_rmb();
91b2d54669SAndrew Jones 		on_cpu_info[cpu].func(on_cpu_info[cpu].data);
92b2d54669SAndrew Jones 		on_cpu_info[cpu].func = NULL;
93b2d54669SAndrew Jones 		smp_wmb();
94b2d54669SAndrew Jones 		set_cpu_idle(cpu, true);
95b2d54669SAndrew Jones 		smp_send_event();
96b2d54669SAndrew Jones 	}
97b2d54669SAndrew Jones }
98b2d54669SAndrew Jones 
99b2d54669SAndrew Jones void on_cpu_async(int cpu, void (*func)(void *data), void *data)
100b2d54669SAndrew Jones {
101b2d54669SAndrew Jones 	if (cpu == smp_processor_id()) {
102b2d54669SAndrew Jones 		func(data);
103b2d54669SAndrew Jones 		return;
104b2d54669SAndrew Jones 	}
105b2d54669SAndrew Jones 
106b2d54669SAndrew Jones 	assert_msg(cpu != 0 || cpu0_calls_idle, "Waiting on CPU0, which is unlikely to idle. "
107b2d54669SAndrew Jones 						"If this is intended set cpu0_calls_idle=1");
108b2d54669SAndrew Jones 
109b2d54669SAndrew Jones 	smp_boot_secondary_nofail(cpu, do_idle);
110b2d54669SAndrew Jones 
111b2d54669SAndrew Jones 	for (;;) {
112b2d54669SAndrew Jones 		cpu_wait(cpu);
113b2d54669SAndrew Jones 		if (get_on_cpu_info(cpu)) {
114b2d54669SAndrew Jones 			if ((volatile void *)on_cpu_info[cpu].func == NULL)
115b2d54669SAndrew Jones 				break;
116b2d54669SAndrew Jones 			put_on_cpu_info(cpu);
117b2d54669SAndrew Jones 		}
118b2d54669SAndrew Jones 	}
119b2d54669SAndrew Jones 
120b2d54669SAndrew Jones 	on_cpu_info[cpu].func = func;
121b2d54669SAndrew Jones 	on_cpu_info[cpu].data = data;
122b2d54669SAndrew Jones 	set_cpu_idle(cpu, false);
123b2d54669SAndrew Jones 	put_on_cpu_info(cpu);
124b2d54669SAndrew Jones 	smp_send_event();
125b2d54669SAndrew Jones }
126b2d54669SAndrew Jones 
127*d012cfd5SAndrew Jones void on_cpumask_async(const cpumask_t *mask, void (*func)(void *data), void *data)
128*d012cfd5SAndrew Jones {
129*d012cfd5SAndrew Jones 	int cpu, me = smp_processor_id();
130*d012cfd5SAndrew Jones 
131*d012cfd5SAndrew Jones 	for_each_cpu(cpu, mask) {
132*d012cfd5SAndrew Jones 		if (cpu == me)
133*d012cfd5SAndrew Jones 			continue;
134*d012cfd5SAndrew Jones 		on_cpu_async(cpu, func, data);
135*d012cfd5SAndrew Jones 	}
136*d012cfd5SAndrew Jones 	if (cpumask_test_cpu(me, mask))
137*d012cfd5SAndrew Jones 		func(data);
138*d012cfd5SAndrew Jones }
139*d012cfd5SAndrew Jones 
140*d012cfd5SAndrew Jones void on_cpumask(const cpumask_t *mask, void (*func)(void *data), void *data)
141*d012cfd5SAndrew Jones {
142*d012cfd5SAndrew Jones 	int cpu, me = smp_processor_id();
143*d012cfd5SAndrew Jones 
144*d012cfd5SAndrew Jones 	for_each_cpu(cpu, mask) {
145*d012cfd5SAndrew Jones 		if (cpu == me)
146*d012cfd5SAndrew Jones 			continue;
147*d012cfd5SAndrew Jones 		on_cpu_async(cpu, func, data);
148*d012cfd5SAndrew Jones 	}
149*d012cfd5SAndrew Jones 	if (cpumask_test_cpu(me, mask))
150*d012cfd5SAndrew Jones 		func(data);
151*d012cfd5SAndrew Jones 
152*d012cfd5SAndrew Jones 	for_each_cpu(cpu, mask) {
153*d012cfd5SAndrew Jones 		if (cpu == me)
154*d012cfd5SAndrew Jones 			continue;
155*d012cfd5SAndrew Jones 		cpumask_set_cpu(me, &on_cpu_info[cpu].waiters);
156*d012cfd5SAndrew Jones 		deadlock_check(me, cpu);
157*d012cfd5SAndrew Jones 	}
158*d012cfd5SAndrew Jones 	while (cpumask_weight(&cpu_idle_mask) < nr_cpus - 1)
159*d012cfd5SAndrew Jones 		smp_wait_for_event();
160*d012cfd5SAndrew Jones 	for_each_cpu(cpu, mask)
161*d012cfd5SAndrew Jones 		cpumask_clear_cpu(me, &on_cpu_info[cpu].waiters);
162*d012cfd5SAndrew Jones }
163*d012cfd5SAndrew Jones 
164b2d54669SAndrew Jones void on_cpu(int cpu, void (*func)(void *data), void *data)
165b2d54669SAndrew Jones {
166b2d54669SAndrew Jones 	on_cpu_async(cpu, func, data);
167b2d54669SAndrew Jones 	cpu_wait(cpu);
168b2d54669SAndrew Jones }
169b2d54669SAndrew Jones 
170b2d54669SAndrew Jones void on_cpus(void (*func)(void *data), void *data)
171b2d54669SAndrew Jones {
172*d012cfd5SAndrew Jones 	on_cpumask(&cpu_present_mask, func, data);
173b2d54669SAndrew Jones }
174