xref: /kvm-unit-tests/lib/on-cpus.c (revision 71f7db53297d39b7d9b779d6ecbd49f0d8da1dfc)
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