The test harness uses spinlocks if they are implemented with larx/stcx. it can prevent some test scenarios such as testing migration of a reservation. Signed-off-by: Nicholas Piggin <npiggin@xxxxxxxxx> --- lib/powerpc/asm/smp.h | 1 + lib/powerpc/smp.c | 6 ++++++ lib/powerpc/spinlock.c | 28 ++++++++++++++++++++++++++++ lib/ppc64/asm/spinlock.h | 7 ++++++- powerpc/Makefile.common | 1 + 5 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 lib/powerpc/spinlock.c diff --git a/lib/powerpc/asm/smp.h b/lib/powerpc/asm/smp.h index 163bbeec..e2c03295 100644 --- a/lib/powerpc/asm/smp.h +++ b/lib/powerpc/asm/smp.h @@ -19,5 +19,6 @@ void local_ipi_disable(void); void send_ipi(int cpu_id); extern int nr_cpus_online; +extern bool multithreaded; #endif /* _ASMPOWERPC_SMP_H_ */ diff --git a/lib/powerpc/smp.c b/lib/powerpc/smp.c index 96e3219a..b473ba41 100644 --- a/lib/powerpc/smp.c +++ b/lib/powerpc/smp.c @@ -280,6 +280,8 @@ static void start_each_secondary(int fdtnode, u64 regval __unused, void *info) datap->nr_started += start_core(fdtnode, datap->entry); } +bool multithreaded = false; + /* * Start all stopped cpus on the guest at entry with register 3 set to r3 * We expect that we come in with only one thread currently started @@ -293,8 +295,10 @@ bool start_all_cpus(secondary_entry_fn entry) memset(start_secondary_cpus, 0xff, sizeof(start_secondary_cpus)); + assert(!multithreaded); assert(nr_cpus_online == 1); + multithreaded = true; nr_started = 0; nr_cpus_present = 0; ret = dt_for_each_cpu_node(start_each_secondary, &data); @@ -305,6 +309,8 @@ bool start_all_cpus(secondary_entry_fn entry) void stop_all_cpus(void) { + assert(multithreaded); while (nr_cpus_online > 1) cpu_relax(); + multithreaded = false; } diff --git a/lib/powerpc/spinlock.c b/lib/powerpc/spinlock.c new file mode 100644 index 00000000..238549f1 --- /dev/null +++ b/lib/powerpc/spinlock.c @@ -0,0 +1,28 @@ +#include <asm/spinlock.h> +#include <asm/smp.h> + +/* + * Skip the atomic when single-threaded, which helps avoid larx/stcx. in + * the harness when testing tricky larx/stcx. sequences (e.g., migration + * vs reservation). + */ +void spin_lock(struct spinlock *lock) +{ + if (!multithreaded) { + assert(lock->v == 0); + lock->v = 1; + } else { + while (__sync_lock_test_and_set(&lock->v, 1)) + ; + } +} + +void spin_unlock(struct spinlock *lock) +{ + assert(lock->v == 1); + if (!multithreaded) { + lock->v = 0; + } else { + __sync_lock_release(&lock->v); + } +} diff --git a/lib/ppc64/asm/spinlock.h b/lib/ppc64/asm/spinlock.h index f59eed19..b952386d 100644 --- a/lib/ppc64/asm/spinlock.h +++ b/lib/ppc64/asm/spinlock.h @@ -1,6 +1,11 @@ #ifndef _ASMPPC64_SPINLOCK_H_ #define _ASMPPC64_SPINLOCK_H_ -#include <asm-generic/spinlock.h> +struct spinlock { + unsigned int v; +}; + +void spin_lock(struct spinlock *lock); +void spin_unlock(struct spinlock *lock); #endif /* _ASMPPC64_SPINLOCK_H_ */ diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common index f9dd937a..caa807f2 100644 --- a/powerpc/Makefile.common +++ b/powerpc/Makefile.common @@ -47,6 +47,7 @@ cflatobjs += lib/powerpc/rtas.o cflatobjs += lib/powerpc/processor.o cflatobjs += lib/powerpc/handlers.o cflatobjs += lib/powerpc/smp.o +cflatobjs += lib/powerpc/spinlock.o OBJDIRS += lib/powerpc -- 2.42.0