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>
157cefda52SNico Boehr #include <migrate.h>
16de582149SEric Auger #include <errata.h>
17ac4a67b6SAndrew Jones #include <asm/setup.h>
18ac4a67b6SAndrew Jones #include <asm/processor.h>
19ac4a67b6SAndrew Jones #include <asm/delay.h>
20ac4a67b6SAndrew Jones #include <asm/gic.h>
21ba74b106SEric Auger #include <asm/gic-v3-its.h>
22ac4a67b6SAndrew Jones #include <asm/smp.h>
23ac4a67b6SAndrew Jones #include <asm/barrier.h>
24ac4a67b6SAndrew Jones #include <asm/io.h>
25ac4a67b6SAndrew Jones
26ca1b7a7bSAndrew Jones #define IPI_SENDER 1
27ca1b7a7bSAndrew Jones #define IPI_IRQ 1
28ca1b7a7bSAndrew Jones
292e2d471dSAndrew Jones struct gic {
302e2d471dSAndrew Jones struct {
312e2d471dSAndrew Jones void (*send_self)(void);
322e2d471dSAndrew Jones void (*send_broadcast)(void);
332e2d471dSAndrew Jones } ipi;
342e2d471dSAndrew Jones };
352e2d471dSAndrew Jones
362e2d471dSAndrew Jones static struct gic *gic;
37ac4a67b6SAndrew Jones static int acked[NR_CPUS], spurious[NR_CPUS];
380e0a39dfSAlexandru Elisei static int irq_sender[NR_CPUS], irq_number[NR_CPUS];
39ac4a67b6SAndrew Jones static cpumask_t ready;
40ac4a67b6SAndrew Jones
nr_cpu_check(int nr)41ac4a67b6SAndrew Jones static void nr_cpu_check(int nr)
42ac4a67b6SAndrew Jones {
43ac4a67b6SAndrew Jones if (nr_cpus < nr)
44ac4a67b6SAndrew Jones report_abort("At least %d cpus required", nr);
45ac4a67b6SAndrew Jones }
46ac4a67b6SAndrew Jones
wait_on_ready(void)47ac4a67b6SAndrew Jones static void wait_on_ready(void)
48ac4a67b6SAndrew Jones {
49ac4a67b6SAndrew Jones cpumask_set_cpu(smp_processor_id(), &ready);
50ac4a67b6SAndrew Jones while (!cpumask_full(&ready))
51ac4a67b6SAndrew Jones cpu_relax();
52ac4a67b6SAndrew Jones }
53ac4a67b6SAndrew Jones
stats_reset(void)54ca1b7a7bSAndrew Jones static void stats_reset(void)
55ca1b7a7bSAndrew Jones {
56ca1b7a7bSAndrew Jones int i;
57ca1b7a7bSAndrew Jones
58ca1b7a7bSAndrew Jones for (i = 0; i < nr_cpus; ++i) {
59ca1b7a7bSAndrew Jones acked[i] = 0;
600e0a39dfSAlexandru Elisei irq_sender[i] = -1;
610e0a39dfSAlexandru Elisei irq_number[i] = -1;
62ca1b7a7bSAndrew Jones }
63ca1b7a7bSAndrew Jones }
64ca1b7a7bSAndrew Jones
wait_for_interrupts(cpumask_t * mask)657af008b1SAlexandru Elisei static void wait_for_interrupts(cpumask_t *mask)
66ac4a67b6SAndrew Jones {
67ac4a67b6SAndrew Jones int nr_pass, cpu, i;
68ac4a67b6SAndrew Jones
69ac4a67b6SAndrew Jones /* Wait up to 5s for all interrupts to be delivered */
707af008b1SAlexandru Elisei for (i = 0; i < 50; i++) {
71ac4a67b6SAndrew Jones mdelay(100);
72ac4a67b6SAndrew Jones nr_pass = 0;
73ac4a67b6SAndrew Jones for_each_present_cpu(cpu) {
747af008b1SAlexandru Elisei /*
757af008b1SAlexandru Elisei * A CPU having received more than one interrupts will
767af008b1SAlexandru Elisei * show up in check_acked(), and no matter how long we
777af008b1SAlexandru Elisei * wait it cannot un-receive it. Consider at least one
787af008b1SAlexandru Elisei * interrupt as a pass.
797af008b1SAlexandru Elisei */
80ac4a67b6SAndrew Jones nr_pass += cpumask_test_cpu(cpu, mask) ?
817af008b1SAlexandru Elisei acked[cpu] >= 1 : acked[cpu] == 0;
82ca1b7a7bSAndrew Jones }
83ca1b7a7bSAndrew Jones
84ac4a67b6SAndrew Jones if (nr_pass == nr_cpus) {
8596edb026SAndre Przywara if (i)
867af008b1SAlexandru Elisei report_info("interrupts took more than %d ms", i * 100);
877af008b1SAlexandru Elisei /* Wait for unexpected interrupts to fire */
887af008b1SAlexandru Elisei mdelay(100);
89ac4a67b6SAndrew Jones return;
90ac4a67b6SAndrew Jones }
91ac4a67b6SAndrew Jones }
92ac4a67b6SAndrew Jones
937af008b1SAlexandru Elisei report_info("interrupts timed-out (5s)");
947af008b1SAlexandru Elisei }
957af008b1SAlexandru Elisei
check_acked(cpumask_t * mask,int sender,int irqnum)960e0a39dfSAlexandru Elisei static bool check_acked(cpumask_t *mask, int sender, int irqnum)
977af008b1SAlexandru Elisei {
987af008b1SAlexandru Elisei int missing = 0, extra = 0, unexpected = 0;
990e0a39dfSAlexandru Elisei bool has_gicv2 = (gic_version() == 2);
1007af008b1SAlexandru Elisei bool pass = true;
1017af008b1SAlexandru Elisei int cpu;
1027af008b1SAlexandru Elisei
103ac4a67b6SAndrew Jones for_each_present_cpu(cpu) {
104ac4a67b6SAndrew Jones if (cpumask_test_cpu(cpu, mask)) {
105ac4a67b6SAndrew Jones if (!acked[cpu])
106ac4a67b6SAndrew Jones ++missing;
107ac4a67b6SAndrew Jones else if (acked[cpu] > 1)
108ac4a67b6SAndrew Jones ++extra;
1091b3e4553SAlexandru Elisei } else if (acked[cpu]) {
110ac4a67b6SAndrew Jones ++unexpected;
111ac4a67b6SAndrew Jones }
1120e0a39dfSAlexandru Elisei if (!acked[cpu])
1130e0a39dfSAlexandru Elisei continue;
1141b3e4553SAlexandru Elisei smp_rmb(); /* pairs with smp_wmb in irq_handler */
1157af008b1SAlexandru Elisei
1160e0a39dfSAlexandru Elisei if (has_gicv2 && irq_sender[cpu] != sender) {
1177af008b1SAlexandru Elisei report_info("cpu%d received IPI from wrong sender %d",
1180e0a39dfSAlexandru Elisei cpu, irq_sender[cpu]);
1197af008b1SAlexandru Elisei pass = false;
120ac4a67b6SAndrew Jones }
121ac4a67b6SAndrew Jones
1220e0a39dfSAlexandru Elisei if (irq_number[cpu] != irqnum) {
1237af008b1SAlexandru Elisei report_info("cpu%d received wrong irq %d",
1240e0a39dfSAlexandru Elisei cpu, irq_number[cpu]);
1257af008b1SAlexandru Elisei pass = false;
1267af008b1SAlexandru Elisei }
1277af008b1SAlexandru Elisei }
1287af008b1SAlexandru Elisei
1297af008b1SAlexandru Elisei if (missing || extra || unexpected) {
1307af008b1SAlexandru Elisei report_info("ACKS: missing=%d extra=%d unexpected=%d",
13196edb026SAndre Przywara missing, extra, unexpected);
1327af008b1SAlexandru Elisei pass = false;
1337af008b1SAlexandru Elisei }
1347af008b1SAlexandru Elisei
1357af008b1SAlexandru Elisei return pass;
136ac4a67b6SAndrew Jones }
137ac4a67b6SAndrew Jones
check_spurious(void)138ac4a67b6SAndrew Jones static void check_spurious(void)
139ac4a67b6SAndrew Jones {
140ac4a67b6SAndrew Jones int cpu;
141ac4a67b6SAndrew Jones
142ac4a67b6SAndrew Jones for_each_present_cpu(cpu) {
143ac4a67b6SAndrew Jones if (spurious[cpu])
144ac4a67b6SAndrew Jones report_info("WARN: cpu%d got %d spurious interrupts",
145ac4a67b6SAndrew Jones cpu, spurious[cpu]);
146ac4a67b6SAndrew Jones }
147ac4a67b6SAndrew Jones }
148ac4a67b6SAndrew Jones
gic_get_sender(int irqstat)1490e0a39dfSAlexandru Elisei static int gic_get_sender(int irqstat)
150ca1b7a7bSAndrew Jones {
1510e0a39dfSAlexandru Elisei if (gic_version() == 2)
1521b3e4553SAlexandru Elisei /* GICC_IAR.CPUID is RAZ for non-SGIs */
1530e0a39dfSAlexandru Elisei return (irqstat >> 10) & 7;
1540e0a39dfSAlexandru Elisei return -1;
155ca1b7a7bSAndrew Jones }
156ca1b7a7bSAndrew Jones
irq_handler(struct pt_regs * regs __unused)1571b3e4553SAlexandru Elisei static void irq_handler(struct pt_regs *regs __unused)
158ac4a67b6SAndrew Jones {
1592e2d471dSAndrew Jones u32 irqstat = gic_read_iar();
1602e2d471dSAndrew Jones u32 irqnr = gic_iar_irqnr(irqstat);
1610e0a39dfSAlexandru Elisei int this_cpu = smp_processor_id();
162ac4a67b6SAndrew Jones
163ac4a67b6SAndrew Jones if (irqnr != GICC_INT_SPURIOUS) {
1642e2d471dSAndrew Jones gic_write_eoir(irqstat);
1650e0a39dfSAlexandru Elisei irq_sender[this_cpu] = gic_get_sender(irqstat);
1660e0a39dfSAlexandru Elisei irq_number[this_cpu] = irqnr;
167718d77f1SAlexandru Elisei smp_wmb(); /* pairs with smp_rmb in check_acked */
1680e0a39dfSAlexandru Elisei ++acked[this_cpu];
169ac4a67b6SAndrew Jones } else {
1700e0a39dfSAlexandru Elisei ++spurious[this_cpu];
171ac4a67b6SAndrew Jones }
172b3029e53SAlexandru Elisei
173b3029e53SAlexandru Elisei /* Wait for writes to acked/spurious to complete */
174b3029e53SAlexandru Elisei dsb(ishst);
175ac4a67b6SAndrew Jones }
176ac4a67b6SAndrew Jones
setup_irq(irq_handler_fn handler)1770ef02cd6SEric Auger static void setup_irq(irq_handler_fn handler)
1780ef02cd6SEric Auger {
1790ef02cd6SEric Auger gic_enable_defaults();
1800ef02cd6SEric Auger #ifdef __arm__
1810ef02cd6SEric Auger install_exception_handler(EXCPTN_IRQ, handler);
1820ef02cd6SEric Auger #else
1830ef02cd6SEric Auger install_irq_handler(EL1H_IRQ, handler);
1840ef02cd6SEric Auger #endif
1850ef02cd6SEric Auger local_irq_enable();
1860ef02cd6SEric Auger }
1870ef02cd6SEric Auger
1880ef02cd6SEric Auger #if defined(__aarch64__)
check_lpi_hits(int * expected,const char * msg)189de582149SEric Auger static void check_lpi_hits(int *expected, const char *msg)
190de582149SEric Auger {
191de582149SEric Auger bool pass = true;
192de582149SEric Auger int i;
193de582149SEric Auger
194de582149SEric Auger for_each_present_cpu(i) {
195de582149SEric Auger if (acked[i] != expected[i]) {
196de582149SEric Auger report_info("expected %d LPIs on PE #%d, %d observed",
197de582149SEric Auger expected[i], i, acked[i]);
198de582149SEric Auger pass = false;
199de582149SEric Auger break;
200de582149SEric Auger }
201de582149SEric Auger }
202de582149SEric Auger report(pass, "%s", msg);
203de582149SEric Auger }
2040ef02cd6SEric Auger #endif
2050ef02cd6SEric Auger
gicv2_ipi_send_self(void)2062e2d471dSAndrew Jones static void gicv2_ipi_send_self(void)
2072e2d471dSAndrew Jones {
20810e3685fSAlexandru Elisei /*
20910e3685fSAlexandru Elisei * The wmb() in writel and rmb() when acknowledging the interrupt are
21010e3685fSAlexandru Elisei * sufficient for ensuring that writes that happen in program order
21110e3685fSAlexandru Elisei * before the interrupt are observed in the interrupt handler after
21210e3685fSAlexandru Elisei * acknowledging the interrupt.
21310e3685fSAlexandru Elisei */
214ca1b7a7bSAndrew Jones writel(2 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
2152e2d471dSAndrew Jones }
2162e2d471dSAndrew Jones
gicv2_ipi_send_broadcast(void)2172e2d471dSAndrew Jones static void gicv2_ipi_send_broadcast(void)
2182e2d471dSAndrew Jones {
21910e3685fSAlexandru Elisei /* No barriers are needed, same situation as gicv2_ipi_send_self() */
220ca1b7a7bSAndrew Jones writel(1 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
2212e2d471dSAndrew Jones }
2222e2d471dSAndrew Jones
gicv3_ipi_send_self(void)2232e2d471dSAndrew Jones static void gicv3_ipi_send_self(void)
2242e2d471dSAndrew Jones {
225ca1b7a7bSAndrew Jones gic_ipi_send_single(IPI_IRQ, smp_processor_id());
2262e2d471dSAndrew Jones }
2272e2d471dSAndrew Jones
gicv3_ipi_send_broadcast(void)2282e2d471dSAndrew Jones static void gicv3_ipi_send_broadcast(void)
2292e2d471dSAndrew Jones {
2300c03f4b1SAlexandru Elisei /*
2310c03f4b1SAlexandru Elisei * Ensure stores to Normal memory are visible to other CPUs before
2320c03f4b1SAlexandru Elisei * sending the IPI
2330c03f4b1SAlexandru Elisei */
2340c03f4b1SAlexandru Elisei wmb();
235ca1b7a7bSAndrew Jones gicv3_write_sgi1r(1ULL << 40 | IPI_IRQ << 24);
2362e2d471dSAndrew Jones isb();
2372e2d471dSAndrew Jones }
2382e2d471dSAndrew Jones
ipi_test_self(void)239ac4a67b6SAndrew Jones static void ipi_test_self(void)
240ac4a67b6SAndrew Jones {
2410e0a39dfSAlexandru Elisei int this_cpu = smp_processor_id();
242ac4a67b6SAndrew Jones cpumask_t mask;
243ac4a67b6SAndrew Jones
244ac4a67b6SAndrew Jones report_prefix_push("self");
245ca1b7a7bSAndrew Jones stats_reset();
246ac4a67b6SAndrew Jones cpumask_clear(&mask);
2470e0a39dfSAlexandru Elisei cpumask_set_cpu(this_cpu, &mask);
2482e2d471dSAndrew Jones gic->ipi.send_self();
2497af008b1SAlexandru Elisei wait_for_interrupts(&mask);
2500e0a39dfSAlexandru Elisei report(check_acked(&mask, this_cpu, IPI_IRQ), "Interrupts received");
251ac4a67b6SAndrew Jones report_prefix_pop();
252ac4a67b6SAndrew Jones }
253ac4a67b6SAndrew Jones
ipi_test_smp(void)254ac4a67b6SAndrew Jones static void ipi_test_smp(void)
255ac4a67b6SAndrew Jones {
2560e0a39dfSAlexandru Elisei int this_cpu = smp_processor_id();
257ac4a67b6SAndrew Jones cpumask_t mask;
2582e2d471dSAndrew Jones int i;
259ac4a67b6SAndrew Jones
260ac4a67b6SAndrew Jones report_prefix_push("target-list");
261ca1b7a7bSAndrew Jones stats_reset();
2622e2d471dSAndrew Jones cpumask_copy(&mask, &cpu_present_mask);
2630e0a39dfSAlexandru Elisei for (i = this_cpu & 1; i < nr_cpus; i += 2)
2642e2d471dSAndrew Jones cpumask_clear_cpu(i, &mask);
265ca1b7a7bSAndrew Jones gic_ipi_send_mask(IPI_IRQ, &mask);
2667af008b1SAlexandru Elisei wait_for_interrupts(&mask);
2670e0a39dfSAlexandru Elisei report(check_acked(&mask, this_cpu, IPI_IRQ), "Interrupts received");
268ac4a67b6SAndrew Jones report_prefix_pop();
269ac4a67b6SAndrew Jones
270ac4a67b6SAndrew Jones report_prefix_push("broadcast");
271ca1b7a7bSAndrew Jones stats_reset();
272ac4a67b6SAndrew Jones cpumask_copy(&mask, &cpu_present_mask);
2730e0a39dfSAlexandru Elisei cpumask_clear_cpu(this_cpu, &mask);
2742e2d471dSAndrew Jones gic->ipi.send_broadcast();
2757af008b1SAlexandru Elisei wait_for_interrupts(&mask);
2760e0a39dfSAlexandru Elisei report(check_acked(&mask, this_cpu, IPI_IRQ), "Interrupts received");
277ac4a67b6SAndrew Jones report_prefix_pop();
278ac4a67b6SAndrew Jones }
279ac4a67b6SAndrew Jones
ipi_send(void)280ca1b7a7bSAndrew Jones static void ipi_send(void)
281ca1b7a7bSAndrew Jones {
2821b3e4553SAlexandru Elisei setup_irq(irq_handler);
283ca1b7a7bSAndrew Jones wait_on_ready();
284ca1b7a7bSAndrew Jones ipi_test_self();
285ca1b7a7bSAndrew Jones ipi_test_smp();
286ca1b7a7bSAndrew Jones check_spurious();
287ca1b7a7bSAndrew Jones exit(report_summary());
288ca1b7a7bSAndrew Jones }
289ca1b7a7bSAndrew Jones
irq_recv(void)2901b3e4553SAlexandru Elisei static void irq_recv(void)
291ac4a67b6SAndrew Jones {
2921b3e4553SAlexandru Elisei setup_irq(irq_handler);
293ac4a67b6SAndrew Jones cpumask_set_cpu(smp_processor_id(), &ready);
294ac4a67b6SAndrew Jones while (1)
295ac4a67b6SAndrew Jones wfi();
296ac4a67b6SAndrew Jones }
297ac4a67b6SAndrew Jones
ipi_test(void * data __unused)29800b34f56SAndrew Jones static void ipi_test(void *data __unused)
299bfd500b4SAndrew Jones {
300bfd500b4SAndrew Jones if (smp_processor_id() == IPI_SENDER)
301bfd500b4SAndrew Jones ipi_send();
302bfd500b4SAndrew Jones else
3031b3e4553SAlexandru Elisei irq_recv();
304bfd500b4SAndrew Jones }
305bfd500b4SAndrew Jones
3062e2d471dSAndrew Jones static struct gic gicv2 = {
3072e2d471dSAndrew Jones .ipi = {
3082e2d471dSAndrew Jones .send_self = gicv2_ipi_send_self,
3092e2d471dSAndrew Jones .send_broadcast = gicv2_ipi_send_broadcast,
3102e2d471dSAndrew Jones },
3112e2d471dSAndrew Jones };
3122e2d471dSAndrew Jones
3132e2d471dSAndrew Jones static struct gic gicv3 = {
3142e2d471dSAndrew Jones .ipi = {
3152e2d471dSAndrew Jones .send_self = gicv3_ipi_send_self,
3162e2d471dSAndrew Jones .send_broadcast = gicv3_ipi_send_broadcast,
3172e2d471dSAndrew Jones },
3182e2d471dSAndrew Jones };
3192e2d471dSAndrew Jones
320680beae9SAlexandru Elisei /* Runs on the same CPU as the sender, no need for memory synchronization */
ipi_clear_active_handler(struct pt_regs * regs __unused)321c152d8bcSChristoffer Dall static void ipi_clear_active_handler(struct pt_regs *regs __unused)
322c152d8bcSChristoffer Dall {
323c152d8bcSChristoffer Dall u32 irqstat = gic_read_iar();
324c152d8bcSChristoffer Dall u32 irqnr = gic_iar_irqnr(irqstat);
3250e0a39dfSAlexandru Elisei int this_cpu = smp_processor_id();
326c152d8bcSChristoffer Dall
327c152d8bcSChristoffer Dall if (irqnr != GICC_INT_SPURIOUS) {
328c152d8bcSChristoffer Dall void *base;
329c152d8bcSChristoffer Dall u32 val = 1 << IPI_IRQ;
330c152d8bcSChristoffer Dall
331c152d8bcSChristoffer Dall if (gic_version() == 2)
332c152d8bcSChristoffer Dall base = gicv2_dist_base();
333c152d8bcSChristoffer Dall else
3346d4d7c4bSAndrew Jones base = gicv3_sgi_base();
335c152d8bcSChristoffer Dall
336c152d8bcSChristoffer Dall writel(val, base + GICD_ICACTIVER);
337c152d8bcSChristoffer Dall
3380e0a39dfSAlexandru Elisei irq_sender[this_cpu] = gic_get_sender(irqstat);
3390e0a39dfSAlexandru Elisei irq_number[this_cpu] = irqnr;
3400e0a39dfSAlexandru Elisei ++acked[this_cpu];
341c152d8bcSChristoffer Dall } else {
3420e0a39dfSAlexandru Elisei ++spurious[this_cpu];
343c152d8bcSChristoffer Dall }
344c152d8bcSChristoffer Dall }
345c152d8bcSChristoffer Dall
run_active_clear_test(void)346c152d8bcSChristoffer Dall static void run_active_clear_test(void)
347c152d8bcSChristoffer Dall {
348c152d8bcSChristoffer Dall report_prefix_push("active");
34925f66327SEric Auger setup_irq(ipi_clear_active_handler);
350c152d8bcSChristoffer Dall ipi_test_self();
35164366016SAlexandru Elisei check_spurious();
352c152d8bcSChristoffer Dall report_prefix_pop();
353c152d8bcSChristoffer Dall }
354c152d8bcSChristoffer Dall
test_ro_pattern_32(void * address,u32 pattern,u32 orig)35578ad7e95SAndre Przywara static bool test_ro_pattern_32(void *address, u32 pattern, u32 orig)
35678ad7e95SAndre Przywara {
35778ad7e95SAndre Przywara u32 reg;
35878ad7e95SAndre Przywara
35978ad7e95SAndre Przywara writel(pattern, address);
36078ad7e95SAndre Przywara reg = readl(address);
36178ad7e95SAndre Przywara
36278ad7e95SAndre Przywara if (reg != orig)
36378ad7e95SAndre Przywara writel(orig, address);
36478ad7e95SAndre Przywara
36578ad7e95SAndre Przywara return reg == orig;
36678ad7e95SAndre Przywara }
36778ad7e95SAndre Przywara
test_readonly_32(void * address,bool razwi)36878ad7e95SAndre Przywara static bool test_readonly_32(void *address, bool razwi)
36978ad7e95SAndre Przywara {
37078ad7e95SAndre Przywara u32 orig, pattern;
37178ad7e95SAndre Przywara
37278ad7e95SAndre Przywara orig = readl(address);
37378ad7e95SAndre Przywara if (razwi && orig)
37478ad7e95SAndre Przywara return false;
37578ad7e95SAndre Przywara
37678ad7e95SAndre Przywara pattern = 0xffffffff;
37778ad7e95SAndre Przywara if (orig != pattern) {
37878ad7e95SAndre Przywara if (!test_ro_pattern_32(address, pattern, orig))
37978ad7e95SAndre Przywara return false;
38078ad7e95SAndre Przywara }
38178ad7e95SAndre Przywara
38278ad7e95SAndre Przywara pattern = 0xa5a55a5a;
38378ad7e95SAndre Przywara if (orig != pattern) {
38478ad7e95SAndre Przywara if (!test_ro_pattern_32(address, pattern, orig))
38578ad7e95SAndre Przywara return false;
38678ad7e95SAndre Przywara }
38778ad7e95SAndre Przywara
38878ad7e95SAndre Przywara pattern = 0;
38978ad7e95SAndre Przywara if (orig != pattern) {
39078ad7e95SAndre Przywara if (!test_ro_pattern_32(address, pattern, orig))
39178ad7e95SAndre Przywara return false;
39278ad7e95SAndre Przywara }
39378ad7e95SAndre Przywara
39478ad7e95SAndre Przywara return true;
39578ad7e95SAndre Przywara }
39678ad7e95SAndre Przywara
test_typer_v2(uint32_t reg)39778ad7e95SAndre Przywara static void test_typer_v2(uint32_t reg)
39878ad7e95SAndre Przywara {
39978ad7e95SAndre Przywara int nr_gic_cpus = ((reg >> 5) & 0x7) + 1;
40078ad7e95SAndre Przywara
4018e0a4f41SAndre Przywara report_info("nr_cpus=%d", nr_cpus);
402a299895bSThomas Huth report(nr_cpus == nr_gic_cpus, "all CPUs have interrupts");
40378ad7e95SAndre Przywara }
40478ad7e95SAndre Przywara
405ff31a1c4SAndre Przywara #define BYTE(reg32, byte) (((reg32) >> ((byte) * 8)) & 0xff)
406ff31a1c4SAndre Przywara #define REPLACE_BYTE(reg32, byte, new) (((reg32) & ~(0xff << ((byte) * 8))) |\
407ff31a1c4SAndre Przywara ((new) << ((byte) * 8)))
408ff31a1c4SAndre Przywara
409ff31a1c4SAndre Przywara /*
410ff31a1c4SAndre Przywara * Some registers are byte accessible, do a byte-wide read and write of known
411ff31a1c4SAndre Przywara * content to check for this.
412ff31a1c4SAndre Przywara * Apply a @mask to cater for special register properties.
413ff31a1c4SAndre Przywara * @pattern contains the value already in the register.
414ff31a1c4SAndre Przywara */
test_byte_access(void * base_addr,u32 pattern,u32 mask)415ff31a1c4SAndre Przywara static void test_byte_access(void *base_addr, u32 pattern, u32 mask)
416ff31a1c4SAndre Przywara {
417ff31a1c4SAndre Przywara u32 reg = readb(base_addr + 1);
4188e0a4f41SAndre Przywara bool res;
419ff31a1c4SAndre Przywara
4208e0a4f41SAndre Przywara res = (reg == (BYTE(pattern, 1) & (mask >> 8)));
421a299895bSThomas Huth report(res, "byte reads successful");
4228e0a4f41SAndre Przywara if (!res)
42346ca10f4SAlexandru Elisei report_info("byte 1 of 0x%08"PRIx32" => 0x%02"PRIx32, pattern & mask, reg);
424ff31a1c4SAndre Przywara
425ff31a1c4SAndre Przywara pattern = REPLACE_BYTE(pattern, 2, 0x1f);
426ff31a1c4SAndre Przywara writeb(BYTE(pattern, 2), base_addr + 2);
427ff31a1c4SAndre Przywara reg = readl(base_addr);
4288e0a4f41SAndre Przywara res = (reg == (pattern & mask));
429a299895bSThomas Huth report(res, "byte writes successful");
4308e0a4f41SAndre Przywara if (!res)
43146ca10f4SAlexandru Elisei report_info("writing 0x%02"PRIx32" into bytes 2 => 0x%08"PRIx32,
4328e0a4f41SAndre Przywara BYTE(pattern, 2), reg);
433ff31a1c4SAndre Przywara }
434ff31a1c4SAndre Przywara
test_priorities(int nr_irqs,void * priptr)435ff31a1c4SAndre Przywara static void test_priorities(int nr_irqs, void *priptr)
436ff31a1c4SAndre Przywara {
437ff31a1c4SAndre Przywara u32 orig_prio, reg, pri_bits;
438ff31a1c4SAndre Przywara u32 pri_mask, pattern;
439ff31a1c4SAndre Przywara void *first_spi = priptr + GIC_FIRST_SPI;
440ff31a1c4SAndre Przywara
441ff31a1c4SAndre Przywara orig_prio = readl(first_spi);
442ff31a1c4SAndre Przywara report_prefix_push("IPRIORITYR");
443ff31a1c4SAndre Przywara
444ff31a1c4SAndre Przywara /*
445ff31a1c4SAndre Przywara * Determine implemented number of priority bits by writing all 1's
446ff31a1c4SAndre Przywara * and checking the number of cleared bits in the value read back.
447ff31a1c4SAndre Przywara */
448ff31a1c4SAndre Przywara writel(0xffffffff, first_spi);
449ff31a1c4SAndre Przywara pri_mask = readl(first_spi);
450ff31a1c4SAndre Przywara
451ff31a1c4SAndre Przywara reg = ~pri_mask;
452a299895bSThomas Huth report((((reg >> 16) == (reg & 0xffff)) &&
453a299895bSThomas Huth ((reg & 0xff) == ((reg >> 8) & 0xff))),
454a299895bSThomas Huth "consistent priority masking");
45546ca10f4SAlexandru Elisei report_info("priority mask is 0x%08"PRIx32, pri_mask);
456ff31a1c4SAndre Przywara
457ff31a1c4SAndre Przywara reg = reg & 0xff;
458ff31a1c4SAndre Przywara for (pri_bits = 8; reg & 1; reg >>= 1, pri_bits--)
459ff31a1c4SAndre Przywara ;
460a299895bSThomas Huth report(pri_bits >= 4, "implements at least 4 priority bits");
46146ca10f4SAlexandru Elisei report_info("%"PRIu32" priority bits implemented", pri_bits);
462ff31a1c4SAndre Przywara
463ff31a1c4SAndre Przywara pattern = 0;
464ff31a1c4SAndre Przywara writel(pattern, first_spi);
465a299895bSThomas Huth report(readl(first_spi) == pattern, "clearing priorities");
466ff31a1c4SAndre Przywara
467ff31a1c4SAndre Przywara /* setting all priorities to their max valus was tested above */
468ff31a1c4SAndre Przywara
469a299895bSThomas Huth report(test_readonly_32(priptr + nr_irqs, true),
470a299895bSThomas Huth "accesses beyond limit RAZ/WI");
471ff31a1c4SAndre Przywara
472ff31a1c4SAndre Przywara writel(pattern, priptr + nr_irqs - 4);
473a299895bSThomas Huth report(readl(priptr + nr_irqs - 4) == (pattern & pri_mask),
474a299895bSThomas Huth "accessing last SPIs");
475ff31a1c4SAndre Przywara
476ff31a1c4SAndre Przywara pattern = 0xff7fbf3f;
477ff31a1c4SAndre Przywara writel(pattern, first_spi);
478a299895bSThomas Huth report(readl(first_spi) == (pattern & pri_mask),
479a299895bSThomas Huth "priorities are preserved");
480ff31a1c4SAndre Przywara
481ff31a1c4SAndre Przywara /* The PRIORITY registers are byte accessible. */
482ff31a1c4SAndre Przywara test_byte_access(first_spi, pattern, pri_mask);
483ff31a1c4SAndre Przywara
484ff31a1c4SAndre Przywara report_prefix_pop();
485ff31a1c4SAndre Przywara writel(orig_prio, first_spi);
486ff31a1c4SAndre Przywara }
487ff31a1c4SAndre Przywara
488fe572a5eSAndre Przywara /* GICD_ITARGETSR is only used by GICv2. */
test_targets(int nr_irqs)489fe572a5eSAndre Przywara static void test_targets(int nr_irqs)
490fe572a5eSAndre Przywara {
491fe572a5eSAndre Przywara void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR;
492fe572a5eSAndre Przywara u32 orig_targets;
493fe572a5eSAndre Przywara u32 cpu_mask;
494fe572a5eSAndre Przywara u32 pattern, reg;
495fe572a5eSAndre Przywara
496fe572a5eSAndre Przywara orig_targets = readl(targetsptr + GIC_FIRST_SPI);
497fe572a5eSAndre Przywara report_prefix_push("ITARGETSR");
498fe572a5eSAndre Przywara
499fe572a5eSAndre Przywara cpu_mask = (1 << nr_cpus) - 1;
500fe572a5eSAndre Przywara cpu_mask |= cpu_mask << 8;
501fe572a5eSAndre Przywara cpu_mask |= cpu_mask << 16;
502fe572a5eSAndre Przywara
503fe572a5eSAndre Przywara /* Check that bits for non implemented CPUs are RAZ/WI. */
504fe572a5eSAndre Przywara if (nr_cpus < 8) {
505fe572a5eSAndre Przywara writel(0xffffffff, targetsptr + GIC_FIRST_SPI);
506a299895bSThomas Huth report(!(readl(targetsptr + GIC_FIRST_SPI) & ~cpu_mask),
507a299895bSThomas Huth "bits for non-existent CPUs masked");
5088e0a4f41SAndre Przywara report_info("%d non-existent CPUs", 8 - nr_cpus);
509fe572a5eSAndre Przywara } else {
510fe572a5eSAndre Przywara report_skip("CPU masking (all CPUs implemented)");
511fe572a5eSAndre Przywara }
512fe572a5eSAndre Przywara
513a299895bSThomas Huth report(test_readonly_32(targetsptr + nr_irqs, true),
514a299895bSThomas Huth "accesses beyond limit RAZ/WI");
515fe572a5eSAndre Przywara
516fe572a5eSAndre Przywara pattern = 0x0103020f;
517fe572a5eSAndre Przywara writel(pattern, targetsptr + GIC_FIRST_SPI);
518fe572a5eSAndre Przywara reg = readl(targetsptr + GIC_FIRST_SPI);
519a299895bSThomas Huth report(reg == (pattern & cpu_mask), "register content preserved");
5208e0a4f41SAndre Przywara if (reg != (pattern & cpu_mask))
52146ca10f4SAlexandru Elisei report_info("writing %08"PRIx32" reads back as %08"PRIx32,
5228e0a4f41SAndre Przywara pattern & cpu_mask, reg);
523fe572a5eSAndre Przywara
524fe572a5eSAndre Przywara /* The TARGETS registers are byte accessible. */
525fe572a5eSAndre Przywara test_byte_access(targetsptr + GIC_FIRST_SPI, pattern, cpu_mask);
526fe572a5eSAndre Przywara
527fe572a5eSAndre Przywara writel(orig_targets, targetsptr + GIC_FIRST_SPI);
528da5b8576SAndre Przywara
529da5b8576SAndre Przywara report_prefix_pop();
530fe572a5eSAndre Przywara }
531fe572a5eSAndre Przywara
gic_test_mmio(void)53278ad7e95SAndre Przywara static void gic_test_mmio(void)
53378ad7e95SAndre Przywara {
53478ad7e95SAndre Przywara u32 reg;
53578ad7e95SAndre Przywara int nr_irqs;
53678ad7e95SAndre Przywara void *gic_dist_base, *idreg;
53778ad7e95SAndre Przywara
53878ad7e95SAndre Przywara switch(gic_version()) {
53978ad7e95SAndre Przywara case 0x2:
54078ad7e95SAndre Przywara gic_dist_base = gicv2_dist_base();
54178ad7e95SAndre Przywara idreg = gic_dist_base + GICD_ICPIDR2;
54278ad7e95SAndre Przywara break;
54378ad7e95SAndre Przywara case 0x3:
54478ad7e95SAndre Przywara report_abort("GICv3 MMIO tests NYI");
54578ad7e95SAndre Przywara default:
54678ad7e95SAndre Przywara report_abort("GIC version %d not supported", gic_version());
54778ad7e95SAndre Przywara }
54878ad7e95SAndre Przywara
54978ad7e95SAndre Przywara reg = readl(gic_dist_base + GICD_TYPER);
55078ad7e95SAndre Przywara nr_irqs = GICD_TYPER_IRQS(reg);
55178ad7e95SAndre Przywara report_info("number of implemented SPIs: %d", nr_irqs - GIC_FIRST_SPI);
55278ad7e95SAndre Przywara
55378ad7e95SAndre Przywara test_typer_v2(reg);
55478ad7e95SAndre Przywara
55546ca10f4SAlexandru Elisei report_info("IIDR: 0x%08"PRIx32, readl(gic_dist_base + GICD_IIDR));
55678ad7e95SAndre Przywara
557a299895bSThomas Huth report(test_readonly_32(gic_dist_base + GICD_TYPER, false),
558a299895bSThomas Huth "GICD_TYPER is read-only");
559a299895bSThomas Huth report(test_readonly_32(gic_dist_base + GICD_IIDR, false),
560a299895bSThomas Huth "GICD_IIDR is read-only");
56178ad7e95SAndre Przywara
56278ad7e95SAndre Przywara reg = readl(idreg);
563a299895bSThomas Huth report(test_readonly_32(idreg, false), "ICPIDR2 is read-only");
56446ca10f4SAlexandru Elisei report_info("value of ICPIDR2: 0x%08"PRIx32, reg);
565ff31a1c4SAndre Przywara
566ff31a1c4SAndre Przywara test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR);
567fe572a5eSAndre Przywara
568fe572a5eSAndre Przywara if (gic_version() == 2)
569fe572a5eSAndre Przywara test_targets(nr_irqs);
57078ad7e95SAndre Przywara }
57178ad7e95SAndre Przywara
572ba74b106SEric Auger #if defined(__arm__)
573ba74b106SEric Auger
test_its_introspection(void)574ba74b106SEric Auger static void test_its_introspection(void) {}
test_its_trigger(void)5750ef02cd6SEric Auger static void test_its_trigger(void) {}
test_its_migration(void)57664260a5fSEric Auger static void test_its_migration(void) {}
test_its_pending_migration(void)577de582149SEric Auger static void test_its_pending_migration(void) {}
test_migrate_unmapped_collection(void)578de582149SEric Auger static void test_migrate_unmapped_collection(void) {}
579ba74b106SEric Auger
580ba74b106SEric Auger #else /* __aarch64__ */
581ba74b106SEric Auger
test_its_introspection(void)582ba74b106SEric Auger static void test_its_introspection(void)
583ba74b106SEric Auger {
584ba74b106SEric Auger struct its_baser *dev_baser = &its_data.device_baser;
585ba74b106SEric Auger struct its_baser *coll_baser = &its_data.coll_baser;
586ba74b106SEric Auger struct its_typer *typer = &its_data.typer;
587ba74b106SEric Auger
588ba74b106SEric Auger if (!gicv3_its_base()) {
589ba74b106SEric Auger report_skip("No ITS, skip ...");
590ba74b106SEric Auger return;
591ba74b106SEric Auger }
592ba74b106SEric Auger
593ba74b106SEric Auger /* IIDR */
594ba74b106SEric Auger report(test_readonly_32(gicv3_its_base() + GITS_IIDR, false),
595ba74b106SEric Auger "GITS_IIDR is read-only"),
596ba74b106SEric Auger
597ba74b106SEric Auger /* TYPER */
598ba74b106SEric Auger report(test_readonly_32(gicv3_its_base() + GITS_TYPER, false),
599ba74b106SEric Auger "GITS_TYPER is read-only");
600ba74b106SEric Auger
601ba74b106SEric Auger report(typer->phys_lpi, "ITS supports physical LPIs");
602ba74b106SEric Auger report_info("vLPI support: %s", typer->virt_lpi ? "yes" : "no");
603ba74b106SEric Auger report_info("ITT entry size = 0x%x", typer->ite_size);
604ba74b106SEric Auger report_info("Bit Count: EventID=%d DeviceId=%d CollId=%d",
605ba74b106SEric Auger typer->eventid_bits, typer->deviceid_bits,
606ba74b106SEric Auger typer->collid_bits);
607ba74b106SEric Auger report(typer->eventid_bits && typer->deviceid_bits &&
608ba74b106SEric Auger typer->collid_bits, "ID spaces");
609ba74b106SEric Auger report_info("Target address format %s",
610ba74b106SEric Auger typer->pta ? "Redist base address" : "PE #");
611ba74b106SEric Auger
612ba74b106SEric Auger report(dev_baser && coll_baser, "detect device and collection BASER");
613ba74b106SEric Auger report_info("device table entry_size = 0x%x", dev_baser->esz);
614ba74b106SEric Auger report_info("collection table entry_size = 0x%x", coll_baser->esz);
615ba74b106SEric Auger }
616ba74b106SEric Auger
its_prerequisites(int nb_cpus)6170ef02cd6SEric Auger static int its_prerequisites(int nb_cpus)
6180ef02cd6SEric Auger {
6190ef02cd6SEric Auger int cpu;
6200ef02cd6SEric Auger
6210ef02cd6SEric Auger if (!gicv3_its_base()) {
6220ef02cd6SEric Auger report_skip("No ITS, skip ...");
6230ef02cd6SEric Auger return -1;
6240ef02cd6SEric Auger }
6250ef02cd6SEric Auger
6260ef02cd6SEric Auger if (nr_cpus < nb_cpus) {
6270ef02cd6SEric Auger report_skip("Test requires at least %d vcpus", nb_cpus);
6280ef02cd6SEric Auger return -1;
6290ef02cd6SEric Auger }
6300ef02cd6SEric Auger
6311b3e4553SAlexandru Elisei setup_irq(irq_handler);
6320ef02cd6SEric Auger
6330ef02cd6SEric Auger for_each_present_cpu(cpu) {
6340ef02cd6SEric Auger if (cpu == 0)
6350ef02cd6SEric Auger continue;
6361b3e4553SAlexandru Elisei smp_boot_secondary(cpu, irq_recv);
6370ef02cd6SEric Auger }
6380ef02cd6SEric Auger wait_on_ready();
6390ef02cd6SEric Auger
6400ef02cd6SEric Auger its_enable_defaults();
6410ef02cd6SEric Auger
6420ef02cd6SEric Auger return 0;
6430ef02cd6SEric Auger }
6440ef02cd6SEric Auger
64564260a5fSEric Auger /*
64664260a5fSEric Auger * Setup the configuration for those mappings:
64764260a5fSEric Auger * dev_id=2 event=20 -> vcpu 3, intid=8195
64864260a5fSEric Auger * dev_id=7 event=255 -> vcpu 2, intid=8196
64964260a5fSEric Auger * LPIs ready to hit
65064260a5fSEric Auger */
its_setup1(void)65164260a5fSEric Auger static int its_setup1(void)
6520ef02cd6SEric Auger {
6530ef02cd6SEric Auger struct its_collection *col3, *col2;
6540ef02cd6SEric Auger struct its_device *dev2, *dev7;
6550ef02cd6SEric Auger
6560ef02cd6SEric Auger if (its_prerequisites(4))
65764260a5fSEric Auger return -1;
6580ef02cd6SEric Auger
6590ef02cd6SEric Auger dev2 = its_create_device(2 /* dev id */, 8 /* nb_ites */);
6600ef02cd6SEric Auger dev7 = its_create_device(7 /* dev id */, 8 /* nb_ites */);
6610ef02cd6SEric Auger
6620ef02cd6SEric Auger col3 = its_create_collection(3 /* col id */, 3/* target PE */);
6630ef02cd6SEric Auger col2 = its_create_collection(2 /* col id */, 2/* target PE */);
6640ef02cd6SEric Auger
6650ef02cd6SEric Auger gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT);
6660ef02cd6SEric Auger gicv3_lpi_set_config(8196, LPI_PROP_DEFAULT);
6670ef02cd6SEric Auger
6680ef02cd6SEric Auger /*
6690ef02cd6SEric Auger * dev=2, eventid=20 -> lpi= 8195, col=3
6700ef02cd6SEric Auger * dev=7, eventid=255 -> lpi= 8196, col=2
6710ef02cd6SEric Auger */
6720ef02cd6SEric Auger its_send_mapd(dev2, true);
6730ef02cd6SEric Auger its_send_mapd(dev7, true);
6740ef02cd6SEric Auger
6750ef02cd6SEric Auger its_send_mapc(col3, true);
6760ef02cd6SEric Auger its_send_mapc(col2, true);
6770ef02cd6SEric Auger
6780ef02cd6SEric Auger its_send_invall(col2);
6790ef02cd6SEric Auger its_send_invall(col3);
6800ef02cd6SEric Auger
6810ef02cd6SEric Auger its_send_mapti(dev2, 8195 /* lpi id */, 20 /* event id */, col3);
6820ef02cd6SEric Auger its_send_mapti(dev7, 8196 /* lpi id */, 255 /* event id */, col2);
68364260a5fSEric Auger return 0;
68464260a5fSEric Auger }
68564260a5fSEric Auger
test_its_trigger(void)68664260a5fSEric Auger static void test_its_trigger(void)
68764260a5fSEric Auger {
68864260a5fSEric Auger struct its_collection *col3;
68964260a5fSEric Auger struct its_device *dev2, *dev7;
6901b3e4553SAlexandru Elisei cpumask_t mask;
69164260a5fSEric Auger
69264260a5fSEric Auger if (its_setup1())
69364260a5fSEric Auger return;
69464260a5fSEric Auger
69564260a5fSEric Auger col3 = its_get_collection(3);
69664260a5fSEric Auger dev2 = its_get_device(2);
69764260a5fSEric Auger dev7 = its_get_device(7);
69864260a5fSEric Auger
69964260a5fSEric Auger report_prefix_push("int");
7000ef02cd6SEric Auger
7011b3e4553SAlexandru Elisei stats_reset();
7021b3e4553SAlexandru Elisei cpumask_clear(&mask);
7031b3e4553SAlexandru Elisei cpumask_set_cpu(3, &mask);
7040ef02cd6SEric Auger its_send_int(dev2, 20);
7051b3e4553SAlexandru Elisei wait_for_interrupts(&mask);
7061b3e4553SAlexandru Elisei report(check_acked(&mask, 0, 8195),
7071b3e4553SAlexandru Elisei "dev=2, eventid=20 -> lpi= 8195, col=3");
7080ef02cd6SEric Auger
7091b3e4553SAlexandru Elisei stats_reset();
7101b3e4553SAlexandru Elisei cpumask_clear(&mask);
7111b3e4553SAlexandru Elisei cpumask_set_cpu(2, &mask);
7120ef02cd6SEric Auger its_send_int(dev7, 255);
7131b3e4553SAlexandru Elisei wait_for_interrupts(&mask);
7141b3e4553SAlexandru Elisei report(check_acked(&mask, 0, 8196),
7151b3e4553SAlexandru Elisei "dev=7, eventid=255 -> lpi= 8196, col=2");
7160ef02cd6SEric Auger
7170ef02cd6SEric Auger report_prefix_pop();
7180ef02cd6SEric Auger
7190ef02cd6SEric Auger report_prefix_push("inv/invall");
7200ef02cd6SEric Auger
7210ef02cd6SEric Auger /*
7220ef02cd6SEric Auger * disable 8195, check dev2/eventid=20 does not trigger the
7230ef02cd6SEric Auger * corresponding LPI
7240ef02cd6SEric Auger */
7250ef02cd6SEric Auger gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT & ~LPI_PROP_ENABLED);
7260ef02cd6SEric Auger its_send_inv(dev2, 20);
7270ef02cd6SEric Auger
7281b3e4553SAlexandru Elisei stats_reset();
7291b3e4553SAlexandru Elisei cpumask_clear(&mask);
7300ef02cd6SEric Auger its_send_int(dev2, 20);
7311b3e4553SAlexandru Elisei wait_for_interrupts(&mask);
7321b3e4553SAlexandru Elisei report(check_acked(&mask, -1, -1),
7331b3e4553SAlexandru Elisei "dev2/eventid=20 does not trigger any LPI");
7340ef02cd6SEric Auger
7350ef02cd6SEric Auger /*
73610396befSAlex Bennée * re-enable the LPI. While "A change to the LPI configuration
73710396befSAlex Bennée * is not guaranteed to be visible until an appropriate
73810396befSAlex Bennée * invalidation operation has completed" hardware that doesn't
73910396befSAlex Bennée * implement caches may have delivered the event at any point
74010396befSAlex Bennée * after the enabling. Check the LPI has hit by the time the
74110396befSAlex Bennée * invall is done.
7420ef02cd6SEric Auger */
7430ef02cd6SEric Auger gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT);
7441b3e4553SAlexandru Elisei stats_reset();
7451b3e4553SAlexandru Elisei cpumask_clear(&mask);
7460ef02cd6SEric Auger its_send_int(dev2, 20);
7471b3e4553SAlexandru Elisei cpumask_set_cpu(3, &mask);
7480ef02cd6SEric Auger its_send_invall(col3);
7491b3e4553SAlexandru Elisei wait_for_interrupts(&mask);
7501b3e4553SAlexandru Elisei report(check_acked(&mask, 0, 8195),
7511b3e4553SAlexandru Elisei "dev2/eventid=20 pending LPI is received");
752ae7dac4eSAlexandru Elisei
7531b3e4553SAlexandru Elisei stats_reset();
7541b3e4553SAlexandru Elisei cpumask_clear(&mask);
7551b3e4553SAlexandru Elisei cpumask_set_cpu(3, &mask);
7560ef02cd6SEric Auger its_send_int(dev2, 20);
7571b3e4553SAlexandru Elisei wait_for_interrupts(&mask);
7581b3e4553SAlexandru Elisei report(check_acked(&mask, 0, 8195),
7591b3e4553SAlexandru Elisei "dev2/eventid=20 now triggers an LPI");
7600ef02cd6SEric Auger
7610ef02cd6SEric Auger report_prefix_pop();
7620ef02cd6SEric Auger
7630ef02cd6SEric Auger report_prefix_push("mapd valid=false");
7640ef02cd6SEric Auger /*
7650ef02cd6SEric Auger * Unmap device 2 and check the eventid 20 formerly
7660ef02cd6SEric Auger * attached to it does not hit anymore
7670ef02cd6SEric Auger */
7680ef02cd6SEric Auger
7690ef02cd6SEric Auger its_send_mapd(dev2, false);
7701b3e4553SAlexandru Elisei stats_reset();
7711b3e4553SAlexandru Elisei cpumask_clear(&mask);
7720ef02cd6SEric Auger its_send_int(dev2, 20);
7731b3e4553SAlexandru Elisei wait_for_interrupts(&mask);
7741b3e4553SAlexandru Elisei report(check_acked(&mask, -1, -1), "no LPI after device unmap");
7751b3e4553SAlexandru Elisei
7761b3e4553SAlexandru Elisei check_spurious();
7770ef02cd6SEric Auger report_prefix_pop();
7780ef02cd6SEric Auger }
77964260a5fSEric Auger
test_its_migration(void)78064260a5fSEric Auger static void test_its_migration(void)
78164260a5fSEric Auger {
78264260a5fSEric Auger struct its_device *dev2, *dev7;
7831b3e4553SAlexandru Elisei cpumask_t mask;
78464260a5fSEric Auger
785e6e1a201SNicholas Piggin if (its_setup1()) {
786e6e1a201SNicholas Piggin migrate_skip();
7877cefda52SNico Boehr return;
788e6e1a201SNicholas Piggin }
78964260a5fSEric Auger
79064260a5fSEric Auger dev2 = its_get_device(2);
79164260a5fSEric Auger dev7 = its_get_device(7);
79264260a5fSEric Auger
793e6e1a201SNicholas Piggin migrate();
79464260a5fSEric Auger
7951b3e4553SAlexandru Elisei stats_reset();
7961b3e4553SAlexandru Elisei cpumask_clear(&mask);
7971b3e4553SAlexandru Elisei cpumask_set_cpu(3, &mask);
79864260a5fSEric Auger its_send_int(dev2, 20);
7991b3e4553SAlexandru Elisei wait_for_interrupts(&mask);
8001b3e4553SAlexandru Elisei report(check_acked(&mask, 0, 8195),
8011b3e4553SAlexandru Elisei "dev2/eventid=20 triggers LPI 8195 on PE #3 after migration");
80264260a5fSEric Auger
8031b3e4553SAlexandru Elisei stats_reset();
8041b3e4553SAlexandru Elisei cpumask_clear(&mask);
8051b3e4553SAlexandru Elisei cpumask_set_cpu(2, &mask);
80664260a5fSEric Auger its_send_int(dev7, 255);
8071b3e4553SAlexandru Elisei wait_for_interrupts(&mask);
8081b3e4553SAlexandru Elisei report(check_acked(&mask, 0, 8196),
8091b3e4553SAlexandru Elisei "dev7/eventid=255 triggers LPI 8196 on PE #2 after migration");
8101b3e4553SAlexandru Elisei
8111b3e4553SAlexandru Elisei check_spurious();
81264260a5fSEric Auger }
813de582149SEric Auger
814de582149SEric Auger #define ERRATA_UNMAPPED_COLLECTIONS "ERRATA_8c58be34494b"
815de582149SEric Auger
test_migrate_unmapped_collection(void)816de582149SEric Auger static void test_migrate_unmapped_collection(void)
817de582149SEric Auger {
818de582149SEric Auger struct its_collection *col = NULL;
819de582149SEric Auger struct its_device *dev2 = NULL, *dev7 = NULL;
8201b3e4553SAlexandru Elisei cpumask_t mask;
821de582149SEric Auger int pe0 = 0;
822de582149SEric Auger u8 config;
823de582149SEric Auger
824e6e1a201SNicholas Piggin if (its_setup1()) {
825e6e1a201SNicholas Piggin migrate_skip();
8267cefda52SNico Boehr return;
827e6e1a201SNicholas Piggin }
828de582149SEric Auger
829de582149SEric Auger if (!errata(ERRATA_UNMAPPED_COLLECTIONS)) {
830de582149SEric Auger report_skip("Skipping test, as this test hangs without the fix. "
831de582149SEric Auger "Set %s=y to enable.", ERRATA_UNMAPPED_COLLECTIONS);
832*71e899d9SJan Richter migrate_skip();
8337cefda52SNico Boehr return;
834de582149SEric Auger }
835de582149SEric Auger
836de582149SEric Auger col = its_create_collection(pe0, pe0);
837de582149SEric Auger dev2 = its_get_device(2);
838de582149SEric Auger dev7 = its_get_device(7);
839de582149SEric Auger
840de582149SEric Auger /* MAPTI with the collection unmapped */
841de582149SEric Auger its_send_mapti(dev2, 8192, 0, col);
842de582149SEric Auger gicv3_lpi_set_config(8192, LPI_PROP_DEFAULT);
843de582149SEric Auger
844e6e1a201SNicholas Piggin migrate();
845de582149SEric Auger
846de582149SEric Auger /* on the destination, map the collection */
847de582149SEric Auger its_send_mapc(col, true);
848de582149SEric Auger its_send_invall(col);
849de582149SEric Auger
8501b3e4553SAlexandru Elisei stats_reset();
8511b3e4553SAlexandru Elisei cpumask_clear(&mask);
8521b3e4553SAlexandru Elisei cpumask_set_cpu(2, &mask);
853de582149SEric Auger its_send_int(dev7, 255);
8541b3e4553SAlexandru Elisei wait_for_interrupts(&mask);
8551b3e4553SAlexandru Elisei report(check_acked(&mask, 0, 8196),
8561b3e4553SAlexandru Elisei "dev7/eventid= 255 triggered LPI 8196 on PE #2");
857de582149SEric Auger
858de582149SEric Auger config = gicv3_lpi_get_config(8192);
859de582149SEric Auger report(config == LPI_PROP_DEFAULT,
860de582149SEric Auger "Config of LPI 8192 was properly migrated");
861de582149SEric Auger
8621b3e4553SAlexandru Elisei stats_reset();
8631b3e4553SAlexandru Elisei cpumask_clear(&mask);
8641b3e4553SAlexandru Elisei cpumask_set_cpu(pe0, &mask);
865de582149SEric Auger its_send_int(dev2, 0);
8661b3e4553SAlexandru Elisei wait_for_interrupts(&mask);
8671b3e4553SAlexandru Elisei report(check_acked(&mask, 0, 8192),
8681b3e4553SAlexandru Elisei "dev2/eventid = 0 triggered LPI 8192 on PE0");
8691b3e4553SAlexandru Elisei
8701b3e4553SAlexandru Elisei check_spurious();
871de582149SEric Auger }
872de582149SEric Auger
test_its_pending_migration(void)873de582149SEric Auger static void test_its_pending_migration(void)
874de582149SEric Auger {
875de582149SEric Auger struct its_device *dev;
876de582149SEric Auger struct its_collection *collection[2];
877de582149SEric Auger int *expected = calloc(nr_cpus, sizeof(int));
878de582149SEric Auger int pe0 = nr_cpus - 1, pe1 = nr_cpus - 2;
879de582149SEric Auger u64 pendbaser;
880de582149SEric Auger void *ptr;
881de582149SEric Auger int i;
882de582149SEric Auger
883e6e1a201SNicholas Piggin if (its_prerequisites(4)) {
884e6e1a201SNicholas Piggin migrate_skip();
8857cefda52SNico Boehr return;
886e6e1a201SNicholas Piggin }
887de582149SEric Auger
888de582149SEric Auger dev = its_create_device(2 /* dev id */, 8 /* nb_ites */);
889de582149SEric Auger its_send_mapd(dev, true);
890de582149SEric Auger
891de582149SEric Auger collection[0] = its_create_collection(pe0, pe0);
892de582149SEric Auger collection[1] = its_create_collection(pe1, pe1);
893de582149SEric Auger its_send_mapc(collection[0], true);
894de582149SEric Auger its_send_mapc(collection[1], true);
895de582149SEric Auger
896de582149SEric Auger /* disable lpi at redist level */
897de582149SEric Auger gicv3_lpi_rdist_disable(pe0);
898de582149SEric Auger gicv3_lpi_rdist_disable(pe1);
899de582149SEric Auger
9007a84b7b2SThomas Huth /* lpis are interleaved between the 2 PEs */
901de582149SEric Auger for (i = 0; i < 256; i++) {
902de582149SEric Auger struct its_collection *col = i % 2 ? collection[0] :
903de582149SEric Auger collection[1];
904de582149SEric Auger int vcpu = col->target_address >> 16;
905de582149SEric Auger
906de582149SEric Auger its_send_mapti(dev, LPI(i), i, col);
907de582149SEric Auger gicv3_lpi_set_config(LPI(i), LPI_PROP_DEFAULT);
908de582149SEric Auger gicv3_lpi_set_clr_pending(vcpu, LPI(i), true);
909de582149SEric Auger }
910de582149SEric Auger its_send_invall(collection[0]);
911de582149SEric Auger its_send_invall(collection[1]);
912de582149SEric Auger
913de582149SEric Auger /* Clear the PTZ bit on each pendbaser */
914de582149SEric Auger
915de582149SEric Auger expected[pe0] = 128;
916de582149SEric Auger expected[pe1] = 128;
917de582149SEric Auger
918de582149SEric Auger ptr = gicv3_data.redist_base[pe0] + GICR_PENDBASER;
919de582149SEric Auger pendbaser = readq(ptr);
920de582149SEric Auger writeq(pendbaser & ~GICR_PENDBASER_PTZ, ptr);
921de582149SEric Auger
922de582149SEric Auger ptr = gicv3_data.redist_base[pe1] + GICR_PENDBASER;
923de582149SEric Auger pendbaser = readq(ptr);
924de582149SEric Auger writeq(pendbaser & ~GICR_PENDBASER_PTZ, ptr);
925de582149SEric Auger
9261b3e4553SAlexandru Elisei /*
9271b3e4553SAlexandru Elisei * Reset and initialization values for acked are the same, so we don't
9281b3e4553SAlexandru Elisei * need to explicitely call stats_reset().
9291b3e4553SAlexandru Elisei */
930de582149SEric Auger gicv3_lpi_rdist_enable(pe0);
931de582149SEric Auger gicv3_lpi_rdist_enable(pe1);
932de582149SEric Auger
933e6e1a201SNicholas Piggin migrate();
934de582149SEric Auger
935de582149SEric Auger /* let's wait for the 256 LPIs to be handled */
936de582149SEric Auger mdelay(1000);
937de582149SEric Auger
938de582149SEric Auger check_lpi_hits(expected, "128 LPIs on both PE0 and PE1 after migration");
939de582149SEric Auger }
940ba74b106SEric Auger #endif
941ba74b106SEric Auger
main(int argc,char ** argv)942ac4a67b6SAndrew Jones int main(int argc, char **argv)
943ac4a67b6SAndrew Jones {
9442e2d471dSAndrew Jones if (!gic_init()) {
945ac4a67b6SAndrew Jones printf("No supported gic present, skipping tests...\n");
946ac4a67b6SAndrew Jones return report_summary();
947ac4a67b6SAndrew Jones }
948ac4a67b6SAndrew Jones
9492b19b829SAndrew Jones report_prefix_pushf("gicv%d", gic_version());
950ac4a67b6SAndrew Jones
9512e2d471dSAndrew Jones switch (gic_version()) {
9522e2d471dSAndrew Jones case 2:
9532e2d471dSAndrew Jones gic = &gicv2;
9542e2d471dSAndrew Jones break;
9552e2d471dSAndrew Jones case 3:
9562e2d471dSAndrew Jones gic = &gicv3;
9572e2d471dSAndrew Jones break;
9582e2d471dSAndrew Jones }
9592e2d471dSAndrew Jones
960ac4a67b6SAndrew Jones if (argc < 2)
961ac4a67b6SAndrew Jones report_abort("no test specified");
962ac4a67b6SAndrew Jones
963ac4a67b6SAndrew Jones if (strcmp(argv[1], "ipi") == 0) {
964ac4a67b6SAndrew Jones report_prefix_push(argv[1]);
965ac4a67b6SAndrew Jones nr_cpu_check(2);
96600b34f56SAndrew Jones on_cpus(ipi_test, NULL);
967c152d8bcSChristoffer Dall } else if (strcmp(argv[1], "active") == 0) {
968c152d8bcSChristoffer Dall run_active_clear_test();
96978ad7e95SAndre Przywara } else if (strcmp(argv[1], "mmio") == 0) {
97078ad7e95SAndre Przywara report_prefix_push(argv[1]);
97178ad7e95SAndre Przywara gic_test_mmio();
97278ad7e95SAndre Przywara report_prefix_pop();
9730ef02cd6SEric Auger } else if (!strcmp(argv[1], "its-trigger")) {
9740ef02cd6SEric Auger report_prefix_push(argv[1]);
9750ef02cd6SEric Auger test_its_trigger();
9760ef02cd6SEric Auger report_prefix_pop();
97764260a5fSEric Auger } else if (!strcmp(argv[1], "its-migration")) {
97864260a5fSEric Auger report_prefix_push(argv[1]);
97964260a5fSEric Auger test_its_migration();
98064260a5fSEric Auger report_prefix_pop();
981de582149SEric Auger } else if (!strcmp(argv[1], "its-pending-migration")) {
982de582149SEric Auger report_prefix_push(argv[1]);
983de582149SEric Auger test_its_pending_migration();
984de582149SEric Auger report_prefix_pop();
985de582149SEric Auger } else if (!strcmp(argv[1], "its-migrate-unmapped-collection")) {
986de582149SEric Auger report_prefix_push(argv[1]);
987de582149SEric Auger test_migrate_unmapped_collection();
988de582149SEric Auger report_prefix_pop();
989ba74b106SEric Auger } else if (strcmp(argv[1], "its-introspection") == 0) {
990ba74b106SEric Auger report_prefix_push(argv[1]);
991ba74b106SEric Auger test_its_introspection();
992ba74b106SEric Auger report_prefix_pop();
993ac4a67b6SAndrew Jones } else {
994ac4a67b6SAndrew Jones report_abort("Unknown subtest '%s'", argv[1]);
995ac4a67b6SAndrew Jones }
996ac4a67b6SAndrew Jones
997ac4a67b6SAndrew Jones return report_summary();
998ac4a67b6SAndrew Jones }
999