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