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