xref: /kvm-unit-tests/arm/gic.c (revision de582149c5be94a1ff7d3d8ee3526501b26c7f03)
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>
15*de582149SEric Auger #include <errata.h>
16ac4a67b6SAndrew Jones #include <asm/setup.h>
17ac4a67b6SAndrew Jones #include <asm/processor.h>
18ac4a67b6SAndrew Jones #include <asm/delay.h>
19ac4a67b6SAndrew Jones #include <asm/gic.h>
20ba74b106SEric Auger #include <asm/gic-v3-its.h>
21ac4a67b6SAndrew Jones #include <asm/smp.h>
22ac4a67b6SAndrew Jones #include <asm/barrier.h>
23ac4a67b6SAndrew Jones #include <asm/io.h>
24ac4a67b6SAndrew Jones 
25ca1b7a7bSAndrew Jones #define IPI_SENDER	1
26ca1b7a7bSAndrew Jones #define IPI_IRQ		1
27ca1b7a7bSAndrew Jones 
282e2d471dSAndrew Jones struct gic {
292e2d471dSAndrew Jones 	struct {
302e2d471dSAndrew Jones 		void (*send_self)(void);
312e2d471dSAndrew Jones 		void (*send_broadcast)(void);
322e2d471dSAndrew Jones 	} ipi;
332e2d471dSAndrew Jones };
342e2d471dSAndrew Jones 
352e2d471dSAndrew Jones static struct gic *gic;
36ac4a67b6SAndrew Jones static int acked[NR_CPUS], spurious[NR_CPUS];
37ca1b7a7bSAndrew Jones static int bad_sender[NR_CPUS], bad_irq[NR_CPUS];
38ac4a67b6SAndrew Jones static cpumask_t ready;
39ac4a67b6SAndrew Jones 
40ac4a67b6SAndrew Jones static void nr_cpu_check(int nr)
41ac4a67b6SAndrew Jones {
42ac4a67b6SAndrew Jones 	if (nr_cpus < nr)
43ac4a67b6SAndrew Jones 		report_abort("At least %d cpus required", nr);
44ac4a67b6SAndrew Jones }
45ac4a67b6SAndrew Jones 
46ac4a67b6SAndrew Jones static void wait_on_ready(void)
47ac4a67b6SAndrew Jones {
48ac4a67b6SAndrew Jones 	cpumask_set_cpu(smp_processor_id(), &ready);
49ac4a67b6SAndrew Jones 	while (!cpumask_full(&ready))
50ac4a67b6SAndrew Jones 		cpu_relax();
51ac4a67b6SAndrew Jones }
52ac4a67b6SAndrew Jones 
53ca1b7a7bSAndrew Jones static void stats_reset(void)
54ca1b7a7bSAndrew Jones {
55ca1b7a7bSAndrew Jones 	int i;
56ca1b7a7bSAndrew Jones 
57ca1b7a7bSAndrew Jones 	for (i = 0; i < nr_cpus; ++i) {
58ca1b7a7bSAndrew Jones 		acked[i] = 0;
59ca1b7a7bSAndrew Jones 		bad_sender[i] = -1;
60ca1b7a7bSAndrew Jones 		bad_irq[i] = -1;
61ca1b7a7bSAndrew Jones 	}
62ca1b7a7bSAndrew Jones 	smp_wmb();
63ca1b7a7bSAndrew Jones }
64ca1b7a7bSAndrew Jones 
6596edb026SAndre Przywara static void check_acked(const char *testname, cpumask_t *mask)
66ac4a67b6SAndrew Jones {
67ac4a67b6SAndrew Jones 	int missing = 0, extra = 0, unexpected = 0;
68ac4a67b6SAndrew Jones 	int nr_pass, cpu, i;
69ca1b7a7bSAndrew Jones 	bool bad = false;
70ac4a67b6SAndrew Jones 
71ac4a67b6SAndrew Jones 	/* Wait up to 5s for all interrupts to be delivered */
72ac4a67b6SAndrew Jones 	for (i = 0; i < 50; ++i) {
73ac4a67b6SAndrew Jones 		mdelay(100);
74ac4a67b6SAndrew Jones 		nr_pass = 0;
75ac4a67b6SAndrew Jones 		for_each_present_cpu(cpu) {
76ac4a67b6SAndrew Jones 			smp_rmb();
77ac4a67b6SAndrew Jones 			nr_pass += cpumask_test_cpu(cpu, mask) ?
78ac4a67b6SAndrew Jones 				acked[cpu] == 1 : acked[cpu] == 0;
79ca1b7a7bSAndrew Jones 
80ca1b7a7bSAndrew Jones 			if (bad_sender[cpu] != -1) {
81ca1b7a7bSAndrew Jones 				printf("cpu%d received IPI from wrong sender %d\n",
82ca1b7a7bSAndrew Jones 					cpu, bad_sender[cpu]);
83ca1b7a7bSAndrew Jones 				bad = true;
84ca1b7a7bSAndrew Jones 			}
85ca1b7a7bSAndrew Jones 
86ca1b7a7bSAndrew Jones 			if (bad_irq[cpu] != -1) {
87ca1b7a7bSAndrew Jones 				printf("cpu%d received wrong irq %d\n",
88ca1b7a7bSAndrew Jones 					cpu, bad_irq[cpu]);
89ca1b7a7bSAndrew Jones 				bad = true;
90ca1b7a7bSAndrew Jones 			}
91ac4a67b6SAndrew Jones 		}
92ac4a67b6SAndrew Jones 		if (nr_pass == nr_cpus) {
93a299895bSThomas Huth 			report(!bad, "%s", testname);
9496edb026SAndre Przywara 			if (i)
9596edb026SAndre Przywara 				report_info("took more than %d ms", i * 100);
96ac4a67b6SAndrew Jones 			return;
97ac4a67b6SAndrew Jones 		}
98ac4a67b6SAndrew Jones 	}
99ac4a67b6SAndrew Jones 
100ac4a67b6SAndrew Jones 	for_each_present_cpu(cpu) {
101ac4a67b6SAndrew Jones 		if (cpumask_test_cpu(cpu, mask)) {
102ac4a67b6SAndrew Jones 			if (!acked[cpu])
103ac4a67b6SAndrew Jones 				++missing;
104ac4a67b6SAndrew Jones 			else if (acked[cpu] > 1)
105ac4a67b6SAndrew Jones 				++extra;
106ac4a67b6SAndrew Jones 		} else {
107ac4a67b6SAndrew Jones 			if (acked[cpu])
108ac4a67b6SAndrew Jones 				++unexpected;
109ac4a67b6SAndrew Jones 		}
110ac4a67b6SAndrew Jones 	}
111ac4a67b6SAndrew Jones 
112a299895bSThomas Huth 	report(false, "%s", testname);
11396edb026SAndre Przywara 	report_info("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d",
11496edb026SAndre Przywara 		    missing, extra, unexpected);
115ac4a67b6SAndrew Jones }
116ac4a67b6SAndrew Jones 
117ac4a67b6SAndrew Jones static void check_spurious(void)
118ac4a67b6SAndrew Jones {
119ac4a67b6SAndrew Jones 	int cpu;
120ac4a67b6SAndrew Jones 
121ac4a67b6SAndrew Jones 	smp_rmb();
122ac4a67b6SAndrew Jones 	for_each_present_cpu(cpu) {
123ac4a67b6SAndrew Jones 		if (spurious[cpu])
124ac4a67b6SAndrew Jones 			report_info("WARN: cpu%d got %d spurious interrupts",
125ac4a67b6SAndrew Jones 				cpu, spurious[cpu]);
126ac4a67b6SAndrew Jones 	}
127ac4a67b6SAndrew Jones }
128ac4a67b6SAndrew Jones 
129ca1b7a7bSAndrew Jones static void check_ipi_sender(u32 irqstat)
130ca1b7a7bSAndrew Jones {
131ca1b7a7bSAndrew Jones 	if (gic_version() == 2) {
132ca1b7a7bSAndrew Jones 		int src = (irqstat >> 10) & 7;
133ca1b7a7bSAndrew Jones 
134ca1b7a7bSAndrew Jones 		if (src != IPI_SENDER)
135ca1b7a7bSAndrew Jones 			bad_sender[smp_processor_id()] = src;
136ca1b7a7bSAndrew Jones 	}
137ca1b7a7bSAndrew Jones }
138ca1b7a7bSAndrew Jones 
139ca1b7a7bSAndrew Jones static void check_irqnr(u32 irqnr)
140ca1b7a7bSAndrew Jones {
141ca1b7a7bSAndrew Jones 	if (irqnr != IPI_IRQ)
142ca1b7a7bSAndrew Jones 		bad_irq[smp_processor_id()] = irqnr;
143ca1b7a7bSAndrew Jones }
144ca1b7a7bSAndrew Jones 
145ac4a67b6SAndrew Jones static void ipi_handler(struct pt_regs *regs __unused)
146ac4a67b6SAndrew Jones {
1472e2d471dSAndrew Jones 	u32 irqstat = gic_read_iar();
1482e2d471dSAndrew Jones 	u32 irqnr = gic_iar_irqnr(irqstat);
149ac4a67b6SAndrew Jones 
150ac4a67b6SAndrew Jones 	if (irqnr != GICC_INT_SPURIOUS) {
1512e2d471dSAndrew Jones 		gic_write_eoir(irqstat);
152ca1b7a7bSAndrew Jones 		smp_rmb(); /* pairs with wmb in stats_reset */
153ac4a67b6SAndrew Jones 		++acked[smp_processor_id()];
154ca1b7a7bSAndrew Jones 		check_ipi_sender(irqstat);
155ca1b7a7bSAndrew Jones 		check_irqnr(irqnr);
156ac4a67b6SAndrew Jones 		smp_wmb(); /* pairs with rmb in check_acked */
157ac4a67b6SAndrew Jones 	} else {
158ac4a67b6SAndrew Jones 		++spurious[smp_processor_id()];
159ac4a67b6SAndrew Jones 		smp_wmb();
160ac4a67b6SAndrew Jones 	}
161ac4a67b6SAndrew Jones }
162ac4a67b6SAndrew Jones 
1630ef02cd6SEric Auger static void setup_irq(irq_handler_fn handler)
1640ef02cd6SEric Auger {
1650ef02cd6SEric Auger 	gic_enable_defaults();
1660ef02cd6SEric Auger #ifdef __arm__
1670ef02cd6SEric Auger 	install_exception_handler(EXCPTN_IRQ, handler);
1680ef02cd6SEric Auger #else
1690ef02cd6SEric Auger 	install_irq_handler(EL1H_IRQ, handler);
1700ef02cd6SEric Auger #endif
1710ef02cd6SEric Auger 	local_irq_enable();
1720ef02cd6SEric Auger }
1730ef02cd6SEric Auger 
1740ef02cd6SEric Auger #if defined(__aarch64__)
1750ef02cd6SEric Auger struct its_event {
1760ef02cd6SEric Auger 	int cpu_id;
1770ef02cd6SEric Auger 	int lpi_id;
1780ef02cd6SEric Auger };
1790ef02cd6SEric Auger 
1800ef02cd6SEric Auger struct its_stats {
1810ef02cd6SEric Auger 	struct its_event expected;
1820ef02cd6SEric Auger 	struct its_event observed;
1830ef02cd6SEric Auger };
1840ef02cd6SEric Auger 
1850ef02cd6SEric Auger static struct its_stats lpi_stats;
1860ef02cd6SEric Auger 
1870ef02cd6SEric Auger static void lpi_handler(struct pt_regs *regs __unused)
1880ef02cd6SEric Auger {
1890ef02cd6SEric Auger 	u32 irqstat = gic_read_iar();
1900ef02cd6SEric Auger 	int irqnr = gic_iar_irqnr(irqstat);
1910ef02cd6SEric Auger 
1920ef02cd6SEric Auger 	gic_write_eoir(irqstat);
1930ef02cd6SEric Auger 	assert(irqnr >= 8192);
1940ef02cd6SEric Auger 	smp_rmb(); /* pairs with wmb in lpi_stats_expect */
1950ef02cd6SEric Auger 	lpi_stats.observed.cpu_id = smp_processor_id();
1960ef02cd6SEric Auger 	lpi_stats.observed.lpi_id = irqnr;
197*de582149SEric Auger 	acked[lpi_stats.observed.cpu_id]++;
1980ef02cd6SEric Auger 	smp_wmb(); /* pairs with rmb in check_lpi_stats */
1990ef02cd6SEric Auger }
2000ef02cd6SEric Auger 
2010ef02cd6SEric Auger static void lpi_stats_expect(int exp_cpu_id, int exp_lpi_id)
2020ef02cd6SEric Auger {
2030ef02cd6SEric Auger 	lpi_stats.expected.cpu_id = exp_cpu_id;
2040ef02cd6SEric Auger 	lpi_stats.expected.lpi_id = exp_lpi_id;
2050ef02cd6SEric Auger 	lpi_stats.observed.cpu_id = -1;
2060ef02cd6SEric Auger 	lpi_stats.observed.lpi_id = -1;
2070ef02cd6SEric Auger 	smp_wmb(); /* pairs with rmb in handler */
2080ef02cd6SEric Auger }
2090ef02cd6SEric Auger 
2100ef02cd6SEric Auger static void check_lpi_stats(const char *msg)
2110ef02cd6SEric Auger {
2120ef02cd6SEric Auger 	int i;
2130ef02cd6SEric Auger 
2140ef02cd6SEric Auger 	for (i = 0; i < 50; i++) {
2150ef02cd6SEric Auger 		mdelay(100);
2160ef02cd6SEric Auger 		smp_rmb(); /* pairs with wmb in lpi_handler */
2170ef02cd6SEric Auger 		if (lpi_stats.observed.cpu_id == lpi_stats.expected.cpu_id &&
2180ef02cd6SEric Auger 		    lpi_stats.observed.lpi_id == lpi_stats.expected.lpi_id) {
2190ef02cd6SEric Auger 			report(true, "%s", msg);
2200ef02cd6SEric Auger 			return;
2210ef02cd6SEric Auger 		}
2220ef02cd6SEric Auger 	}
2230ef02cd6SEric Auger 
2240ef02cd6SEric Auger 	if (lpi_stats.observed.cpu_id == -1 && lpi_stats.observed.lpi_id == -1) {
2250ef02cd6SEric Auger 		report_info("No LPI received whereas (cpuid=%d, intid=%d) "
2260ef02cd6SEric Auger 			    "was expected", lpi_stats.expected.cpu_id,
2270ef02cd6SEric Auger 			    lpi_stats.expected.lpi_id);
2280ef02cd6SEric Auger 	} else {
2290ef02cd6SEric Auger 		report_info("Unexpected LPI (cpuid=%d, intid=%d)",
2300ef02cd6SEric Auger 			    lpi_stats.observed.cpu_id,
2310ef02cd6SEric Auger 			    lpi_stats.observed.lpi_id);
2320ef02cd6SEric Auger 	}
2330ef02cd6SEric Auger 	report(false, "%s", msg);
2340ef02cd6SEric Auger }
2350ef02cd6SEric Auger 
2360ef02cd6SEric Auger static void secondary_lpi_test(void)
2370ef02cd6SEric Auger {
2380ef02cd6SEric Auger 	setup_irq(lpi_handler);
2390ef02cd6SEric Auger 	cpumask_set_cpu(smp_processor_id(), &ready);
2400ef02cd6SEric Auger 	while (1)
2410ef02cd6SEric Auger 		wfi();
2420ef02cd6SEric Auger }
243*de582149SEric Auger 
244*de582149SEric Auger static void check_lpi_hits(int *expected, const char *msg)
245*de582149SEric Auger {
246*de582149SEric Auger 	bool pass = true;
247*de582149SEric Auger 	int i;
248*de582149SEric Auger 
249*de582149SEric Auger 	for_each_present_cpu(i) {
250*de582149SEric Auger 		if (acked[i] != expected[i]) {
251*de582149SEric Auger 			report_info("expected %d LPIs on PE #%d, %d observed",
252*de582149SEric Auger 				    expected[i], i, acked[i]);
253*de582149SEric Auger 			pass = false;
254*de582149SEric Auger 			break;
255*de582149SEric Auger 		}
256*de582149SEric Auger 	}
257*de582149SEric Auger 	report(pass, "%s", msg);
258*de582149SEric Auger }
2590ef02cd6SEric Auger #endif
2600ef02cd6SEric Auger 
2612e2d471dSAndrew Jones static void gicv2_ipi_send_self(void)
2622e2d471dSAndrew Jones {
263ca1b7a7bSAndrew Jones 	writel(2 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
2642e2d471dSAndrew Jones }
2652e2d471dSAndrew Jones 
2662e2d471dSAndrew Jones static void gicv2_ipi_send_broadcast(void)
2672e2d471dSAndrew Jones {
268ca1b7a7bSAndrew Jones 	writel(1 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
2692e2d471dSAndrew Jones }
2702e2d471dSAndrew Jones 
2712e2d471dSAndrew Jones static void gicv3_ipi_send_self(void)
2722e2d471dSAndrew Jones {
273ca1b7a7bSAndrew Jones 	gic_ipi_send_single(IPI_IRQ, smp_processor_id());
2742e2d471dSAndrew Jones }
2752e2d471dSAndrew Jones 
2762e2d471dSAndrew Jones static void gicv3_ipi_send_broadcast(void)
2772e2d471dSAndrew Jones {
278ca1b7a7bSAndrew Jones 	gicv3_write_sgi1r(1ULL << 40 | IPI_IRQ << 24);
2792e2d471dSAndrew Jones 	isb();
2802e2d471dSAndrew Jones }
2812e2d471dSAndrew Jones 
282ac4a67b6SAndrew Jones static void ipi_test_self(void)
283ac4a67b6SAndrew Jones {
284ac4a67b6SAndrew Jones 	cpumask_t mask;
285ac4a67b6SAndrew Jones 
286ac4a67b6SAndrew Jones 	report_prefix_push("self");
287ca1b7a7bSAndrew Jones 	stats_reset();
288ac4a67b6SAndrew Jones 	cpumask_clear(&mask);
289ca1b7a7bSAndrew Jones 	cpumask_set_cpu(smp_processor_id(), &mask);
2902e2d471dSAndrew Jones 	gic->ipi.send_self();
29196edb026SAndre Przywara 	check_acked("IPI: self", &mask);
292ac4a67b6SAndrew Jones 	report_prefix_pop();
293ac4a67b6SAndrew Jones }
294ac4a67b6SAndrew Jones 
295ac4a67b6SAndrew Jones static void ipi_test_smp(void)
296ac4a67b6SAndrew Jones {
297ac4a67b6SAndrew Jones 	cpumask_t mask;
2982e2d471dSAndrew Jones 	int i;
299ac4a67b6SAndrew Jones 
300ac4a67b6SAndrew Jones 	report_prefix_push("target-list");
301ca1b7a7bSAndrew Jones 	stats_reset();
3022e2d471dSAndrew Jones 	cpumask_copy(&mask, &cpu_present_mask);
303ca1b7a7bSAndrew Jones 	for (i = smp_processor_id() & 1; i < nr_cpus; i += 2)
3042e2d471dSAndrew Jones 		cpumask_clear_cpu(i, &mask);
305ca1b7a7bSAndrew Jones 	gic_ipi_send_mask(IPI_IRQ, &mask);
30696edb026SAndre Przywara 	check_acked("IPI: directed", &mask);
307ac4a67b6SAndrew Jones 	report_prefix_pop();
308ac4a67b6SAndrew Jones 
309ac4a67b6SAndrew Jones 	report_prefix_push("broadcast");
310ca1b7a7bSAndrew Jones 	stats_reset();
311ac4a67b6SAndrew Jones 	cpumask_copy(&mask, &cpu_present_mask);
312ca1b7a7bSAndrew Jones 	cpumask_clear_cpu(smp_processor_id(), &mask);
3132e2d471dSAndrew Jones 	gic->ipi.send_broadcast();
31496edb026SAndre Przywara 	check_acked("IPI: broadcast", &mask);
315ac4a67b6SAndrew Jones 	report_prefix_pop();
316ac4a67b6SAndrew Jones }
317ac4a67b6SAndrew Jones 
318ca1b7a7bSAndrew Jones static void ipi_send(void)
319ca1b7a7bSAndrew Jones {
32025f66327SEric Auger 	setup_irq(ipi_handler);
321ca1b7a7bSAndrew Jones 	wait_on_ready();
322ca1b7a7bSAndrew Jones 	ipi_test_self();
323ca1b7a7bSAndrew Jones 	ipi_test_smp();
324ca1b7a7bSAndrew Jones 	check_spurious();
325ca1b7a7bSAndrew Jones 	exit(report_summary());
326ca1b7a7bSAndrew Jones }
327ca1b7a7bSAndrew Jones 
328ac4a67b6SAndrew Jones static void ipi_recv(void)
329ac4a67b6SAndrew Jones {
33025f66327SEric Auger 	setup_irq(ipi_handler);
331ac4a67b6SAndrew Jones 	cpumask_set_cpu(smp_processor_id(), &ready);
332ac4a67b6SAndrew Jones 	while (1)
333ac4a67b6SAndrew Jones 		wfi();
334ac4a67b6SAndrew Jones }
335ac4a67b6SAndrew Jones 
33600b34f56SAndrew Jones static void ipi_test(void *data __unused)
337bfd500b4SAndrew Jones {
338bfd500b4SAndrew Jones 	if (smp_processor_id() == IPI_SENDER)
339bfd500b4SAndrew Jones 		ipi_send();
340bfd500b4SAndrew Jones 	else
341bfd500b4SAndrew Jones 		ipi_recv();
342bfd500b4SAndrew Jones }
343bfd500b4SAndrew Jones 
3442e2d471dSAndrew Jones static struct gic gicv2 = {
3452e2d471dSAndrew Jones 	.ipi = {
3462e2d471dSAndrew Jones 		.send_self = gicv2_ipi_send_self,
3472e2d471dSAndrew Jones 		.send_broadcast = gicv2_ipi_send_broadcast,
3482e2d471dSAndrew Jones 	},
3492e2d471dSAndrew Jones };
3502e2d471dSAndrew Jones 
3512e2d471dSAndrew Jones static struct gic gicv3 = {
3522e2d471dSAndrew Jones 	.ipi = {
3532e2d471dSAndrew Jones 		.send_self = gicv3_ipi_send_self,
3542e2d471dSAndrew Jones 		.send_broadcast = gicv3_ipi_send_broadcast,
3552e2d471dSAndrew Jones 	},
3562e2d471dSAndrew Jones };
3572e2d471dSAndrew Jones 
358c152d8bcSChristoffer Dall static void ipi_clear_active_handler(struct pt_regs *regs __unused)
359c152d8bcSChristoffer Dall {
360c152d8bcSChristoffer Dall 	u32 irqstat = gic_read_iar();
361c152d8bcSChristoffer Dall 	u32 irqnr = gic_iar_irqnr(irqstat);
362c152d8bcSChristoffer Dall 
363c152d8bcSChristoffer Dall 	if (irqnr != GICC_INT_SPURIOUS) {
364c152d8bcSChristoffer Dall 		void *base;
365c152d8bcSChristoffer Dall 		u32 val = 1 << IPI_IRQ;
366c152d8bcSChristoffer Dall 
367c152d8bcSChristoffer Dall 		if (gic_version() == 2)
368c152d8bcSChristoffer Dall 			base = gicv2_dist_base();
369c152d8bcSChristoffer Dall 		else
3706d4d7c4bSAndrew Jones 			base = gicv3_sgi_base();
371c152d8bcSChristoffer Dall 
372c152d8bcSChristoffer Dall 		writel(val, base + GICD_ICACTIVER);
373c152d8bcSChristoffer Dall 
374c152d8bcSChristoffer Dall 		smp_rmb(); /* pairs with wmb in stats_reset */
375c152d8bcSChristoffer Dall 		++acked[smp_processor_id()];
376c152d8bcSChristoffer Dall 		check_irqnr(irqnr);
377c152d8bcSChristoffer Dall 		smp_wmb(); /* pairs with rmb in check_acked */
378c152d8bcSChristoffer Dall 	} else {
379c152d8bcSChristoffer Dall 		++spurious[smp_processor_id()];
380c152d8bcSChristoffer Dall 		smp_wmb();
381c152d8bcSChristoffer Dall 	}
382c152d8bcSChristoffer Dall }
383c152d8bcSChristoffer Dall 
384c152d8bcSChristoffer Dall static void run_active_clear_test(void)
385c152d8bcSChristoffer Dall {
386c152d8bcSChristoffer Dall 	report_prefix_push("active");
38725f66327SEric Auger 	setup_irq(ipi_clear_active_handler);
388c152d8bcSChristoffer Dall 	ipi_test_self();
389c152d8bcSChristoffer Dall 	report_prefix_pop();
390c152d8bcSChristoffer Dall }
391c152d8bcSChristoffer Dall 
39278ad7e95SAndre Przywara static bool test_ro_pattern_32(void *address, u32 pattern, u32 orig)
39378ad7e95SAndre Przywara {
39478ad7e95SAndre Przywara 	u32 reg;
39578ad7e95SAndre Przywara 
39678ad7e95SAndre Przywara 	writel(pattern, address);
39778ad7e95SAndre Przywara 	reg = readl(address);
39878ad7e95SAndre Przywara 
39978ad7e95SAndre Przywara 	if (reg != orig)
40078ad7e95SAndre Przywara 		writel(orig, address);
40178ad7e95SAndre Przywara 
40278ad7e95SAndre Przywara 	return reg == orig;
40378ad7e95SAndre Przywara }
40478ad7e95SAndre Przywara 
40578ad7e95SAndre Przywara static bool test_readonly_32(void *address, bool razwi)
40678ad7e95SAndre Przywara {
40778ad7e95SAndre Przywara 	u32 orig, pattern;
40878ad7e95SAndre Przywara 
40978ad7e95SAndre Przywara 	orig = readl(address);
41078ad7e95SAndre Przywara 	if (razwi && orig)
41178ad7e95SAndre Przywara 		return false;
41278ad7e95SAndre Przywara 
41378ad7e95SAndre Przywara 	pattern = 0xffffffff;
41478ad7e95SAndre Przywara 	if (orig != pattern) {
41578ad7e95SAndre Przywara 		if (!test_ro_pattern_32(address, pattern, orig))
41678ad7e95SAndre Przywara 			return false;
41778ad7e95SAndre Przywara 	}
41878ad7e95SAndre Przywara 
41978ad7e95SAndre Przywara 	pattern = 0xa5a55a5a;
42078ad7e95SAndre Przywara 	if (orig != pattern) {
42178ad7e95SAndre Przywara 		if (!test_ro_pattern_32(address, pattern, orig))
42278ad7e95SAndre Przywara 			return false;
42378ad7e95SAndre Przywara 	}
42478ad7e95SAndre Przywara 
42578ad7e95SAndre Przywara 	pattern = 0;
42678ad7e95SAndre Przywara 	if (orig != pattern) {
42778ad7e95SAndre Przywara 		if (!test_ro_pattern_32(address, pattern, orig))
42878ad7e95SAndre Przywara 			return false;
42978ad7e95SAndre Przywara 	}
43078ad7e95SAndre Przywara 
43178ad7e95SAndre Przywara 	return true;
43278ad7e95SAndre Przywara }
43378ad7e95SAndre Przywara 
43478ad7e95SAndre Przywara static void test_typer_v2(uint32_t reg)
43578ad7e95SAndre Przywara {
43678ad7e95SAndre Przywara 	int nr_gic_cpus = ((reg >> 5) & 0x7) + 1;
43778ad7e95SAndre Przywara 
4388e0a4f41SAndre Przywara 	report_info("nr_cpus=%d", nr_cpus);
439a299895bSThomas Huth 	report(nr_cpus == nr_gic_cpus, "all CPUs have interrupts");
44078ad7e95SAndre Przywara }
44178ad7e95SAndre Przywara 
442ff31a1c4SAndre Przywara #define BYTE(reg32, byte) (((reg32) >> ((byte) * 8)) & 0xff)
443ff31a1c4SAndre Przywara #define REPLACE_BYTE(reg32, byte, new) (((reg32) & ~(0xff << ((byte) * 8))) |\
444ff31a1c4SAndre Przywara 					((new) << ((byte) * 8)))
445ff31a1c4SAndre Przywara 
446ff31a1c4SAndre Przywara /*
447ff31a1c4SAndre Przywara  * Some registers are byte accessible, do a byte-wide read and write of known
448ff31a1c4SAndre Przywara  * content to check for this.
449ff31a1c4SAndre Przywara  * Apply a @mask to cater for special register properties.
450ff31a1c4SAndre Przywara  * @pattern contains the value already in the register.
451ff31a1c4SAndre Przywara  */
452ff31a1c4SAndre Przywara static void test_byte_access(void *base_addr, u32 pattern, u32 mask)
453ff31a1c4SAndre Przywara {
454ff31a1c4SAndre Przywara 	u32 reg = readb(base_addr + 1);
4558e0a4f41SAndre Przywara 	bool res;
456ff31a1c4SAndre Przywara 
4578e0a4f41SAndre Przywara 	res = (reg == (BYTE(pattern, 1) & (mask >> 8)));
458a299895bSThomas Huth 	report(res, "byte reads successful");
4598e0a4f41SAndre Przywara 	if (!res)
4608e0a4f41SAndre Przywara 		report_info("byte 1 of 0x%08x => 0x%02x", pattern & mask, reg);
461ff31a1c4SAndre Przywara 
462ff31a1c4SAndre Przywara 	pattern = REPLACE_BYTE(pattern, 2, 0x1f);
463ff31a1c4SAndre Przywara 	writeb(BYTE(pattern, 2), base_addr + 2);
464ff31a1c4SAndre Przywara 	reg = readl(base_addr);
4658e0a4f41SAndre Przywara 	res = (reg == (pattern & mask));
466a299895bSThomas Huth 	report(res, "byte writes successful");
4678e0a4f41SAndre Przywara 	if (!res)
4688e0a4f41SAndre Przywara 		report_info("writing 0x%02x into bytes 2 => 0x%08x",
4698e0a4f41SAndre Przywara 			    BYTE(pattern, 2), reg);
470ff31a1c4SAndre Przywara }
471ff31a1c4SAndre Przywara 
472ff31a1c4SAndre Przywara static void test_priorities(int nr_irqs, void *priptr)
473ff31a1c4SAndre Przywara {
474ff31a1c4SAndre Przywara 	u32 orig_prio, reg, pri_bits;
475ff31a1c4SAndre Przywara 	u32 pri_mask, pattern;
476ff31a1c4SAndre Przywara 	void *first_spi = priptr + GIC_FIRST_SPI;
477ff31a1c4SAndre Przywara 
478ff31a1c4SAndre Przywara 	orig_prio = readl(first_spi);
479ff31a1c4SAndre Przywara 	report_prefix_push("IPRIORITYR");
480ff31a1c4SAndre Przywara 
481ff31a1c4SAndre Przywara 	/*
482ff31a1c4SAndre Przywara 	 * Determine implemented number of priority bits by writing all 1's
483ff31a1c4SAndre Przywara 	 * and checking the number of cleared bits in the value read back.
484ff31a1c4SAndre Przywara 	 */
485ff31a1c4SAndre Przywara 	writel(0xffffffff, first_spi);
486ff31a1c4SAndre Przywara 	pri_mask = readl(first_spi);
487ff31a1c4SAndre Przywara 
488ff31a1c4SAndre Przywara 	reg = ~pri_mask;
489a299895bSThomas Huth 	report((((reg >> 16) == (reg & 0xffff)) &&
490a299895bSThomas Huth 	        ((reg & 0xff) == ((reg >> 8) & 0xff))),
491a299895bSThomas Huth 	       "consistent priority masking");
4928e0a4f41SAndre Przywara 	report_info("priority mask is 0x%08x", pri_mask);
493ff31a1c4SAndre Przywara 
494ff31a1c4SAndre Przywara 	reg = reg & 0xff;
495ff31a1c4SAndre Przywara 	for (pri_bits = 8; reg & 1; reg >>= 1, pri_bits--)
496ff31a1c4SAndre Przywara 		;
497a299895bSThomas Huth 	report(pri_bits >= 4, "implements at least 4 priority bits");
4988e0a4f41SAndre Przywara 	report_info("%d priority bits implemented", pri_bits);
499ff31a1c4SAndre Przywara 
500ff31a1c4SAndre Przywara 	pattern = 0;
501ff31a1c4SAndre Przywara 	writel(pattern, first_spi);
502a299895bSThomas Huth 	report(readl(first_spi) == pattern, "clearing priorities");
503ff31a1c4SAndre Przywara 
504ff31a1c4SAndre Przywara 	/* setting all priorities to their max valus was tested above */
505ff31a1c4SAndre Przywara 
506a299895bSThomas Huth 	report(test_readonly_32(priptr + nr_irqs, true),
507a299895bSThomas Huth 	       "accesses beyond limit RAZ/WI");
508ff31a1c4SAndre Przywara 
509ff31a1c4SAndre Przywara 	writel(pattern, priptr + nr_irqs - 4);
510a299895bSThomas Huth 	report(readl(priptr + nr_irqs - 4) == (pattern & pri_mask),
511a299895bSThomas Huth 	       "accessing last SPIs");
512ff31a1c4SAndre Przywara 
513ff31a1c4SAndre Przywara 	pattern = 0xff7fbf3f;
514ff31a1c4SAndre Przywara 	writel(pattern, first_spi);
515a299895bSThomas Huth 	report(readl(first_spi) == (pattern & pri_mask),
516a299895bSThomas Huth 	       "priorities are preserved");
517ff31a1c4SAndre Przywara 
518ff31a1c4SAndre Przywara 	/* The PRIORITY registers are byte accessible. */
519ff31a1c4SAndre Przywara 	test_byte_access(first_spi, pattern, pri_mask);
520ff31a1c4SAndre Przywara 
521ff31a1c4SAndre Przywara 	report_prefix_pop();
522ff31a1c4SAndre Przywara 	writel(orig_prio, first_spi);
523ff31a1c4SAndre Przywara }
524ff31a1c4SAndre Przywara 
525fe572a5eSAndre Przywara /* GICD_ITARGETSR is only used by GICv2. */
526fe572a5eSAndre Przywara static void test_targets(int nr_irqs)
527fe572a5eSAndre Przywara {
528fe572a5eSAndre Przywara 	void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR;
529fe572a5eSAndre Przywara 	u32 orig_targets;
530fe572a5eSAndre Przywara 	u32 cpu_mask;
531fe572a5eSAndre Przywara 	u32 pattern, reg;
532fe572a5eSAndre Przywara 
533fe572a5eSAndre Przywara 	orig_targets = readl(targetsptr + GIC_FIRST_SPI);
534fe572a5eSAndre Przywara 	report_prefix_push("ITARGETSR");
535fe572a5eSAndre Przywara 
536fe572a5eSAndre Przywara 	cpu_mask = (1 << nr_cpus) - 1;
537fe572a5eSAndre Przywara 	cpu_mask |= cpu_mask << 8;
538fe572a5eSAndre Przywara 	cpu_mask |= cpu_mask << 16;
539fe572a5eSAndre Przywara 
540fe572a5eSAndre Przywara 	/* Check that bits for non implemented CPUs are RAZ/WI. */
541fe572a5eSAndre Przywara 	if (nr_cpus < 8) {
542fe572a5eSAndre Przywara 		writel(0xffffffff, targetsptr + GIC_FIRST_SPI);
543a299895bSThomas Huth 		report(!(readl(targetsptr + GIC_FIRST_SPI) & ~cpu_mask),
544a299895bSThomas Huth 		       "bits for non-existent CPUs masked");
5458e0a4f41SAndre Przywara 		report_info("%d non-existent CPUs", 8 - nr_cpus);
546fe572a5eSAndre Przywara 	} else {
547fe572a5eSAndre Przywara 		report_skip("CPU masking (all CPUs implemented)");
548fe572a5eSAndre Przywara 	}
549fe572a5eSAndre Przywara 
550a299895bSThomas Huth 	report(test_readonly_32(targetsptr + nr_irqs, true),
551a299895bSThomas Huth 	       "accesses beyond limit RAZ/WI");
552fe572a5eSAndre Przywara 
553fe572a5eSAndre Przywara 	pattern = 0x0103020f;
554fe572a5eSAndre Przywara 	writel(pattern, targetsptr + GIC_FIRST_SPI);
555fe572a5eSAndre Przywara 	reg = readl(targetsptr + GIC_FIRST_SPI);
556a299895bSThomas Huth 	report(reg == (pattern & cpu_mask), "register content preserved");
5578e0a4f41SAndre Przywara 	if (reg != (pattern & cpu_mask))
5588e0a4f41SAndre Przywara 		report_info("writing %08x reads back as %08x",
5598e0a4f41SAndre Przywara 			    pattern & cpu_mask, reg);
560fe572a5eSAndre Przywara 
561fe572a5eSAndre Przywara 	/* The TARGETS registers are byte accessible. */
562fe572a5eSAndre Przywara 	test_byte_access(targetsptr + GIC_FIRST_SPI, pattern, cpu_mask);
563fe572a5eSAndre Przywara 
564fe572a5eSAndre Przywara 	writel(orig_targets, targetsptr + GIC_FIRST_SPI);
565da5b8576SAndre Przywara 
566da5b8576SAndre Przywara 	report_prefix_pop();
567fe572a5eSAndre Przywara }
568fe572a5eSAndre Przywara 
56978ad7e95SAndre Przywara static void gic_test_mmio(void)
57078ad7e95SAndre Przywara {
57178ad7e95SAndre Przywara 	u32 reg;
57278ad7e95SAndre Przywara 	int nr_irqs;
57378ad7e95SAndre Przywara 	void *gic_dist_base, *idreg;
57478ad7e95SAndre Przywara 
57578ad7e95SAndre Przywara 	switch(gic_version()) {
57678ad7e95SAndre Przywara 	case 0x2:
57778ad7e95SAndre Przywara 		gic_dist_base = gicv2_dist_base();
57878ad7e95SAndre Przywara 		idreg = gic_dist_base + GICD_ICPIDR2;
57978ad7e95SAndre Przywara 		break;
58078ad7e95SAndre Przywara 	case 0x3:
58178ad7e95SAndre Przywara 		report_abort("GICv3 MMIO tests NYI");
58278ad7e95SAndre Przywara 	default:
58378ad7e95SAndre Przywara 		report_abort("GIC version %d not supported", gic_version());
58478ad7e95SAndre Przywara 	}
58578ad7e95SAndre Przywara 
58678ad7e95SAndre Przywara 	reg = readl(gic_dist_base + GICD_TYPER);
58778ad7e95SAndre Przywara 	nr_irqs = GICD_TYPER_IRQS(reg);
58878ad7e95SAndre Przywara 	report_info("number of implemented SPIs: %d", nr_irqs - GIC_FIRST_SPI);
58978ad7e95SAndre Przywara 
59078ad7e95SAndre Przywara 	test_typer_v2(reg);
59178ad7e95SAndre Przywara 
59278ad7e95SAndre Przywara 	report_info("IIDR: 0x%08x", readl(gic_dist_base + GICD_IIDR));
59378ad7e95SAndre Przywara 
594a299895bSThomas Huth 	report(test_readonly_32(gic_dist_base + GICD_TYPER, false),
595a299895bSThomas Huth                "GICD_TYPER is read-only");
596a299895bSThomas Huth 	report(test_readonly_32(gic_dist_base + GICD_IIDR, false),
597a299895bSThomas Huth                "GICD_IIDR is read-only");
59878ad7e95SAndre Przywara 
59978ad7e95SAndre Przywara 	reg = readl(idreg);
600a299895bSThomas Huth 	report(test_readonly_32(idreg, false), "ICPIDR2 is read-only");
6018e0a4f41SAndre Przywara 	report_info("value of ICPIDR2: 0x%08x", reg);
602ff31a1c4SAndre Przywara 
603ff31a1c4SAndre Przywara 	test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR);
604fe572a5eSAndre Przywara 
605fe572a5eSAndre Przywara 	if (gic_version() == 2)
606fe572a5eSAndre Przywara 		test_targets(nr_irqs);
60778ad7e95SAndre Przywara }
60878ad7e95SAndre Przywara 
609ba74b106SEric Auger #if defined(__arm__)
610ba74b106SEric Auger 
611ba74b106SEric Auger static void test_its_introspection(void) {}
6120ef02cd6SEric Auger static void test_its_trigger(void) {}
61364260a5fSEric Auger static void test_its_migration(void) {}
614*de582149SEric Auger static void test_its_pending_migration(void) {}
615*de582149SEric Auger static void test_migrate_unmapped_collection(void) {}
616ba74b106SEric Auger 
617ba74b106SEric Auger #else /* __aarch64__ */
618ba74b106SEric Auger 
619ba74b106SEric Auger static void test_its_introspection(void)
620ba74b106SEric Auger {
621ba74b106SEric Auger 	struct its_baser *dev_baser = &its_data.device_baser;
622ba74b106SEric Auger 	struct its_baser *coll_baser = &its_data.coll_baser;
623ba74b106SEric Auger 	struct its_typer *typer = &its_data.typer;
624ba74b106SEric Auger 
625ba74b106SEric Auger 	if (!gicv3_its_base()) {
626ba74b106SEric Auger 		report_skip("No ITS, skip ...");
627ba74b106SEric Auger 		return;
628ba74b106SEric Auger 	}
629ba74b106SEric Auger 
630ba74b106SEric Auger 	/* IIDR */
631ba74b106SEric Auger 	report(test_readonly_32(gicv3_its_base() + GITS_IIDR, false),
632ba74b106SEric Auger 	       "GITS_IIDR is read-only"),
633ba74b106SEric Auger 
634ba74b106SEric Auger 	/* TYPER */
635ba74b106SEric Auger 	report(test_readonly_32(gicv3_its_base() + GITS_TYPER, false),
636ba74b106SEric Auger 	       "GITS_TYPER is read-only");
637ba74b106SEric Auger 
638ba74b106SEric Auger 	report(typer->phys_lpi, "ITS supports physical LPIs");
639ba74b106SEric Auger 	report_info("vLPI support: %s", typer->virt_lpi ? "yes" : "no");
640ba74b106SEric Auger 	report_info("ITT entry size = 0x%x", typer->ite_size);
641ba74b106SEric Auger 	report_info("Bit Count: EventID=%d DeviceId=%d CollId=%d",
642ba74b106SEric Auger 		    typer->eventid_bits, typer->deviceid_bits,
643ba74b106SEric Auger 		    typer->collid_bits);
644ba74b106SEric Auger 	report(typer->eventid_bits && typer->deviceid_bits &&
645ba74b106SEric Auger 	       typer->collid_bits, "ID spaces");
646ba74b106SEric Auger 	report_info("Target address format %s",
647ba74b106SEric Auger 			typer->pta ? "Redist base address" : "PE #");
648ba74b106SEric Auger 
649ba74b106SEric Auger 	report(dev_baser && coll_baser, "detect device and collection BASER");
650ba74b106SEric Auger 	report_info("device table entry_size = 0x%x", dev_baser->esz);
651ba74b106SEric Auger 	report_info("collection table entry_size = 0x%x", coll_baser->esz);
652ba74b106SEric Auger }
653ba74b106SEric Auger 
6540ef02cd6SEric Auger static int its_prerequisites(int nb_cpus)
6550ef02cd6SEric Auger {
6560ef02cd6SEric Auger 	int cpu;
6570ef02cd6SEric Auger 
6580ef02cd6SEric Auger 	if (!gicv3_its_base()) {
6590ef02cd6SEric Auger 		report_skip("No ITS, skip ...");
6600ef02cd6SEric Auger 		return -1;
6610ef02cd6SEric Auger 	}
6620ef02cd6SEric Auger 
6630ef02cd6SEric Auger 	if (nr_cpus < nb_cpus) {
6640ef02cd6SEric Auger 		report_skip("Test requires at least %d vcpus", nb_cpus);
6650ef02cd6SEric Auger 		return -1;
6660ef02cd6SEric Auger 	}
6670ef02cd6SEric Auger 
6680ef02cd6SEric Auger 	stats_reset();
6690ef02cd6SEric Auger 
6700ef02cd6SEric Auger 	setup_irq(lpi_handler);
6710ef02cd6SEric Auger 
6720ef02cd6SEric Auger 	for_each_present_cpu(cpu) {
6730ef02cd6SEric Auger 		if (cpu == 0)
6740ef02cd6SEric Auger 			continue;
6750ef02cd6SEric Auger 		smp_boot_secondary(cpu, secondary_lpi_test);
6760ef02cd6SEric Auger 	}
6770ef02cd6SEric Auger 	wait_on_ready();
6780ef02cd6SEric Auger 
6790ef02cd6SEric Auger 	its_enable_defaults();
6800ef02cd6SEric Auger 
6810ef02cd6SEric Auger 	return 0;
6820ef02cd6SEric Auger }
6830ef02cd6SEric Auger 
68464260a5fSEric Auger /*
68564260a5fSEric Auger  * Setup the configuration for those mappings:
68664260a5fSEric Auger  * dev_id=2 event=20 -> vcpu 3, intid=8195
68764260a5fSEric Auger  * dev_id=7 event=255 -> vcpu 2, intid=8196
68864260a5fSEric Auger  * LPIs ready to hit
68964260a5fSEric Auger  */
69064260a5fSEric Auger static int its_setup1(void)
6910ef02cd6SEric Auger {
6920ef02cd6SEric Auger 	struct its_collection *col3, *col2;
6930ef02cd6SEric Auger 	struct its_device *dev2, *dev7;
6940ef02cd6SEric Auger 
6950ef02cd6SEric Auger 	if (its_prerequisites(4))
69664260a5fSEric Auger 		return -1;
6970ef02cd6SEric Auger 
6980ef02cd6SEric Auger 	dev2 = its_create_device(2 /* dev id */, 8 /* nb_ites */);
6990ef02cd6SEric Auger 	dev7 = its_create_device(7 /* dev id */, 8 /* nb_ites */);
7000ef02cd6SEric Auger 
7010ef02cd6SEric Auger 	col3 = its_create_collection(3 /* col id */, 3/* target PE */);
7020ef02cd6SEric Auger 	col2 = its_create_collection(2 /* col id */, 2/* target PE */);
7030ef02cd6SEric Auger 
7040ef02cd6SEric Auger 	gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT);
7050ef02cd6SEric Auger 	gicv3_lpi_set_config(8196, LPI_PROP_DEFAULT);
7060ef02cd6SEric Auger 
7070ef02cd6SEric Auger 	/*
7080ef02cd6SEric Auger 	 * dev=2, eventid=20  -> lpi= 8195, col=3
7090ef02cd6SEric Auger 	 * dev=7, eventid=255 -> lpi= 8196, col=2
7100ef02cd6SEric Auger 	 */
7110ef02cd6SEric Auger 	its_send_mapd(dev2, true);
7120ef02cd6SEric Auger 	its_send_mapd(dev7, true);
7130ef02cd6SEric Auger 
7140ef02cd6SEric Auger 	its_send_mapc(col3, true);
7150ef02cd6SEric Auger 	its_send_mapc(col2, true);
7160ef02cd6SEric Auger 
7170ef02cd6SEric Auger 	its_send_invall(col2);
7180ef02cd6SEric Auger 	its_send_invall(col3);
7190ef02cd6SEric Auger 
7200ef02cd6SEric Auger 	its_send_mapti(dev2, 8195 /* lpi id */, 20 /* event id */, col3);
7210ef02cd6SEric Auger 	its_send_mapti(dev7, 8196 /* lpi id */, 255 /* event id */, col2);
72264260a5fSEric Auger 	return 0;
72364260a5fSEric Auger }
72464260a5fSEric Auger 
72564260a5fSEric Auger static void test_its_trigger(void)
72664260a5fSEric Auger {
72764260a5fSEric Auger 	struct its_collection *col3;
72864260a5fSEric Auger 	struct its_device *dev2, *dev7;
72964260a5fSEric Auger 
73064260a5fSEric Auger 	if (its_setup1())
73164260a5fSEric Auger 		return;
73264260a5fSEric Auger 
73364260a5fSEric Auger 	col3 = its_get_collection(3);
73464260a5fSEric Auger 	dev2 = its_get_device(2);
73564260a5fSEric Auger 	dev7 = its_get_device(7);
73664260a5fSEric Auger 
73764260a5fSEric Auger 	report_prefix_push("int");
7380ef02cd6SEric Auger 
7390ef02cd6SEric Auger 	lpi_stats_expect(3, 8195);
7400ef02cd6SEric Auger 	its_send_int(dev2, 20);
7410ef02cd6SEric Auger 	check_lpi_stats("dev=2, eventid=20  -> lpi= 8195, col=3");
7420ef02cd6SEric Auger 
7430ef02cd6SEric Auger 	lpi_stats_expect(2, 8196);
7440ef02cd6SEric Auger 	its_send_int(dev7, 255);
7450ef02cd6SEric Auger 	check_lpi_stats("dev=7, eventid=255 -> lpi= 8196, col=2");
7460ef02cd6SEric Auger 
7470ef02cd6SEric Auger 	report_prefix_pop();
7480ef02cd6SEric Auger 
7490ef02cd6SEric Auger 	report_prefix_push("inv/invall");
7500ef02cd6SEric Auger 
7510ef02cd6SEric Auger 	/*
7520ef02cd6SEric Auger 	 * disable 8195, check dev2/eventid=20 does not trigger the
7530ef02cd6SEric Auger 	 * corresponding LPI
7540ef02cd6SEric Auger 	 */
7550ef02cd6SEric Auger 	gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT & ~LPI_PROP_ENABLED);
7560ef02cd6SEric Auger 	its_send_inv(dev2, 20);
7570ef02cd6SEric Auger 
7580ef02cd6SEric Auger 	lpi_stats_expect(-1, -1);
7590ef02cd6SEric Auger 	its_send_int(dev2, 20);
7600ef02cd6SEric Auger 	check_lpi_stats("dev2/eventid=20 does not trigger any LPI");
7610ef02cd6SEric Auger 
7620ef02cd6SEric Auger 	/*
7630ef02cd6SEric Auger 	 * re-enable the LPI but willingly do not call invall
7640ef02cd6SEric Auger 	 * so the change in config is not taken into account.
7650ef02cd6SEric Auger 	 * The LPI should not hit
7660ef02cd6SEric Auger 	 */
7670ef02cd6SEric Auger 	gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT);
7680ef02cd6SEric Auger 	lpi_stats_expect(-1, -1);
7690ef02cd6SEric Auger 	its_send_int(dev2, 20);
7700ef02cd6SEric Auger 	check_lpi_stats("dev2/eventid=20 still does not trigger any LPI");
7710ef02cd6SEric Auger 
7720ef02cd6SEric Auger 	/* Now call the invall and check the LPI hits */
7730ef02cd6SEric Auger 	its_send_invall(col3);
7740ef02cd6SEric Auger 	lpi_stats_expect(3, 8195);
7750ef02cd6SEric Auger 	its_send_int(dev2, 20);
7760ef02cd6SEric Auger 	check_lpi_stats("dev2/eventid=20 now triggers an LPI");
7770ef02cd6SEric Auger 
7780ef02cd6SEric Auger 	report_prefix_pop();
7790ef02cd6SEric Auger 
7800ef02cd6SEric Auger 	report_prefix_push("mapd valid=false");
7810ef02cd6SEric Auger 	/*
7820ef02cd6SEric Auger 	 * Unmap device 2 and check the eventid 20 formerly
7830ef02cd6SEric Auger 	 * attached to it does not hit anymore
7840ef02cd6SEric Auger 	 */
7850ef02cd6SEric Auger 
7860ef02cd6SEric Auger 	its_send_mapd(dev2, false);
7870ef02cd6SEric Auger 	lpi_stats_expect(-1, -1);
7880ef02cd6SEric Auger 	its_send_int(dev2, 20);
7890ef02cd6SEric Auger 	check_lpi_stats("no LPI after device unmap");
7900ef02cd6SEric Auger 	report_prefix_pop();
7910ef02cd6SEric Auger }
79264260a5fSEric Auger 
79364260a5fSEric Auger static void test_its_migration(void)
79464260a5fSEric Auger {
79564260a5fSEric Auger 	struct its_device *dev2, *dev7;
79664260a5fSEric Auger 	bool test_skipped = false;
79764260a5fSEric Auger 
79864260a5fSEric Auger 	if (its_setup1()) {
79964260a5fSEric Auger 		test_skipped = true;
80064260a5fSEric Auger 		goto do_migrate;
80164260a5fSEric Auger 	}
80264260a5fSEric Auger 
80364260a5fSEric Auger 	dev2 = its_get_device(2);
80464260a5fSEric Auger 	dev7 = its_get_device(7);
80564260a5fSEric Auger 
80664260a5fSEric Auger do_migrate:
80764260a5fSEric Auger 	puts("Now migrate the VM, then press a key to continue...\n");
80864260a5fSEric Auger 	(void)getchar();
80964260a5fSEric Auger 	report_info("Migration complete");
81064260a5fSEric Auger 	if (test_skipped)
81164260a5fSEric Auger 		return;
81264260a5fSEric Auger 
81364260a5fSEric Auger 	lpi_stats_expect(3, 8195);
81464260a5fSEric Auger 	its_send_int(dev2, 20);
81564260a5fSEric Auger 	check_lpi_stats("dev2/eventid=20 triggers LPI 8195 on PE #3 after migration");
81664260a5fSEric Auger 
81764260a5fSEric Auger 	lpi_stats_expect(2, 8196);
81864260a5fSEric Auger 	its_send_int(dev7, 255);
81964260a5fSEric Auger 	check_lpi_stats("dev7/eventid=255 triggers LPI 8196 on PE #2 after migration");
82064260a5fSEric Auger }
821*de582149SEric Auger 
822*de582149SEric Auger #define ERRATA_UNMAPPED_COLLECTIONS "ERRATA_8c58be34494b"
823*de582149SEric Auger 
824*de582149SEric Auger static void test_migrate_unmapped_collection(void)
825*de582149SEric Auger {
826*de582149SEric Auger 	struct its_collection *col = NULL;
827*de582149SEric Auger 	struct its_device *dev2 = NULL, *dev7 = NULL;
828*de582149SEric Auger 	bool test_skipped = false;
829*de582149SEric Auger 	int pe0 = 0;
830*de582149SEric Auger 	u8 config;
831*de582149SEric Auger 
832*de582149SEric Auger 	if (its_setup1()) {
833*de582149SEric Auger 		test_skipped = true;
834*de582149SEric Auger 		goto do_migrate;
835*de582149SEric Auger 	}
836*de582149SEric Auger 
837*de582149SEric Auger 	if (!errata(ERRATA_UNMAPPED_COLLECTIONS)) {
838*de582149SEric Auger 		report_skip("Skipping test, as this test hangs without the fix. "
839*de582149SEric Auger 			    "Set %s=y to enable.", ERRATA_UNMAPPED_COLLECTIONS);
840*de582149SEric Auger 		test_skipped = true;
841*de582149SEric Auger 		goto do_migrate;
842*de582149SEric Auger 	}
843*de582149SEric Auger 
844*de582149SEric Auger 	col = its_create_collection(pe0, pe0);
845*de582149SEric Auger 	dev2 = its_get_device(2);
846*de582149SEric Auger 	dev7 = its_get_device(7);
847*de582149SEric Auger 
848*de582149SEric Auger 	/* MAPTI with the collection unmapped */
849*de582149SEric Auger 	its_send_mapti(dev2, 8192, 0, col);
850*de582149SEric Auger 	gicv3_lpi_set_config(8192, LPI_PROP_DEFAULT);
851*de582149SEric Auger 
852*de582149SEric Auger do_migrate:
853*de582149SEric Auger 	puts("Now migrate the VM, then press a key to continue...\n");
854*de582149SEric Auger 	(void)getchar();
855*de582149SEric Auger 	report_info("Migration complete");
856*de582149SEric Auger 	if (test_skipped)
857*de582149SEric Auger 		return;
858*de582149SEric Auger 
859*de582149SEric Auger 	/* on the destination, map the collection */
860*de582149SEric Auger 	its_send_mapc(col, true);
861*de582149SEric Auger 	its_send_invall(col);
862*de582149SEric Auger 
863*de582149SEric Auger 	lpi_stats_expect(2, 8196);
864*de582149SEric Auger 	its_send_int(dev7, 255);
865*de582149SEric Auger 	check_lpi_stats("dev7/eventid= 255 triggered LPI 8196 on PE #2");
866*de582149SEric Auger 
867*de582149SEric Auger 	config = gicv3_lpi_get_config(8192);
868*de582149SEric Auger 	report(config == LPI_PROP_DEFAULT,
869*de582149SEric Auger 	       "Config of LPI 8192 was properly migrated");
870*de582149SEric Auger 
871*de582149SEric Auger 	lpi_stats_expect(pe0, 8192);
872*de582149SEric Auger 	its_send_int(dev2, 0);
873*de582149SEric Auger 	check_lpi_stats("dev2/eventid = 0 triggered LPI 8192 on PE0");
874*de582149SEric Auger }
875*de582149SEric Auger 
876*de582149SEric Auger static void test_its_pending_migration(void)
877*de582149SEric Auger {
878*de582149SEric Auger 	struct its_device *dev;
879*de582149SEric Auger 	struct its_collection *collection[2];
880*de582149SEric Auger 	int *expected = calloc(nr_cpus, sizeof(int));
881*de582149SEric Auger 	int pe0 = nr_cpus - 1, pe1 = nr_cpus - 2;
882*de582149SEric Auger 	bool test_skipped = false;
883*de582149SEric Auger 	u64 pendbaser;
884*de582149SEric Auger 	void *ptr;
885*de582149SEric Auger 	int i;
886*de582149SEric Auger 
887*de582149SEric Auger 	if (its_prerequisites(4)) {
888*de582149SEric Auger 		test_skipped = true;
889*de582149SEric Auger 		goto do_migrate;
890*de582149SEric Auger 	}
891*de582149SEric Auger 
892*de582149SEric Auger 	dev = its_create_device(2 /* dev id */, 8 /* nb_ites */);
893*de582149SEric Auger 	its_send_mapd(dev, true);
894*de582149SEric Auger 
895*de582149SEric Auger 	collection[0] = its_create_collection(pe0, pe0);
896*de582149SEric Auger 	collection[1] = its_create_collection(pe1, pe1);
897*de582149SEric Auger 	its_send_mapc(collection[0], true);
898*de582149SEric Auger 	its_send_mapc(collection[1], true);
899*de582149SEric Auger 
900*de582149SEric Auger 	/* disable lpi at redist level */
901*de582149SEric Auger 	gicv3_lpi_rdist_disable(pe0);
902*de582149SEric Auger 	gicv3_lpi_rdist_disable(pe1);
903*de582149SEric Auger 
904*de582149SEric Auger 	/* lpis are interleaved inbetween the 2 PEs */
905*de582149SEric Auger 	for (i = 0; i < 256; i++) {
906*de582149SEric Auger 		struct its_collection *col = i % 2 ? collection[0] :
907*de582149SEric Auger 						     collection[1];
908*de582149SEric Auger 		int vcpu = col->target_address >> 16;
909*de582149SEric Auger 
910*de582149SEric Auger 		its_send_mapti(dev, LPI(i), i, col);
911*de582149SEric Auger 		gicv3_lpi_set_config(LPI(i), LPI_PROP_DEFAULT);
912*de582149SEric Auger 		gicv3_lpi_set_clr_pending(vcpu, LPI(i), true);
913*de582149SEric Auger 	}
914*de582149SEric Auger 	its_send_invall(collection[0]);
915*de582149SEric Auger 	its_send_invall(collection[1]);
916*de582149SEric Auger 
917*de582149SEric Auger 	/* Clear the PTZ bit on each pendbaser */
918*de582149SEric Auger 
919*de582149SEric Auger 	expected[pe0] = 128;
920*de582149SEric Auger 	expected[pe1] = 128;
921*de582149SEric Auger 
922*de582149SEric Auger 	ptr = gicv3_data.redist_base[pe0] + GICR_PENDBASER;
923*de582149SEric Auger 	pendbaser = readq(ptr);
924*de582149SEric Auger 	writeq(pendbaser & ~GICR_PENDBASER_PTZ, ptr);
925*de582149SEric Auger 
926*de582149SEric Auger 	ptr = gicv3_data.redist_base[pe1] + GICR_PENDBASER;
927*de582149SEric Auger 	pendbaser = readq(ptr);
928*de582149SEric Auger 	writeq(pendbaser & ~GICR_PENDBASER_PTZ, ptr);
929*de582149SEric Auger 
930*de582149SEric Auger 	gicv3_lpi_rdist_enable(pe0);
931*de582149SEric Auger 	gicv3_lpi_rdist_enable(pe1);
932*de582149SEric Auger 
933*de582149SEric Auger do_migrate:
934*de582149SEric Auger 	puts("Now migrate the VM, then press a key to continue...\n");
935*de582149SEric Auger 	(void)getchar();
936*de582149SEric Auger 	report_info("Migration complete");
937*de582149SEric Auger 	if (test_skipped)
938*de582149SEric Auger 		return;
939*de582149SEric Auger 
940*de582149SEric Auger 	/* let's wait for the 256 LPIs to be handled */
941*de582149SEric Auger 	mdelay(1000);
942*de582149SEric Auger 
943*de582149SEric Auger 	check_lpi_hits(expected, "128 LPIs on both PE0 and PE1 after migration");
944*de582149SEric Auger }
945ba74b106SEric Auger #endif
946ba74b106SEric Auger 
947ac4a67b6SAndrew Jones int main(int argc, char **argv)
948ac4a67b6SAndrew Jones {
9492e2d471dSAndrew Jones 	if (!gic_init()) {
950ac4a67b6SAndrew Jones 		printf("No supported gic present, skipping tests...\n");
951ac4a67b6SAndrew Jones 		return report_summary();
952ac4a67b6SAndrew Jones 	}
953ac4a67b6SAndrew Jones 
9542b19b829SAndrew Jones 	report_prefix_pushf("gicv%d", gic_version());
955ac4a67b6SAndrew Jones 
9562e2d471dSAndrew Jones 	switch (gic_version()) {
9572e2d471dSAndrew Jones 	case 2:
9582e2d471dSAndrew Jones 		gic = &gicv2;
9592e2d471dSAndrew Jones 		break;
9602e2d471dSAndrew Jones 	case 3:
9612e2d471dSAndrew Jones 		gic = &gicv3;
9622e2d471dSAndrew Jones 		break;
9632e2d471dSAndrew Jones 	}
9642e2d471dSAndrew Jones 
965ac4a67b6SAndrew Jones 	if (argc < 2)
966ac4a67b6SAndrew Jones 		report_abort("no test specified");
967ac4a67b6SAndrew Jones 
968ac4a67b6SAndrew Jones 	if (strcmp(argv[1], "ipi") == 0) {
969ac4a67b6SAndrew Jones 		report_prefix_push(argv[1]);
970ac4a67b6SAndrew Jones 		nr_cpu_check(2);
97100b34f56SAndrew Jones 		on_cpus(ipi_test, NULL);
972c152d8bcSChristoffer Dall 	} else if (strcmp(argv[1], "active") == 0) {
973c152d8bcSChristoffer Dall 		run_active_clear_test();
97478ad7e95SAndre Przywara 	} else if (strcmp(argv[1], "mmio") == 0) {
97578ad7e95SAndre Przywara 		report_prefix_push(argv[1]);
97678ad7e95SAndre Przywara 		gic_test_mmio();
97778ad7e95SAndre Przywara 		report_prefix_pop();
9780ef02cd6SEric Auger 	} else if (!strcmp(argv[1], "its-trigger")) {
9790ef02cd6SEric Auger 		report_prefix_push(argv[1]);
9800ef02cd6SEric Auger 		test_its_trigger();
9810ef02cd6SEric Auger 		report_prefix_pop();
98264260a5fSEric Auger 	} else if (!strcmp(argv[1], "its-migration")) {
98364260a5fSEric Auger 		report_prefix_push(argv[1]);
98464260a5fSEric Auger 		test_its_migration();
98564260a5fSEric Auger 		report_prefix_pop();
986*de582149SEric Auger 	} else if (!strcmp(argv[1], "its-pending-migration")) {
987*de582149SEric Auger 		report_prefix_push(argv[1]);
988*de582149SEric Auger 		test_its_pending_migration();
989*de582149SEric Auger 		report_prefix_pop();
990*de582149SEric Auger 	} else if (!strcmp(argv[1], "its-migrate-unmapped-collection")) {
991*de582149SEric Auger 		report_prefix_push(argv[1]);
992*de582149SEric Auger 		test_migrate_unmapped_collection();
993*de582149SEric Auger 		report_prefix_pop();
994ba74b106SEric Auger 	} else if (strcmp(argv[1], "its-introspection") == 0) {
995ba74b106SEric Auger 		report_prefix_push(argv[1]);
996ba74b106SEric Auger 		test_its_introspection();
997ba74b106SEric Auger 		report_prefix_pop();
998ac4a67b6SAndrew Jones 	} else {
999ac4a67b6SAndrew Jones 		report_abort("Unknown subtest '%s'", argv[1]);
1000ac4a67b6SAndrew Jones 	}
1001ac4a67b6SAndrew Jones 
1002ac4a67b6SAndrew Jones 	return report_summary();
1003ac4a67b6SAndrew Jones }
1004