xref: /kvm-unit-tests/arm/gic.c (revision 0ef02cd6cbaaf6e41cdc429fd8b08e86c65dfb94)
1ac4a67b6SAndrew Jones /*
2ac4a67b6SAndrew Jones  * GIC tests
3ac4a67b6SAndrew Jones  *
4ac4a67b6SAndrew Jones  * GICv2
5ac4a67b6SAndrew Jones  *   + test sending/receiving IPIs
678ad7e95SAndre Przywara  *   + MMIO access tests
72e2d471dSAndrew Jones  * GICv3
82e2d471dSAndrew Jones  *   + test sending/receiving IPIs
9ac4a67b6SAndrew Jones  *
10ac4a67b6SAndrew Jones  * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
11ac4a67b6SAndrew Jones  *
12ac4a67b6SAndrew Jones  * This work is licensed under the terms of the GNU LGPL, version 2.
13ac4a67b6SAndrew Jones  */
14ac4a67b6SAndrew Jones #include <libcflat.h>
15ac4a67b6SAndrew Jones #include <asm/setup.h>
16ac4a67b6SAndrew Jones #include <asm/processor.h>
17ac4a67b6SAndrew Jones #include <asm/delay.h>
18ac4a67b6SAndrew Jones #include <asm/gic.h>
19ba74b106SEric Auger #include <asm/gic-v3-its.h>
20ac4a67b6SAndrew Jones #include <asm/smp.h>
21ac4a67b6SAndrew Jones #include <asm/barrier.h>
22ac4a67b6SAndrew Jones #include <asm/io.h>
23ac4a67b6SAndrew Jones 
24ca1b7a7bSAndrew Jones #define IPI_SENDER	1
25ca1b7a7bSAndrew Jones #define IPI_IRQ		1
26ca1b7a7bSAndrew Jones 
272e2d471dSAndrew Jones struct gic {
282e2d471dSAndrew Jones 	struct {
292e2d471dSAndrew Jones 		void (*send_self)(void);
302e2d471dSAndrew Jones 		void (*send_broadcast)(void);
312e2d471dSAndrew Jones 	} ipi;
322e2d471dSAndrew Jones };
332e2d471dSAndrew Jones 
342e2d471dSAndrew Jones static struct gic *gic;
35ac4a67b6SAndrew Jones static int acked[NR_CPUS], spurious[NR_CPUS];
36ca1b7a7bSAndrew Jones static int bad_sender[NR_CPUS], bad_irq[NR_CPUS];
37ac4a67b6SAndrew Jones static cpumask_t ready;
38ac4a67b6SAndrew Jones 
39ac4a67b6SAndrew Jones static void nr_cpu_check(int nr)
40ac4a67b6SAndrew Jones {
41ac4a67b6SAndrew Jones 	if (nr_cpus < nr)
42ac4a67b6SAndrew Jones 		report_abort("At least %d cpus required", nr);
43ac4a67b6SAndrew Jones }
44ac4a67b6SAndrew Jones 
45ac4a67b6SAndrew Jones static void wait_on_ready(void)
46ac4a67b6SAndrew Jones {
47ac4a67b6SAndrew Jones 	cpumask_set_cpu(smp_processor_id(), &ready);
48ac4a67b6SAndrew Jones 	while (!cpumask_full(&ready))
49ac4a67b6SAndrew Jones 		cpu_relax();
50ac4a67b6SAndrew Jones }
51ac4a67b6SAndrew Jones 
52ca1b7a7bSAndrew Jones static void stats_reset(void)
53ca1b7a7bSAndrew Jones {
54ca1b7a7bSAndrew Jones 	int i;
55ca1b7a7bSAndrew Jones 
56ca1b7a7bSAndrew Jones 	for (i = 0; i < nr_cpus; ++i) {
57ca1b7a7bSAndrew Jones 		acked[i] = 0;
58ca1b7a7bSAndrew Jones 		bad_sender[i] = -1;
59ca1b7a7bSAndrew Jones 		bad_irq[i] = -1;
60ca1b7a7bSAndrew Jones 	}
61ca1b7a7bSAndrew Jones 	smp_wmb();
62ca1b7a7bSAndrew Jones }
63ca1b7a7bSAndrew Jones 
6496edb026SAndre Przywara static void check_acked(const char *testname, cpumask_t *mask)
65ac4a67b6SAndrew Jones {
66ac4a67b6SAndrew Jones 	int missing = 0, extra = 0, unexpected = 0;
67ac4a67b6SAndrew Jones 	int nr_pass, cpu, i;
68ca1b7a7bSAndrew Jones 	bool bad = false;
69ac4a67b6SAndrew Jones 
70ac4a67b6SAndrew Jones 	/* Wait up to 5s for all interrupts to be delivered */
71ac4a67b6SAndrew Jones 	for (i = 0; i < 50; ++i) {
72ac4a67b6SAndrew Jones 		mdelay(100);
73ac4a67b6SAndrew Jones 		nr_pass = 0;
74ac4a67b6SAndrew Jones 		for_each_present_cpu(cpu) {
75ac4a67b6SAndrew Jones 			smp_rmb();
76ac4a67b6SAndrew Jones 			nr_pass += cpumask_test_cpu(cpu, mask) ?
77ac4a67b6SAndrew Jones 				acked[cpu] == 1 : acked[cpu] == 0;
78ca1b7a7bSAndrew Jones 
79ca1b7a7bSAndrew Jones 			if (bad_sender[cpu] != -1) {
80ca1b7a7bSAndrew Jones 				printf("cpu%d received IPI from wrong sender %d\n",
81ca1b7a7bSAndrew Jones 					cpu, bad_sender[cpu]);
82ca1b7a7bSAndrew Jones 				bad = true;
83ca1b7a7bSAndrew Jones 			}
84ca1b7a7bSAndrew Jones 
85ca1b7a7bSAndrew Jones 			if (bad_irq[cpu] != -1) {
86ca1b7a7bSAndrew Jones 				printf("cpu%d received wrong irq %d\n",
87ca1b7a7bSAndrew Jones 					cpu, bad_irq[cpu]);
88ca1b7a7bSAndrew Jones 				bad = true;
89ca1b7a7bSAndrew Jones 			}
90ac4a67b6SAndrew Jones 		}
91ac4a67b6SAndrew Jones 		if (nr_pass == nr_cpus) {
92a299895bSThomas Huth 			report(!bad, "%s", testname);
9396edb026SAndre Przywara 			if (i)
9496edb026SAndre Przywara 				report_info("took more than %d ms", i * 100);
95ac4a67b6SAndrew Jones 			return;
96ac4a67b6SAndrew Jones 		}
97ac4a67b6SAndrew Jones 	}
98ac4a67b6SAndrew Jones 
99ac4a67b6SAndrew Jones 	for_each_present_cpu(cpu) {
100ac4a67b6SAndrew Jones 		if (cpumask_test_cpu(cpu, mask)) {
101ac4a67b6SAndrew Jones 			if (!acked[cpu])
102ac4a67b6SAndrew Jones 				++missing;
103ac4a67b6SAndrew Jones 			else if (acked[cpu] > 1)
104ac4a67b6SAndrew Jones 				++extra;
105ac4a67b6SAndrew Jones 		} else {
106ac4a67b6SAndrew Jones 			if (acked[cpu])
107ac4a67b6SAndrew Jones 				++unexpected;
108ac4a67b6SAndrew Jones 		}
109ac4a67b6SAndrew Jones 	}
110ac4a67b6SAndrew Jones 
111a299895bSThomas Huth 	report(false, "%s", testname);
11296edb026SAndre Przywara 	report_info("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d",
11396edb026SAndre Przywara 		    missing, extra, unexpected);
114ac4a67b6SAndrew Jones }
115ac4a67b6SAndrew Jones 
116ac4a67b6SAndrew Jones static void check_spurious(void)
117ac4a67b6SAndrew Jones {
118ac4a67b6SAndrew Jones 	int cpu;
119ac4a67b6SAndrew Jones 
120ac4a67b6SAndrew Jones 	smp_rmb();
121ac4a67b6SAndrew Jones 	for_each_present_cpu(cpu) {
122ac4a67b6SAndrew Jones 		if (spurious[cpu])
123ac4a67b6SAndrew Jones 			report_info("WARN: cpu%d got %d spurious interrupts",
124ac4a67b6SAndrew Jones 				cpu, spurious[cpu]);
125ac4a67b6SAndrew Jones 	}
126ac4a67b6SAndrew Jones }
127ac4a67b6SAndrew Jones 
128ca1b7a7bSAndrew Jones static void check_ipi_sender(u32 irqstat)
129ca1b7a7bSAndrew Jones {
130ca1b7a7bSAndrew Jones 	if (gic_version() == 2) {
131ca1b7a7bSAndrew Jones 		int src = (irqstat >> 10) & 7;
132ca1b7a7bSAndrew Jones 
133ca1b7a7bSAndrew Jones 		if (src != IPI_SENDER)
134ca1b7a7bSAndrew Jones 			bad_sender[smp_processor_id()] = src;
135ca1b7a7bSAndrew Jones 	}
136ca1b7a7bSAndrew Jones }
137ca1b7a7bSAndrew Jones 
138ca1b7a7bSAndrew Jones static void check_irqnr(u32 irqnr)
139ca1b7a7bSAndrew Jones {
140ca1b7a7bSAndrew Jones 	if (irqnr != IPI_IRQ)
141ca1b7a7bSAndrew Jones 		bad_irq[smp_processor_id()] = irqnr;
142ca1b7a7bSAndrew Jones }
143ca1b7a7bSAndrew Jones 
144ac4a67b6SAndrew Jones static void ipi_handler(struct pt_regs *regs __unused)
145ac4a67b6SAndrew Jones {
1462e2d471dSAndrew Jones 	u32 irqstat = gic_read_iar();
1472e2d471dSAndrew Jones 	u32 irqnr = gic_iar_irqnr(irqstat);
148ac4a67b6SAndrew Jones 
149ac4a67b6SAndrew Jones 	if (irqnr != GICC_INT_SPURIOUS) {
1502e2d471dSAndrew Jones 		gic_write_eoir(irqstat);
151ca1b7a7bSAndrew Jones 		smp_rmb(); /* pairs with wmb in stats_reset */
152ac4a67b6SAndrew Jones 		++acked[smp_processor_id()];
153ca1b7a7bSAndrew Jones 		check_ipi_sender(irqstat);
154ca1b7a7bSAndrew Jones 		check_irqnr(irqnr);
155ac4a67b6SAndrew Jones 		smp_wmb(); /* pairs with rmb in check_acked */
156ac4a67b6SAndrew Jones 	} else {
157ac4a67b6SAndrew Jones 		++spurious[smp_processor_id()];
158ac4a67b6SAndrew Jones 		smp_wmb();
159ac4a67b6SAndrew Jones 	}
160ac4a67b6SAndrew Jones }
161ac4a67b6SAndrew Jones 
162*0ef02cd6SEric Auger static void setup_irq(irq_handler_fn handler)
163*0ef02cd6SEric Auger {
164*0ef02cd6SEric Auger 	gic_enable_defaults();
165*0ef02cd6SEric Auger #ifdef __arm__
166*0ef02cd6SEric Auger 	install_exception_handler(EXCPTN_IRQ, handler);
167*0ef02cd6SEric Auger #else
168*0ef02cd6SEric Auger 	install_irq_handler(EL1H_IRQ, handler);
169*0ef02cd6SEric Auger #endif
170*0ef02cd6SEric Auger 	local_irq_enable();
171*0ef02cd6SEric Auger }
172*0ef02cd6SEric Auger 
173*0ef02cd6SEric Auger #if defined(__aarch64__)
174*0ef02cd6SEric Auger struct its_event {
175*0ef02cd6SEric Auger 	int cpu_id;
176*0ef02cd6SEric Auger 	int lpi_id;
177*0ef02cd6SEric Auger };
178*0ef02cd6SEric Auger 
179*0ef02cd6SEric Auger struct its_stats {
180*0ef02cd6SEric Auger 	struct its_event expected;
181*0ef02cd6SEric Auger 	struct its_event observed;
182*0ef02cd6SEric Auger };
183*0ef02cd6SEric Auger 
184*0ef02cd6SEric Auger static struct its_stats lpi_stats;
185*0ef02cd6SEric Auger 
186*0ef02cd6SEric Auger static void lpi_handler(struct pt_regs *regs __unused)
187*0ef02cd6SEric Auger {
188*0ef02cd6SEric Auger 	u32 irqstat = gic_read_iar();
189*0ef02cd6SEric Auger 	int irqnr = gic_iar_irqnr(irqstat);
190*0ef02cd6SEric Auger 
191*0ef02cd6SEric Auger 	gic_write_eoir(irqstat);
192*0ef02cd6SEric Auger 	assert(irqnr >= 8192);
193*0ef02cd6SEric Auger 	smp_rmb(); /* pairs with wmb in lpi_stats_expect */
194*0ef02cd6SEric Auger 	lpi_stats.observed.cpu_id = smp_processor_id();
195*0ef02cd6SEric Auger 	lpi_stats.observed.lpi_id = irqnr;
196*0ef02cd6SEric Auger 	smp_wmb(); /* pairs with rmb in check_lpi_stats */
197*0ef02cd6SEric Auger }
198*0ef02cd6SEric Auger 
199*0ef02cd6SEric Auger static void lpi_stats_expect(int exp_cpu_id, int exp_lpi_id)
200*0ef02cd6SEric Auger {
201*0ef02cd6SEric Auger 	lpi_stats.expected.cpu_id = exp_cpu_id;
202*0ef02cd6SEric Auger 	lpi_stats.expected.lpi_id = exp_lpi_id;
203*0ef02cd6SEric Auger 	lpi_stats.observed.cpu_id = -1;
204*0ef02cd6SEric Auger 	lpi_stats.observed.lpi_id = -1;
205*0ef02cd6SEric Auger 	smp_wmb(); /* pairs with rmb in handler */
206*0ef02cd6SEric Auger }
207*0ef02cd6SEric Auger 
208*0ef02cd6SEric Auger static void check_lpi_stats(const char *msg)
209*0ef02cd6SEric Auger {
210*0ef02cd6SEric Auger 	int i;
211*0ef02cd6SEric Auger 
212*0ef02cd6SEric Auger 	for (i = 0; i < 50; i++) {
213*0ef02cd6SEric Auger 		mdelay(100);
214*0ef02cd6SEric Auger 		smp_rmb(); /* pairs with wmb in lpi_handler */
215*0ef02cd6SEric Auger 		if (lpi_stats.observed.cpu_id == lpi_stats.expected.cpu_id &&
216*0ef02cd6SEric Auger 		    lpi_stats.observed.lpi_id == lpi_stats.expected.lpi_id) {
217*0ef02cd6SEric Auger 			report(true, "%s", msg);
218*0ef02cd6SEric Auger 			return;
219*0ef02cd6SEric Auger 		}
220*0ef02cd6SEric Auger 	}
221*0ef02cd6SEric Auger 
222*0ef02cd6SEric Auger 	if (lpi_stats.observed.cpu_id == -1 && lpi_stats.observed.lpi_id == -1) {
223*0ef02cd6SEric Auger 		report_info("No LPI received whereas (cpuid=%d, intid=%d) "
224*0ef02cd6SEric Auger 			    "was expected", lpi_stats.expected.cpu_id,
225*0ef02cd6SEric Auger 			    lpi_stats.expected.lpi_id);
226*0ef02cd6SEric Auger 	} else {
227*0ef02cd6SEric Auger 		report_info("Unexpected LPI (cpuid=%d, intid=%d)",
228*0ef02cd6SEric Auger 			    lpi_stats.observed.cpu_id,
229*0ef02cd6SEric Auger 			    lpi_stats.observed.lpi_id);
230*0ef02cd6SEric Auger 	}
231*0ef02cd6SEric Auger 	report(false, "%s", msg);
232*0ef02cd6SEric Auger }
233*0ef02cd6SEric Auger 
234*0ef02cd6SEric Auger static void secondary_lpi_test(void)
235*0ef02cd6SEric Auger {
236*0ef02cd6SEric Auger 	setup_irq(lpi_handler);
237*0ef02cd6SEric Auger 	cpumask_set_cpu(smp_processor_id(), &ready);
238*0ef02cd6SEric Auger 	while (1)
239*0ef02cd6SEric Auger 		wfi();
240*0ef02cd6SEric Auger }
241*0ef02cd6SEric Auger #endif
242*0ef02cd6SEric Auger 
2432e2d471dSAndrew Jones static void gicv2_ipi_send_self(void)
2442e2d471dSAndrew Jones {
245ca1b7a7bSAndrew Jones 	writel(2 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
2462e2d471dSAndrew Jones }
2472e2d471dSAndrew Jones 
2482e2d471dSAndrew Jones static void gicv2_ipi_send_broadcast(void)
2492e2d471dSAndrew Jones {
250ca1b7a7bSAndrew Jones 	writel(1 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
2512e2d471dSAndrew Jones }
2522e2d471dSAndrew Jones 
2532e2d471dSAndrew Jones static void gicv3_ipi_send_self(void)
2542e2d471dSAndrew Jones {
255ca1b7a7bSAndrew Jones 	gic_ipi_send_single(IPI_IRQ, smp_processor_id());
2562e2d471dSAndrew Jones }
2572e2d471dSAndrew Jones 
2582e2d471dSAndrew Jones static void gicv3_ipi_send_broadcast(void)
2592e2d471dSAndrew Jones {
260ca1b7a7bSAndrew Jones 	gicv3_write_sgi1r(1ULL << 40 | IPI_IRQ << 24);
2612e2d471dSAndrew Jones 	isb();
2622e2d471dSAndrew Jones }
2632e2d471dSAndrew Jones 
264ac4a67b6SAndrew Jones static void ipi_test_self(void)
265ac4a67b6SAndrew Jones {
266ac4a67b6SAndrew Jones 	cpumask_t mask;
267ac4a67b6SAndrew Jones 
268ac4a67b6SAndrew Jones 	report_prefix_push("self");
269ca1b7a7bSAndrew Jones 	stats_reset();
270ac4a67b6SAndrew Jones 	cpumask_clear(&mask);
271ca1b7a7bSAndrew Jones 	cpumask_set_cpu(smp_processor_id(), &mask);
2722e2d471dSAndrew Jones 	gic->ipi.send_self();
27396edb026SAndre Przywara 	check_acked("IPI: self", &mask);
274ac4a67b6SAndrew Jones 	report_prefix_pop();
275ac4a67b6SAndrew Jones }
276ac4a67b6SAndrew Jones 
277ac4a67b6SAndrew Jones static void ipi_test_smp(void)
278ac4a67b6SAndrew Jones {
279ac4a67b6SAndrew Jones 	cpumask_t mask;
2802e2d471dSAndrew Jones 	int i;
281ac4a67b6SAndrew Jones 
282ac4a67b6SAndrew Jones 	report_prefix_push("target-list");
283ca1b7a7bSAndrew Jones 	stats_reset();
2842e2d471dSAndrew Jones 	cpumask_copy(&mask, &cpu_present_mask);
285ca1b7a7bSAndrew Jones 	for (i = smp_processor_id() & 1; i < nr_cpus; i += 2)
2862e2d471dSAndrew Jones 		cpumask_clear_cpu(i, &mask);
287ca1b7a7bSAndrew Jones 	gic_ipi_send_mask(IPI_IRQ, &mask);
28896edb026SAndre Przywara 	check_acked("IPI: directed", &mask);
289ac4a67b6SAndrew Jones 	report_prefix_pop();
290ac4a67b6SAndrew Jones 
291ac4a67b6SAndrew Jones 	report_prefix_push("broadcast");
292ca1b7a7bSAndrew Jones 	stats_reset();
293ac4a67b6SAndrew Jones 	cpumask_copy(&mask, &cpu_present_mask);
294ca1b7a7bSAndrew Jones 	cpumask_clear_cpu(smp_processor_id(), &mask);
2952e2d471dSAndrew Jones 	gic->ipi.send_broadcast();
29696edb026SAndre Przywara 	check_acked("IPI: broadcast", &mask);
297ac4a67b6SAndrew Jones 	report_prefix_pop();
298ac4a67b6SAndrew Jones }
299ac4a67b6SAndrew Jones 
300ca1b7a7bSAndrew Jones static void ipi_send(void)
301ca1b7a7bSAndrew Jones {
30225f66327SEric Auger 	setup_irq(ipi_handler);
303ca1b7a7bSAndrew Jones 	wait_on_ready();
304ca1b7a7bSAndrew Jones 	ipi_test_self();
305ca1b7a7bSAndrew Jones 	ipi_test_smp();
306ca1b7a7bSAndrew Jones 	check_spurious();
307ca1b7a7bSAndrew Jones 	exit(report_summary());
308ca1b7a7bSAndrew Jones }
309ca1b7a7bSAndrew Jones 
310ac4a67b6SAndrew Jones static void ipi_recv(void)
311ac4a67b6SAndrew Jones {
31225f66327SEric Auger 	setup_irq(ipi_handler);
313ac4a67b6SAndrew Jones 	cpumask_set_cpu(smp_processor_id(), &ready);
314ac4a67b6SAndrew Jones 	while (1)
315ac4a67b6SAndrew Jones 		wfi();
316ac4a67b6SAndrew Jones }
317ac4a67b6SAndrew Jones 
31800b34f56SAndrew Jones static void ipi_test(void *data __unused)
319bfd500b4SAndrew Jones {
320bfd500b4SAndrew Jones 	if (smp_processor_id() == IPI_SENDER)
321bfd500b4SAndrew Jones 		ipi_send();
322bfd500b4SAndrew Jones 	else
323bfd500b4SAndrew Jones 		ipi_recv();
324bfd500b4SAndrew Jones }
325bfd500b4SAndrew Jones 
3262e2d471dSAndrew Jones static struct gic gicv2 = {
3272e2d471dSAndrew Jones 	.ipi = {
3282e2d471dSAndrew Jones 		.send_self = gicv2_ipi_send_self,
3292e2d471dSAndrew Jones 		.send_broadcast = gicv2_ipi_send_broadcast,
3302e2d471dSAndrew Jones 	},
3312e2d471dSAndrew Jones };
3322e2d471dSAndrew Jones 
3332e2d471dSAndrew Jones static struct gic gicv3 = {
3342e2d471dSAndrew Jones 	.ipi = {
3352e2d471dSAndrew Jones 		.send_self = gicv3_ipi_send_self,
3362e2d471dSAndrew Jones 		.send_broadcast = gicv3_ipi_send_broadcast,
3372e2d471dSAndrew Jones 	},
3382e2d471dSAndrew Jones };
3392e2d471dSAndrew Jones 
340c152d8bcSChristoffer Dall static void ipi_clear_active_handler(struct pt_regs *regs __unused)
341c152d8bcSChristoffer Dall {
342c152d8bcSChristoffer Dall 	u32 irqstat = gic_read_iar();
343c152d8bcSChristoffer Dall 	u32 irqnr = gic_iar_irqnr(irqstat);
344c152d8bcSChristoffer Dall 
345c152d8bcSChristoffer Dall 	if (irqnr != GICC_INT_SPURIOUS) {
346c152d8bcSChristoffer Dall 		void *base;
347c152d8bcSChristoffer Dall 		u32 val = 1 << IPI_IRQ;
348c152d8bcSChristoffer Dall 
349c152d8bcSChristoffer Dall 		if (gic_version() == 2)
350c152d8bcSChristoffer Dall 			base = gicv2_dist_base();
351c152d8bcSChristoffer Dall 		else
3526d4d7c4bSAndrew Jones 			base = gicv3_sgi_base();
353c152d8bcSChristoffer Dall 
354c152d8bcSChristoffer Dall 		writel(val, base + GICD_ICACTIVER);
355c152d8bcSChristoffer Dall 
356c152d8bcSChristoffer Dall 		smp_rmb(); /* pairs with wmb in stats_reset */
357c152d8bcSChristoffer Dall 		++acked[smp_processor_id()];
358c152d8bcSChristoffer Dall 		check_irqnr(irqnr);
359c152d8bcSChristoffer Dall 		smp_wmb(); /* pairs with rmb in check_acked */
360c152d8bcSChristoffer Dall 	} else {
361c152d8bcSChristoffer Dall 		++spurious[smp_processor_id()];
362c152d8bcSChristoffer Dall 		smp_wmb();
363c152d8bcSChristoffer Dall 	}
364c152d8bcSChristoffer Dall }
365c152d8bcSChristoffer Dall 
366c152d8bcSChristoffer Dall static void run_active_clear_test(void)
367c152d8bcSChristoffer Dall {
368c152d8bcSChristoffer Dall 	report_prefix_push("active");
36925f66327SEric Auger 	setup_irq(ipi_clear_active_handler);
370c152d8bcSChristoffer Dall 	ipi_test_self();
371c152d8bcSChristoffer Dall 	report_prefix_pop();
372c152d8bcSChristoffer Dall }
373c152d8bcSChristoffer Dall 
37478ad7e95SAndre Przywara static bool test_ro_pattern_32(void *address, u32 pattern, u32 orig)
37578ad7e95SAndre Przywara {
37678ad7e95SAndre Przywara 	u32 reg;
37778ad7e95SAndre Przywara 
37878ad7e95SAndre Przywara 	writel(pattern, address);
37978ad7e95SAndre Przywara 	reg = readl(address);
38078ad7e95SAndre Przywara 
38178ad7e95SAndre Przywara 	if (reg != orig)
38278ad7e95SAndre Przywara 		writel(orig, address);
38378ad7e95SAndre Przywara 
38478ad7e95SAndre Przywara 	return reg == orig;
38578ad7e95SAndre Przywara }
38678ad7e95SAndre Przywara 
38778ad7e95SAndre Przywara static bool test_readonly_32(void *address, bool razwi)
38878ad7e95SAndre Przywara {
38978ad7e95SAndre Przywara 	u32 orig, pattern;
39078ad7e95SAndre Przywara 
39178ad7e95SAndre Przywara 	orig = readl(address);
39278ad7e95SAndre Przywara 	if (razwi && orig)
39378ad7e95SAndre Przywara 		return false;
39478ad7e95SAndre Przywara 
39578ad7e95SAndre Przywara 	pattern = 0xffffffff;
39678ad7e95SAndre Przywara 	if (orig != pattern) {
39778ad7e95SAndre Przywara 		if (!test_ro_pattern_32(address, pattern, orig))
39878ad7e95SAndre Przywara 			return false;
39978ad7e95SAndre Przywara 	}
40078ad7e95SAndre Przywara 
40178ad7e95SAndre Przywara 	pattern = 0xa5a55a5a;
40278ad7e95SAndre Przywara 	if (orig != pattern) {
40378ad7e95SAndre Przywara 		if (!test_ro_pattern_32(address, pattern, orig))
40478ad7e95SAndre Przywara 			return false;
40578ad7e95SAndre Przywara 	}
40678ad7e95SAndre Przywara 
40778ad7e95SAndre Przywara 	pattern = 0;
40878ad7e95SAndre Przywara 	if (orig != pattern) {
40978ad7e95SAndre Przywara 		if (!test_ro_pattern_32(address, pattern, orig))
41078ad7e95SAndre Przywara 			return false;
41178ad7e95SAndre Przywara 	}
41278ad7e95SAndre Przywara 
41378ad7e95SAndre Przywara 	return true;
41478ad7e95SAndre Przywara }
41578ad7e95SAndre Przywara 
41678ad7e95SAndre Przywara static void test_typer_v2(uint32_t reg)
41778ad7e95SAndre Przywara {
41878ad7e95SAndre Przywara 	int nr_gic_cpus = ((reg >> 5) & 0x7) + 1;
41978ad7e95SAndre Przywara 
4208e0a4f41SAndre Przywara 	report_info("nr_cpus=%d", nr_cpus);
421a299895bSThomas Huth 	report(nr_cpus == nr_gic_cpus, "all CPUs have interrupts");
42278ad7e95SAndre Przywara }
42378ad7e95SAndre Przywara 
424ff31a1c4SAndre Przywara #define BYTE(reg32, byte) (((reg32) >> ((byte) * 8)) & 0xff)
425ff31a1c4SAndre Przywara #define REPLACE_BYTE(reg32, byte, new) (((reg32) & ~(0xff << ((byte) * 8))) |\
426ff31a1c4SAndre Przywara 					((new) << ((byte) * 8)))
427ff31a1c4SAndre Przywara 
428ff31a1c4SAndre Przywara /*
429ff31a1c4SAndre Przywara  * Some registers are byte accessible, do a byte-wide read and write of known
430ff31a1c4SAndre Przywara  * content to check for this.
431ff31a1c4SAndre Przywara  * Apply a @mask to cater for special register properties.
432ff31a1c4SAndre Przywara  * @pattern contains the value already in the register.
433ff31a1c4SAndre Przywara  */
434ff31a1c4SAndre Przywara static void test_byte_access(void *base_addr, u32 pattern, u32 mask)
435ff31a1c4SAndre Przywara {
436ff31a1c4SAndre Przywara 	u32 reg = readb(base_addr + 1);
4378e0a4f41SAndre Przywara 	bool res;
438ff31a1c4SAndre Przywara 
4398e0a4f41SAndre Przywara 	res = (reg == (BYTE(pattern, 1) & (mask >> 8)));
440a299895bSThomas Huth 	report(res, "byte reads successful");
4418e0a4f41SAndre Przywara 	if (!res)
4428e0a4f41SAndre Przywara 		report_info("byte 1 of 0x%08x => 0x%02x", pattern & mask, reg);
443ff31a1c4SAndre Przywara 
444ff31a1c4SAndre Przywara 	pattern = REPLACE_BYTE(pattern, 2, 0x1f);
445ff31a1c4SAndre Przywara 	writeb(BYTE(pattern, 2), base_addr + 2);
446ff31a1c4SAndre Przywara 	reg = readl(base_addr);
4478e0a4f41SAndre Przywara 	res = (reg == (pattern & mask));
448a299895bSThomas Huth 	report(res, "byte writes successful");
4498e0a4f41SAndre Przywara 	if (!res)
4508e0a4f41SAndre Przywara 		report_info("writing 0x%02x into bytes 2 => 0x%08x",
4518e0a4f41SAndre Przywara 			    BYTE(pattern, 2), reg);
452ff31a1c4SAndre Przywara }
453ff31a1c4SAndre Przywara 
454ff31a1c4SAndre Przywara static void test_priorities(int nr_irqs, void *priptr)
455ff31a1c4SAndre Przywara {
456ff31a1c4SAndre Przywara 	u32 orig_prio, reg, pri_bits;
457ff31a1c4SAndre Przywara 	u32 pri_mask, pattern;
458ff31a1c4SAndre Przywara 	void *first_spi = priptr + GIC_FIRST_SPI;
459ff31a1c4SAndre Przywara 
460ff31a1c4SAndre Przywara 	orig_prio = readl(first_spi);
461ff31a1c4SAndre Przywara 	report_prefix_push("IPRIORITYR");
462ff31a1c4SAndre Przywara 
463ff31a1c4SAndre Przywara 	/*
464ff31a1c4SAndre Przywara 	 * Determine implemented number of priority bits by writing all 1's
465ff31a1c4SAndre Przywara 	 * and checking the number of cleared bits in the value read back.
466ff31a1c4SAndre Przywara 	 */
467ff31a1c4SAndre Przywara 	writel(0xffffffff, first_spi);
468ff31a1c4SAndre Przywara 	pri_mask = readl(first_spi);
469ff31a1c4SAndre Przywara 
470ff31a1c4SAndre Przywara 	reg = ~pri_mask;
471a299895bSThomas Huth 	report((((reg >> 16) == (reg & 0xffff)) &&
472a299895bSThomas Huth 	        ((reg & 0xff) == ((reg >> 8) & 0xff))),
473a299895bSThomas Huth 	       "consistent priority masking");
4748e0a4f41SAndre Przywara 	report_info("priority mask is 0x%08x", pri_mask);
475ff31a1c4SAndre Przywara 
476ff31a1c4SAndre Przywara 	reg = reg & 0xff;
477ff31a1c4SAndre Przywara 	for (pri_bits = 8; reg & 1; reg >>= 1, pri_bits--)
478ff31a1c4SAndre Przywara 		;
479a299895bSThomas Huth 	report(pri_bits >= 4, "implements at least 4 priority bits");
4808e0a4f41SAndre Przywara 	report_info("%d priority bits implemented", pri_bits);
481ff31a1c4SAndre Przywara 
482ff31a1c4SAndre Przywara 	pattern = 0;
483ff31a1c4SAndre Przywara 	writel(pattern, first_spi);
484a299895bSThomas Huth 	report(readl(first_spi) == pattern, "clearing priorities");
485ff31a1c4SAndre Przywara 
486ff31a1c4SAndre Przywara 	/* setting all priorities to their max valus was tested above */
487ff31a1c4SAndre Przywara 
488a299895bSThomas Huth 	report(test_readonly_32(priptr + nr_irqs, true),
489a299895bSThomas Huth 	       "accesses beyond limit RAZ/WI");
490ff31a1c4SAndre Przywara 
491ff31a1c4SAndre Przywara 	writel(pattern, priptr + nr_irqs - 4);
492a299895bSThomas Huth 	report(readl(priptr + nr_irqs - 4) == (pattern & pri_mask),
493a299895bSThomas Huth 	       "accessing last SPIs");
494ff31a1c4SAndre Przywara 
495ff31a1c4SAndre Przywara 	pattern = 0xff7fbf3f;
496ff31a1c4SAndre Przywara 	writel(pattern, first_spi);
497a299895bSThomas Huth 	report(readl(first_spi) == (pattern & pri_mask),
498a299895bSThomas Huth 	       "priorities are preserved");
499ff31a1c4SAndre Przywara 
500ff31a1c4SAndre Przywara 	/* The PRIORITY registers are byte accessible. */
501ff31a1c4SAndre Przywara 	test_byte_access(first_spi, pattern, pri_mask);
502ff31a1c4SAndre Przywara 
503ff31a1c4SAndre Przywara 	report_prefix_pop();
504ff31a1c4SAndre Przywara 	writel(orig_prio, first_spi);
505ff31a1c4SAndre Przywara }
506ff31a1c4SAndre Przywara 
507fe572a5eSAndre Przywara /* GICD_ITARGETSR is only used by GICv2. */
508fe572a5eSAndre Przywara static void test_targets(int nr_irqs)
509fe572a5eSAndre Przywara {
510fe572a5eSAndre Przywara 	void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR;
511fe572a5eSAndre Przywara 	u32 orig_targets;
512fe572a5eSAndre Przywara 	u32 cpu_mask;
513fe572a5eSAndre Przywara 	u32 pattern, reg;
514fe572a5eSAndre Przywara 
515fe572a5eSAndre Przywara 	orig_targets = readl(targetsptr + GIC_FIRST_SPI);
516fe572a5eSAndre Przywara 	report_prefix_push("ITARGETSR");
517fe572a5eSAndre Przywara 
518fe572a5eSAndre Przywara 	cpu_mask = (1 << nr_cpus) - 1;
519fe572a5eSAndre Przywara 	cpu_mask |= cpu_mask << 8;
520fe572a5eSAndre Przywara 	cpu_mask |= cpu_mask << 16;
521fe572a5eSAndre Przywara 
522fe572a5eSAndre Przywara 	/* Check that bits for non implemented CPUs are RAZ/WI. */
523fe572a5eSAndre Przywara 	if (nr_cpus < 8) {
524fe572a5eSAndre Przywara 		writel(0xffffffff, targetsptr + GIC_FIRST_SPI);
525a299895bSThomas Huth 		report(!(readl(targetsptr + GIC_FIRST_SPI) & ~cpu_mask),
526a299895bSThomas Huth 		       "bits for non-existent CPUs masked");
5278e0a4f41SAndre Przywara 		report_info("%d non-existent CPUs", 8 - nr_cpus);
528fe572a5eSAndre Przywara 	} else {
529fe572a5eSAndre Przywara 		report_skip("CPU masking (all CPUs implemented)");
530fe572a5eSAndre Przywara 	}
531fe572a5eSAndre Przywara 
532a299895bSThomas Huth 	report(test_readonly_32(targetsptr + nr_irqs, true),
533a299895bSThomas Huth 	       "accesses beyond limit RAZ/WI");
534fe572a5eSAndre Przywara 
535fe572a5eSAndre Przywara 	pattern = 0x0103020f;
536fe572a5eSAndre Przywara 	writel(pattern, targetsptr + GIC_FIRST_SPI);
537fe572a5eSAndre Przywara 	reg = readl(targetsptr + GIC_FIRST_SPI);
538a299895bSThomas Huth 	report(reg == (pattern & cpu_mask), "register content preserved");
5398e0a4f41SAndre Przywara 	if (reg != (pattern & cpu_mask))
5408e0a4f41SAndre Przywara 		report_info("writing %08x reads back as %08x",
5418e0a4f41SAndre Przywara 			    pattern & cpu_mask, reg);
542fe572a5eSAndre Przywara 
543fe572a5eSAndre Przywara 	/* The TARGETS registers are byte accessible. */
544fe572a5eSAndre Przywara 	test_byte_access(targetsptr + GIC_FIRST_SPI, pattern, cpu_mask);
545fe572a5eSAndre Przywara 
546fe572a5eSAndre Przywara 	writel(orig_targets, targetsptr + GIC_FIRST_SPI);
547da5b8576SAndre Przywara 
548da5b8576SAndre Przywara 	report_prefix_pop();
549fe572a5eSAndre Przywara }
550fe572a5eSAndre Przywara 
55178ad7e95SAndre Przywara static void gic_test_mmio(void)
55278ad7e95SAndre Przywara {
55378ad7e95SAndre Przywara 	u32 reg;
55478ad7e95SAndre Przywara 	int nr_irqs;
55578ad7e95SAndre Przywara 	void *gic_dist_base, *idreg;
55678ad7e95SAndre Przywara 
55778ad7e95SAndre Przywara 	switch(gic_version()) {
55878ad7e95SAndre Przywara 	case 0x2:
55978ad7e95SAndre Przywara 		gic_dist_base = gicv2_dist_base();
56078ad7e95SAndre Przywara 		idreg = gic_dist_base + GICD_ICPIDR2;
56178ad7e95SAndre Przywara 		break;
56278ad7e95SAndre Przywara 	case 0x3:
56378ad7e95SAndre Przywara 		report_abort("GICv3 MMIO tests NYI");
56478ad7e95SAndre Przywara 	default:
56578ad7e95SAndre Przywara 		report_abort("GIC version %d not supported", gic_version());
56678ad7e95SAndre Przywara 	}
56778ad7e95SAndre Przywara 
56878ad7e95SAndre Przywara 	reg = readl(gic_dist_base + GICD_TYPER);
56978ad7e95SAndre Przywara 	nr_irqs = GICD_TYPER_IRQS(reg);
57078ad7e95SAndre Przywara 	report_info("number of implemented SPIs: %d", nr_irqs - GIC_FIRST_SPI);
57178ad7e95SAndre Przywara 
57278ad7e95SAndre Przywara 	test_typer_v2(reg);
57378ad7e95SAndre Przywara 
57478ad7e95SAndre Przywara 	report_info("IIDR: 0x%08x", readl(gic_dist_base + GICD_IIDR));
57578ad7e95SAndre Przywara 
576a299895bSThomas Huth 	report(test_readonly_32(gic_dist_base + GICD_TYPER, false),
577a299895bSThomas Huth                "GICD_TYPER is read-only");
578a299895bSThomas Huth 	report(test_readonly_32(gic_dist_base + GICD_IIDR, false),
579a299895bSThomas Huth                "GICD_IIDR is read-only");
58078ad7e95SAndre Przywara 
58178ad7e95SAndre Przywara 	reg = readl(idreg);
582a299895bSThomas Huth 	report(test_readonly_32(idreg, false), "ICPIDR2 is read-only");
5838e0a4f41SAndre Przywara 	report_info("value of ICPIDR2: 0x%08x", reg);
584ff31a1c4SAndre Przywara 
585ff31a1c4SAndre Przywara 	test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR);
586fe572a5eSAndre Przywara 
587fe572a5eSAndre Przywara 	if (gic_version() == 2)
588fe572a5eSAndre Przywara 		test_targets(nr_irqs);
58978ad7e95SAndre Przywara }
59078ad7e95SAndre Przywara 
591ba74b106SEric Auger #if defined(__arm__)
592ba74b106SEric Auger 
593ba74b106SEric Auger static void test_its_introspection(void) {}
594*0ef02cd6SEric Auger static void test_its_trigger(void) {}
595ba74b106SEric Auger 
596ba74b106SEric Auger #else /* __aarch64__ */
597ba74b106SEric Auger 
598ba74b106SEric Auger static void test_its_introspection(void)
599ba74b106SEric Auger {
600ba74b106SEric Auger 	struct its_baser *dev_baser = &its_data.device_baser;
601ba74b106SEric Auger 	struct its_baser *coll_baser = &its_data.coll_baser;
602ba74b106SEric Auger 	struct its_typer *typer = &its_data.typer;
603ba74b106SEric Auger 
604ba74b106SEric Auger 	if (!gicv3_its_base()) {
605ba74b106SEric Auger 		report_skip("No ITS, skip ...");
606ba74b106SEric Auger 		return;
607ba74b106SEric Auger 	}
608ba74b106SEric Auger 
609ba74b106SEric Auger 	/* IIDR */
610ba74b106SEric Auger 	report(test_readonly_32(gicv3_its_base() + GITS_IIDR, false),
611ba74b106SEric Auger 	       "GITS_IIDR is read-only"),
612ba74b106SEric Auger 
613ba74b106SEric Auger 	/* TYPER */
614ba74b106SEric Auger 	report(test_readonly_32(gicv3_its_base() + GITS_TYPER, false),
615ba74b106SEric Auger 	       "GITS_TYPER is read-only");
616ba74b106SEric Auger 
617ba74b106SEric Auger 	report(typer->phys_lpi, "ITS supports physical LPIs");
618ba74b106SEric Auger 	report_info("vLPI support: %s", typer->virt_lpi ? "yes" : "no");
619ba74b106SEric Auger 	report_info("ITT entry size = 0x%x", typer->ite_size);
620ba74b106SEric Auger 	report_info("Bit Count: EventID=%d DeviceId=%d CollId=%d",
621ba74b106SEric Auger 		    typer->eventid_bits, typer->deviceid_bits,
622ba74b106SEric Auger 		    typer->collid_bits);
623ba74b106SEric Auger 	report(typer->eventid_bits && typer->deviceid_bits &&
624ba74b106SEric Auger 	       typer->collid_bits, "ID spaces");
625ba74b106SEric Auger 	report_info("Target address format %s",
626ba74b106SEric Auger 			typer->pta ? "Redist base address" : "PE #");
627ba74b106SEric Auger 
628ba74b106SEric Auger 	report(dev_baser && coll_baser, "detect device and collection BASER");
629ba74b106SEric Auger 	report_info("device table entry_size = 0x%x", dev_baser->esz);
630ba74b106SEric Auger 	report_info("collection table entry_size = 0x%x", coll_baser->esz);
631ba74b106SEric Auger }
632ba74b106SEric Auger 
633*0ef02cd6SEric Auger static int its_prerequisites(int nb_cpus)
634*0ef02cd6SEric Auger {
635*0ef02cd6SEric Auger 	int cpu;
636*0ef02cd6SEric Auger 
637*0ef02cd6SEric Auger 	if (!gicv3_its_base()) {
638*0ef02cd6SEric Auger 		report_skip("No ITS, skip ...");
639*0ef02cd6SEric Auger 		return -1;
640*0ef02cd6SEric Auger 	}
641*0ef02cd6SEric Auger 
642*0ef02cd6SEric Auger 	if (nr_cpus < nb_cpus) {
643*0ef02cd6SEric Auger 		report_skip("Test requires at least %d vcpus", nb_cpus);
644*0ef02cd6SEric Auger 		return -1;
645*0ef02cd6SEric Auger 	}
646*0ef02cd6SEric Auger 
647*0ef02cd6SEric Auger 	stats_reset();
648*0ef02cd6SEric Auger 
649*0ef02cd6SEric Auger 	setup_irq(lpi_handler);
650*0ef02cd6SEric Auger 
651*0ef02cd6SEric Auger 	for_each_present_cpu(cpu) {
652*0ef02cd6SEric Auger 		if (cpu == 0)
653*0ef02cd6SEric Auger 			continue;
654*0ef02cd6SEric Auger 		smp_boot_secondary(cpu, secondary_lpi_test);
655*0ef02cd6SEric Auger 	}
656*0ef02cd6SEric Auger 	wait_on_ready();
657*0ef02cd6SEric Auger 
658*0ef02cd6SEric Auger 	its_enable_defaults();
659*0ef02cd6SEric Auger 
660*0ef02cd6SEric Auger 	return 0;
661*0ef02cd6SEric Auger }
662*0ef02cd6SEric Auger 
663*0ef02cd6SEric Auger static void test_its_trigger(void)
664*0ef02cd6SEric Auger {
665*0ef02cd6SEric Auger 	struct its_collection *col3, *col2;
666*0ef02cd6SEric Auger 	struct its_device *dev2, *dev7;
667*0ef02cd6SEric Auger 
668*0ef02cd6SEric Auger 	if (its_prerequisites(4))
669*0ef02cd6SEric Auger 		return;
670*0ef02cd6SEric Auger 
671*0ef02cd6SEric Auger 	dev2 = its_create_device(2 /* dev id */, 8 /* nb_ites */);
672*0ef02cd6SEric Auger 	dev7 = its_create_device(7 /* dev id */, 8 /* nb_ites */);
673*0ef02cd6SEric Auger 
674*0ef02cd6SEric Auger 	col3 = its_create_collection(3 /* col id */, 3/* target PE */);
675*0ef02cd6SEric Auger 	col2 = its_create_collection(2 /* col id */, 2/* target PE */);
676*0ef02cd6SEric Auger 
677*0ef02cd6SEric Auger 	gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT);
678*0ef02cd6SEric Auger 	gicv3_lpi_set_config(8196, LPI_PROP_DEFAULT);
679*0ef02cd6SEric Auger 
680*0ef02cd6SEric Auger 	report_prefix_push("int");
681*0ef02cd6SEric Auger 	/*
682*0ef02cd6SEric Auger 	 * dev=2, eventid=20  -> lpi= 8195, col=3
683*0ef02cd6SEric Auger 	 * dev=7, eventid=255 -> lpi= 8196, col=2
684*0ef02cd6SEric Auger 	 * Trigger dev2, eventid=20 and dev7, eventid=255
685*0ef02cd6SEric Auger 	 * Check both LPIs hit
686*0ef02cd6SEric Auger 	 */
687*0ef02cd6SEric Auger 
688*0ef02cd6SEric Auger 	its_send_mapd(dev2, true);
689*0ef02cd6SEric Auger 	its_send_mapd(dev7, true);
690*0ef02cd6SEric Auger 
691*0ef02cd6SEric Auger 	its_send_mapc(col3, true);
692*0ef02cd6SEric Auger 	its_send_mapc(col2, true);
693*0ef02cd6SEric Auger 
694*0ef02cd6SEric Auger 	its_send_invall(col2);
695*0ef02cd6SEric Auger 	its_send_invall(col3);
696*0ef02cd6SEric Auger 
697*0ef02cd6SEric Auger 	its_send_mapti(dev2, 8195 /* lpi id */, 20 /* event id */, col3);
698*0ef02cd6SEric Auger 	its_send_mapti(dev7, 8196 /* lpi id */, 255 /* event id */, col2);
699*0ef02cd6SEric Auger 
700*0ef02cd6SEric Auger 	lpi_stats_expect(3, 8195);
701*0ef02cd6SEric Auger 	its_send_int(dev2, 20);
702*0ef02cd6SEric Auger 	check_lpi_stats("dev=2, eventid=20  -> lpi= 8195, col=3");
703*0ef02cd6SEric Auger 
704*0ef02cd6SEric Auger 	lpi_stats_expect(2, 8196);
705*0ef02cd6SEric Auger 	its_send_int(dev7, 255);
706*0ef02cd6SEric Auger 	check_lpi_stats("dev=7, eventid=255 -> lpi= 8196, col=2");
707*0ef02cd6SEric Auger 
708*0ef02cd6SEric Auger 	report_prefix_pop();
709*0ef02cd6SEric Auger 
710*0ef02cd6SEric Auger 	report_prefix_push("inv/invall");
711*0ef02cd6SEric Auger 
712*0ef02cd6SEric Auger 	/*
713*0ef02cd6SEric Auger 	 * disable 8195, check dev2/eventid=20 does not trigger the
714*0ef02cd6SEric Auger 	 * corresponding LPI
715*0ef02cd6SEric Auger 	 */
716*0ef02cd6SEric Auger 	gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT & ~LPI_PROP_ENABLED);
717*0ef02cd6SEric Auger 	its_send_inv(dev2, 20);
718*0ef02cd6SEric Auger 
719*0ef02cd6SEric Auger 	lpi_stats_expect(-1, -1);
720*0ef02cd6SEric Auger 	its_send_int(dev2, 20);
721*0ef02cd6SEric Auger 	check_lpi_stats("dev2/eventid=20 does not trigger any LPI");
722*0ef02cd6SEric Auger 
723*0ef02cd6SEric Auger 	/*
724*0ef02cd6SEric Auger 	 * re-enable the LPI but willingly do not call invall
725*0ef02cd6SEric Auger 	 * so the change in config is not taken into account.
726*0ef02cd6SEric Auger 	 * The LPI should not hit
727*0ef02cd6SEric Auger 	 */
728*0ef02cd6SEric Auger 	gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT);
729*0ef02cd6SEric Auger 	lpi_stats_expect(-1, -1);
730*0ef02cd6SEric Auger 	its_send_int(dev2, 20);
731*0ef02cd6SEric Auger 	check_lpi_stats("dev2/eventid=20 still does not trigger any LPI");
732*0ef02cd6SEric Auger 
733*0ef02cd6SEric Auger 	/* Now call the invall and check the LPI hits */
734*0ef02cd6SEric Auger 	its_send_invall(col3);
735*0ef02cd6SEric Auger 	lpi_stats_expect(3, 8195);
736*0ef02cd6SEric Auger 	its_send_int(dev2, 20);
737*0ef02cd6SEric Auger 	check_lpi_stats("dev2/eventid=20 now triggers an LPI");
738*0ef02cd6SEric Auger 
739*0ef02cd6SEric Auger 	report_prefix_pop();
740*0ef02cd6SEric Auger 
741*0ef02cd6SEric Auger 	report_prefix_push("mapd valid=false");
742*0ef02cd6SEric Auger 	/*
743*0ef02cd6SEric Auger 	 * Unmap device 2 and check the eventid 20 formerly
744*0ef02cd6SEric Auger 	 * attached to it does not hit anymore
745*0ef02cd6SEric Auger 	 */
746*0ef02cd6SEric Auger 
747*0ef02cd6SEric Auger 	its_send_mapd(dev2, false);
748*0ef02cd6SEric Auger 	lpi_stats_expect(-1, -1);
749*0ef02cd6SEric Auger 	its_send_int(dev2, 20);
750*0ef02cd6SEric Auger 	check_lpi_stats("no LPI after device unmap");
751*0ef02cd6SEric Auger 	report_prefix_pop();
752*0ef02cd6SEric Auger }
753ba74b106SEric Auger #endif
754ba74b106SEric Auger 
755ac4a67b6SAndrew Jones int main(int argc, char **argv)
756ac4a67b6SAndrew Jones {
7572e2d471dSAndrew Jones 	if (!gic_init()) {
758ac4a67b6SAndrew Jones 		printf("No supported gic present, skipping tests...\n");
759ac4a67b6SAndrew Jones 		return report_summary();
760ac4a67b6SAndrew Jones 	}
761ac4a67b6SAndrew Jones 
7622b19b829SAndrew Jones 	report_prefix_pushf("gicv%d", gic_version());
763ac4a67b6SAndrew Jones 
7642e2d471dSAndrew Jones 	switch (gic_version()) {
7652e2d471dSAndrew Jones 	case 2:
7662e2d471dSAndrew Jones 		gic = &gicv2;
7672e2d471dSAndrew Jones 		break;
7682e2d471dSAndrew Jones 	case 3:
7692e2d471dSAndrew Jones 		gic = &gicv3;
7702e2d471dSAndrew Jones 		break;
7712e2d471dSAndrew Jones 	}
7722e2d471dSAndrew Jones 
773ac4a67b6SAndrew Jones 	if (argc < 2)
774ac4a67b6SAndrew Jones 		report_abort("no test specified");
775ac4a67b6SAndrew Jones 
776ac4a67b6SAndrew Jones 	if (strcmp(argv[1], "ipi") == 0) {
777ac4a67b6SAndrew Jones 		report_prefix_push(argv[1]);
778ac4a67b6SAndrew Jones 		nr_cpu_check(2);
77900b34f56SAndrew Jones 		on_cpus(ipi_test, NULL);
780c152d8bcSChristoffer Dall 	} else if (strcmp(argv[1], "active") == 0) {
781c152d8bcSChristoffer Dall 		run_active_clear_test();
78278ad7e95SAndre Przywara 	} else if (strcmp(argv[1], "mmio") == 0) {
78378ad7e95SAndre Przywara 		report_prefix_push(argv[1]);
78478ad7e95SAndre Przywara 		gic_test_mmio();
78578ad7e95SAndre Przywara 		report_prefix_pop();
786*0ef02cd6SEric Auger 	} else if (!strcmp(argv[1], "its-trigger")) {
787*0ef02cd6SEric Auger 		report_prefix_push(argv[1]);
788*0ef02cd6SEric Auger 		test_its_trigger();
789*0ef02cd6SEric Auger 		report_prefix_pop();
790ba74b106SEric Auger 	} else if (strcmp(argv[1], "its-introspection") == 0) {
791ba74b106SEric Auger 		report_prefix_push(argv[1]);
792ba74b106SEric Auger 		test_its_introspection();
793ba74b106SEric Auger 		report_prefix_pop();
794ac4a67b6SAndrew Jones 	} else {
795ac4a67b6SAndrew Jones 		report_abort("Unknown subtest '%s'", argv[1]);
796ac4a67b6SAndrew Jones 	}
797ac4a67b6SAndrew Jones 
798ac4a67b6SAndrew Jones 	return report_summary();
799ac4a67b6SAndrew Jones }
800