blob: 73aea76add3e5393886cd14b5bbad99e785896bf [file] [log] [blame]
/*
* Spinlock test
*
* This code is based on code from the tcg_baremetal_tests.
*
* Copyright (C) 2015 Virtual Open Systems SAS
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <libcflat.h>
#include <asm/smp.h>
#include <asm/barrier.h>
#define LOOP_SIZE 10000000
struct lock_ops {
void (*lock)(int *v);
void (*unlock)(int *v);
};
static struct lock_ops lock_ops;
static void gcc_builtin_lock(int *lock_var)
{
while (__sync_lock_test_and_set(lock_var, 1));
}
static void gcc_builtin_unlock(int *lock_var)
{
__sync_lock_release(lock_var);
}
static void none_lock(int *lock_var)
{
while (*(volatile int *)lock_var != 0);
*(volatile int *)lock_var = 1;
}
static void none_unlock(int *lock_var)
{
*(volatile int *)lock_var = 0;
}
static int global_a, global_b;
static int global_lock;
static void test_spinlock(void *data __unused)
{
int i, errors = 0;
int cpu = smp_processor_id();
printf("CPU%d online\n", cpu);
for (i = 0; i < LOOP_SIZE; i++) {
lock_ops.lock(&global_lock);
if (global_a == (cpu + 1) % 2) {
global_a = 1;
global_b = 0;
} else {
global_a = 0;
global_b = 1;
}
if (global_a == global_b)
errors++;
lock_ops.unlock(&global_lock);
}
report(errors == 0, "CPU%d: Done - Errors: %d", cpu, errors);
}
int main(int argc, char **argv)
{
report_prefix_push("spinlock");
if (argc > 1 && strcmp(argv[1], "bad") != 0) {
lock_ops.lock = gcc_builtin_lock;
lock_ops.unlock = gcc_builtin_unlock;
} else {
lock_ops.lock = none_lock;
lock_ops.unlock = none_unlock;
}
on_cpus(test_spinlock, NULL);
return report_summary();
}