xref: /kvm-unit-tests/arm/spinlock-test.c (revision 53ba411b66f8506c4d21fbf5d28328f363e124f3)
1*53ba411bSThomas Huth /*
2*53ba411bSThomas Huth  * Spinlock test
3*53ba411bSThomas Huth  *
4*53ba411bSThomas Huth  * This code is based on code from the tcg_baremetal_tests.
5*53ba411bSThomas Huth  *
6*53ba411bSThomas Huth  * Copyright (C) 2015 Virtual Open Systems SAS
7*53ba411bSThomas Huth  *
8*53ba411bSThomas Huth  * This program is free software; you can redistribute it and/or modify
9*53ba411bSThomas Huth  * it under the terms of the GNU General Public License version 2 as
10*53ba411bSThomas Huth  * published by the Free Software Foundation.
11*53ba411bSThomas Huth  */
12*53ba411bSThomas Huth 
134ea7633eSAndrew Jones #include <libcflat.h>
144ea7633eSAndrew Jones #include <asm/smp.h>
154ea7633eSAndrew Jones #include <asm/cpumask.h>
164ea7633eSAndrew Jones #include <asm/barrier.h>
174ea7633eSAndrew Jones 
184ea7633eSAndrew Jones #define LOOP_SIZE 10000000
194ea7633eSAndrew Jones 
204ea7633eSAndrew Jones struct lock_ops {
214ea7633eSAndrew Jones 	void (*lock)(int *v);
224ea7633eSAndrew Jones 	void (*unlock)(int *v);
234ea7633eSAndrew Jones };
244ea7633eSAndrew Jones static struct lock_ops lock_ops;
254ea7633eSAndrew Jones 
264ea7633eSAndrew Jones static void gcc_builtin_lock(int *lock_var)
274ea7633eSAndrew Jones {
284ea7633eSAndrew Jones 	while (__sync_lock_test_and_set(lock_var, 1));
294ea7633eSAndrew Jones }
304ea7633eSAndrew Jones static void gcc_builtin_unlock(int *lock_var)
314ea7633eSAndrew Jones {
324ea7633eSAndrew Jones 	__sync_lock_release(lock_var);
334ea7633eSAndrew Jones }
344ea7633eSAndrew Jones static void none_lock(int *lock_var)
354ea7633eSAndrew Jones {
3662423b6eSPaolo Bonzini 	while (*(volatile int *)lock_var != 0);
3762423b6eSPaolo Bonzini 	*(volatile int *)lock_var = 1;
384ea7633eSAndrew Jones }
394ea7633eSAndrew Jones static void none_unlock(int *lock_var)
404ea7633eSAndrew Jones {
4162423b6eSPaolo Bonzini 	*(volatile int *)lock_var = 0;
424ea7633eSAndrew Jones }
434ea7633eSAndrew Jones 
444ea7633eSAndrew Jones static int global_a, global_b;
454ea7633eSAndrew Jones static int global_lock;
464ea7633eSAndrew Jones 
474ea7633eSAndrew Jones static cpumask_t smp_test_complete;
484ea7633eSAndrew Jones 
494ea7633eSAndrew Jones static void test_spinlock(void)
504ea7633eSAndrew Jones {
514ea7633eSAndrew Jones 	int i, errors = 0;
524ea7633eSAndrew Jones 	int cpu = smp_processor_id();
534ea7633eSAndrew Jones 
544ea7633eSAndrew Jones 	printf("CPU%d online\n", cpu);
554ea7633eSAndrew Jones 
564ea7633eSAndrew Jones 	for (i = 0; i < LOOP_SIZE; i++) {
574ea7633eSAndrew Jones 
584ea7633eSAndrew Jones 		lock_ops.lock(&global_lock);
594ea7633eSAndrew Jones 
604ea7633eSAndrew Jones 		if (global_a == (cpu + 1) % 2) {
614ea7633eSAndrew Jones 			global_a = 1;
624ea7633eSAndrew Jones 			global_b = 0;
634ea7633eSAndrew Jones 		} else {
644ea7633eSAndrew Jones 			global_a = 0;
654ea7633eSAndrew Jones 			global_b = 1;
664ea7633eSAndrew Jones 		}
674ea7633eSAndrew Jones 
684ea7633eSAndrew Jones 		if (global_a == global_b)
694ea7633eSAndrew Jones 			errors++;
704ea7633eSAndrew Jones 
714ea7633eSAndrew Jones 		lock_ops.unlock(&global_lock);
724ea7633eSAndrew Jones 	}
73d637cb11SAndrew Jones 	report("CPU%d: Done - Errors: %d", errors == 0, cpu, errors);
744ea7633eSAndrew Jones 
754ea7633eSAndrew Jones 	cpumask_set_cpu(cpu, &smp_test_complete);
764ea7633eSAndrew Jones 	if (cpu != 0)
774ea7633eSAndrew Jones 		halt();
784ea7633eSAndrew Jones }
794ea7633eSAndrew Jones 
804ea7633eSAndrew Jones int main(int argc, char **argv)
814ea7633eSAndrew Jones {
824ea7633eSAndrew Jones 	int cpu;
834ea7633eSAndrew Jones 
846ffea954SAndrew Jones 	if (argc > 1 && strcmp(argv[1], "bad") != 0) {
854ea7633eSAndrew Jones 		lock_ops.lock = gcc_builtin_lock;
864ea7633eSAndrew Jones 		lock_ops.unlock = gcc_builtin_unlock;
874ea7633eSAndrew Jones 	} else {
884ea7633eSAndrew Jones 		lock_ops.lock = none_lock;
894ea7633eSAndrew Jones 		lock_ops.unlock = none_unlock;
904ea7633eSAndrew Jones 	}
914ea7633eSAndrew Jones 
924ea7633eSAndrew Jones 	for_each_present_cpu(cpu) {
934ea7633eSAndrew Jones 		if (cpu == 0)
944ea7633eSAndrew Jones 			continue;
954ea7633eSAndrew Jones 		smp_boot_secondary(cpu, test_spinlock);
964ea7633eSAndrew Jones 	}
974ea7633eSAndrew Jones 
984ea7633eSAndrew Jones 	test_spinlock();
994ea7633eSAndrew Jones 
1004ea7633eSAndrew Jones 	while (!cpumask_full(&smp_test_complete))
1014ea7633eSAndrew Jones 		cpu_relax();
1024ea7633eSAndrew Jones 
1034ea7633eSAndrew Jones 	return report_summary();
1044ea7633eSAndrew Jones }
105