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 25 static void gcc_builtin_lock(int *lock_var) 26 { 27 while (__sync_lock_test_and_set(lock_var, 1)); 28 } 29 static void gcc_builtin_unlock(int *lock_var) 30 { 31 __sync_lock_release(lock_var); 32 } 33 static void none_lock(int *lock_var) 34 { 35 while (*(volatile int *)lock_var != 0); 36 *(volatile int *)lock_var = 1; 37 } 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 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 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