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 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 } 294ea7633eSAndrew Jones static void gcc_builtin_unlock(int *lock_var) 304ea7633eSAndrew Jones { 314ea7633eSAndrew Jones __sync_lock_release(lock_var); 324ea7633eSAndrew Jones } 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 } 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 46*00b34f56SAndrew 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 } 70d637cb11SAndrew Jones report("CPU%d: Done - Errors: %d", errors == 0, cpu, errors); 714ea7633eSAndrew Jones } 724ea7633eSAndrew Jones 734ea7633eSAndrew Jones int main(int argc, char **argv) 744ea7633eSAndrew Jones { 756ffea954SAndrew Jones if (argc > 1 && strcmp(argv[1], "bad") != 0) { 764ea7633eSAndrew Jones lock_ops.lock = gcc_builtin_lock; 774ea7633eSAndrew Jones lock_ops.unlock = gcc_builtin_unlock; 784ea7633eSAndrew Jones } else { 794ea7633eSAndrew Jones lock_ops.lock = none_lock; 804ea7633eSAndrew Jones lock_ops.unlock = none_unlock; 814ea7633eSAndrew Jones } 824ea7633eSAndrew Jones 83*00b34f56SAndrew Jones on_cpus(test_spinlock, NULL); 844ea7633eSAndrew Jones 854ea7633eSAndrew Jones return report_summary(); 864ea7633eSAndrew Jones } 87