xref: /kvm-unit-tests/powerpc/timebase.c (revision 28ac3b10d6f982b1d9c2fe629f23d23ec5024b4f)
1*28ac3b10SNicholas Piggin // SPDX-License-Identifier: GPL-2.0-only
2*28ac3b10SNicholas Piggin /*
3*28ac3b10SNicholas Piggin  * Test Timebase
4*28ac3b10SNicholas Piggin  *
5*28ac3b10SNicholas Piggin  * Copyright 2024 Nicholas Piggin, IBM Corp.
6*28ac3b10SNicholas Piggin  *
7*28ac3b10SNicholas Piggin  * This contains tests of timebase facility, TB, DEC, etc.
8*28ac3b10SNicholas Piggin  */
9*28ac3b10SNicholas Piggin #include <libcflat.h>
10*28ac3b10SNicholas Piggin #include <util.h>
11*28ac3b10SNicholas Piggin #include <migrate.h>
12*28ac3b10SNicholas Piggin #include <alloc.h>
13*28ac3b10SNicholas Piggin #include <asm/handlers.h>
14*28ac3b10SNicholas Piggin #include <devicetree.h>
15*28ac3b10SNicholas Piggin #include <asm/hcall.h>
16*28ac3b10SNicholas Piggin #include <asm/processor.h>
17*28ac3b10SNicholas Piggin #include <asm/time.h>
18*28ac3b10SNicholas Piggin #include <asm/barrier.h>
19*28ac3b10SNicholas Piggin 
20*28ac3b10SNicholas Piggin static int dec_bits = 0;
21*28ac3b10SNicholas Piggin 
cpu_dec_bits(int fdtnode,u64 regval __unused,void * arg __unused)22*28ac3b10SNicholas Piggin static void cpu_dec_bits(int fdtnode, u64 regval __unused, void *arg __unused)
23*28ac3b10SNicholas Piggin {
24*28ac3b10SNicholas Piggin 	const struct fdt_property *prop;
25*28ac3b10SNicholas Piggin 	int plen;
26*28ac3b10SNicholas Piggin 
27*28ac3b10SNicholas Piggin 	prop = fdt_get_property(dt_fdt(), fdtnode, "ibm,dec-bits", &plen);
28*28ac3b10SNicholas Piggin 	if (!prop) {
29*28ac3b10SNicholas Piggin 		dec_bits = 32;
30*28ac3b10SNicholas Piggin 		return;
31*28ac3b10SNicholas Piggin 	}
32*28ac3b10SNicholas Piggin 
33*28ac3b10SNicholas Piggin 	/* Sanity check for the property layout (first two bytes are header) */
34*28ac3b10SNicholas Piggin 	assert(plen == 4);
35*28ac3b10SNicholas Piggin 
36*28ac3b10SNicholas Piggin 	/* Check all CPU nodes have the same value of dec-bits */
37*28ac3b10SNicholas Piggin 	if (dec_bits)
38*28ac3b10SNicholas Piggin 		assert(dec_bits == fdt32_to_cpu(*(uint32_t *)prop->data));
39*28ac3b10SNicholas Piggin 	else
40*28ac3b10SNicholas Piggin 		dec_bits = fdt32_to_cpu(*(uint32_t *)prop->data);
41*28ac3b10SNicholas Piggin }
42*28ac3b10SNicholas Piggin 
43*28ac3b10SNicholas Piggin /* Check amount of CPUs nodes that have the TM flag */
find_dec_bits(void)44*28ac3b10SNicholas Piggin static int find_dec_bits(void)
45*28ac3b10SNicholas Piggin {
46*28ac3b10SNicholas Piggin 	int ret;
47*28ac3b10SNicholas Piggin 
48*28ac3b10SNicholas Piggin 	ret = dt_for_each_cpu_node(cpu_dec_bits, NULL);
49*28ac3b10SNicholas Piggin 	if (ret < 0)
50*28ac3b10SNicholas Piggin 		return ret;
51*28ac3b10SNicholas Piggin 
52*28ac3b10SNicholas Piggin 	return dec_bits;
53*28ac3b10SNicholas Piggin }
54*28ac3b10SNicholas Piggin 
55*28ac3b10SNicholas Piggin 
56*28ac3b10SNicholas Piggin static bool do_migrate = false;
57*28ac3b10SNicholas Piggin static volatile bool got_interrupt;
58*28ac3b10SNicholas Piggin static volatile struct pt_regs recorded_regs;
59*28ac3b10SNicholas Piggin 
60*28ac3b10SNicholas Piggin static uint64_t dec_max;
61*28ac3b10SNicholas Piggin static uint64_t dec_min;
62*28ac3b10SNicholas Piggin 
test_tb(int argc,char ** argv)63*28ac3b10SNicholas Piggin static void test_tb(int argc, char **argv)
64*28ac3b10SNicholas Piggin {
65*28ac3b10SNicholas Piggin 	uint64_t tb;
66*28ac3b10SNicholas Piggin 	int i;
67*28ac3b10SNicholas Piggin 
68*28ac3b10SNicholas Piggin 	tb = get_tb();
69*28ac3b10SNicholas Piggin 	report(get_tb() >= tb, "timebase is not going backwards");
70*28ac3b10SNicholas Piggin 	if (do_migrate) {
71*28ac3b10SNicholas Piggin 		tb = get_tb();
72*28ac3b10SNicholas Piggin 		migrate();
73*28ac3b10SNicholas Piggin 		report(get_tb() >= tb,
74*28ac3b10SNicholas Piggin 		       "timebase is not going backwards over migration");
75*28ac3b10SNicholas Piggin 	}
76*28ac3b10SNicholas Piggin 
77*28ac3b10SNicholas Piggin 	for (i = 0; i < 100; i++) {
78*28ac3b10SNicholas Piggin 		if (get_tb() > tb)
79*28ac3b10SNicholas Piggin 			break;
80*28ac3b10SNicholas Piggin 	}
81*28ac3b10SNicholas Piggin 	report(get_tb() > tb, "timebase is incrementing");
82*28ac3b10SNicholas Piggin }
83*28ac3b10SNicholas Piggin 
dec_stop_handler(struct pt_regs * regs,void * data)84*28ac3b10SNicholas Piggin static void dec_stop_handler(struct pt_regs *regs, void *data)
85*28ac3b10SNicholas Piggin {
86*28ac3b10SNicholas Piggin 	mtspr(SPR_DEC, dec_max);
87*28ac3b10SNicholas Piggin }
88*28ac3b10SNicholas Piggin 
dec_handler(struct pt_regs * regs,void * data)89*28ac3b10SNicholas Piggin static void dec_handler(struct pt_regs *regs, void *data)
90*28ac3b10SNicholas Piggin {
91*28ac3b10SNicholas Piggin 	got_interrupt = true;
92*28ac3b10SNicholas Piggin 	memcpy((void *)&recorded_regs, regs, sizeof(struct pt_regs));
93*28ac3b10SNicholas Piggin 	regs->msr &= ~MSR_EE;
94*28ac3b10SNicholas Piggin }
95*28ac3b10SNicholas Piggin 
test_dec(int argc,char ** argv)96*28ac3b10SNicholas Piggin static void test_dec(int argc, char **argv)
97*28ac3b10SNicholas Piggin {
98*28ac3b10SNicholas Piggin 	uint64_t tb1, tb2, dec;
99*28ac3b10SNicholas Piggin 	int i;
100*28ac3b10SNicholas Piggin 
101*28ac3b10SNicholas Piggin 	handle_exception(0x900, &dec_handler, NULL);
102*28ac3b10SNicholas Piggin 
103*28ac3b10SNicholas Piggin 	for (i = 0; i < 100; i++) {
104*28ac3b10SNicholas Piggin 		tb1 = get_tb();
105*28ac3b10SNicholas Piggin 		mtspr(SPR_DEC, dec_max);
106*28ac3b10SNicholas Piggin 		dec = mfspr(SPR_DEC);
107*28ac3b10SNicholas Piggin 		tb2 = get_tb();
108*28ac3b10SNicholas Piggin 		if (tb2 - tb1 < dec_max - dec)
109*28ac3b10SNicholas Piggin 			break;
110*28ac3b10SNicholas Piggin 	}
111*28ac3b10SNicholas Piggin 	/* POWER CPUs can have a slight (few ticks) variation here */
112*28ac3b10SNicholas Piggin 	report_kfail(!host_is_tcg, tb2 - tb1 >= dec_max - dec,
113*28ac3b10SNicholas Piggin 		     "decrementer remains within TB after mtDEC");
114*28ac3b10SNicholas Piggin 
115*28ac3b10SNicholas Piggin 	tb1 = get_tb();
116*28ac3b10SNicholas Piggin 	mtspr(SPR_DEC, dec_max);
117*28ac3b10SNicholas Piggin 	mdelay(1000);
118*28ac3b10SNicholas Piggin 	dec = mfspr(SPR_DEC);
119*28ac3b10SNicholas Piggin 	tb2 = get_tb();
120*28ac3b10SNicholas Piggin 	report(tb2 - tb1 >= dec_max - dec,
121*28ac3b10SNicholas Piggin 	       "decrementer remains within TB after 1s");
122*28ac3b10SNicholas Piggin 
123*28ac3b10SNicholas Piggin 	mtspr(SPR_DEC, dec_max);
124*28ac3b10SNicholas Piggin 	local_irq_enable();
125*28ac3b10SNicholas Piggin 	local_irq_disable();
126*28ac3b10SNicholas Piggin 	if (mfspr(SPR_DEC) <= dec_max) {
127*28ac3b10SNicholas Piggin 		report(!got_interrupt,
128*28ac3b10SNicholas Piggin 		       "no interrupt on decrementer positive");
129*28ac3b10SNicholas Piggin 	}
130*28ac3b10SNicholas Piggin 	got_interrupt = false;
131*28ac3b10SNicholas Piggin 
132*28ac3b10SNicholas Piggin 	mtspr(SPR_DEC, 1);
133*28ac3b10SNicholas Piggin 	mdelay(100); /* Give the timer a chance to run */
134*28ac3b10SNicholas Piggin 	if (do_migrate)
135*28ac3b10SNicholas Piggin 		migrate();
136*28ac3b10SNicholas Piggin 	local_irq_enable();
137*28ac3b10SNicholas Piggin 	local_irq_disable();
138*28ac3b10SNicholas Piggin 	report(got_interrupt, "interrupt on decrementer underflow");
139*28ac3b10SNicholas Piggin 	got_interrupt = false;
140*28ac3b10SNicholas Piggin 
141*28ac3b10SNicholas Piggin 	if (do_migrate)
142*28ac3b10SNicholas Piggin 		migrate();
143*28ac3b10SNicholas Piggin 	local_irq_enable();
144*28ac3b10SNicholas Piggin 	local_irq_disable();
145*28ac3b10SNicholas Piggin 	report(got_interrupt, "interrupt on decrementer still underflown");
146*28ac3b10SNicholas Piggin 	got_interrupt = false;
147*28ac3b10SNicholas Piggin 
148*28ac3b10SNicholas Piggin 	mtspr(SPR_DEC, 0);
149*28ac3b10SNicholas Piggin 	mdelay(100); /* Give the timer a chance to run */
150*28ac3b10SNicholas Piggin 	if (do_migrate)
151*28ac3b10SNicholas Piggin 		migrate();
152*28ac3b10SNicholas Piggin 	local_irq_enable();
153*28ac3b10SNicholas Piggin 	local_irq_disable();
154*28ac3b10SNicholas Piggin 	report(got_interrupt, "DEC deal with set to 0");
155*28ac3b10SNicholas Piggin 	got_interrupt = false;
156*28ac3b10SNicholas Piggin 
157*28ac3b10SNicholas Piggin 	/* Test for level-triggered decrementer */
158*28ac3b10SNicholas Piggin 	mtspr(SPR_DEC, -1ULL);
159*28ac3b10SNicholas Piggin 	if (do_migrate)
160*28ac3b10SNicholas Piggin 		migrate();
161*28ac3b10SNicholas Piggin 	local_irq_enable();
162*28ac3b10SNicholas Piggin 	local_irq_disable();
163*28ac3b10SNicholas Piggin 	report(got_interrupt, "interrupt on decrementer write MSB");
164*28ac3b10SNicholas Piggin 	got_interrupt = false;
165*28ac3b10SNicholas Piggin 
166*28ac3b10SNicholas Piggin 	mtspr(SPR_DEC, dec_max);
167*28ac3b10SNicholas Piggin 	local_irq_enable();
168*28ac3b10SNicholas Piggin 	if (do_migrate)
169*28ac3b10SNicholas Piggin 		migrate();
170*28ac3b10SNicholas Piggin 	mtspr(SPR_DEC, -1);
171*28ac3b10SNicholas Piggin 	local_irq_disable();
172*28ac3b10SNicholas Piggin 	report(got_interrupt, "interrupt on decrementer write MSB with irqs on");
173*28ac3b10SNicholas Piggin 	got_interrupt = false;
174*28ac3b10SNicholas Piggin 
175*28ac3b10SNicholas Piggin 	mtspr(SPR_DEC, dec_min + 1);
176*28ac3b10SNicholas Piggin 	mdelay(100);
177*28ac3b10SNicholas Piggin 	local_irq_enable();
178*28ac3b10SNicholas Piggin 	local_irq_disable();
179*28ac3b10SNicholas Piggin 	/* TCG does not model this correctly */
180*28ac3b10SNicholas Piggin 	report_kfail(host_is_tcg, !got_interrupt,
181*28ac3b10SNicholas Piggin 		     "no interrupt after wrap to positive");
182*28ac3b10SNicholas Piggin 	got_interrupt = false;
183*28ac3b10SNicholas Piggin 
184*28ac3b10SNicholas Piggin 	handle_exception(0x900, NULL, NULL);
185*28ac3b10SNicholas Piggin }
186*28ac3b10SNicholas Piggin 
test_hdec(int argc,char ** argv)187*28ac3b10SNicholas Piggin static void test_hdec(int argc, char **argv)
188*28ac3b10SNicholas Piggin {
189*28ac3b10SNicholas Piggin 	uint64_t tb1, tb2, hdec;
190*28ac3b10SNicholas Piggin 
191*28ac3b10SNicholas Piggin 	if (!machine_is_powernv()) {
192*28ac3b10SNicholas Piggin 		report_skip("test reqiures powernv machine");
193*28ac3b10SNicholas Piggin 		return;
194*28ac3b10SNicholas Piggin 	}
195*28ac3b10SNicholas Piggin 
196*28ac3b10SNicholas Piggin 	handle_exception(0x900, &dec_stop_handler, NULL);
197*28ac3b10SNicholas Piggin 	handle_exception(0x980, &dec_handler, NULL);
198*28ac3b10SNicholas Piggin 
199*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, dec_max);
200*28ac3b10SNicholas Piggin 	mtspr(SPR_LPCR, mfspr(SPR_LPCR) | LPCR_HDICE);
201*28ac3b10SNicholas Piggin 
202*28ac3b10SNicholas Piggin 	tb1 = get_tb();
203*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, dec_max);
204*28ac3b10SNicholas Piggin 	hdec = mfspr(SPR_HDEC);
205*28ac3b10SNicholas Piggin 	tb2 = get_tb();
206*28ac3b10SNicholas Piggin 	report(tb2 - tb1 >= dec_max - hdec, "hdecrementer remains within TB");
207*28ac3b10SNicholas Piggin 
208*28ac3b10SNicholas Piggin 	tb1 = get_tb();
209*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, dec_max);
210*28ac3b10SNicholas Piggin 	mdelay(1000);
211*28ac3b10SNicholas Piggin 	hdec = mfspr(SPR_HDEC);
212*28ac3b10SNicholas Piggin 	tb2 = get_tb();
213*28ac3b10SNicholas Piggin 	report(tb2 - tb1 >= dec_max - hdec, "hdecrementer remains within TB after 1s");
214*28ac3b10SNicholas Piggin 
215*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, dec_max);
216*28ac3b10SNicholas Piggin 	local_irq_enable();
217*28ac3b10SNicholas Piggin 	local_irq_disable();
218*28ac3b10SNicholas Piggin 	if (mfspr(SPR_HDEC) <= dec_max) {
219*28ac3b10SNicholas Piggin 		report(!got_interrupt, "no interrupt on decrementer positive");
220*28ac3b10SNicholas Piggin 	}
221*28ac3b10SNicholas Piggin 	got_interrupt = false;
222*28ac3b10SNicholas Piggin 
223*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, 1);
224*28ac3b10SNicholas Piggin 	mdelay(100); /* Give the timer a chance to run */
225*28ac3b10SNicholas Piggin 	if (do_migrate)
226*28ac3b10SNicholas Piggin 		migrate();
227*28ac3b10SNicholas Piggin 	/* HDEC is edge triggered so ensure it still fires */
228*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, dec_max);
229*28ac3b10SNicholas Piggin 	local_irq_enable();
230*28ac3b10SNicholas Piggin 	local_irq_disable();
231*28ac3b10SNicholas Piggin 	report(got_interrupt, "interrupt on hdecrementer underflow");
232*28ac3b10SNicholas Piggin 	got_interrupt = false;
233*28ac3b10SNicholas Piggin 
234*28ac3b10SNicholas Piggin 	if (do_migrate)
235*28ac3b10SNicholas Piggin 		migrate();
236*28ac3b10SNicholas Piggin 	local_irq_enable();
237*28ac3b10SNicholas Piggin 	local_irq_disable();
238*28ac3b10SNicholas Piggin 	report(!got_interrupt, "no interrupt on hdecrementer still underflown");
239*28ac3b10SNicholas Piggin 	got_interrupt = false;
240*28ac3b10SNicholas Piggin 
241*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, -1ULL);
242*28ac3b10SNicholas Piggin 	if (do_migrate)
243*28ac3b10SNicholas Piggin 		migrate();
244*28ac3b10SNicholas Piggin 	local_irq_enable();
245*28ac3b10SNicholas Piggin 	local_irq_disable();
246*28ac3b10SNicholas Piggin 	report(got_interrupt, "no interrupt on hdecrementer underflown write MSB");
247*28ac3b10SNicholas Piggin 	got_interrupt = false;
248*28ac3b10SNicholas Piggin 
249*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, 0);
250*28ac3b10SNicholas Piggin 	mdelay(100); /* Give the timer a chance to run */
251*28ac3b10SNicholas Piggin 	if (do_migrate)
252*28ac3b10SNicholas Piggin 		migrate();
253*28ac3b10SNicholas Piggin 	/* HDEC is edge triggered so ensure it still fires */
254*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, dec_max);
255*28ac3b10SNicholas Piggin 	local_irq_enable();
256*28ac3b10SNicholas Piggin 	local_irq_disable();
257*28ac3b10SNicholas Piggin 	report(got_interrupt, "HDEC deal with set to 0");
258*28ac3b10SNicholas Piggin 	got_interrupt = false;
259*28ac3b10SNicholas Piggin 
260*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, dec_max);
261*28ac3b10SNicholas Piggin 	local_irq_enable();
262*28ac3b10SNicholas Piggin 	if (do_migrate)
263*28ac3b10SNicholas Piggin 		migrate();
264*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, -1ULL);
265*28ac3b10SNicholas Piggin 	local_irq_disable();
266*28ac3b10SNicholas Piggin 	report(got_interrupt, "interrupt on hdecrementer write MSB with irqs on");
267*28ac3b10SNicholas Piggin 	got_interrupt = false;
268*28ac3b10SNicholas Piggin 
269*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, dec_max);
270*28ac3b10SNicholas Piggin 	got_interrupt = false;
271*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, dec_min + 1);
272*28ac3b10SNicholas Piggin 	if (do_migrate)
273*28ac3b10SNicholas Piggin 		migrate();
274*28ac3b10SNicholas Piggin 	mdelay(100);
275*28ac3b10SNicholas Piggin 	local_irq_enable();
276*28ac3b10SNicholas Piggin 	local_irq_disable();
277*28ac3b10SNicholas Piggin 	report(got_interrupt, "got interrupt after wrap to positive");
278*28ac3b10SNicholas Piggin 	got_interrupt = false;
279*28ac3b10SNicholas Piggin 
280*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, -1ULL);
281*28ac3b10SNicholas Piggin 	local_irq_enable();
282*28ac3b10SNicholas Piggin 	local_irq_disable();
283*28ac3b10SNicholas Piggin 	got_interrupt = false;
284*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, dec_min + 1000000);
285*28ac3b10SNicholas Piggin 	if (do_migrate)
286*28ac3b10SNicholas Piggin 		migrate();
287*28ac3b10SNicholas Piggin 	mdelay(100);
288*28ac3b10SNicholas Piggin 	mtspr(SPR_HDEC, -1ULL);
289*28ac3b10SNicholas Piggin 	local_irq_enable();
290*28ac3b10SNicholas Piggin 	local_irq_disable();
291*28ac3b10SNicholas Piggin 	report(got_interrupt, "edge re-armed after wrap to positive");
292*28ac3b10SNicholas Piggin 	got_interrupt = false;
293*28ac3b10SNicholas Piggin 
294*28ac3b10SNicholas Piggin 	mtspr(SPR_LPCR, mfspr(SPR_LPCR) & ~LPCR_HDICE);
295*28ac3b10SNicholas Piggin 
296*28ac3b10SNicholas Piggin 	handle_exception(0x900, NULL, NULL);
297*28ac3b10SNicholas Piggin 	handle_exception(0x980, NULL, NULL);
298*28ac3b10SNicholas Piggin }
299*28ac3b10SNicholas Piggin 
300*28ac3b10SNicholas Piggin struct {
301*28ac3b10SNicholas Piggin 	const char *name;
302*28ac3b10SNicholas Piggin 	void (*func)(int argc, char **argv);
303*28ac3b10SNicholas Piggin } hctests[] = {
304*28ac3b10SNicholas Piggin 	{ "tb", test_tb },
305*28ac3b10SNicholas Piggin 	{ "dec", test_dec },
306*28ac3b10SNicholas Piggin 	{ "hdec", test_hdec },
307*28ac3b10SNicholas Piggin 	{ NULL, NULL }
308*28ac3b10SNicholas Piggin };
309*28ac3b10SNicholas Piggin 
main(int argc,char ** argv)310*28ac3b10SNicholas Piggin int main(int argc, char **argv)
311*28ac3b10SNicholas Piggin {
312*28ac3b10SNicholas Piggin 	bool all;
313*28ac3b10SNicholas Piggin 	int i;
314*28ac3b10SNicholas Piggin 
315*28ac3b10SNicholas Piggin 	all = argc == 1 || !strcmp(argv[1], "all");
316*28ac3b10SNicholas Piggin 
317*28ac3b10SNicholas Piggin 	for (i = 1; i < argc; i++) {
318*28ac3b10SNicholas Piggin 		if (!strcmp(argv[i], "-w")) {
319*28ac3b10SNicholas Piggin 			do_migrate = true;
320*28ac3b10SNicholas Piggin 			if (!all && argc == 2)
321*28ac3b10SNicholas Piggin 				all = true;
322*28ac3b10SNicholas Piggin 		}
323*28ac3b10SNicholas Piggin 	}
324*28ac3b10SNicholas Piggin 
325*28ac3b10SNicholas Piggin 	find_dec_bits();
326*28ac3b10SNicholas Piggin 	dec_max = (1ULL << (dec_bits - 1)) - 1;
327*28ac3b10SNicholas Piggin 	dec_min = (1ULL << (dec_bits - 1));
328*28ac3b10SNicholas Piggin 
329*28ac3b10SNicholas Piggin 	if (machine_is_powernv() && dec_bits > 32) {
330*28ac3b10SNicholas Piggin 		mtspr(SPR_LPCR, mfspr(SPR_LPCR) | LPCR_LD);
331*28ac3b10SNicholas Piggin 	}
332*28ac3b10SNicholas Piggin 
333*28ac3b10SNicholas Piggin 	report_prefix_push("timebase");
334*28ac3b10SNicholas Piggin 
335*28ac3b10SNicholas Piggin 	for (i = 0; hctests[i].name != NULL; i++) {
336*28ac3b10SNicholas Piggin 		if (all || strcmp(argv[1], hctests[i].name) == 0) {
337*28ac3b10SNicholas Piggin 			report_prefix_push(hctests[i].name);
338*28ac3b10SNicholas Piggin 			hctests[i].func(argc, argv);
339*28ac3b10SNicholas Piggin 			report_prefix_pop();
340*28ac3b10SNicholas Piggin 		}
341*28ac3b10SNicholas Piggin 	}
342*28ac3b10SNicholas Piggin 
343*28ac3b10SNicholas Piggin 	report_prefix_pop();
344*28ac3b10SNicholas Piggin 
345*28ac3b10SNicholas Piggin 	if (machine_is_powernv() && dec_bits > 32) {
346*28ac3b10SNicholas Piggin 		mtspr(SPR_LPCR, mfspr(SPR_LPCR) & ~LPCR_LD);
347*28ac3b10SNicholas Piggin 	}
348*28ac3b10SNicholas Piggin 
349*28ac3b10SNicholas Piggin 	return report_summary();
350*28ac3b10SNicholas Piggin }
351