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 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 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 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 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 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 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 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 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 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__) 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 */ 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 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. */ 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 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 574ba74b106SEric Auger static void test_its_introspection(void) {} 5750ef02cd6SEric Auger static void test_its_trigger(void) {} 57664260a5fSEric Auger static void test_its_migration(void) {} 577de582149SEric Auger static void test_its_pending_migration(void) {} 578de582149SEric Auger static void test_migrate_unmapped_collection(void) {} 579ba74b106SEric Auger 580ba74b106SEric Auger #else /* __aarch64__ */ 581ba74b106SEric Auger 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 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 */ 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 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 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 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 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 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