xref: /kvm-unit-tests/arm/spinlock-test.c (revision 3c13c64209599d16c1b04655144af5097aabb857)
153ba411bSThomas Huth /*
253ba411bSThomas Huth  * Spinlock test
353ba411bSThomas Huth  *
453ba411bSThomas Huth  * This code is based on code from the tcg_baremetal_tests.
553ba411bSThomas Huth  *
653ba411bSThomas Huth  * Copyright (C) 2015 Virtual Open Systems SAS
753ba411bSThomas Huth  *
853ba411bSThomas Huth  * This program is free software; you can redistribute it and/or modify
953ba411bSThomas Huth  * it under the terms of the GNU General Public License version 2 as
1053ba411bSThomas Huth  * published by the Free Software Foundation.
1153ba411bSThomas Huth  */
1253ba411bSThomas Huth 
134ea7633eSAndrew Jones #include <libcflat.h>
144ea7633eSAndrew Jones #include <asm/smp.h>
154ea7633eSAndrew Jones #include <asm/barrier.h>
164ea7633eSAndrew Jones 
174ea7633eSAndrew Jones #define LOOP_SIZE 10000000
184ea7633eSAndrew Jones 
194ea7633eSAndrew Jones struct lock_ops {
204ea7633eSAndrew Jones 	void (*lock)(int *v);
214ea7633eSAndrew Jones 	void (*unlock)(int *v);
224ea7633eSAndrew Jones };
234ea7633eSAndrew Jones static struct lock_ops lock_ops;
244ea7633eSAndrew Jones 
gcc_builtin_lock(int * lock_var)254ea7633eSAndrew Jones static void gcc_builtin_lock(int *lock_var)
264ea7633eSAndrew Jones {
274ea7633eSAndrew Jones 	while (__sync_lock_test_and_set(lock_var, 1));
284ea7633eSAndrew Jones }
gcc_builtin_unlock(int * lock_var)294ea7633eSAndrew Jones static void gcc_builtin_unlock(int *lock_var)
304ea7633eSAndrew Jones {
314ea7633eSAndrew Jones 	__sync_lock_release(lock_var);
324ea7633eSAndrew Jones }
none_lock(int * lock_var)334ea7633eSAndrew Jones static void none_lock(int *lock_var)
344ea7633eSAndrew Jones {
3562423b6eSPaolo Bonzini 	while (*(volatile int *)lock_var != 0);
3662423b6eSPaolo Bonzini 	*(volatile int *)lock_var = 1;
374ea7633eSAndrew Jones }
none_unlock(int * lock_var)384ea7633eSAndrew Jones static void none_unlock(int *lock_var)
394ea7633eSAndrew Jones {
4062423b6eSPaolo Bonzini 	*(volatile int *)lock_var = 0;
414ea7633eSAndrew Jones }
424ea7633eSAndrew Jones 
434ea7633eSAndrew Jones static int global_a, global_b;
444ea7633eSAndrew Jones static int global_lock;
454ea7633eSAndrew Jones 
test_spinlock(void * data __unused)4600b34f56SAndrew Jones static void test_spinlock(void *data __unused)
474ea7633eSAndrew Jones {
484ea7633eSAndrew Jones 	int i, errors = 0;
494ea7633eSAndrew Jones 	int cpu = smp_processor_id();
504ea7633eSAndrew Jones 
514ea7633eSAndrew Jones 	printf("CPU%d online\n", cpu);
524ea7633eSAndrew Jones 
534ea7633eSAndrew Jones 	for (i = 0; i < LOOP_SIZE; i++) {
544ea7633eSAndrew Jones 
554ea7633eSAndrew Jones 		lock_ops.lock(&global_lock);
564ea7633eSAndrew Jones 
574ea7633eSAndrew Jones 		if (global_a == (cpu + 1) % 2) {
584ea7633eSAndrew Jones 			global_a = 1;
594ea7633eSAndrew Jones 			global_b = 0;
604ea7633eSAndrew Jones 		} else {
614ea7633eSAndrew Jones 			global_a = 0;
624ea7633eSAndrew Jones 			global_b = 1;
634ea7633eSAndrew Jones 		}
644ea7633eSAndrew Jones 
654ea7633eSAndrew Jones 		if (global_a == global_b)
664ea7633eSAndrew Jones 			errors++;
674ea7633eSAndrew Jones 
684ea7633eSAndrew Jones 		lock_ops.unlock(&global_lock);
694ea7633eSAndrew Jones 	}
70a299895bSThomas Huth 	report(errors == 0, "CPU%d: Done - Errors: %d", cpu, errors);
714ea7633eSAndrew Jones }
724ea7633eSAndrew Jones 
main(int argc,char ** argv)734ea7633eSAndrew Jones int main(int argc, char **argv)
744ea7633eSAndrew Jones {
75*e3f9c6f6SChen Qun 	report_prefix_push("spinlock");
766ffea954SAndrew Jones 	if (argc > 1 && strcmp(argv[1], "bad") != 0) {
774ea7633eSAndrew Jones 		lock_ops.lock = gcc_builtin_lock;
784ea7633eSAndrew Jones 		lock_ops.unlock = gcc_builtin_unlock;
794ea7633eSAndrew Jones 	} else {
804ea7633eSAndrew Jones 		lock_ops.lock = none_lock;
814ea7633eSAndrew Jones 		lock_ops.unlock = none_unlock;
824ea7633eSAndrew Jones 	}
834ea7633eSAndrew Jones 
8400b34f56SAndrew Jones 	on_cpus(test_spinlock, NULL);
854ea7633eSAndrew Jones 
864ea7633eSAndrew Jones 	return report_summary();
874ea7633eSAndrew Jones }
88