xref: /kvm-unit-tests/arm/spinlock-test.c (revision 9a008986caac35c1120b8552eb610b7793fe613a)
1 #include <libcflat.h>
2 #include <asm/smp.h>
3 #include <asm/cpumask.h>
4 #include <asm/barrier.h>
5 
6 #define LOOP_SIZE 10000000
7 
8 struct lock_ops {
9 	void (*lock)(int *v);
10 	void (*unlock)(int *v);
11 };
12 static struct lock_ops lock_ops;
13 
14 static void gcc_builtin_lock(int *lock_var)
15 {
16 	while (__sync_lock_test_and_set(lock_var, 1));
17 }
18 static void gcc_builtin_unlock(int *lock_var)
19 {
20 	__sync_lock_release(lock_var);
21 }
22 static void none_lock(int *lock_var)
23 {
24 	while (*(volatile int *)lock_var != 0);
25 	*(volatile int *)lock_var = 1;
26 }
27 static void none_unlock(int *lock_var)
28 {
29 	*(volatile int *)lock_var = 0;
30 }
31 
32 static int global_a, global_b;
33 static int global_lock;
34 
35 static cpumask_t smp_test_complete;
36 
37 static void test_spinlock(void)
38 {
39 	int i, errors = 0;
40 	int cpu = smp_processor_id();
41 
42 	printf("CPU%d online\n", cpu);
43 
44 	for (i = 0; i < LOOP_SIZE; i++) {
45 
46 		lock_ops.lock(&global_lock);
47 
48 		if (global_a == (cpu + 1) % 2) {
49 			global_a = 1;
50 			global_b = 0;
51 		} else {
52 			global_a = 0;
53 			global_b = 1;
54 		}
55 
56 		if (global_a == global_b)
57 			errors++;
58 
59 		lock_ops.unlock(&global_lock);
60 	}
61 	report("CPU%d: Done - Errors: %d\n", errors == 0, cpu, errors);
62 
63 	cpumask_set_cpu(cpu, &smp_test_complete);
64 	if (cpu != 0)
65 		halt();
66 }
67 
68 int main(int argc, char **argv)
69 {
70 	int cpu;
71 
72 	if (argc > 1 && strcmp(argv[1], "bad") != 0) {
73 		lock_ops.lock = gcc_builtin_lock;
74 		lock_ops.unlock = gcc_builtin_unlock;
75 	} else {
76 		lock_ops.lock = none_lock;
77 		lock_ops.unlock = none_unlock;
78 	}
79 
80 	for_each_present_cpu(cpu) {
81 		if (cpu == 0)
82 			continue;
83 		smp_boot_secondary(cpu, test_spinlock);
84 	}
85 
86 	test_spinlock();
87 
88 	while (!cpumask_full(&smp_test_complete))
89 		cpu_relax();
90 
91 	return report_summary();
92 }
93