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