xref: /kvm-unit-tests/arm/spinlock-test.c (revision d637cb111c007e20ac78d397f31edea36bbb9d99)
14ea7633eSAndrew Jones #include <libcflat.h>
24ea7633eSAndrew Jones #include <asm/smp.h>
34ea7633eSAndrew Jones #include <asm/cpumask.h>
44ea7633eSAndrew Jones #include <asm/barrier.h>
54ea7633eSAndrew Jones 
64ea7633eSAndrew Jones #define LOOP_SIZE 10000000
74ea7633eSAndrew Jones 
84ea7633eSAndrew Jones struct lock_ops {
94ea7633eSAndrew Jones 	void (*lock)(int *v);
104ea7633eSAndrew Jones 	void (*unlock)(int *v);
114ea7633eSAndrew Jones };
124ea7633eSAndrew Jones static struct lock_ops lock_ops;
134ea7633eSAndrew Jones 
144ea7633eSAndrew Jones static void gcc_builtin_lock(int *lock_var)
154ea7633eSAndrew Jones {
164ea7633eSAndrew Jones 	while (__sync_lock_test_and_set(lock_var, 1));
174ea7633eSAndrew Jones }
184ea7633eSAndrew Jones static void gcc_builtin_unlock(int *lock_var)
194ea7633eSAndrew Jones {
204ea7633eSAndrew Jones 	__sync_lock_release(lock_var);
214ea7633eSAndrew Jones }
224ea7633eSAndrew Jones static void none_lock(int *lock_var)
234ea7633eSAndrew Jones {
2462423b6eSPaolo Bonzini 	while (*(volatile int *)lock_var != 0);
2562423b6eSPaolo Bonzini 	*(volatile int *)lock_var = 1;
264ea7633eSAndrew Jones }
274ea7633eSAndrew Jones static void none_unlock(int *lock_var)
284ea7633eSAndrew Jones {
2962423b6eSPaolo Bonzini 	*(volatile int *)lock_var = 0;
304ea7633eSAndrew Jones }
314ea7633eSAndrew Jones 
324ea7633eSAndrew Jones static int global_a, global_b;
334ea7633eSAndrew Jones static int global_lock;
344ea7633eSAndrew Jones 
354ea7633eSAndrew Jones static cpumask_t smp_test_complete;
364ea7633eSAndrew Jones 
374ea7633eSAndrew Jones static void test_spinlock(void)
384ea7633eSAndrew Jones {
394ea7633eSAndrew Jones 	int i, errors = 0;
404ea7633eSAndrew Jones 	int cpu = smp_processor_id();
414ea7633eSAndrew Jones 
424ea7633eSAndrew Jones 	printf("CPU%d online\n", cpu);
434ea7633eSAndrew Jones 
444ea7633eSAndrew Jones 	for (i = 0; i < LOOP_SIZE; i++) {
454ea7633eSAndrew Jones 
464ea7633eSAndrew Jones 		lock_ops.lock(&global_lock);
474ea7633eSAndrew Jones 
484ea7633eSAndrew Jones 		if (global_a == (cpu + 1) % 2) {
494ea7633eSAndrew Jones 			global_a = 1;
504ea7633eSAndrew Jones 			global_b = 0;
514ea7633eSAndrew Jones 		} else {
524ea7633eSAndrew Jones 			global_a = 0;
534ea7633eSAndrew Jones 			global_b = 1;
544ea7633eSAndrew Jones 		}
554ea7633eSAndrew Jones 
564ea7633eSAndrew Jones 		if (global_a == global_b)
574ea7633eSAndrew Jones 			errors++;
584ea7633eSAndrew Jones 
594ea7633eSAndrew Jones 		lock_ops.unlock(&global_lock);
604ea7633eSAndrew Jones 	}
61*d637cb11SAndrew Jones 	report("CPU%d: Done - Errors: %d", errors == 0, cpu, errors);
624ea7633eSAndrew Jones 
634ea7633eSAndrew Jones 	cpumask_set_cpu(cpu, &smp_test_complete);
644ea7633eSAndrew Jones 	if (cpu != 0)
654ea7633eSAndrew Jones 		halt();
664ea7633eSAndrew Jones }
674ea7633eSAndrew Jones 
684ea7633eSAndrew Jones int main(int argc, char **argv)
694ea7633eSAndrew Jones {
704ea7633eSAndrew Jones 	int cpu;
714ea7633eSAndrew Jones 
726ffea954SAndrew Jones 	if (argc > 1 && strcmp(argv[1], "bad") != 0) {
734ea7633eSAndrew Jones 		lock_ops.lock = gcc_builtin_lock;
744ea7633eSAndrew Jones 		lock_ops.unlock = gcc_builtin_unlock;
754ea7633eSAndrew Jones 	} else {
764ea7633eSAndrew Jones 		lock_ops.lock = none_lock;
774ea7633eSAndrew Jones 		lock_ops.unlock = none_unlock;
784ea7633eSAndrew Jones 	}
794ea7633eSAndrew Jones 
804ea7633eSAndrew Jones 	for_each_present_cpu(cpu) {
814ea7633eSAndrew Jones 		if (cpu == 0)
824ea7633eSAndrew Jones 			continue;
834ea7633eSAndrew Jones 		smp_boot_secondary(cpu, test_spinlock);
844ea7633eSAndrew Jones 	}
854ea7633eSAndrew Jones 
864ea7633eSAndrew Jones 	test_spinlock();
874ea7633eSAndrew Jones 
884ea7633eSAndrew Jones 	while (!cpumask_full(&smp_test_complete))
894ea7633eSAndrew Jones 		cpu_relax();
904ea7633eSAndrew Jones 
914ea7633eSAndrew Jones 	return report_summary();
924ea7633eSAndrew Jones }
93