xref: /kvm-unit-tests/arm/gic.c (revision 6163f75d09a0a96a5c3db82dd768b13f79629c00)
1 /*
2  * GIC tests
3  *
4  * GICv2
5  *   + test sending/receiving IPIs
6  *   + MMIO access tests
7  * GICv3
8  *   + test sending/receiving IPIs
9  *
10  * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
11  *
12  * This work is licensed under the terms of the GNU LGPL, version 2.
13  */
14 #include <libcflat.h>
15 #include <asm/setup.h>
16 #include <asm/processor.h>
17 #include <asm/delay.h>
18 #include <asm/gic.h>
19 #include <asm/smp.h>
20 #include <asm/barrier.h>
21 #include <asm/io.h>
22 
23 #define IPI_SENDER	1
24 #define IPI_IRQ		1
25 
26 struct gic {
27 	struct {
28 		void (*send_self)(void);
29 		void (*send_broadcast)(void);
30 	} ipi;
31 };
32 
33 static struct gic *gic;
34 static int acked[NR_CPUS], spurious[NR_CPUS];
35 static int bad_sender[NR_CPUS], bad_irq[NR_CPUS];
36 static cpumask_t ready;
37 
38 static void nr_cpu_check(int nr)
39 {
40 	if (nr_cpus < nr)
41 		report_abort("At least %d cpus required", nr);
42 }
43 
44 static void wait_on_ready(void)
45 {
46 	cpumask_set_cpu(smp_processor_id(), &ready);
47 	while (!cpumask_full(&ready))
48 		cpu_relax();
49 }
50 
51 static void stats_reset(void)
52 {
53 	int i;
54 
55 	for (i = 0; i < nr_cpus; ++i) {
56 		acked[i] = 0;
57 		bad_sender[i] = -1;
58 		bad_irq[i] = -1;
59 	}
60 	smp_wmb();
61 }
62 
63 static void check_acked(const char *testname, cpumask_t *mask)
64 {
65 	int missing = 0, extra = 0, unexpected = 0;
66 	int nr_pass, cpu, i;
67 	bool bad = false;
68 
69 	/* Wait up to 5s for all interrupts to be delivered */
70 	for (i = 0; i < 50; ++i) {
71 		mdelay(100);
72 		nr_pass = 0;
73 		for_each_present_cpu(cpu) {
74 			smp_rmb();
75 			nr_pass += cpumask_test_cpu(cpu, mask) ?
76 				acked[cpu] == 1 : acked[cpu] == 0;
77 
78 			if (bad_sender[cpu] != -1) {
79 				printf("cpu%d received IPI from wrong sender %d\n",
80 					cpu, bad_sender[cpu]);
81 				bad = true;
82 			}
83 
84 			if (bad_irq[cpu] != -1) {
85 				printf("cpu%d received wrong irq %d\n",
86 					cpu, bad_irq[cpu]);
87 				bad = true;
88 			}
89 		}
90 		if (nr_pass == nr_cpus) {
91 			report("%s", !bad, testname);
92 			if (i)
93 				report_info("took more than %d ms", i * 100);
94 			return;
95 		}
96 	}
97 
98 	for_each_present_cpu(cpu) {
99 		if (cpumask_test_cpu(cpu, mask)) {
100 			if (!acked[cpu])
101 				++missing;
102 			else if (acked[cpu] > 1)
103 				++extra;
104 		} else {
105 			if (acked[cpu])
106 				++unexpected;
107 		}
108 	}
109 
110 	report("%s", false, testname);
111 	report_info("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d",
112 		    missing, extra, unexpected);
113 }
114 
115 static void check_spurious(void)
116 {
117 	int cpu;
118 
119 	smp_rmb();
120 	for_each_present_cpu(cpu) {
121 		if (spurious[cpu])
122 			report_info("WARN: cpu%d got %d spurious interrupts",
123 				cpu, spurious[cpu]);
124 	}
125 }
126 
127 static void check_ipi_sender(u32 irqstat)
128 {
129 	if (gic_version() == 2) {
130 		int src = (irqstat >> 10) & 7;
131 
132 		if (src != IPI_SENDER)
133 			bad_sender[smp_processor_id()] = src;
134 	}
135 }
136 
137 static void check_irqnr(u32 irqnr)
138 {
139 	if (irqnr != IPI_IRQ)
140 		bad_irq[smp_processor_id()] = irqnr;
141 }
142 
143 static void ipi_handler(struct pt_regs *regs __unused)
144 {
145 	u32 irqstat = gic_read_iar();
146 	u32 irqnr = gic_iar_irqnr(irqstat);
147 
148 	if (irqnr != GICC_INT_SPURIOUS) {
149 		gic_write_eoir(irqstat);
150 		smp_rmb(); /* pairs with wmb in stats_reset */
151 		++acked[smp_processor_id()];
152 		check_ipi_sender(irqstat);
153 		check_irqnr(irqnr);
154 		smp_wmb(); /* pairs with rmb in check_acked */
155 	} else {
156 		++spurious[smp_processor_id()];
157 		smp_wmb();
158 	}
159 }
160 
161 static void gicv2_ipi_send_self(void)
162 {
163 	writel(2 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
164 }
165 
166 static void gicv2_ipi_send_broadcast(void)
167 {
168 	writel(1 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
169 }
170 
171 static void gicv3_ipi_send_self(void)
172 {
173 	gic_ipi_send_single(IPI_IRQ, smp_processor_id());
174 }
175 
176 static void gicv3_ipi_send_broadcast(void)
177 {
178 	gicv3_write_sgi1r(1ULL << 40 | IPI_IRQ << 24);
179 	isb();
180 }
181 
182 static void ipi_test_self(void)
183 {
184 	cpumask_t mask;
185 
186 	report_prefix_push("self");
187 	stats_reset();
188 	cpumask_clear(&mask);
189 	cpumask_set_cpu(smp_processor_id(), &mask);
190 	gic->ipi.send_self();
191 	check_acked("IPI: self", &mask);
192 	report_prefix_pop();
193 }
194 
195 static void ipi_test_smp(void)
196 {
197 	cpumask_t mask;
198 	int i;
199 
200 	report_prefix_push("target-list");
201 	stats_reset();
202 	cpumask_copy(&mask, &cpu_present_mask);
203 	for (i = smp_processor_id() & 1; i < nr_cpus; i += 2)
204 		cpumask_clear_cpu(i, &mask);
205 	gic_ipi_send_mask(IPI_IRQ, &mask);
206 	check_acked("IPI: directed", &mask);
207 	report_prefix_pop();
208 
209 	report_prefix_push("broadcast");
210 	stats_reset();
211 	cpumask_copy(&mask, &cpu_present_mask);
212 	cpumask_clear_cpu(smp_processor_id(), &mask);
213 	gic->ipi.send_broadcast();
214 	check_acked("IPI: broadcast", &mask);
215 	report_prefix_pop();
216 }
217 
218 static void ipi_enable(void)
219 {
220 	gic_enable_defaults();
221 #ifdef __arm__
222 	install_exception_handler(EXCPTN_IRQ, ipi_handler);
223 #else
224 	install_irq_handler(EL1H_IRQ, ipi_handler);
225 #endif
226 	local_irq_enable();
227 }
228 
229 static void ipi_send(void)
230 {
231 	ipi_enable();
232 	wait_on_ready();
233 	ipi_test_self();
234 	ipi_test_smp();
235 	check_spurious();
236 	exit(report_summary());
237 }
238 
239 static void ipi_recv(void)
240 {
241 	ipi_enable();
242 	cpumask_set_cpu(smp_processor_id(), &ready);
243 	while (1)
244 		wfi();
245 }
246 
247 static void ipi_test(void *data __unused)
248 {
249 	if (smp_processor_id() == IPI_SENDER)
250 		ipi_send();
251 	else
252 		ipi_recv();
253 }
254 
255 static struct gic gicv2 = {
256 	.ipi = {
257 		.send_self = gicv2_ipi_send_self,
258 		.send_broadcast = gicv2_ipi_send_broadcast,
259 	},
260 };
261 
262 static struct gic gicv3 = {
263 	.ipi = {
264 		.send_self = gicv3_ipi_send_self,
265 		.send_broadcast = gicv3_ipi_send_broadcast,
266 	},
267 };
268 
269 static void ipi_clear_active_handler(struct pt_regs *regs __unused)
270 {
271 	u32 irqstat = gic_read_iar();
272 	u32 irqnr = gic_iar_irqnr(irqstat);
273 
274 	if (irqnr != GICC_INT_SPURIOUS) {
275 		void *base;
276 		u32 val = 1 << IPI_IRQ;
277 
278 		if (gic_version() == 2)
279 			base = gicv2_dist_base();
280 		else
281 			base = gicv3_sgi_base();
282 
283 		writel(val, base + GICD_ICACTIVER);
284 
285 		smp_rmb(); /* pairs with wmb in stats_reset */
286 		++acked[smp_processor_id()];
287 		check_irqnr(irqnr);
288 		smp_wmb(); /* pairs with rmb in check_acked */
289 	} else {
290 		++spurious[smp_processor_id()];
291 		smp_wmb();
292 	}
293 }
294 
295 static void run_active_clear_test(void)
296 {
297 	report_prefix_push("active");
298 	gic_enable_defaults();
299 #ifdef __arm__
300 	install_exception_handler(EXCPTN_IRQ, ipi_clear_active_handler);
301 #else
302 	install_irq_handler(EL1H_IRQ, ipi_clear_active_handler);
303 #endif
304 	local_irq_enable();
305 
306 	ipi_test_self();
307 	report_prefix_pop();
308 }
309 
310 static bool test_ro_pattern_32(void *address, u32 pattern, u32 orig)
311 {
312 	u32 reg;
313 
314 	writel(pattern, address);
315 	reg = readl(address);
316 
317 	if (reg != orig)
318 		writel(orig, address);
319 
320 	return reg == orig;
321 }
322 
323 static bool test_readonly_32(void *address, bool razwi)
324 {
325 	u32 orig, pattern;
326 
327 	orig = readl(address);
328 	if (razwi && orig)
329 		return false;
330 
331 	pattern = 0xffffffff;
332 	if (orig != pattern) {
333 		if (!test_ro_pattern_32(address, pattern, orig))
334 			return false;
335 	}
336 
337 	pattern = 0xa5a55a5a;
338 	if (orig != pattern) {
339 		if (!test_ro_pattern_32(address, pattern, orig))
340 			return false;
341 	}
342 
343 	pattern = 0;
344 	if (orig != pattern) {
345 		if (!test_ro_pattern_32(address, pattern, orig))
346 			return false;
347 	}
348 
349 	return true;
350 }
351 
352 static void test_typer_v2(uint32_t reg)
353 {
354 	int nr_gic_cpus = ((reg >> 5) & 0x7) + 1;
355 
356 	report_info("nr_cpus=%d", nr_cpus);
357 	report("all CPUs have interrupts", nr_cpus == nr_gic_cpus);
358 }
359 
360 #define BYTE(reg32, byte) (((reg32) >> ((byte) * 8)) & 0xff)
361 #define REPLACE_BYTE(reg32, byte, new) (((reg32) & ~(0xff << ((byte) * 8))) |\
362 					((new) << ((byte) * 8)))
363 
364 /*
365  * Some registers are byte accessible, do a byte-wide read and write of known
366  * content to check for this.
367  * Apply a @mask to cater for special register properties.
368  * @pattern contains the value already in the register.
369  */
370 static void test_byte_access(void *base_addr, u32 pattern, u32 mask)
371 {
372 	u32 reg = readb(base_addr + 1);
373 	bool res;
374 
375 	res = (reg == (BYTE(pattern, 1) & (mask >> 8)));
376 	report("byte reads successful", res);
377 	if (!res)
378 		report_info("byte 1 of 0x%08x => 0x%02x", pattern & mask, reg);
379 
380 	pattern = REPLACE_BYTE(pattern, 2, 0x1f);
381 	writeb(BYTE(pattern, 2), base_addr + 2);
382 	reg = readl(base_addr);
383 	res = (reg == (pattern & mask));
384 	report("byte writes successful", res);
385 	if (!res)
386 		report_info("writing 0x%02x into bytes 2 => 0x%08x",
387 			    BYTE(pattern, 2), reg);
388 }
389 
390 static void test_priorities(int nr_irqs, void *priptr)
391 {
392 	u32 orig_prio, reg, pri_bits;
393 	u32 pri_mask, pattern;
394 	void *first_spi = priptr + GIC_FIRST_SPI;
395 
396 	orig_prio = readl(first_spi);
397 	report_prefix_push("IPRIORITYR");
398 
399 	/*
400 	 * Determine implemented number of priority bits by writing all 1's
401 	 * and checking the number of cleared bits in the value read back.
402 	 */
403 	writel(0xffffffff, first_spi);
404 	pri_mask = readl(first_spi);
405 
406 	reg = ~pri_mask;
407 	report("consistent priority masking",
408 	       (((reg >> 16) == (reg & 0xffff)) &&
409 	        ((reg & 0xff) == ((reg >> 8) & 0xff))));
410 	report_info("priority mask is 0x%08x", pri_mask);
411 
412 	reg = reg & 0xff;
413 	for (pri_bits = 8; reg & 1; reg >>= 1, pri_bits--)
414 		;
415 	report("implements at least 4 priority bits", pri_bits >= 4);
416 	report_info("%d priority bits implemented", pri_bits);
417 
418 	pattern = 0;
419 	writel(pattern, first_spi);
420 	report("clearing priorities", readl(first_spi) == pattern);
421 
422 	/* setting all priorities to their max valus was tested above */
423 
424 	report("accesses beyond limit RAZ/WI",
425 	       test_readonly_32(priptr + nr_irqs, true));
426 
427 	writel(pattern, priptr + nr_irqs - 4);
428 	report("accessing last SPIs",
429 	       readl(priptr + nr_irqs - 4) == (pattern & pri_mask));
430 
431 	pattern = 0xff7fbf3f;
432 	writel(pattern, first_spi);
433 	report("priorities are preserved",
434 	       readl(first_spi) == (pattern & pri_mask));
435 
436 	/* The PRIORITY registers are byte accessible. */
437 	test_byte_access(first_spi, pattern, pri_mask);
438 
439 	report_prefix_pop();
440 	writel(orig_prio, first_spi);
441 }
442 
443 /* GICD_ITARGETSR is only used by GICv2. */
444 static void test_targets(int nr_irqs)
445 {
446 	void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR;
447 	u32 orig_targets;
448 	u32 cpu_mask;
449 	u32 pattern, reg;
450 
451 	orig_targets = readl(targetsptr + GIC_FIRST_SPI);
452 	report_prefix_push("ITARGETSR");
453 
454 	cpu_mask = (1 << nr_cpus) - 1;
455 	cpu_mask |= cpu_mask << 8;
456 	cpu_mask |= cpu_mask << 16;
457 
458 	/* Check that bits for non implemented CPUs are RAZ/WI. */
459 	if (nr_cpus < 8) {
460 		writel(0xffffffff, targetsptr + GIC_FIRST_SPI);
461 		report("bits for non-existent CPUs masked",
462 		       !(readl(targetsptr + GIC_FIRST_SPI) & ~cpu_mask));
463 		report_info("%d non-existent CPUs", 8 - nr_cpus);
464 	} else {
465 		report_skip("CPU masking (all CPUs implemented)");
466 	}
467 
468 	report("accesses beyond limit RAZ/WI",
469 	       test_readonly_32(targetsptr + nr_irqs, true));
470 
471 	pattern = 0x0103020f;
472 	writel(pattern, targetsptr + GIC_FIRST_SPI);
473 	reg = readl(targetsptr + GIC_FIRST_SPI);
474 	report("register content preserved", reg == (pattern & cpu_mask));
475 	if (reg != (pattern & cpu_mask))
476 		report_info("writing %08x reads back as %08x",
477 			    pattern & cpu_mask, reg);
478 
479 	/* The TARGETS registers are byte accessible. */
480 	test_byte_access(targetsptr + GIC_FIRST_SPI, pattern, cpu_mask);
481 
482 	writel(orig_targets, targetsptr + GIC_FIRST_SPI);
483 
484 	report_prefix_pop();
485 }
486 
487 static void gic_test_mmio(void)
488 {
489 	u32 reg;
490 	int nr_irqs;
491 	void *gic_dist_base, *idreg;
492 
493 	switch(gic_version()) {
494 	case 0x2:
495 		gic_dist_base = gicv2_dist_base();
496 		idreg = gic_dist_base + GICD_ICPIDR2;
497 		break;
498 	case 0x3:
499 		report_abort("GICv3 MMIO tests NYI");
500 	default:
501 		report_abort("GIC version %d not supported", gic_version());
502 	}
503 
504 	reg = readl(gic_dist_base + GICD_TYPER);
505 	nr_irqs = GICD_TYPER_IRQS(reg);
506 	report_info("number of implemented SPIs: %d", nr_irqs - GIC_FIRST_SPI);
507 
508 	test_typer_v2(reg);
509 
510 	report_info("IIDR: 0x%08x", readl(gic_dist_base + GICD_IIDR));
511 
512 	report("GICD_TYPER is read-only",
513 	       test_readonly_32(gic_dist_base + GICD_TYPER, false));
514 	report("GICD_IIDR is read-only",
515 	       test_readonly_32(gic_dist_base + GICD_IIDR, false));
516 
517 	reg = readl(idreg);
518 	report("ICPIDR2 is read-only", test_readonly_32(idreg, false));
519 	report_info("value of ICPIDR2: 0x%08x", reg);
520 
521 	test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR);
522 
523 	if (gic_version() == 2)
524 		test_targets(nr_irqs);
525 }
526 
527 int main(int argc, char **argv)
528 {
529 	if (!gic_init()) {
530 		printf("No supported gic present, skipping tests...\n");
531 		return report_summary();
532 	}
533 
534 	report_prefix_pushf("gicv%d", gic_version());
535 
536 	switch (gic_version()) {
537 	case 2:
538 		gic = &gicv2;
539 		break;
540 	case 3:
541 		gic = &gicv3;
542 		break;
543 	}
544 
545 	if (argc < 2)
546 		report_abort("no test specified");
547 
548 	if (strcmp(argv[1], "ipi") == 0) {
549 		report_prefix_push(argv[1]);
550 		nr_cpu_check(2);
551 		on_cpus(ipi_test, NULL);
552 	} else if (strcmp(argv[1], "active") == 0) {
553 		run_active_clear_test();
554 	} else if (strcmp(argv[1], "mmio") == 0) {
555 		report_prefix_push(argv[1]);
556 		gic_test_mmio();
557 		report_prefix_pop();
558 	} else {
559 		report_abort("Unknown subtest '%s'", argv[1]);
560 	}
561 
562 	return report_summary();
563 }
564