xref: /kvm-unit-tests/powerpc/atomics.c (revision 1422f720633622f15800590785bc4f1ce92d4452)
1*1422f720SNicholas Piggin // SPDX-License-Identifier: GPL-2.0-only
2*1422f720SNicholas Piggin /*
3*1422f720SNicholas Piggin  * Test some powerpc instructions
4*1422f720SNicholas Piggin  *
5*1422f720SNicholas Piggin  * Copyright 2024 Nicholas Piggin, IBM Corp.
6*1422f720SNicholas Piggin  */
7*1422f720SNicholas Piggin #include <stdint.h>
8*1422f720SNicholas Piggin #include <libcflat.h>
9*1422f720SNicholas Piggin #include <migrate.h>
10*1422f720SNicholas Piggin #include <asm/processor.h>
11*1422f720SNicholas Piggin #include <asm/time.h>
12*1422f720SNicholas Piggin #include <asm/atomic.h>
13*1422f720SNicholas Piggin #include <asm/setup.h>
14*1422f720SNicholas Piggin #include <asm/barrier.h>
15*1422f720SNicholas Piggin #include <asm/smp.h>
16*1422f720SNicholas Piggin 
17*1422f720SNicholas Piggin static bool do_migrate;
18*1422f720SNicholas Piggin static bool do_record;
19*1422f720SNicholas Piggin 
20*1422f720SNicholas Piggin #define RSV_SIZE 128
21*1422f720SNicholas Piggin 
22*1422f720SNicholas Piggin static uint8_t granule[RSV_SIZE] __attribute((__aligned__(RSV_SIZE)));
23*1422f720SNicholas Piggin 
spin_lock(unsigned int * lock)24*1422f720SNicholas Piggin static void spin_lock(unsigned int *lock)
25*1422f720SNicholas Piggin {
26*1422f720SNicholas Piggin 	unsigned int old;
27*1422f720SNicholas Piggin 
28*1422f720SNicholas Piggin 	asm volatile ("1:"
29*1422f720SNicholas Piggin 		      "lwarx	%0,0,%2;"
30*1422f720SNicholas Piggin 		      "cmpwi	%0,0;"
31*1422f720SNicholas Piggin 		      "bne	1b;"
32*1422f720SNicholas Piggin 		      "stwcx.	%1,0,%2;"
33*1422f720SNicholas Piggin 		      "bne-	1b;"
34*1422f720SNicholas Piggin 		      "lwsync;"
35*1422f720SNicholas Piggin 		      : "=&r"(old) : "r"(1), "r"(lock) : "cr0", "memory");
36*1422f720SNicholas Piggin }
37*1422f720SNicholas Piggin 
spin_unlock(unsigned int * lock)38*1422f720SNicholas Piggin static void spin_unlock(unsigned int *lock)
39*1422f720SNicholas Piggin {
40*1422f720SNicholas Piggin 	asm volatile("lwsync;"
41*1422f720SNicholas Piggin 		     "stw	%1,%0;"
42*1422f720SNicholas Piggin 		     : "+m"(*lock) : "r"(0) : "memory");
43*1422f720SNicholas Piggin }
44*1422f720SNicholas Piggin 
45*1422f720SNicholas Piggin static volatile bool got_interrupt;
46*1422f720SNicholas Piggin static volatile struct pt_regs recorded_regs;
47*1422f720SNicholas Piggin 
interrupt_handler(struct pt_regs * regs,void * opaque)48*1422f720SNicholas Piggin static void interrupt_handler(struct pt_regs *regs, void *opaque)
49*1422f720SNicholas Piggin {
50*1422f720SNicholas Piggin 	assert(!got_interrupt);
51*1422f720SNicholas Piggin 	got_interrupt = true;
52*1422f720SNicholas Piggin 	memcpy((void *)&recorded_regs, regs, sizeof(struct pt_regs));
53*1422f720SNicholas Piggin 	regs_advance_insn(regs);
54*1422f720SNicholas Piggin }
55*1422f720SNicholas Piggin 
test_lwarx_stwcx(int argc,char * argv[])56*1422f720SNicholas Piggin static void test_lwarx_stwcx(int argc, char *argv[])
57*1422f720SNicholas Piggin {
58*1422f720SNicholas Piggin 	unsigned int *var = (unsigned int *)granule;
59*1422f720SNicholas Piggin 	unsigned int old;
60*1422f720SNicholas Piggin 	unsigned int result;
61*1422f720SNicholas Piggin 
62*1422f720SNicholas Piggin 	*var = 0;
63*1422f720SNicholas Piggin 	asm volatile ("1:"
64*1422f720SNicholas Piggin 		      "lwarx	%0,0,%2;"
65*1422f720SNicholas Piggin 		      "stwcx.	%1,0,%2;"
66*1422f720SNicholas Piggin 		      "bne-	1b;"
67*1422f720SNicholas Piggin 		      : "=&r"(old) : "r"(1), "r"(var) : "cr0", "memory");
68*1422f720SNicholas Piggin 	report(old == 0 && *var == 1, "simple update");
69*1422f720SNicholas Piggin 
70*1422f720SNicholas Piggin 	*var = 0;
71*1422f720SNicholas Piggin 	asm volatile ("li	%0,0;"
72*1422f720SNicholas Piggin 		      "stwcx.	%1,0,%2;"
73*1422f720SNicholas Piggin 		      "stwcx.	%1,0,%2;"
74*1422f720SNicholas Piggin 		      "bne-	1f;"
75*1422f720SNicholas Piggin 		      "li	%0,1;"
76*1422f720SNicholas Piggin 		      "1:"
77*1422f720SNicholas Piggin 		      : "=&r"(result)
78*1422f720SNicholas Piggin 		      : "r"(1), "r"(var) : "cr0", "memory");
79*1422f720SNicholas Piggin 	report(result == 0 && *var == 0, "failed stwcx. (no reservation)");
80*1422f720SNicholas Piggin 
81*1422f720SNicholas Piggin 	*var = 0;
82*1422f720SNicholas Piggin 	asm volatile ("li	%0,0;"
83*1422f720SNicholas Piggin 		      "lwarx	%1,0,%4;"
84*1422f720SNicholas Piggin 		      "stw	%3,0(%4);"
85*1422f720SNicholas Piggin 		      "stwcx.	%2,0,%4;"
86*1422f720SNicholas Piggin 		      "bne-	1f;"
87*1422f720SNicholas Piggin 		      "li	%0,1;"
88*1422f720SNicholas Piggin 		      "1:"
89*1422f720SNicholas Piggin 		      : "=&r"(result), "=&r"(old)
90*1422f720SNicholas Piggin 		      : "r"(1), "r"(2), "r"(var) : "cr0", "memory");
91*1422f720SNicholas Piggin 	/* This is implementation specific, so don't fail */
92*1422f720SNicholas Piggin 	if (result == 0 && *var == 2)
93*1422f720SNicholas Piggin 		report(true, "failed stwcx. (intervening store)");
94*1422f720SNicholas Piggin 	else
95*1422f720SNicholas Piggin 		report(true, "succeeded stwcx. (intervening store)");
96*1422f720SNicholas Piggin 
97*1422f720SNicholas Piggin 	handle_exception(0x600, interrupt_handler, NULL);
98*1422f720SNicholas Piggin 	handle_exception(0x700, interrupt_handler, NULL);
99*1422f720SNicholas Piggin 
100*1422f720SNicholas Piggin 	/* Implementations may not necessarily invoke the alignment interrupt */
101*1422f720SNicholas Piggin 	old = 10;
102*1422f720SNicholas Piggin 	*var = 0;
103*1422f720SNicholas Piggin 	asm volatile (
104*1422f720SNicholas Piggin 		      "lwarx	%0,0,%1;"
105*1422f720SNicholas Piggin 		      : "+&r"(old) : "r"((char *)var + 1));
106*1422f720SNicholas Piggin 	report(old == 10 && got_interrupt && recorded_regs.trap == 0x600,
107*1422f720SNicholas Piggin 	       "unaligned lwarx causes fault");
108*1422f720SNicholas Piggin 	got_interrupt = false;
109*1422f720SNicholas Piggin 
110*1422f720SNicholas Piggin 	/*
111*1422f720SNicholas Piggin 	 * Unaligned stwcx. is more difficult to test, at least under QEMU,
112*1422f720SNicholas Piggin 	 * the store does not proceed if there is no matching reservation, so
113*1422f720SNicholas Piggin 	 * the alignment handler does not get invoked. This is okay according
114*1422f720SNicholas Piggin 	 * to the Power ISA (unalignment does not necessarily invoke the
115*1422f720SNicholas Piggin 	 * alignment interrupt). But POWER CPUs do cause alignment interrupt.
116*1422f720SNicholas Piggin 	 */
117*1422f720SNicholas Piggin 	*var = 0;
118*1422f720SNicholas Piggin 	asm volatile (
119*1422f720SNicholas Piggin 		      "lwarx	%0,0,%2;"
120*1422f720SNicholas Piggin 		      "stwcx.	%1,0,%3;"
121*1422f720SNicholas Piggin 		      : "=&r"(old) : "r"(1), "r"(var), "r"((char *)var+1)
122*1422f720SNicholas Piggin 		      : "cr0", "memory");
123*1422f720SNicholas Piggin 	/*
124*1422f720SNicholas Piggin 	 * An unaligned larx/stcx. is not required by the ISA to cause an
125*1422f720SNicholas Piggin 	 * exception, and in TCG the stcx does not though it does on POWER CPUs.
126*1422f720SNicholas Piggin 	 */
127*1422f720SNicholas Piggin 	report_kfail(host_is_tcg, old == 0 && *var == 0 &&
128*1422f720SNicholas Piggin 				  got_interrupt && recorded_regs.trap == 0x600,
129*1422f720SNicholas Piggin 		     "unaligned stwcx. causes fault");
130*1422f720SNicholas Piggin 	got_interrupt = false;
131*1422f720SNicholas Piggin 
132*1422f720SNicholas Piggin 	handle_exception(0x600, NULL, NULL);
133*1422f720SNicholas Piggin 
134*1422f720SNicholas Piggin }
135*1422f720SNicholas Piggin 
test_lqarx_stqcx(int argc,char * argv[])136*1422f720SNicholas Piggin static void test_lqarx_stqcx(int argc, char *argv[])
137*1422f720SNicholas Piggin {
138*1422f720SNicholas Piggin 	union {
139*1422f720SNicholas Piggin 		__int128_t var;
140*1422f720SNicholas Piggin 		struct {
141*1422f720SNicholas Piggin #if  __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
142*1422f720SNicholas Piggin 			unsigned long var1;
143*1422f720SNicholas Piggin 			unsigned long var2;
144*1422f720SNicholas Piggin #else
145*1422f720SNicholas Piggin 			unsigned long var2;
146*1422f720SNicholas Piggin 			unsigned long var1;
147*1422f720SNicholas Piggin #endif
148*1422f720SNicholas Piggin 		};
149*1422f720SNicholas Piggin 	} var __attribute__((aligned(16)));
150*1422f720SNicholas Piggin 	register unsigned long new1 asm("r8");
151*1422f720SNicholas Piggin 	register unsigned long new2 asm("r9");
152*1422f720SNicholas Piggin 	register unsigned long old1 asm("r10");
153*1422f720SNicholas Piggin 	register unsigned long old2 asm("r11");
154*1422f720SNicholas Piggin 	unsigned int result;
155*1422f720SNicholas Piggin 
156*1422f720SNicholas Piggin 	var.var1 = 1;
157*1422f720SNicholas Piggin 	var.var2 = 2;
158*1422f720SNicholas Piggin 
159*1422f720SNicholas Piggin 	(void)new2;
160*1422f720SNicholas Piggin 	(void)old2;
161*1422f720SNicholas Piggin 
162*1422f720SNicholas Piggin 	old1 = 0;
163*1422f720SNicholas Piggin 	old2 = 0;
164*1422f720SNicholas Piggin 	new1 = 3;
165*1422f720SNicholas Piggin 	new2 = 4;
166*1422f720SNicholas Piggin 	asm volatile ("1:"
167*1422f720SNicholas Piggin 		      "lqarx	%0,0,%4;"
168*1422f720SNicholas Piggin 		      "stqcx.	%2,0,%4;"
169*1422f720SNicholas Piggin 		      "bne-	1b;"
170*1422f720SNicholas Piggin 		      : "=&r"(old1), "=&r"(old2)
171*1422f720SNicholas Piggin 		      : "r"(new1), "r"(new2), "r"(&var)
172*1422f720SNicholas Piggin 		      : "cr0", "memory");
173*1422f720SNicholas Piggin 
174*1422f720SNicholas Piggin 	report(old1 == 2 && old2 == 1 && var.var1 == 4 && var.var2 == 3,
175*1422f720SNicholas Piggin 	       "simple update");
176*1422f720SNicholas Piggin 
177*1422f720SNicholas Piggin 	var.var1 = 1;
178*1422f720SNicholas Piggin 	var.var2 = 2;
179*1422f720SNicholas Piggin 	new1 = 3;
180*1422f720SNicholas Piggin 	new2 = 4;
181*1422f720SNicholas Piggin 	asm volatile ("li	%0,0;"
182*1422f720SNicholas Piggin 		      "stqcx.	%1,0,%3;"
183*1422f720SNicholas Piggin 		      "stqcx.	%1,0,%3;"
184*1422f720SNicholas Piggin 		      "bne-	1f;"
185*1422f720SNicholas Piggin 		      "li	%0,1;"
186*1422f720SNicholas Piggin 		      "1:"
187*1422f720SNicholas Piggin 		      : "=&r"(result)
188*1422f720SNicholas Piggin 		      : "r"(new1), "r"(new2), "r"(&var)
189*1422f720SNicholas Piggin 		      : "cr0", "memory");
190*1422f720SNicholas Piggin 	report(result == 0 && var.var1 == 1 && var.var2 == 2,
191*1422f720SNicholas Piggin 	       "failed stqcx. (no reservation)");
192*1422f720SNicholas Piggin 
193*1422f720SNicholas Piggin 	var.var1 = 1;
194*1422f720SNicholas Piggin 	var.var2 = 2;
195*1422f720SNicholas Piggin 	new1 = 3;
196*1422f720SNicholas Piggin 	new2 = 4;
197*1422f720SNicholas Piggin 	asm volatile ("li	%0,0;"
198*1422f720SNicholas Piggin 		      "lqarx	%1,0,%6;"
199*1422f720SNicholas Piggin 		      "std	%5,0(%6);"
200*1422f720SNicholas Piggin 		      "stqcx.	%3,0,%6;"
201*1422f720SNicholas Piggin 		      "bne-	1f;"
202*1422f720SNicholas Piggin 		      "li	%0,1;"
203*1422f720SNicholas Piggin 		      "1:"
204*1422f720SNicholas Piggin 		      : "=&r"(result), "=&r"(old1), "=&r"(old2)
205*1422f720SNicholas Piggin 		      : "r"(new1), "r"(new2), "r"(0), "r"(&var)
206*1422f720SNicholas Piggin 		      : "cr0", "memory");
207*1422f720SNicholas Piggin 	/* This is implementation specific, so don't fail */
208*1422f720SNicholas Piggin 	if (result == 0 && (var.var1 == 0 || var.var2 == 0))
209*1422f720SNicholas Piggin 		report(true, "failed stqcx. (intervening store)");
210*1422f720SNicholas Piggin 	else
211*1422f720SNicholas Piggin 		report(true, "succeeded stqcx. (intervening store)");
212*1422f720SNicholas Piggin }
213*1422f720SNicholas Piggin 
test_migrate_reserve(int argc,char * argv[])214*1422f720SNicholas Piggin static void test_migrate_reserve(int argc, char *argv[])
215*1422f720SNicholas Piggin {
216*1422f720SNicholas Piggin 	unsigned int *var = (unsigned int *)granule;
217*1422f720SNicholas Piggin 	unsigned int old;
218*1422f720SNicholas Piggin 	int i;
219*1422f720SNicholas Piggin 	int succeed = 0;
220*1422f720SNicholas Piggin 
221*1422f720SNicholas Piggin 	if (!do_migrate)
222*1422f720SNicholas Piggin 		return;
223*1422f720SNicholas Piggin 
224*1422f720SNicholas Piggin 	for (i = 0; i < 10; i++) {
225*1422f720SNicholas Piggin 		*var = 0x12345;
226*1422f720SNicholas Piggin 		asm volatile ("lwarx	%0,0,%1" : "=&r"(old) : "r"(var) : "memory");
227*1422f720SNicholas Piggin 		migrate_quiet();
228*1422f720SNicholas Piggin 		asm volatile ("stwcx.	%0,0,%1" : : "r"(0xf00d), "r"(var) : "cr0", "memory");
229*1422f720SNicholas Piggin 		if (*var == 0xf00d)
230*1422f720SNicholas Piggin 			succeed++;
231*1422f720SNicholas Piggin 	}
232*1422f720SNicholas Piggin 
233*1422f720SNicholas Piggin 	if (do_record) {
234*1422f720SNicholas Piggin 		/*
235*1422f720SNicholas Piggin 		 * Running under TCG record-replay, reservations must not
236*1422f720SNicholas Piggin 		 * be lost by migration
237*1422f720SNicholas Piggin 		 */
238*1422f720SNicholas Piggin 		report(succeed > 0, "migrated reservation is not lost");
239*1422f720SNicholas Piggin 	} else {
240*1422f720SNicholas Piggin 		report(succeed == 0, "migrated reservation is lost");
241*1422f720SNicholas Piggin 	}
242*1422f720SNicholas Piggin 
243*1422f720SNicholas Piggin 	report_prefix_pop();
244*1422f720SNicholas Piggin }
245*1422f720SNicholas Piggin 
246*1422f720SNicholas Piggin #define ITERS 10000000
247*1422f720SNicholas Piggin static int test_counter = 0;
test_inc_perf(int argc,char * argv[])248*1422f720SNicholas Piggin static void test_inc_perf(int argc, char *argv[])
249*1422f720SNicholas Piggin {
250*1422f720SNicholas Piggin 	int i;
251*1422f720SNicholas Piggin 	uint64_t tb1, tb2;
252*1422f720SNicholas Piggin 
253*1422f720SNicholas Piggin 	tb1 = get_tb();
254*1422f720SNicholas Piggin 	for (i = 0; i < ITERS; i++)
255*1422f720SNicholas Piggin 		__atomic_fetch_add(&test_counter, 1, __ATOMIC_RELAXED);
256*1422f720SNicholas Piggin 	tb2 = get_tb();
257*1422f720SNicholas Piggin 	report(true, "atomic add takes %ldns",
258*1422f720SNicholas Piggin 		    (tb2 - tb1) * 1000000000 / ITERS / tb_hz);
259*1422f720SNicholas Piggin 
260*1422f720SNicholas Piggin 	tb1 = get_tb();
261*1422f720SNicholas Piggin 	for (i = 0; i < ITERS; i++)
262*1422f720SNicholas Piggin 		__atomic_fetch_add(&test_counter, 1, __ATOMIC_SEQ_CST);
263*1422f720SNicholas Piggin 	tb2 = get_tb();
264*1422f720SNicholas Piggin 	report(true, "sequentially conssistent atomic add takes %ldns",
265*1422f720SNicholas Piggin 	       (tb2 - tb1) * 1000000000 / ITERS / tb_hz);
266*1422f720SNicholas Piggin }
267*1422f720SNicholas Piggin 
268*1422f720SNicholas Piggin static long smp_inc_counter = 0;
269*1422f720SNicholas Piggin static int smp_inc_started;
270*1422f720SNicholas Piggin 
smp_inc_fn(int cpu_id)271*1422f720SNicholas Piggin static void smp_inc_fn(int cpu_id)
272*1422f720SNicholas Piggin {
273*1422f720SNicholas Piggin 	long i;
274*1422f720SNicholas Piggin 
275*1422f720SNicholas Piggin 	atomic_fetch_inc(&smp_inc_started);
276*1422f720SNicholas Piggin 	while (smp_inc_started < nr_cpus_present)
277*1422f720SNicholas Piggin 		cpu_relax();
278*1422f720SNicholas Piggin 
279*1422f720SNicholas Piggin 	for (i = 0; i < ITERS; i++)
280*1422f720SNicholas Piggin 		atomic_fetch_inc(&smp_inc_counter);
281*1422f720SNicholas Piggin 	atomic_fetch_dec(&smp_inc_started);
282*1422f720SNicholas Piggin }
283*1422f720SNicholas Piggin 
test_smp_inc(int argc,char ** argv)284*1422f720SNicholas Piggin static void test_smp_inc(int argc, char **argv)
285*1422f720SNicholas Piggin {
286*1422f720SNicholas Piggin 	if (nr_cpus_present < 2)
287*1422f720SNicholas Piggin 		return;
288*1422f720SNicholas Piggin 
289*1422f720SNicholas Piggin 	if (!start_all_cpus(smp_inc_fn))
290*1422f720SNicholas Piggin 		report_abort("Failed to start secondary cpus");
291*1422f720SNicholas Piggin 
292*1422f720SNicholas Piggin 	while (smp_inc_started < nr_cpus_present - 1)
293*1422f720SNicholas Piggin 		cpu_relax();
294*1422f720SNicholas Piggin 	smp_inc_fn(smp_processor_id());
295*1422f720SNicholas Piggin 	while (smp_inc_started > 0)
296*1422f720SNicholas Piggin 		cpu_relax();
297*1422f720SNicholas Piggin 
298*1422f720SNicholas Piggin 	stop_all_cpus();
299*1422f720SNicholas Piggin 
300*1422f720SNicholas Piggin 	report(smp_inc_counter == nr_cpus_present * ITERS,
301*1422f720SNicholas Piggin 	       "counter lost no increments");
302*1422f720SNicholas Piggin }
303*1422f720SNicholas Piggin 
304*1422f720SNicholas Piggin static long smp_lock_counter __attribute__((aligned(128))) = 0;
305*1422f720SNicholas Piggin static unsigned int smp_lock __attribute__((aligned(128)));
306*1422f720SNicholas Piggin static int smp_lock_started;
307*1422f720SNicholas Piggin 
smp_lock_fn(int cpu_id)308*1422f720SNicholas Piggin static void smp_lock_fn(int cpu_id)
309*1422f720SNicholas Piggin {
310*1422f720SNicholas Piggin 	long i;
311*1422f720SNicholas Piggin 
312*1422f720SNicholas Piggin 	atomic_fetch_inc(&smp_lock_started);
313*1422f720SNicholas Piggin 	while (smp_lock_started < nr_cpus_present)
314*1422f720SNicholas Piggin 		cpu_relax();
315*1422f720SNicholas Piggin 
316*1422f720SNicholas Piggin 	for (i = 0; i < ITERS; i++) {
317*1422f720SNicholas Piggin 		spin_lock(&smp_lock);
318*1422f720SNicholas Piggin 		smp_lock_counter++;
319*1422f720SNicholas Piggin 		spin_unlock(&smp_lock);
320*1422f720SNicholas Piggin 	}
321*1422f720SNicholas Piggin 	atomic_fetch_dec(&smp_lock_started);
322*1422f720SNicholas Piggin }
323*1422f720SNicholas Piggin 
test_smp_lock(int argc,char ** argv)324*1422f720SNicholas Piggin static void test_smp_lock(int argc, char **argv)
325*1422f720SNicholas Piggin {
326*1422f720SNicholas Piggin 	if (nr_cpus_present < 2)
327*1422f720SNicholas Piggin 		return;
328*1422f720SNicholas Piggin 
329*1422f720SNicholas Piggin 	if (!start_all_cpus(smp_lock_fn))
330*1422f720SNicholas Piggin 		report_abort("Failed to start secondary cpus");
331*1422f720SNicholas Piggin 
332*1422f720SNicholas Piggin 	while (smp_lock_started < nr_cpus_present - 1)
333*1422f720SNicholas Piggin 		cpu_relax();
334*1422f720SNicholas Piggin 	smp_lock_fn(smp_processor_id());
335*1422f720SNicholas Piggin 	while (smp_lock_started > 0)
336*1422f720SNicholas Piggin 		cpu_relax();
337*1422f720SNicholas Piggin 
338*1422f720SNicholas Piggin 	stop_all_cpus();
339*1422f720SNicholas Piggin 
340*1422f720SNicholas Piggin 	report(smp_lock_counter == nr_cpus_present * ITERS,
341*1422f720SNicholas Piggin 	       "counter lost no increments");
342*1422f720SNicholas Piggin }
343*1422f720SNicholas Piggin 
344*1422f720SNicholas Piggin struct {
345*1422f720SNicholas Piggin 	const char *name;
346*1422f720SNicholas Piggin 	void (*func)(int argc, char **argv);
347*1422f720SNicholas Piggin } hctests[] = {
348*1422f720SNicholas Piggin 	{ "lwarx/stwcx", test_lwarx_stwcx },
349*1422f720SNicholas Piggin 	{ "lqarx/stqcx", test_lqarx_stqcx },
350*1422f720SNicholas Piggin 	{ "migration", test_migrate_reserve },
351*1422f720SNicholas Piggin 	{ "performance", test_inc_perf },
352*1422f720SNicholas Piggin 	{ "SMP-atomic", test_smp_inc },
353*1422f720SNicholas Piggin 	{ "SMP-lock", test_smp_lock },
354*1422f720SNicholas Piggin 	{ NULL, NULL }
355*1422f720SNicholas Piggin };
356*1422f720SNicholas Piggin 
main(int argc,char ** argv)357*1422f720SNicholas Piggin int main(int argc, char **argv)
358*1422f720SNicholas Piggin {
359*1422f720SNicholas Piggin 	int i;
360*1422f720SNicholas Piggin 	int all;
361*1422f720SNicholas Piggin 
362*1422f720SNicholas Piggin 	all = argc == 1 || !strcmp(argv[1], "all");
363*1422f720SNicholas Piggin 
364*1422f720SNicholas Piggin 	for (i = 1; i < argc; i++) {
365*1422f720SNicholas Piggin 		if (strcmp(argv[i], "-r") == 0) {
366*1422f720SNicholas Piggin 			do_record = true;
367*1422f720SNicholas Piggin 		}
368*1422f720SNicholas Piggin 		if (strcmp(argv[i], "-m") == 0) {
369*1422f720SNicholas Piggin 			do_migrate = true;
370*1422f720SNicholas Piggin 		}
371*1422f720SNicholas Piggin 	}
372*1422f720SNicholas Piggin 
373*1422f720SNicholas Piggin 	report_prefix_push("atomics");
374*1422f720SNicholas Piggin 
375*1422f720SNicholas Piggin 	for (i = 0; hctests[i].name != NULL; i++) {
376*1422f720SNicholas Piggin 		if (all || strcmp(argv[1], hctests[i].name) == 0) {
377*1422f720SNicholas Piggin 			report_prefix_push(hctests[i].name);
378*1422f720SNicholas Piggin 			hctests[i].func(argc, argv);
379*1422f720SNicholas Piggin 			report_prefix_pop();
380*1422f720SNicholas Piggin 		}
381*1422f720SNicholas Piggin 	}
382*1422f720SNicholas Piggin 
383*1422f720SNicholas Piggin 	report_prefix_pop();
384*1422f720SNicholas Piggin 
385*1422f720SNicholas Piggin 	return report_summary();
386*1422f720SNicholas Piggin }
387