1 /*
2 * Spinlock test
3 *
4 * This code is based on code from the tcg_baremetal_tests.
5 *
6 * Copyright (C) 2015 Virtual Open Systems SAS
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13 #include <libcflat.h>
14 #include <asm/smp.h>
15 #include <asm/barrier.h>
16
17 #define LOOP_SIZE 10000000
18
19 struct lock_ops {
20 void (*lock)(int *v);
21 void (*unlock)(int *v);
22 };
23 static struct lock_ops lock_ops;
24
gcc_builtin_lock(int * lock_var)25 static void gcc_builtin_lock(int *lock_var)
26 {
27 while (__sync_lock_test_and_set(lock_var, 1));
28 }
gcc_builtin_unlock(int * lock_var)29 static void gcc_builtin_unlock(int *lock_var)
30 {
31 __sync_lock_release(lock_var);
32 }
none_lock(int * lock_var)33 static void none_lock(int *lock_var)
34 {
35 while (*(volatile int *)lock_var != 0);
36 *(volatile int *)lock_var = 1;
37 }
none_unlock(int * lock_var)38 static void none_unlock(int *lock_var)
39 {
40 *(volatile int *)lock_var = 0;
41 }
42
43 static int global_a, global_b;
44 static int global_lock;
45
test_spinlock(void * data __unused)46 static void test_spinlock(void *data __unused)
47 {
48 int i, errors = 0;
49 int cpu = smp_processor_id();
50
51 printf("CPU%d online\n", cpu);
52
53 for (i = 0; i < LOOP_SIZE; i++) {
54
55 lock_ops.lock(&global_lock);
56
57 if (global_a == (cpu + 1) % 2) {
58 global_a = 1;
59 global_b = 0;
60 } else {
61 global_a = 0;
62 global_b = 1;
63 }
64
65 if (global_a == global_b)
66 errors++;
67
68 lock_ops.unlock(&global_lock);
69 }
70 report(errors == 0, "CPU%d: Done - Errors: %d", cpu, errors);
71 }
72
main(int argc,char ** argv)73 int main(int argc, char **argv)
74 {
75 report_prefix_push("spinlock");
76 if (argc > 1 && strcmp(argv[1], "bad") != 0) {
77 lock_ops.lock = gcc_builtin_lock;
78 lock_ops.unlock = gcc_builtin_unlock;
79 } else {
80 lock_ops.lock = none_lock;
81 lock_ops.unlock = none_unlock;
82 }
83
84 on_cpus(test_spinlock, NULL);
85
86 return report_summary();
87 }
88