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> 19ac4a67b6SAndrew Jones #include <asm/smp.h> 20ac4a67b6SAndrew Jones #include <asm/barrier.h> 21ac4a67b6SAndrew Jones #include <asm/io.h> 22ac4a67b6SAndrew Jones 23ca1b7a7bSAndrew Jones #define IPI_SENDER 1 24ca1b7a7bSAndrew Jones #define IPI_IRQ 1 25ca1b7a7bSAndrew Jones 262e2d471dSAndrew Jones struct gic { 272e2d471dSAndrew Jones struct { 282e2d471dSAndrew Jones void (*send_self)(void); 292e2d471dSAndrew Jones void (*send_broadcast)(void); 302e2d471dSAndrew Jones } ipi; 312e2d471dSAndrew Jones }; 322e2d471dSAndrew Jones 332e2d471dSAndrew Jones static struct gic *gic; 34ac4a67b6SAndrew Jones static int acked[NR_CPUS], spurious[NR_CPUS]; 35ca1b7a7bSAndrew Jones static int bad_sender[NR_CPUS], bad_irq[NR_CPUS]; 36ac4a67b6SAndrew Jones static cpumask_t ready; 37ac4a67b6SAndrew Jones 38ac4a67b6SAndrew Jones static void nr_cpu_check(int nr) 39ac4a67b6SAndrew Jones { 40ac4a67b6SAndrew Jones if (nr_cpus < nr) 41ac4a67b6SAndrew Jones report_abort("At least %d cpus required", nr); 42ac4a67b6SAndrew Jones } 43ac4a67b6SAndrew Jones 44ac4a67b6SAndrew Jones static void wait_on_ready(void) 45ac4a67b6SAndrew Jones { 46ac4a67b6SAndrew Jones cpumask_set_cpu(smp_processor_id(), &ready); 47ac4a67b6SAndrew Jones while (!cpumask_full(&ready)) 48ac4a67b6SAndrew Jones cpu_relax(); 49ac4a67b6SAndrew Jones } 50ac4a67b6SAndrew Jones 51ca1b7a7bSAndrew Jones static void stats_reset(void) 52ca1b7a7bSAndrew Jones { 53ca1b7a7bSAndrew Jones int i; 54ca1b7a7bSAndrew Jones 55ca1b7a7bSAndrew Jones for (i = 0; i < nr_cpus; ++i) { 56ca1b7a7bSAndrew Jones acked[i] = 0; 57ca1b7a7bSAndrew Jones bad_sender[i] = -1; 58ca1b7a7bSAndrew Jones bad_irq[i] = -1; 59ca1b7a7bSAndrew Jones } 60ca1b7a7bSAndrew Jones smp_wmb(); 61ca1b7a7bSAndrew Jones } 62ca1b7a7bSAndrew Jones 63ac4a67b6SAndrew Jones static void check_acked(cpumask_t *mask) 64ac4a67b6SAndrew Jones { 65ac4a67b6SAndrew Jones int missing = 0, extra = 0, unexpected = 0; 66ac4a67b6SAndrew Jones int nr_pass, cpu, i; 67ca1b7a7bSAndrew Jones bool bad = false; 68ac4a67b6SAndrew Jones 69ac4a67b6SAndrew Jones /* Wait up to 5s for all interrupts to be delivered */ 70ac4a67b6SAndrew Jones for (i = 0; i < 50; ++i) { 71ac4a67b6SAndrew Jones mdelay(100); 72ac4a67b6SAndrew Jones nr_pass = 0; 73ac4a67b6SAndrew Jones for_each_present_cpu(cpu) { 74ac4a67b6SAndrew Jones smp_rmb(); 75ac4a67b6SAndrew Jones nr_pass += cpumask_test_cpu(cpu, mask) ? 76ac4a67b6SAndrew Jones acked[cpu] == 1 : acked[cpu] == 0; 77ca1b7a7bSAndrew Jones 78ca1b7a7bSAndrew Jones if (bad_sender[cpu] != -1) { 79ca1b7a7bSAndrew Jones printf("cpu%d received IPI from wrong sender %d\n", 80ca1b7a7bSAndrew Jones cpu, bad_sender[cpu]); 81ca1b7a7bSAndrew Jones bad = true; 82ca1b7a7bSAndrew Jones } 83ca1b7a7bSAndrew Jones 84ca1b7a7bSAndrew Jones if (bad_irq[cpu] != -1) { 85ca1b7a7bSAndrew Jones printf("cpu%d received wrong irq %d\n", 86ca1b7a7bSAndrew Jones cpu, bad_irq[cpu]); 87ca1b7a7bSAndrew Jones bad = true; 88ca1b7a7bSAndrew Jones } 89ac4a67b6SAndrew Jones } 90ac4a67b6SAndrew Jones if (nr_pass == nr_cpus) { 91ca1b7a7bSAndrew Jones report("Completed in %d ms", !bad, ++i * 100); 92ac4a67b6SAndrew Jones return; 93ac4a67b6SAndrew Jones } 94ac4a67b6SAndrew Jones } 95ac4a67b6SAndrew Jones 96ac4a67b6SAndrew Jones for_each_present_cpu(cpu) { 97ac4a67b6SAndrew Jones if (cpumask_test_cpu(cpu, mask)) { 98ac4a67b6SAndrew Jones if (!acked[cpu]) 99ac4a67b6SAndrew Jones ++missing; 100ac4a67b6SAndrew Jones else if (acked[cpu] > 1) 101ac4a67b6SAndrew Jones ++extra; 102ac4a67b6SAndrew Jones } else { 103ac4a67b6SAndrew Jones if (acked[cpu]) 104ac4a67b6SAndrew Jones ++unexpected; 105ac4a67b6SAndrew Jones } 106ac4a67b6SAndrew Jones } 107ac4a67b6SAndrew Jones 108ac4a67b6SAndrew Jones report("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d", 109ac4a67b6SAndrew Jones false, missing, extra, unexpected); 110ac4a67b6SAndrew Jones } 111ac4a67b6SAndrew Jones 112ac4a67b6SAndrew Jones static void check_spurious(void) 113ac4a67b6SAndrew Jones { 114ac4a67b6SAndrew Jones int cpu; 115ac4a67b6SAndrew Jones 116ac4a67b6SAndrew Jones smp_rmb(); 117ac4a67b6SAndrew Jones for_each_present_cpu(cpu) { 118ac4a67b6SAndrew Jones if (spurious[cpu]) 119ac4a67b6SAndrew Jones report_info("WARN: cpu%d got %d spurious interrupts", 120ac4a67b6SAndrew Jones cpu, spurious[cpu]); 121ac4a67b6SAndrew Jones } 122ac4a67b6SAndrew Jones } 123ac4a67b6SAndrew Jones 124ca1b7a7bSAndrew Jones static void check_ipi_sender(u32 irqstat) 125ca1b7a7bSAndrew Jones { 126ca1b7a7bSAndrew Jones if (gic_version() == 2) { 127ca1b7a7bSAndrew Jones int src = (irqstat >> 10) & 7; 128ca1b7a7bSAndrew Jones 129ca1b7a7bSAndrew Jones if (src != IPI_SENDER) 130ca1b7a7bSAndrew Jones bad_sender[smp_processor_id()] = src; 131ca1b7a7bSAndrew Jones } 132ca1b7a7bSAndrew Jones } 133ca1b7a7bSAndrew Jones 134ca1b7a7bSAndrew Jones static void check_irqnr(u32 irqnr) 135ca1b7a7bSAndrew Jones { 136ca1b7a7bSAndrew Jones if (irqnr != IPI_IRQ) 137ca1b7a7bSAndrew Jones bad_irq[smp_processor_id()] = irqnr; 138ca1b7a7bSAndrew Jones } 139ca1b7a7bSAndrew Jones 140ac4a67b6SAndrew Jones static void ipi_handler(struct pt_regs *regs __unused) 141ac4a67b6SAndrew Jones { 1422e2d471dSAndrew Jones u32 irqstat = gic_read_iar(); 1432e2d471dSAndrew Jones u32 irqnr = gic_iar_irqnr(irqstat); 144ac4a67b6SAndrew Jones 145ac4a67b6SAndrew Jones if (irqnr != GICC_INT_SPURIOUS) { 1462e2d471dSAndrew Jones gic_write_eoir(irqstat); 147ca1b7a7bSAndrew Jones smp_rmb(); /* pairs with wmb in stats_reset */ 148ac4a67b6SAndrew Jones ++acked[smp_processor_id()]; 149ca1b7a7bSAndrew Jones check_ipi_sender(irqstat); 150ca1b7a7bSAndrew Jones check_irqnr(irqnr); 151ac4a67b6SAndrew Jones smp_wmb(); /* pairs with rmb in check_acked */ 152ac4a67b6SAndrew Jones } else { 153ac4a67b6SAndrew Jones ++spurious[smp_processor_id()]; 154ac4a67b6SAndrew Jones smp_wmb(); 155ac4a67b6SAndrew Jones } 156ac4a67b6SAndrew Jones } 157ac4a67b6SAndrew Jones 1582e2d471dSAndrew Jones static void gicv2_ipi_send_self(void) 1592e2d471dSAndrew Jones { 160ca1b7a7bSAndrew Jones writel(2 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR); 1612e2d471dSAndrew Jones } 1622e2d471dSAndrew Jones 1632e2d471dSAndrew Jones static void gicv2_ipi_send_broadcast(void) 1642e2d471dSAndrew Jones { 165ca1b7a7bSAndrew Jones writel(1 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR); 1662e2d471dSAndrew Jones } 1672e2d471dSAndrew Jones 1682e2d471dSAndrew Jones static void gicv3_ipi_send_self(void) 1692e2d471dSAndrew Jones { 170ca1b7a7bSAndrew Jones gic_ipi_send_single(IPI_IRQ, smp_processor_id()); 1712e2d471dSAndrew Jones } 1722e2d471dSAndrew Jones 1732e2d471dSAndrew Jones static void gicv3_ipi_send_broadcast(void) 1742e2d471dSAndrew Jones { 175ca1b7a7bSAndrew Jones gicv3_write_sgi1r(1ULL << 40 | IPI_IRQ << 24); 1762e2d471dSAndrew Jones isb(); 1772e2d471dSAndrew Jones } 1782e2d471dSAndrew Jones 179ac4a67b6SAndrew Jones static void ipi_test_self(void) 180ac4a67b6SAndrew Jones { 181ac4a67b6SAndrew Jones cpumask_t mask; 182ac4a67b6SAndrew Jones 183ac4a67b6SAndrew Jones report_prefix_push("self"); 184ca1b7a7bSAndrew Jones stats_reset(); 185ac4a67b6SAndrew Jones cpumask_clear(&mask); 186ca1b7a7bSAndrew Jones cpumask_set_cpu(smp_processor_id(), &mask); 1872e2d471dSAndrew Jones gic->ipi.send_self(); 188ac4a67b6SAndrew Jones check_acked(&mask); 189ac4a67b6SAndrew Jones report_prefix_pop(); 190ac4a67b6SAndrew Jones } 191ac4a67b6SAndrew Jones 192ac4a67b6SAndrew Jones static void ipi_test_smp(void) 193ac4a67b6SAndrew Jones { 194ac4a67b6SAndrew Jones cpumask_t mask; 1952e2d471dSAndrew Jones int i; 196ac4a67b6SAndrew Jones 197ac4a67b6SAndrew Jones report_prefix_push("target-list"); 198ca1b7a7bSAndrew Jones stats_reset(); 1992e2d471dSAndrew Jones cpumask_copy(&mask, &cpu_present_mask); 200ca1b7a7bSAndrew Jones for (i = smp_processor_id() & 1; i < nr_cpus; i += 2) 2012e2d471dSAndrew Jones cpumask_clear_cpu(i, &mask); 202ca1b7a7bSAndrew Jones gic_ipi_send_mask(IPI_IRQ, &mask); 203ac4a67b6SAndrew Jones check_acked(&mask); 204ac4a67b6SAndrew Jones report_prefix_pop(); 205ac4a67b6SAndrew Jones 206ac4a67b6SAndrew Jones report_prefix_push("broadcast"); 207ca1b7a7bSAndrew Jones stats_reset(); 208ac4a67b6SAndrew Jones cpumask_copy(&mask, &cpu_present_mask); 209ca1b7a7bSAndrew Jones cpumask_clear_cpu(smp_processor_id(), &mask); 2102e2d471dSAndrew Jones gic->ipi.send_broadcast(); 211ac4a67b6SAndrew Jones check_acked(&mask); 212ac4a67b6SAndrew Jones report_prefix_pop(); 213ac4a67b6SAndrew Jones } 214ac4a67b6SAndrew Jones 215ac4a67b6SAndrew Jones static void ipi_enable(void) 216ac4a67b6SAndrew Jones { 2172e2d471dSAndrew Jones gic_enable_defaults(); 218ac4a67b6SAndrew Jones #ifdef __arm__ 219ac4a67b6SAndrew Jones install_exception_handler(EXCPTN_IRQ, ipi_handler); 220ac4a67b6SAndrew Jones #else 221ac4a67b6SAndrew Jones install_irq_handler(EL1H_IRQ, ipi_handler); 222ac4a67b6SAndrew Jones #endif 223ac4a67b6SAndrew Jones local_irq_enable(); 224ac4a67b6SAndrew Jones } 225ac4a67b6SAndrew Jones 226ca1b7a7bSAndrew Jones static void ipi_send(void) 227ca1b7a7bSAndrew Jones { 228ca1b7a7bSAndrew Jones ipi_enable(); 229ca1b7a7bSAndrew Jones wait_on_ready(); 230ca1b7a7bSAndrew Jones ipi_test_self(); 231ca1b7a7bSAndrew Jones ipi_test_smp(); 232ca1b7a7bSAndrew Jones check_spurious(); 233ca1b7a7bSAndrew Jones exit(report_summary()); 234ca1b7a7bSAndrew Jones } 235ca1b7a7bSAndrew Jones 236ac4a67b6SAndrew Jones static void ipi_recv(void) 237ac4a67b6SAndrew Jones { 238ac4a67b6SAndrew Jones ipi_enable(); 239ac4a67b6SAndrew Jones cpumask_set_cpu(smp_processor_id(), &ready); 240ac4a67b6SAndrew Jones while (1) 241ac4a67b6SAndrew Jones wfi(); 242ac4a67b6SAndrew Jones } 243ac4a67b6SAndrew Jones 24400b34f56SAndrew Jones static void ipi_test(void *data __unused) 245bfd500b4SAndrew Jones { 246bfd500b4SAndrew Jones if (smp_processor_id() == IPI_SENDER) 247bfd500b4SAndrew Jones ipi_send(); 248bfd500b4SAndrew Jones else 249bfd500b4SAndrew Jones ipi_recv(); 250bfd500b4SAndrew Jones } 251bfd500b4SAndrew Jones 2522e2d471dSAndrew Jones static struct gic gicv2 = { 2532e2d471dSAndrew Jones .ipi = { 2542e2d471dSAndrew Jones .send_self = gicv2_ipi_send_self, 2552e2d471dSAndrew Jones .send_broadcast = gicv2_ipi_send_broadcast, 2562e2d471dSAndrew Jones }, 2572e2d471dSAndrew Jones }; 2582e2d471dSAndrew Jones 2592e2d471dSAndrew Jones static struct gic gicv3 = { 2602e2d471dSAndrew Jones .ipi = { 2612e2d471dSAndrew Jones .send_self = gicv3_ipi_send_self, 2622e2d471dSAndrew Jones .send_broadcast = gicv3_ipi_send_broadcast, 2632e2d471dSAndrew Jones }, 2642e2d471dSAndrew Jones }; 2652e2d471dSAndrew Jones 266c152d8bcSChristoffer Dall static void ipi_clear_active_handler(struct pt_regs *regs __unused) 267c152d8bcSChristoffer Dall { 268c152d8bcSChristoffer Dall u32 irqstat = gic_read_iar(); 269c152d8bcSChristoffer Dall u32 irqnr = gic_iar_irqnr(irqstat); 270c152d8bcSChristoffer Dall 271c152d8bcSChristoffer Dall if (irqnr != GICC_INT_SPURIOUS) { 272c152d8bcSChristoffer Dall void *base; 273c152d8bcSChristoffer Dall u32 val = 1 << IPI_IRQ; 274c152d8bcSChristoffer Dall 275c152d8bcSChristoffer Dall if (gic_version() == 2) 276c152d8bcSChristoffer Dall base = gicv2_dist_base(); 277c152d8bcSChristoffer Dall else 2786d4d7c4bSAndrew Jones base = gicv3_sgi_base(); 279c152d8bcSChristoffer Dall 280c152d8bcSChristoffer Dall writel(val, base + GICD_ICACTIVER); 281c152d8bcSChristoffer Dall 282c152d8bcSChristoffer Dall smp_rmb(); /* pairs with wmb in stats_reset */ 283c152d8bcSChristoffer Dall ++acked[smp_processor_id()]; 284c152d8bcSChristoffer Dall check_irqnr(irqnr); 285c152d8bcSChristoffer Dall smp_wmb(); /* pairs with rmb in check_acked */ 286c152d8bcSChristoffer Dall } else { 287c152d8bcSChristoffer Dall ++spurious[smp_processor_id()]; 288c152d8bcSChristoffer Dall smp_wmb(); 289c152d8bcSChristoffer Dall } 290c152d8bcSChristoffer Dall } 291c152d8bcSChristoffer Dall 292c152d8bcSChristoffer Dall static void run_active_clear_test(void) 293c152d8bcSChristoffer Dall { 294c152d8bcSChristoffer Dall report_prefix_push("active"); 295c152d8bcSChristoffer Dall gic_enable_defaults(); 296c152d8bcSChristoffer Dall #ifdef __arm__ 297c152d8bcSChristoffer Dall install_exception_handler(EXCPTN_IRQ, ipi_clear_active_handler); 298c152d8bcSChristoffer Dall #else 299c152d8bcSChristoffer Dall install_irq_handler(EL1H_IRQ, ipi_clear_active_handler); 300c152d8bcSChristoffer Dall #endif 301c152d8bcSChristoffer Dall local_irq_enable(); 302c152d8bcSChristoffer Dall 303c152d8bcSChristoffer Dall ipi_test_self(); 304c152d8bcSChristoffer Dall report_prefix_pop(); 305c152d8bcSChristoffer Dall } 306c152d8bcSChristoffer Dall 30778ad7e95SAndre Przywara static bool test_ro_pattern_32(void *address, u32 pattern, u32 orig) 30878ad7e95SAndre Przywara { 30978ad7e95SAndre Przywara u32 reg; 31078ad7e95SAndre Przywara 31178ad7e95SAndre Przywara writel(pattern, address); 31278ad7e95SAndre Przywara reg = readl(address); 31378ad7e95SAndre Przywara 31478ad7e95SAndre Przywara if (reg != orig) 31578ad7e95SAndre Przywara writel(orig, address); 31678ad7e95SAndre Przywara 31778ad7e95SAndre Przywara return reg == orig; 31878ad7e95SAndre Przywara } 31978ad7e95SAndre Przywara 32078ad7e95SAndre Przywara static bool test_readonly_32(void *address, bool razwi) 32178ad7e95SAndre Przywara { 32278ad7e95SAndre Przywara u32 orig, pattern; 32378ad7e95SAndre Przywara 32478ad7e95SAndre Przywara orig = readl(address); 32578ad7e95SAndre Przywara if (razwi && orig) 32678ad7e95SAndre Przywara return false; 32778ad7e95SAndre Przywara 32878ad7e95SAndre Przywara pattern = 0xffffffff; 32978ad7e95SAndre Przywara if (orig != pattern) { 33078ad7e95SAndre Przywara if (!test_ro_pattern_32(address, pattern, orig)) 33178ad7e95SAndre Przywara return false; 33278ad7e95SAndre Przywara } 33378ad7e95SAndre Przywara 33478ad7e95SAndre Przywara pattern = 0xa5a55a5a; 33578ad7e95SAndre Przywara if (orig != pattern) { 33678ad7e95SAndre Przywara if (!test_ro_pattern_32(address, pattern, orig)) 33778ad7e95SAndre Przywara return false; 33878ad7e95SAndre Przywara } 33978ad7e95SAndre Przywara 34078ad7e95SAndre Przywara pattern = 0; 34178ad7e95SAndre Przywara if (orig != pattern) { 34278ad7e95SAndre Przywara if (!test_ro_pattern_32(address, pattern, orig)) 34378ad7e95SAndre Przywara return false; 34478ad7e95SAndre Przywara } 34578ad7e95SAndre Przywara 34678ad7e95SAndre Przywara return true; 34778ad7e95SAndre Przywara } 34878ad7e95SAndre Przywara 34978ad7e95SAndre Przywara static void test_typer_v2(uint32_t reg) 35078ad7e95SAndre Przywara { 35178ad7e95SAndre Przywara int nr_gic_cpus = ((reg >> 5) & 0x7) + 1; 35278ad7e95SAndre Przywara 35378ad7e95SAndre Przywara report("all %d CPUs have interrupts", nr_cpus == nr_gic_cpus, 35478ad7e95SAndre Przywara nr_gic_cpus); 35578ad7e95SAndre Przywara } 35678ad7e95SAndre Przywara 357*ff31a1c4SAndre Przywara #define BYTE(reg32, byte) (((reg32) >> ((byte) * 8)) & 0xff) 358*ff31a1c4SAndre Przywara #define REPLACE_BYTE(reg32, byte, new) (((reg32) & ~(0xff << ((byte) * 8))) |\ 359*ff31a1c4SAndre Przywara ((new) << ((byte) * 8))) 360*ff31a1c4SAndre Przywara 361*ff31a1c4SAndre Przywara /* 362*ff31a1c4SAndre Przywara * Some registers are byte accessible, do a byte-wide read and write of known 363*ff31a1c4SAndre Przywara * content to check for this. 364*ff31a1c4SAndre Przywara * Apply a @mask to cater for special register properties. 365*ff31a1c4SAndre Przywara * @pattern contains the value already in the register. 366*ff31a1c4SAndre Przywara */ 367*ff31a1c4SAndre Przywara static void test_byte_access(void *base_addr, u32 pattern, u32 mask) 368*ff31a1c4SAndre Przywara { 369*ff31a1c4SAndre Przywara u32 reg = readb(base_addr + 1); 370*ff31a1c4SAndre Przywara 371*ff31a1c4SAndre Przywara report("byte reads successful (0x%08x => 0x%02x)", 372*ff31a1c4SAndre Przywara reg == (BYTE(pattern, 1) & (mask >> 8)), 373*ff31a1c4SAndre Przywara pattern & mask, reg); 374*ff31a1c4SAndre Przywara 375*ff31a1c4SAndre Przywara pattern = REPLACE_BYTE(pattern, 2, 0x1f); 376*ff31a1c4SAndre Przywara writeb(BYTE(pattern, 2), base_addr + 2); 377*ff31a1c4SAndre Przywara reg = readl(base_addr); 378*ff31a1c4SAndre Przywara report("byte writes successful (0x%02x => 0x%08x)", 379*ff31a1c4SAndre Przywara reg == (pattern & mask), BYTE(pattern, 2), reg); 380*ff31a1c4SAndre Przywara } 381*ff31a1c4SAndre Przywara 382*ff31a1c4SAndre Przywara static void test_priorities(int nr_irqs, void *priptr) 383*ff31a1c4SAndre Przywara { 384*ff31a1c4SAndre Przywara u32 orig_prio, reg, pri_bits; 385*ff31a1c4SAndre Przywara u32 pri_mask, pattern; 386*ff31a1c4SAndre Przywara void *first_spi = priptr + GIC_FIRST_SPI; 387*ff31a1c4SAndre Przywara 388*ff31a1c4SAndre Przywara orig_prio = readl(first_spi); 389*ff31a1c4SAndre Przywara report_prefix_push("IPRIORITYR"); 390*ff31a1c4SAndre Przywara 391*ff31a1c4SAndre Przywara /* 392*ff31a1c4SAndre Przywara * Determine implemented number of priority bits by writing all 1's 393*ff31a1c4SAndre Przywara * and checking the number of cleared bits in the value read back. 394*ff31a1c4SAndre Przywara */ 395*ff31a1c4SAndre Przywara writel(0xffffffff, first_spi); 396*ff31a1c4SAndre Przywara pri_mask = readl(first_spi); 397*ff31a1c4SAndre Przywara 398*ff31a1c4SAndre Przywara reg = ~pri_mask; 399*ff31a1c4SAndre Przywara report("consistent priority masking (0x%08x)", 400*ff31a1c4SAndre Przywara (((reg >> 16) == (reg & 0xffff)) && 401*ff31a1c4SAndre Przywara ((reg & 0xff) == ((reg >> 8) & 0xff))), pri_mask); 402*ff31a1c4SAndre Przywara 403*ff31a1c4SAndre Przywara reg = reg & 0xff; 404*ff31a1c4SAndre Przywara for (pri_bits = 8; reg & 1; reg >>= 1, pri_bits--) 405*ff31a1c4SAndre Przywara ; 406*ff31a1c4SAndre Przywara report("implements at least 4 priority bits (%d)", 407*ff31a1c4SAndre Przywara pri_bits >= 4, pri_bits); 408*ff31a1c4SAndre Przywara 409*ff31a1c4SAndre Przywara pattern = 0; 410*ff31a1c4SAndre Przywara writel(pattern, first_spi); 411*ff31a1c4SAndre Przywara report("clearing priorities", readl(first_spi) == pattern); 412*ff31a1c4SAndre Przywara 413*ff31a1c4SAndre Przywara /* setting all priorities to their max valus was tested above */ 414*ff31a1c4SAndre Przywara 415*ff31a1c4SAndre Przywara report("accesses beyond limit RAZ/WI", 416*ff31a1c4SAndre Przywara test_readonly_32(priptr + nr_irqs, true)); 417*ff31a1c4SAndre Przywara 418*ff31a1c4SAndre Przywara writel(pattern, priptr + nr_irqs - 4); 419*ff31a1c4SAndre Przywara report("accessing last SPIs", 420*ff31a1c4SAndre Przywara readl(priptr + nr_irqs - 4) == (pattern & pri_mask)); 421*ff31a1c4SAndre Przywara 422*ff31a1c4SAndre Przywara pattern = 0xff7fbf3f; 423*ff31a1c4SAndre Przywara writel(pattern, first_spi); 424*ff31a1c4SAndre Przywara report("priorities are preserved", 425*ff31a1c4SAndre Przywara readl(first_spi) == (pattern & pri_mask)); 426*ff31a1c4SAndre Przywara 427*ff31a1c4SAndre Przywara /* The PRIORITY registers are byte accessible. */ 428*ff31a1c4SAndre Przywara test_byte_access(first_spi, pattern, pri_mask); 429*ff31a1c4SAndre Przywara 430*ff31a1c4SAndre Przywara report_prefix_pop(); 431*ff31a1c4SAndre Przywara writel(orig_prio, first_spi); 432*ff31a1c4SAndre Przywara } 433*ff31a1c4SAndre Przywara 43478ad7e95SAndre Przywara static void gic_test_mmio(void) 43578ad7e95SAndre Przywara { 43678ad7e95SAndre Przywara u32 reg; 43778ad7e95SAndre Przywara int nr_irqs; 43878ad7e95SAndre Przywara void *gic_dist_base, *idreg; 43978ad7e95SAndre Przywara 44078ad7e95SAndre Przywara switch(gic_version()) { 44178ad7e95SAndre Przywara case 0x2: 44278ad7e95SAndre Przywara gic_dist_base = gicv2_dist_base(); 44378ad7e95SAndre Przywara idreg = gic_dist_base + GICD_ICPIDR2; 44478ad7e95SAndre Przywara break; 44578ad7e95SAndre Przywara case 0x3: 44678ad7e95SAndre Przywara report_abort("GICv3 MMIO tests NYI"); 44778ad7e95SAndre Przywara default: 44878ad7e95SAndre Przywara report_abort("GIC version %d not supported", gic_version()); 44978ad7e95SAndre Przywara } 45078ad7e95SAndre Przywara 45178ad7e95SAndre Przywara reg = readl(gic_dist_base + GICD_TYPER); 45278ad7e95SAndre Przywara nr_irqs = GICD_TYPER_IRQS(reg); 45378ad7e95SAndre Przywara report_info("number of implemented SPIs: %d", nr_irqs - GIC_FIRST_SPI); 45478ad7e95SAndre Przywara 45578ad7e95SAndre Przywara test_typer_v2(reg); 45678ad7e95SAndre Przywara 45778ad7e95SAndre Przywara report_info("IIDR: 0x%08x", readl(gic_dist_base + GICD_IIDR)); 45878ad7e95SAndre Przywara 45978ad7e95SAndre Przywara report("GICD_TYPER is read-only", 46078ad7e95SAndre Przywara test_readonly_32(gic_dist_base + GICD_TYPER, false)); 46178ad7e95SAndre Przywara report("GICD_IIDR is read-only", 46278ad7e95SAndre Przywara test_readonly_32(gic_dist_base + GICD_IIDR, false)); 46378ad7e95SAndre Przywara 46478ad7e95SAndre Przywara reg = readl(idreg); 46578ad7e95SAndre Przywara report("ICPIDR2 is read-only (0x%08x)", 46678ad7e95SAndre Przywara test_readonly_32(idreg, false), 46778ad7e95SAndre Przywara reg); 468*ff31a1c4SAndre Przywara 469*ff31a1c4SAndre Przywara test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR); 47078ad7e95SAndre Przywara } 47178ad7e95SAndre Przywara 472ac4a67b6SAndrew Jones int main(int argc, char **argv) 473ac4a67b6SAndrew Jones { 4742e2d471dSAndrew Jones if (!gic_init()) { 475ac4a67b6SAndrew Jones printf("No supported gic present, skipping tests...\n"); 476ac4a67b6SAndrew Jones return report_summary(); 477ac4a67b6SAndrew Jones } 478ac4a67b6SAndrew Jones 4792b19b829SAndrew Jones report_prefix_pushf("gicv%d", gic_version()); 480ac4a67b6SAndrew Jones 4812e2d471dSAndrew Jones switch (gic_version()) { 4822e2d471dSAndrew Jones case 2: 4832e2d471dSAndrew Jones gic = &gicv2; 4842e2d471dSAndrew Jones break; 4852e2d471dSAndrew Jones case 3: 4862e2d471dSAndrew Jones gic = &gicv3; 4872e2d471dSAndrew Jones break; 4882e2d471dSAndrew Jones } 4892e2d471dSAndrew Jones 490ac4a67b6SAndrew Jones if (argc < 2) 491ac4a67b6SAndrew Jones report_abort("no test specified"); 492ac4a67b6SAndrew Jones 493ac4a67b6SAndrew Jones if (strcmp(argv[1], "ipi") == 0) { 494ac4a67b6SAndrew Jones report_prefix_push(argv[1]); 495ac4a67b6SAndrew Jones nr_cpu_check(2); 49600b34f56SAndrew Jones on_cpus(ipi_test, NULL); 497c152d8bcSChristoffer Dall } else if (strcmp(argv[1], "active") == 0) { 498c152d8bcSChristoffer Dall run_active_clear_test(); 49978ad7e95SAndre Przywara } else if (strcmp(argv[1], "mmio") == 0) { 50078ad7e95SAndre Przywara report_prefix_push(argv[1]); 50178ad7e95SAndre Przywara gic_test_mmio(); 50278ad7e95SAndre Przywara report_prefix_pop(); 503ac4a67b6SAndrew Jones } else { 504ac4a67b6SAndrew Jones report_abort("Unknown subtest '%s'", argv[1]); 505ac4a67b6SAndrew Jones } 506ac4a67b6SAndrew Jones 507ac4a67b6SAndrew Jones return report_summary(); 508ac4a67b6SAndrew Jones } 509