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> 15*de582149SEric Auger #include <errata.h> 16ac4a67b6SAndrew Jones #include <asm/setup.h> 17ac4a67b6SAndrew Jones #include <asm/processor.h> 18ac4a67b6SAndrew Jones #include <asm/delay.h> 19ac4a67b6SAndrew Jones #include <asm/gic.h> 20ba74b106SEric Auger #include <asm/gic-v3-its.h> 21ac4a67b6SAndrew Jones #include <asm/smp.h> 22ac4a67b6SAndrew Jones #include <asm/barrier.h> 23ac4a67b6SAndrew Jones #include <asm/io.h> 24ac4a67b6SAndrew Jones 25ca1b7a7bSAndrew Jones #define IPI_SENDER 1 26ca1b7a7bSAndrew Jones #define IPI_IRQ 1 27ca1b7a7bSAndrew Jones 282e2d471dSAndrew Jones struct gic { 292e2d471dSAndrew Jones struct { 302e2d471dSAndrew Jones void (*send_self)(void); 312e2d471dSAndrew Jones void (*send_broadcast)(void); 322e2d471dSAndrew Jones } ipi; 332e2d471dSAndrew Jones }; 342e2d471dSAndrew Jones 352e2d471dSAndrew Jones static struct gic *gic; 36ac4a67b6SAndrew Jones static int acked[NR_CPUS], spurious[NR_CPUS]; 37ca1b7a7bSAndrew Jones static int bad_sender[NR_CPUS], bad_irq[NR_CPUS]; 38ac4a67b6SAndrew Jones static cpumask_t ready; 39ac4a67b6SAndrew Jones 40ac4a67b6SAndrew Jones static void nr_cpu_check(int nr) 41ac4a67b6SAndrew Jones { 42ac4a67b6SAndrew Jones if (nr_cpus < nr) 43ac4a67b6SAndrew Jones report_abort("At least %d cpus required", nr); 44ac4a67b6SAndrew Jones } 45ac4a67b6SAndrew Jones 46ac4a67b6SAndrew Jones static void wait_on_ready(void) 47ac4a67b6SAndrew Jones { 48ac4a67b6SAndrew Jones cpumask_set_cpu(smp_processor_id(), &ready); 49ac4a67b6SAndrew Jones while (!cpumask_full(&ready)) 50ac4a67b6SAndrew Jones cpu_relax(); 51ac4a67b6SAndrew Jones } 52ac4a67b6SAndrew Jones 53ca1b7a7bSAndrew Jones static void stats_reset(void) 54ca1b7a7bSAndrew Jones { 55ca1b7a7bSAndrew Jones int i; 56ca1b7a7bSAndrew Jones 57ca1b7a7bSAndrew Jones for (i = 0; i < nr_cpus; ++i) { 58ca1b7a7bSAndrew Jones acked[i] = 0; 59ca1b7a7bSAndrew Jones bad_sender[i] = -1; 60ca1b7a7bSAndrew Jones bad_irq[i] = -1; 61ca1b7a7bSAndrew Jones } 62ca1b7a7bSAndrew Jones smp_wmb(); 63ca1b7a7bSAndrew Jones } 64ca1b7a7bSAndrew Jones 6596edb026SAndre Przywara static void check_acked(const char *testname, cpumask_t *mask) 66ac4a67b6SAndrew Jones { 67ac4a67b6SAndrew Jones int missing = 0, extra = 0, unexpected = 0; 68ac4a67b6SAndrew Jones int nr_pass, cpu, i; 69ca1b7a7bSAndrew Jones bool bad = false; 70ac4a67b6SAndrew Jones 71ac4a67b6SAndrew Jones /* Wait up to 5s for all interrupts to be delivered */ 72ac4a67b6SAndrew Jones for (i = 0; i < 50; ++i) { 73ac4a67b6SAndrew Jones mdelay(100); 74ac4a67b6SAndrew Jones nr_pass = 0; 75ac4a67b6SAndrew Jones for_each_present_cpu(cpu) { 76ac4a67b6SAndrew Jones smp_rmb(); 77ac4a67b6SAndrew Jones nr_pass += cpumask_test_cpu(cpu, mask) ? 78ac4a67b6SAndrew Jones acked[cpu] == 1 : acked[cpu] == 0; 79ca1b7a7bSAndrew Jones 80ca1b7a7bSAndrew Jones if (bad_sender[cpu] != -1) { 81ca1b7a7bSAndrew Jones printf("cpu%d received IPI from wrong sender %d\n", 82ca1b7a7bSAndrew Jones cpu, bad_sender[cpu]); 83ca1b7a7bSAndrew Jones bad = true; 84ca1b7a7bSAndrew Jones } 85ca1b7a7bSAndrew Jones 86ca1b7a7bSAndrew Jones if (bad_irq[cpu] != -1) { 87ca1b7a7bSAndrew Jones printf("cpu%d received wrong irq %d\n", 88ca1b7a7bSAndrew Jones cpu, bad_irq[cpu]); 89ca1b7a7bSAndrew Jones bad = true; 90ca1b7a7bSAndrew Jones } 91ac4a67b6SAndrew Jones } 92ac4a67b6SAndrew Jones if (nr_pass == nr_cpus) { 93a299895bSThomas Huth report(!bad, "%s", testname); 9496edb026SAndre Przywara if (i) 9596edb026SAndre Przywara report_info("took more than %d ms", i * 100); 96ac4a67b6SAndrew Jones return; 97ac4a67b6SAndrew Jones } 98ac4a67b6SAndrew Jones } 99ac4a67b6SAndrew Jones 100ac4a67b6SAndrew Jones for_each_present_cpu(cpu) { 101ac4a67b6SAndrew Jones if (cpumask_test_cpu(cpu, mask)) { 102ac4a67b6SAndrew Jones if (!acked[cpu]) 103ac4a67b6SAndrew Jones ++missing; 104ac4a67b6SAndrew Jones else if (acked[cpu] > 1) 105ac4a67b6SAndrew Jones ++extra; 106ac4a67b6SAndrew Jones } else { 107ac4a67b6SAndrew Jones if (acked[cpu]) 108ac4a67b6SAndrew Jones ++unexpected; 109ac4a67b6SAndrew Jones } 110ac4a67b6SAndrew Jones } 111ac4a67b6SAndrew Jones 112a299895bSThomas Huth report(false, "%s", testname); 11396edb026SAndre Przywara report_info("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d", 11496edb026SAndre Przywara missing, extra, unexpected); 115ac4a67b6SAndrew Jones } 116ac4a67b6SAndrew Jones 117ac4a67b6SAndrew Jones static void check_spurious(void) 118ac4a67b6SAndrew Jones { 119ac4a67b6SAndrew Jones int cpu; 120ac4a67b6SAndrew Jones 121ac4a67b6SAndrew Jones smp_rmb(); 122ac4a67b6SAndrew Jones for_each_present_cpu(cpu) { 123ac4a67b6SAndrew Jones if (spurious[cpu]) 124ac4a67b6SAndrew Jones report_info("WARN: cpu%d got %d spurious interrupts", 125ac4a67b6SAndrew Jones cpu, spurious[cpu]); 126ac4a67b6SAndrew Jones } 127ac4a67b6SAndrew Jones } 128ac4a67b6SAndrew Jones 129ca1b7a7bSAndrew Jones static void check_ipi_sender(u32 irqstat) 130ca1b7a7bSAndrew Jones { 131ca1b7a7bSAndrew Jones if (gic_version() == 2) { 132ca1b7a7bSAndrew Jones int src = (irqstat >> 10) & 7; 133ca1b7a7bSAndrew Jones 134ca1b7a7bSAndrew Jones if (src != IPI_SENDER) 135ca1b7a7bSAndrew Jones bad_sender[smp_processor_id()] = src; 136ca1b7a7bSAndrew Jones } 137ca1b7a7bSAndrew Jones } 138ca1b7a7bSAndrew Jones 139ca1b7a7bSAndrew Jones static void check_irqnr(u32 irqnr) 140ca1b7a7bSAndrew Jones { 141ca1b7a7bSAndrew Jones if (irqnr != IPI_IRQ) 142ca1b7a7bSAndrew Jones bad_irq[smp_processor_id()] = irqnr; 143ca1b7a7bSAndrew Jones } 144ca1b7a7bSAndrew Jones 145ac4a67b6SAndrew Jones static void ipi_handler(struct pt_regs *regs __unused) 146ac4a67b6SAndrew Jones { 1472e2d471dSAndrew Jones u32 irqstat = gic_read_iar(); 1482e2d471dSAndrew Jones u32 irqnr = gic_iar_irqnr(irqstat); 149ac4a67b6SAndrew Jones 150ac4a67b6SAndrew Jones if (irqnr != GICC_INT_SPURIOUS) { 1512e2d471dSAndrew Jones gic_write_eoir(irqstat); 152ca1b7a7bSAndrew Jones smp_rmb(); /* pairs with wmb in stats_reset */ 153ac4a67b6SAndrew Jones ++acked[smp_processor_id()]; 154ca1b7a7bSAndrew Jones check_ipi_sender(irqstat); 155ca1b7a7bSAndrew Jones check_irqnr(irqnr); 156ac4a67b6SAndrew Jones smp_wmb(); /* pairs with rmb in check_acked */ 157ac4a67b6SAndrew Jones } else { 158ac4a67b6SAndrew Jones ++spurious[smp_processor_id()]; 159ac4a67b6SAndrew Jones smp_wmb(); 160ac4a67b6SAndrew Jones } 161ac4a67b6SAndrew Jones } 162ac4a67b6SAndrew Jones 1630ef02cd6SEric Auger static void setup_irq(irq_handler_fn handler) 1640ef02cd6SEric Auger { 1650ef02cd6SEric Auger gic_enable_defaults(); 1660ef02cd6SEric Auger #ifdef __arm__ 1670ef02cd6SEric Auger install_exception_handler(EXCPTN_IRQ, handler); 1680ef02cd6SEric Auger #else 1690ef02cd6SEric Auger install_irq_handler(EL1H_IRQ, handler); 1700ef02cd6SEric Auger #endif 1710ef02cd6SEric Auger local_irq_enable(); 1720ef02cd6SEric Auger } 1730ef02cd6SEric Auger 1740ef02cd6SEric Auger #if defined(__aarch64__) 1750ef02cd6SEric Auger struct its_event { 1760ef02cd6SEric Auger int cpu_id; 1770ef02cd6SEric Auger int lpi_id; 1780ef02cd6SEric Auger }; 1790ef02cd6SEric Auger 1800ef02cd6SEric Auger struct its_stats { 1810ef02cd6SEric Auger struct its_event expected; 1820ef02cd6SEric Auger struct its_event observed; 1830ef02cd6SEric Auger }; 1840ef02cd6SEric Auger 1850ef02cd6SEric Auger static struct its_stats lpi_stats; 1860ef02cd6SEric Auger 1870ef02cd6SEric Auger static void lpi_handler(struct pt_regs *regs __unused) 1880ef02cd6SEric Auger { 1890ef02cd6SEric Auger u32 irqstat = gic_read_iar(); 1900ef02cd6SEric Auger int irqnr = gic_iar_irqnr(irqstat); 1910ef02cd6SEric Auger 1920ef02cd6SEric Auger gic_write_eoir(irqstat); 1930ef02cd6SEric Auger assert(irqnr >= 8192); 1940ef02cd6SEric Auger smp_rmb(); /* pairs with wmb in lpi_stats_expect */ 1950ef02cd6SEric Auger lpi_stats.observed.cpu_id = smp_processor_id(); 1960ef02cd6SEric Auger lpi_stats.observed.lpi_id = irqnr; 197*de582149SEric Auger acked[lpi_stats.observed.cpu_id]++; 1980ef02cd6SEric Auger smp_wmb(); /* pairs with rmb in check_lpi_stats */ 1990ef02cd6SEric Auger } 2000ef02cd6SEric Auger 2010ef02cd6SEric Auger static void lpi_stats_expect(int exp_cpu_id, int exp_lpi_id) 2020ef02cd6SEric Auger { 2030ef02cd6SEric Auger lpi_stats.expected.cpu_id = exp_cpu_id; 2040ef02cd6SEric Auger lpi_stats.expected.lpi_id = exp_lpi_id; 2050ef02cd6SEric Auger lpi_stats.observed.cpu_id = -1; 2060ef02cd6SEric Auger lpi_stats.observed.lpi_id = -1; 2070ef02cd6SEric Auger smp_wmb(); /* pairs with rmb in handler */ 2080ef02cd6SEric Auger } 2090ef02cd6SEric Auger 2100ef02cd6SEric Auger static void check_lpi_stats(const char *msg) 2110ef02cd6SEric Auger { 2120ef02cd6SEric Auger int i; 2130ef02cd6SEric Auger 2140ef02cd6SEric Auger for (i = 0; i < 50; i++) { 2150ef02cd6SEric Auger mdelay(100); 2160ef02cd6SEric Auger smp_rmb(); /* pairs with wmb in lpi_handler */ 2170ef02cd6SEric Auger if (lpi_stats.observed.cpu_id == lpi_stats.expected.cpu_id && 2180ef02cd6SEric Auger lpi_stats.observed.lpi_id == lpi_stats.expected.lpi_id) { 2190ef02cd6SEric Auger report(true, "%s", msg); 2200ef02cd6SEric Auger return; 2210ef02cd6SEric Auger } 2220ef02cd6SEric Auger } 2230ef02cd6SEric Auger 2240ef02cd6SEric Auger if (lpi_stats.observed.cpu_id == -1 && lpi_stats.observed.lpi_id == -1) { 2250ef02cd6SEric Auger report_info("No LPI received whereas (cpuid=%d, intid=%d) " 2260ef02cd6SEric Auger "was expected", lpi_stats.expected.cpu_id, 2270ef02cd6SEric Auger lpi_stats.expected.lpi_id); 2280ef02cd6SEric Auger } else { 2290ef02cd6SEric Auger report_info("Unexpected LPI (cpuid=%d, intid=%d)", 2300ef02cd6SEric Auger lpi_stats.observed.cpu_id, 2310ef02cd6SEric Auger lpi_stats.observed.lpi_id); 2320ef02cd6SEric Auger } 2330ef02cd6SEric Auger report(false, "%s", msg); 2340ef02cd6SEric Auger } 2350ef02cd6SEric Auger 2360ef02cd6SEric Auger static void secondary_lpi_test(void) 2370ef02cd6SEric Auger { 2380ef02cd6SEric Auger setup_irq(lpi_handler); 2390ef02cd6SEric Auger cpumask_set_cpu(smp_processor_id(), &ready); 2400ef02cd6SEric Auger while (1) 2410ef02cd6SEric Auger wfi(); 2420ef02cd6SEric Auger } 243*de582149SEric Auger 244*de582149SEric Auger static void check_lpi_hits(int *expected, const char *msg) 245*de582149SEric Auger { 246*de582149SEric Auger bool pass = true; 247*de582149SEric Auger int i; 248*de582149SEric Auger 249*de582149SEric Auger for_each_present_cpu(i) { 250*de582149SEric Auger if (acked[i] != expected[i]) { 251*de582149SEric Auger report_info("expected %d LPIs on PE #%d, %d observed", 252*de582149SEric Auger expected[i], i, acked[i]); 253*de582149SEric Auger pass = false; 254*de582149SEric Auger break; 255*de582149SEric Auger } 256*de582149SEric Auger } 257*de582149SEric Auger report(pass, "%s", msg); 258*de582149SEric Auger } 2590ef02cd6SEric Auger #endif 2600ef02cd6SEric Auger 2612e2d471dSAndrew Jones static void gicv2_ipi_send_self(void) 2622e2d471dSAndrew Jones { 263ca1b7a7bSAndrew Jones writel(2 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR); 2642e2d471dSAndrew Jones } 2652e2d471dSAndrew Jones 2662e2d471dSAndrew Jones static void gicv2_ipi_send_broadcast(void) 2672e2d471dSAndrew Jones { 268ca1b7a7bSAndrew Jones writel(1 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR); 2692e2d471dSAndrew Jones } 2702e2d471dSAndrew Jones 2712e2d471dSAndrew Jones static void gicv3_ipi_send_self(void) 2722e2d471dSAndrew Jones { 273ca1b7a7bSAndrew Jones gic_ipi_send_single(IPI_IRQ, smp_processor_id()); 2742e2d471dSAndrew Jones } 2752e2d471dSAndrew Jones 2762e2d471dSAndrew Jones static void gicv3_ipi_send_broadcast(void) 2772e2d471dSAndrew Jones { 278ca1b7a7bSAndrew Jones gicv3_write_sgi1r(1ULL << 40 | IPI_IRQ << 24); 2792e2d471dSAndrew Jones isb(); 2802e2d471dSAndrew Jones } 2812e2d471dSAndrew Jones 282ac4a67b6SAndrew Jones static void ipi_test_self(void) 283ac4a67b6SAndrew Jones { 284ac4a67b6SAndrew Jones cpumask_t mask; 285ac4a67b6SAndrew Jones 286ac4a67b6SAndrew Jones report_prefix_push("self"); 287ca1b7a7bSAndrew Jones stats_reset(); 288ac4a67b6SAndrew Jones cpumask_clear(&mask); 289ca1b7a7bSAndrew Jones cpumask_set_cpu(smp_processor_id(), &mask); 2902e2d471dSAndrew Jones gic->ipi.send_self(); 29196edb026SAndre Przywara check_acked("IPI: self", &mask); 292ac4a67b6SAndrew Jones report_prefix_pop(); 293ac4a67b6SAndrew Jones } 294ac4a67b6SAndrew Jones 295ac4a67b6SAndrew Jones static void ipi_test_smp(void) 296ac4a67b6SAndrew Jones { 297ac4a67b6SAndrew Jones cpumask_t mask; 2982e2d471dSAndrew Jones int i; 299ac4a67b6SAndrew Jones 300ac4a67b6SAndrew Jones report_prefix_push("target-list"); 301ca1b7a7bSAndrew Jones stats_reset(); 3022e2d471dSAndrew Jones cpumask_copy(&mask, &cpu_present_mask); 303ca1b7a7bSAndrew Jones for (i = smp_processor_id() & 1; i < nr_cpus; i += 2) 3042e2d471dSAndrew Jones cpumask_clear_cpu(i, &mask); 305ca1b7a7bSAndrew Jones gic_ipi_send_mask(IPI_IRQ, &mask); 30696edb026SAndre Przywara check_acked("IPI: directed", &mask); 307ac4a67b6SAndrew Jones report_prefix_pop(); 308ac4a67b6SAndrew Jones 309ac4a67b6SAndrew Jones report_prefix_push("broadcast"); 310ca1b7a7bSAndrew Jones stats_reset(); 311ac4a67b6SAndrew Jones cpumask_copy(&mask, &cpu_present_mask); 312ca1b7a7bSAndrew Jones cpumask_clear_cpu(smp_processor_id(), &mask); 3132e2d471dSAndrew Jones gic->ipi.send_broadcast(); 31496edb026SAndre Przywara check_acked("IPI: broadcast", &mask); 315ac4a67b6SAndrew Jones report_prefix_pop(); 316ac4a67b6SAndrew Jones } 317ac4a67b6SAndrew Jones 318ca1b7a7bSAndrew Jones static void ipi_send(void) 319ca1b7a7bSAndrew Jones { 32025f66327SEric Auger setup_irq(ipi_handler); 321ca1b7a7bSAndrew Jones wait_on_ready(); 322ca1b7a7bSAndrew Jones ipi_test_self(); 323ca1b7a7bSAndrew Jones ipi_test_smp(); 324ca1b7a7bSAndrew Jones check_spurious(); 325ca1b7a7bSAndrew Jones exit(report_summary()); 326ca1b7a7bSAndrew Jones } 327ca1b7a7bSAndrew Jones 328ac4a67b6SAndrew Jones static void ipi_recv(void) 329ac4a67b6SAndrew Jones { 33025f66327SEric Auger setup_irq(ipi_handler); 331ac4a67b6SAndrew Jones cpumask_set_cpu(smp_processor_id(), &ready); 332ac4a67b6SAndrew Jones while (1) 333ac4a67b6SAndrew Jones wfi(); 334ac4a67b6SAndrew Jones } 335ac4a67b6SAndrew Jones 33600b34f56SAndrew Jones static void ipi_test(void *data __unused) 337bfd500b4SAndrew Jones { 338bfd500b4SAndrew Jones if (smp_processor_id() == IPI_SENDER) 339bfd500b4SAndrew Jones ipi_send(); 340bfd500b4SAndrew Jones else 341bfd500b4SAndrew Jones ipi_recv(); 342bfd500b4SAndrew Jones } 343bfd500b4SAndrew Jones 3442e2d471dSAndrew Jones static struct gic gicv2 = { 3452e2d471dSAndrew Jones .ipi = { 3462e2d471dSAndrew Jones .send_self = gicv2_ipi_send_self, 3472e2d471dSAndrew Jones .send_broadcast = gicv2_ipi_send_broadcast, 3482e2d471dSAndrew Jones }, 3492e2d471dSAndrew Jones }; 3502e2d471dSAndrew Jones 3512e2d471dSAndrew Jones static struct gic gicv3 = { 3522e2d471dSAndrew Jones .ipi = { 3532e2d471dSAndrew Jones .send_self = gicv3_ipi_send_self, 3542e2d471dSAndrew Jones .send_broadcast = gicv3_ipi_send_broadcast, 3552e2d471dSAndrew Jones }, 3562e2d471dSAndrew Jones }; 3572e2d471dSAndrew Jones 358c152d8bcSChristoffer Dall static void ipi_clear_active_handler(struct pt_regs *regs __unused) 359c152d8bcSChristoffer Dall { 360c152d8bcSChristoffer Dall u32 irqstat = gic_read_iar(); 361c152d8bcSChristoffer Dall u32 irqnr = gic_iar_irqnr(irqstat); 362c152d8bcSChristoffer Dall 363c152d8bcSChristoffer Dall if (irqnr != GICC_INT_SPURIOUS) { 364c152d8bcSChristoffer Dall void *base; 365c152d8bcSChristoffer Dall u32 val = 1 << IPI_IRQ; 366c152d8bcSChristoffer Dall 367c152d8bcSChristoffer Dall if (gic_version() == 2) 368c152d8bcSChristoffer Dall base = gicv2_dist_base(); 369c152d8bcSChristoffer Dall else 3706d4d7c4bSAndrew Jones base = gicv3_sgi_base(); 371c152d8bcSChristoffer Dall 372c152d8bcSChristoffer Dall writel(val, base + GICD_ICACTIVER); 373c152d8bcSChristoffer Dall 374c152d8bcSChristoffer Dall smp_rmb(); /* pairs with wmb in stats_reset */ 375c152d8bcSChristoffer Dall ++acked[smp_processor_id()]; 376c152d8bcSChristoffer Dall check_irqnr(irqnr); 377c152d8bcSChristoffer Dall smp_wmb(); /* pairs with rmb in check_acked */ 378c152d8bcSChristoffer Dall } else { 379c152d8bcSChristoffer Dall ++spurious[smp_processor_id()]; 380c152d8bcSChristoffer Dall smp_wmb(); 381c152d8bcSChristoffer Dall } 382c152d8bcSChristoffer Dall } 383c152d8bcSChristoffer Dall 384c152d8bcSChristoffer Dall static void run_active_clear_test(void) 385c152d8bcSChristoffer Dall { 386c152d8bcSChristoffer Dall report_prefix_push("active"); 38725f66327SEric Auger setup_irq(ipi_clear_active_handler); 388c152d8bcSChristoffer Dall ipi_test_self(); 389c152d8bcSChristoffer Dall report_prefix_pop(); 390c152d8bcSChristoffer Dall } 391c152d8bcSChristoffer Dall 39278ad7e95SAndre Przywara static bool test_ro_pattern_32(void *address, u32 pattern, u32 orig) 39378ad7e95SAndre Przywara { 39478ad7e95SAndre Przywara u32 reg; 39578ad7e95SAndre Przywara 39678ad7e95SAndre Przywara writel(pattern, address); 39778ad7e95SAndre Przywara reg = readl(address); 39878ad7e95SAndre Przywara 39978ad7e95SAndre Przywara if (reg != orig) 40078ad7e95SAndre Przywara writel(orig, address); 40178ad7e95SAndre Przywara 40278ad7e95SAndre Przywara return reg == orig; 40378ad7e95SAndre Przywara } 40478ad7e95SAndre Przywara 40578ad7e95SAndre Przywara static bool test_readonly_32(void *address, bool razwi) 40678ad7e95SAndre Przywara { 40778ad7e95SAndre Przywara u32 orig, pattern; 40878ad7e95SAndre Przywara 40978ad7e95SAndre Przywara orig = readl(address); 41078ad7e95SAndre Przywara if (razwi && orig) 41178ad7e95SAndre Przywara return false; 41278ad7e95SAndre Przywara 41378ad7e95SAndre Przywara pattern = 0xffffffff; 41478ad7e95SAndre Przywara if (orig != pattern) { 41578ad7e95SAndre Przywara if (!test_ro_pattern_32(address, pattern, orig)) 41678ad7e95SAndre Przywara return false; 41778ad7e95SAndre Przywara } 41878ad7e95SAndre Przywara 41978ad7e95SAndre Przywara pattern = 0xa5a55a5a; 42078ad7e95SAndre Przywara if (orig != pattern) { 42178ad7e95SAndre Przywara if (!test_ro_pattern_32(address, pattern, orig)) 42278ad7e95SAndre Przywara return false; 42378ad7e95SAndre Przywara } 42478ad7e95SAndre Przywara 42578ad7e95SAndre Przywara pattern = 0; 42678ad7e95SAndre Przywara if (orig != pattern) { 42778ad7e95SAndre Przywara if (!test_ro_pattern_32(address, pattern, orig)) 42878ad7e95SAndre Przywara return false; 42978ad7e95SAndre Przywara } 43078ad7e95SAndre Przywara 43178ad7e95SAndre Przywara return true; 43278ad7e95SAndre Przywara } 43378ad7e95SAndre Przywara 43478ad7e95SAndre Przywara static void test_typer_v2(uint32_t reg) 43578ad7e95SAndre Przywara { 43678ad7e95SAndre Przywara int nr_gic_cpus = ((reg >> 5) & 0x7) + 1; 43778ad7e95SAndre Przywara 4388e0a4f41SAndre Przywara report_info("nr_cpus=%d", nr_cpus); 439a299895bSThomas Huth report(nr_cpus == nr_gic_cpus, "all CPUs have interrupts"); 44078ad7e95SAndre Przywara } 44178ad7e95SAndre Przywara 442ff31a1c4SAndre Przywara #define BYTE(reg32, byte) (((reg32) >> ((byte) * 8)) & 0xff) 443ff31a1c4SAndre Przywara #define REPLACE_BYTE(reg32, byte, new) (((reg32) & ~(0xff << ((byte) * 8))) |\ 444ff31a1c4SAndre Przywara ((new) << ((byte) * 8))) 445ff31a1c4SAndre Przywara 446ff31a1c4SAndre Przywara /* 447ff31a1c4SAndre Przywara * Some registers are byte accessible, do a byte-wide read and write of known 448ff31a1c4SAndre Przywara * content to check for this. 449ff31a1c4SAndre Przywara * Apply a @mask to cater for special register properties. 450ff31a1c4SAndre Przywara * @pattern contains the value already in the register. 451ff31a1c4SAndre Przywara */ 452ff31a1c4SAndre Przywara static void test_byte_access(void *base_addr, u32 pattern, u32 mask) 453ff31a1c4SAndre Przywara { 454ff31a1c4SAndre Przywara u32 reg = readb(base_addr + 1); 4558e0a4f41SAndre Przywara bool res; 456ff31a1c4SAndre Przywara 4578e0a4f41SAndre Przywara res = (reg == (BYTE(pattern, 1) & (mask >> 8))); 458a299895bSThomas Huth report(res, "byte reads successful"); 4598e0a4f41SAndre Przywara if (!res) 4608e0a4f41SAndre Przywara report_info("byte 1 of 0x%08x => 0x%02x", pattern & mask, reg); 461ff31a1c4SAndre Przywara 462ff31a1c4SAndre Przywara pattern = REPLACE_BYTE(pattern, 2, 0x1f); 463ff31a1c4SAndre Przywara writeb(BYTE(pattern, 2), base_addr + 2); 464ff31a1c4SAndre Przywara reg = readl(base_addr); 4658e0a4f41SAndre Przywara res = (reg == (pattern & mask)); 466a299895bSThomas Huth report(res, "byte writes successful"); 4678e0a4f41SAndre Przywara if (!res) 4688e0a4f41SAndre Przywara report_info("writing 0x%02x into bytes 2 => 0x%08x", 4698e0a4f41SAndre Przywara BYTE(pattern, 2), reg); 470ff31a1c4SAndre Przywara } 471ff31a1c4SAndre Przywara 472ff31a1c4SAndre Przywara static void test_priorities(int nr_irqs, void *priptr) 473ff31a1c4SAndre Przywara { 474ff31a1c4SAndre Przywara u32 orig_prio, reg, pri_bits; 475ff31a1c4SAndre Przywara u32 pri_mask, pattern; 476ff31a1c4SAndre Przywara void *first_spi = priptr + GIC_FIRST_SPI; 477ff31a1c4SAndre Przywara 478ff31a1c4SAndre Przywara orig_prio = readl(first_spi); 479ff31a1c4SAndre Przywara report_prefix_push("IPRIORITYR"); 480ff31a1c4SAndre Przywara 481ff31a1c4SAndre Przywara /* 482ff31a1c4SAndre Przywara * Determine implemented number of priority bits by writing all 1's 483ff31a1c4SAndre Przywara * and checking the number of cleared bits in the value read back. 484ff31a1c4SAndre Przywara */ 485ff31a1c4SAndre Przywara writel(0xffffffff, first_spi); 486ff31a1c4SAndre Przywara pri_mask = readl(first_spi); 487ff31a1c4SAndre Przywara 488ff31a1c4SAndre Przywara reg = ~pri_mask; 489a299895bSThomas Huth report((((reg >> 16) == (reg & 0xffff)) && 490a299895bSThomas Huth ((reg & 0xff) == ((reg >> 8) & 0xff))), 491a299895bSThomas Huth "consistent priority masking"); 4928e0a4f41SAndre Przywara report_info("priority mask is 0x%08x", pri_mask); 493ff31a1c4SAndre Przywara 494ff31a1c4SAndre Przywara reg = reg & 0xff; 495ff31a1c4SAndre Przywara for (pri_bits = 8; reg & 1; reg >>= 1, pri_bits--) 496ff31a1c4SAndre Przywara ; 497a299895bSThomas Huth report(pri_bits >= 4, "implements at least 4 priority bits"); 4988e0a4f41SAndre Przywara report_info("%d priority bits implemented", pri_bits); 499ff31a1c4SAndre Przywara 500ff31a1c4SAndre Przywara pattern = 0; 501ff31a1c4SAndre Przywara writel(pattern, first_spi); 502a299895bSThomas Huth report(readl(first_spi) == pattern, "clearing priorities"); 503ff31a1c4SAndre Przywara 504ff31a1c4SAndre Przywara /* setting all priorities to their max valus was tested above */ 505ff31a1c4SAndre Przywara 506a299895bSThomas Huth report(test_readonly_32(priptr + nr_irqs, true), 507a299895bSThomas Huth "accesses beyond limit RAZ/WI"); 508ff31a1c4SAndre Przywara 509ff31a1c4SAndre Przywara writel(pattern, priptr + nr_irqs - 4); 510a299895bSThomas Huth report(readl(priptr + nr_irqs - 4) == (pattern & pri_mask), 511a299895bSThomas Huth "accessing last SPIs"); 512ff31a1c4SAndre Przywara 513ff31a1c4SAndre Przywara pattern = 0xff7fbf3f; 514ff31a1c4SAndre Przywara writel(pattern, first_spi); 515a299895bSThomas Huth report(readl(first_spi) == (pattern & pri_mask), 516a299895bSThomas Huth "priorities are preserved"); 517ff31a1c4SAndre Przywara 518ff31a1c4SAndre Przywara /* The PRIORITY registers are byte accessible. */ 519ff31a1c4SAndre Przywara test_byte_access(first_spi, pattern, pri_mask); 520ff31a1c4SAndre Przywara 521ff31a1c4SAndre Przywara report_prefix_pop(); 522ff31a1c4SAndre Przywara writel(orig_prio, first_spi); 523ff31a1c4SAndre Przywara } 524ff31a1c4SAndre Przywara 525fe572a5eSAndre Przywara /* GICD_ITARGETSR is only used by GICv2. */ 526fe572a5eSAndre Przywara static void test_targets(int nr_irqs) 527fe572a5eSAndre Przywara { 528fe572a5eSAndre Przywara void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR; 529fe572a5eSAndre Przywara u32 orig_targets; 530fe572a5eSAndre Przywara u32 cpu_mask; 531fe572a5eSAndre Przywara u32 pattern, reg; 532fe572a5eSAndre Przywara 533fe572a5eSAndre Przywara orig_targets = readl(targetsptr + GIC_FIRST_SPI); 534fe572a5eSAndre Przywara report_prefix_push("ITARGETSR"); 535fe572a5eSAndre Przywara 536fe572a5eSAndre Przywara cpu_mask = (1 << nr_cpus) - 1; 537fe572a5eSAndre Przywara cpu_mask |= cpu_mask << 8; 538fe572a5eSAndre Przywara cpu_mask |= cpu_mask << 16; 539fe572a5eSAndre Przywara 540fe572a5eSAndre Przywara /* Check that bits for non implemented CPUs are RAZ/WI. */ 541fe572a5eSAndre Przywara if (nr_cpus < 8) { 542fe572a5eSAndre Przywara writel(0xffffffff, targetsptr + GIC_FIRST_SPI); 543a299895bSThomas Huth report(!(readl(targetsptr + GIC_FIRST_SPI) & ~cpu_mask), 544a299895bSThomas Huth "bits for non-existent CPUs masked"); 5458e0a4f41SAndre Przywara report_info("%d non-existent CPUs", 8 - nr_cpus); 546fe572a5eSAndre Przywara } else { 547fe572a5eSAndre Przywara report_skip("CPU masking (all CPUs implemented)"); 548fe572a5eSAndre Przywara } 549fe572a5eSAndre Przywara 550a299895bSThomas Huth report(test_readonly_32(targetsptr + nr_irqs, true), 551a299895bSThomas Huth "accesses beyond limit RAZ/WI"); 552fe572a5eSAndre Przywara 553fe572a5eSAndre Przywara pattern = 0x0103020f; 554fe572a5eSAndre Przywara writel(pattern, targetsptr + GIC_FIRST_SPI); 555fe572a5eSAndre Przywara reg = readl(targetsptr + GIC_FIRST_SPI); 556a299895bSThomas Huth report(reg == (pattern & cpu_mask), "register content preserved"); 5578e0a4f41SAndre Przywara if (reg != (pattern & cpu_mask)) 5588e0a4f41SAndre Przywara report_info("writing %08x reads back as %08x", 5598e0a4f41SAndre Przywara pattern & cpu_mask, reg); 560fe572a5eSAndre Przywara 561fe572a5eSAndre Przywara /* The TARGETS registers are byte accessible. */ 562fe572a5eSAndre Przywara test_byte_access(targetsptr + GIC_FIRST_SPI, pattern, cpu_mask); 563fe572a5eSAndre Przywara 564fe572a5eSAndre Przywara writel(orig_targets, targetsptr + GIC_FIRST_SPI); 565da5b8576SAndre Przywara 566da5b8576SAndre Przywara report_prefix_pop(); 567fe572a5eSAndre Przywara } 568fe572a5eSAndre Przywara 56978ad7e95SAndre Przywara static void gic_test_mmio(void) 57078ad7e95SAndre Przywara { 57178ad7e95SAndre Przywara u32 reg; 57278ad7e95SAndre Przywara int nr_irqs; 57378ad7e95SAndre Przywara void *gic_dist_base, *idreg; 57478ad7e95SAndre Przywara 57578ad7e95SAndre Przywara switch(gic_version()) { 57678ad7e95SAndre Przywara case 0x2: 57778ad7e95SAndre Przywara gic_dist_base = gicv2_dist_base(); 57878ad7e95SAndre Przywara idreg = gic_dist_base + GICD_ICPIDR2; 57978ad7e95SAndre Przywara break; 58078ad7e95SAndre Przywara case 0x3: 58178ad7e95SAndre Przywara report_abort("GICv3 MMIO tests NYI"); 58278ad7e95SAndre Przywara default: 58378ad7e95SAndre Przywara report_abort("GIC version %d not supported", gic_version()); 58478ad7e95SAndre Przywara } 58578ad7e95SAndre Przywara 58678ad7e95SAndre Przywara reg = readl(gic_dist_base + GICD_TYPER); 58778ad7e95SAndre Przywara nr_irqs = GICD_TYPER_IRQS(reg); 58878ad7e95SAndre Przywara report_info("number of implemented SPIs: %d", nr_irqs - GIC_FIRST_SPI); 58978ad7e95SAndre Przywara 59078ad7e95SAndre Przywara test_typer_v2(reg); 59178ad7e95SAndre Przywara 59278ad7e95SAndre Przywara report_info("IIDR: 0x%08x", readl(gic_dist_base + GICD_IIDR)); 59378ad7e95SAndre Przywara 594a299895bSThomas Huth report(test_readonly_32(gic_dist_base + GICD_TYPER, false), 595a299895bSThomas Huth "GICD_TYPER is read-only"); 596a299895bSThomas Huth report(test_readonly_32(gic_dist_base + GICD_IIDR, false), 597a299895bSThomas Huth "GICD_IIDR is read-only"); 59878ad7e95SAndre Przywara 59978ad7e95SAndre Przywara reg = readl(idreg); 600a299895bSThomas Huth report(test_readonly_32(idreg, false), "ICPIDR2 is read-only"); 6018e0a4f41SAndre Przywara report_info("value of ICPIDR2: 0x%08x", reg); 602ff31a1c4SAndre Przywara 603ff31a1c4SAndre Przywara test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR); 604fe572a5eSAndre Przywara 605fe572a5eSAndre Przywara if (gic_version() == 2) 606fe572a5eSAndre Przywara test_targets(nr_irqs); 60778ad7e95SAndre Przywara } 60878ad7e95SAndre Przywara 609ba74b106SEric Auger #if defined(__arm__) 610ba74b106SEric Auger 611ba74b106SEric Auger static void test_its_introspection(void) {} 6120ef02cd6SEric Auger static void test_its_trigger(void) {} 61364260a5fSEric Auger static void test_its_migration(void) {} 614*de582149SEric Auger static void test_its_pending_migration(void) {} 615*de582149SEric Auger static void test_migrate_unmapped_collection(void) {} 616ba74b106SEric Auger 617ba74b106SEric Auger #else /* __aarch64__ */ 618ba74b106SEric Auger 619ba74b106SEric Auger static void test_its_introspection(void) 620ba74b106SEric Auger { 621ba74b106SEric Auger struct its_baser *dev_baser = &its_data.device_baser; 622ba74b106SEric Auger struct its_baser *coll_baser = &its_data.coll_baser; 623ba74b106SEric Auger struct its_typer *typer = &its_data.typer; 624ba74b106SEric Auger 625ba74b106SEric Auger if (!gicv3_its_base()) { 626ba74b106SEric Auger report_skip("No ITS, skip ..."); 627ba74b106SEric Auger return; 628ba74b106SEric Auger } 629ba74b106SEric Auger 630ba74b106SEric Auger /* IIDR */ 631ba74b106SEric Auger report(test_readonly_32(gicv3_its_base() + GITS_IIDR, false), 632ba74b106SEric Auger "GITS_IIDR is read-only"), 633ba74b106SEric Auger 634ba74b106SEric Auger /* TYPER */ 635ba74b106SEric Auger report(test_readonly_32(gicv3_its_base() + GITS_TYPER, false), 636ba74b106SEric Auger "GITS_TYPER is read-only"); 637ba74b106SEric Auger 638ba74b106SEric Auger report(typer->phys_lpi, "ITS supports physical LPIs"); 639ba74b106SEric Auger report_info("vLPI support: %s", typer->virt_lpi ? "yes" : "no"); 640ba74b106SEric Auger report_info("ITT entry size = 0x%x", typer->ite_size); 641ba74b106SEric Auger report_info("Bit Count: EventID=%d DeviceId=%d CollId=%d", 642ba74b106SEric Auger typer->eventid_bits, typer->deviceid_bits, 643ba74b106SEric Auger typer->collid_bits); 644ba74b106SEric Auger report(typer->eventid_bits && typer->deviceid_bits && 645ba74b106SEric Auger typer->collid_bits, "ID spaces"); 646ba74b106SEric Auger report_info("Target address format %s", 647ba74b106SEric Auger typer->pta ? "Redist base address" : "PE #"); 648ba74b106SEric Auger 649ba74b106SEric Auger report(dev_baser && coll_baser, "detect device and collection BASER"); 650ba74b106SEric Auger report_info("device table entry_size = 0x%x", dev_baser->esz); 651ba74b106SEric Auger report_info("collection table entry_size = 0x%x", coll_baser->esz); 652ba74b106SEric Auger } 653ba74b106SEric Auger 6540ef02cd6SEric Auger static int its_prerequisites(int nb_cpus) 6550ef02cd6SEric Auger { 6560ef02cd6SEric Auger int cpu; 6570ef02cd6SEric Auger 6580ef02cd6SEric Auger if (!gicv3_its_base()) { 6590ef02cd6SEric Auger report_skip("No ITS, skip ..."); 6600ef02cd6SEric Auger return -1; 6610ef02cd6SEric Auger } 6620ef02cd6SEric Auger 6630ef02cd6SEric Auger if (nr_cpus < nb_cpus) { 6640ef02cd6SEric Auger report_skip("Test requires at least %d vcpus", nb_cpus); 6650ef02cd6SEric Auger return -1; 6660ef02cd6SEric Auger } 6670ef02cd6SEric Auger 6680ef02cd6SEric Auger stats_reset(); 6690ef02cd6SEric Auger 6700ef02cd6SEric Auger setup_irq(lpi_handler); 6710ef02cd6SEric Auger 6720ef02cd6SEric Auger for_each_present_cpu(cpu) { 6730ef02cd6SEric Auger if (cpu == 0) 6740ef02cd6SEric Auger continue; 6750ef02cd6SEric Auger smp_boot_secondary(cpu, secondary_lpi_test); 6760ef02cd6SEric Auger } 6770ef02cd6SEric Auger wait_on_ready(); 6780ef02cd6SEric Auger 6790ef02cd6SEric Auger its_enable_defaults(); 6800ef02cd6SEric Auger 6810ef02cd6SEric Auger return 0; 6820ef02cd6SEric Auger } 6830ef02cd6SEric Auger 68464260a5fSEric Auger /* 68564260a5fSEric Auger * Setup the configuration for those mappings: 68664260a5fSEric Auger * dev_id=2 event=20 -> vcpu 3, intid=8195 68764260a5fSEric Auger * dev_id=7 event=255 -> vcpu 2, intid=8196 68864260a5fSEric Auger * LPIs ready to hit 68964260a5fSEric Auger */ 69064260a5fSEric Auger static int its_setup1(void) 6910ef02cd6SEric Auger { 6920ef02cd6SEric Auger struct its_collection *col3, *col2; 6930ef02cd6SEric Auger struct its_device *dev2, *dev7; 6940ef02cd6SEric Auger 6950ef02cd6SEric Auger if (its_prerequisites(4)) 69664260a5fSEric Auger return -1; 6970ef02cd6SEric Auger 6980ef02cd6SEric Auger dev2 = its_create_device(2 /* dev id */, 8 /* nb_ites */); 6990ef02cd6SEric Auger dev7 = its_create_device(7 /* dev id */, 8 /* nb_ites */); 7000ef02cd6SEric Auger 7010ef02cd6SEric Auger col3 = its_create_collection(3 /* col id */, 3/* target PE */); 7020ef02cd6SEric Auger col2 = its_create_collection(2 /* col id */, 2/* target PE */); 7030ef02cd6SEric Auger 7040ef02cd6SEric Auger gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT); 7050ef02cd6SEric Auger gicv3_lpi_set_config(8196, LPI_PROP_DEFAULT); 7060ef02cd6SEric Auger 7070ef02cd6SEric Auger /* 7080ef02cd6SEric Auger * dev=2, eventid=20 -> lpi= 8195, col=3 7090ef02cd6SEric Auger * dev=7, eventid=255 -> lpi= 8196, col=2 7100ef02cd6SEric Auger */ 7110ef02cd6SEric Auger its_send_mapd(dev2, true); 7120ef02cd6SEric Auger its_send_mapd(dev7, true); 7130ef02cd6SEric Auger 7140ef02cd6SEric Auger its_send_mapc(col3, true); 7150ef02cd6SEric Auger its_send_mapc(col2, true); 7160ef02cd6SEric Auger 7170ef02cd6SEric Auger its_send_invall(col2); 7180ef02cd6SEric Auger its_send_invall(col3); 7190ef02cd6SEric Auger 7200ef02cd6SEric Auger its_send_mapti(dev2, 8195 /* lpi id */, 20 /* event id */, col3); 7210ef02cd6SEric Auger its_send_mapti(dev7, 8196 /* lpi id */, 255 /* event id */, col2); 72264260a5fSEric Auger return 0; 72364260a5fSEric Auger } 72464260a5fSEric Auger 72564260a5fSEric Auger static void test_its_trigger(void) 72664260a5fSEric Auger { 72764260a5fSEric Auger struct its_collection *col3; 72864260a5fSEric Auger struct its_device *dev2, *dev7; 72964260a5fSEric Auger 73064260a5fSEric Auger if (its_setup1()) 73164260a5fSEric Auger return; 73264260a5fSEric Auger 73364260a5fSEric Auger col3 = its_get_collection(3); 73464260a5fSEric Auger dev2 = its_get_device(2); 73564260a5fSEric Auger dev7 = its_get_device(7); 73664260a5fSEric Auger 73764260a5fSEric Auger report_prefix_push("int"); 7380ef02cd6SEric Auger 7390ef02cd6SEric Auger lpi_stats_expect(3, 8195); 7400ef02cd6SEric Auger its_send_int(dev2, 20); 7410ef02cd6SEric Auger check_lpi_stats("dev=2, eventid=20 -> lpi= 8195, col=3"); 7420ef02cd6SEric Auger 7430ef02cd6SEric Auger lpi_stats_expect(2, 8196); 7440ef02cd6SEric Auger its_send_int(dev7, 255); 7450ef02cd6SEric Auger check_lpi_stats("dev=7, eventid=255 -> lpi= 8196, col=2"); 7460ef02cd6SEric Auger 7470ef02cd6SEric Auger report_prefix_pop(); 7480ef02cd6SEric Auger 7490ef02cd6SEric Auger report_prefix_push("inv/invall"); 7500ef02cd6SEric Auger 7510ef02cd6SEric Auger /* 7520ef02cd6SEric Auger * disable 8195, check dev2/eventid=20 does not trigger the 7530ef02cd6SEric Auger * corresponding LPI 7540ef02cd6SEric Auger */ 7550ef02cd6SEric Auger gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT & ~LPI_PROP_ENABLED); 7560ef02cd6SEric Auger its_send_inv(dev2, 20); 7570ef02cd6SEric Auger 7580ef02cd6SEric Auger lpi_stats_expect(-1, -1); 7590ef02cd6SEric Auger its_send_int(dev2, 20); 7600ef02cd6SEric Auger check_lpi_stats("dev2/eventid=20 does not trigger any LPI"); 7610ef02cd6SEric Auger 7620ef02cd6SEric Auger /* 7630ef02cd6SEric Auger * re-enable the LPI but willingly do not call invall 7640ef02cd6SEric Auger * so the change in config is not taken into account. 7650ef02cd6SEric Auger * The LPI should not hit 7660ef02cd6SEric Auger */ 7670ef02cd6SEric Auger gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT); 7680ef02cd6SEric Auger lpi_stats_expect(-1, -1); 7690ef02cd6SEric Auger its_send_int(dev2, 20); 7700ef02cd6SEric Auger check_lpi_stats("dev2/eventid=20 still does not trigger any LPI"); 7710ef02cd6SEric Auger 7720ef02cd6SEric Auger /* Now call the invall and check the LPI hits */ 7730ef02cd6SEric Auger its_send_invall(col3); 7740ef02cd6SEric Auger lpi_stats_expect(3, 8195); 7750ef02cd6SEric Auger its_send_int(dev2, 20); 7760ef02cd6SEric Auger check_lpi_stats("dev2/eventid=20 now triggers an LPI"); 7770ef02cd6SEric Auger 7780ef02cd6SEric Auger report_prefix_pop(); 7790ef02cd6SEric Auger 7800ef02cd6SEric Auger report_prefix_push("mapd valid=false"); 7810ef02cd6SEric Auger /* 7820ef02cd6SEric Auger * Unmap device 2 and check the eventid 20 formerly 7830ef02cd6SEric Auger * attached to it does not hit anymore 7840ef02cd6SEric Auger */ 7850ef02cd6SEric Auger 7860ef02cd6SEric Auger its_send_mapd(dev2, false); 7870ef02cd6SEric Auger lpi_stats_expect(-1, -1); 7880ef02cd6SEric Auger its_send_int(dev2, 20); 7890ef02cd6SEric Auger check_lpi_stats("no LPI after device unmap"); 7900ef02cd6SEric Auger report_prefix_pop(); 7910ef02cd6SEric Auger } 79264260a5fSEric Auger 79364260a5fSEric Auger static void test_its_migration(void) 79464260a5fSEric Auger { 79564260a5fSEric Auger struct its_device *dev2, *dev7; 79664260a5fSEric Auger bool test_skipped = false; 79764260a5fSEric Auger 79864260a5fSEric Auger if (its_setup1()) { 79964260a5fSEric Auger test_skipped = true; 80064260a5fSEric Auger goto do_migrate; 80164260a5fSEric Auger } 80264260a5fSEric Auger 80364260a5fSEric Auger dev2 = its_get_device(2); 80464260a5fSEric Auger dev7 = its_get_device(7); 80564260a5fSEric Auger 80664260a5fSEric Auger do_migrate: 80764260a5fSEric Auger puts("Now migrate the VM, then press a key to continue...\n"); 80864260a5fSEric Auger (void)getchar(); 80964260a5fSEric Auger report_info("Migration complete"); 81064260a5fSEric Auger if (test_skipped) 81164260a5fSEric Auger return; 81264260a5fSEric Auger 81364260a5fSEric Auger lpi_stats_expect(3, 8195); 81464260a5fSEric Auger its_send_int(dev2, 20); 81564260a5fSEric Auger check_lpi_stats("dev2/eventid=20 triggers LPI 8195 on PE #3 after migration"); 81664260a5fSEric Auger 81764260a5fSEric Auger lpi_stats_expect(2, 8196); 81864260a5fSEric Auger its_send_int(dev7, 255); 81964260a5fSEric Auger check_lpi_stats("dev7/eventid=255 triggers LPI 8196 on PE #2 after migration"); 82064260a5fSEric Auger } 821*de582149SEric Auger 822*de582149SEric Auger #define ERRATA_UNMAPPED_COLLECTIONS "ERRATA_8c58be34494b" 823*de582149SEric Auger 824*de582149SEric Auger static void test_migrate_unmapped_collection(void) 825*de582149SEric Auger { 826*de582149SEric Auger struct its_collection *col = NULL; 827*de582149SEric Auger struct its_device *dev2 = NULL, *dev7 = NULL; 828*de582149SEric Auger bool test_skipped = false; 829*de582149SEric Auger int pe0 = 0; 830*de582149SEric Auger u8 config; 831*de582149SEric Auger 832*de582149SEric Auger if (its_setup1()) { 833*de582149SEric Auger test_skipped = true; 834*de582149SEric Auger goto do_migrate; 835*de582149SEric Auger } 836*de582149SEric Auger 837*de582149SEric Auger if (!errata(ERRATA_UNMAPPED_COLLECTIONS)) { 838*de582149SEric Auger report_skip("Skipping test, as this test hangs without the fix. " 839*de582149SEric Auger "Set %s=y to enable.", ERRATA_UNMAPPED_COLLECTIONS); 840*de582149SEric Auger test_skipped = true; 841*de582149SEric Auger goto do_migrate; 842*de582149SEric Auger } 843*de582149SEric Auger 844*de582149SEric Auger col = its_create_collection(pe0, pe0); 845*de582149SEric Auger dev2 = its_get_device(2); 846*de582149SEric Auger dev7 = its_get_device(7); 847*de582149SEric Auger 848*de582149SEric Auger /* MAPTI with the collection unmapped */ 849*de582149SEric Auger its_send_mapti(dev2, 8192, 0, col); 850*de582149SEric Auger gicv3_lpi_set_config(8192, LPI_PROP_DEFAULT); 851*de582149SEric Auger 852*de582149SEric Auger do_migrate: 853*de582149SEric Auger puts("Now migrate the VM, then press a key to continue...\n"); 854*de582149SEric Auger (void)getchar(); 855*de582149SEric Auger report_info("Migration complete"); 856*de582149SEric Auger if (test_skipped) 857*de582149SEric Auger return; 858*de582149SEric Auger 859*de582149SEric Auger /* on the destination, map the collection */ 860*de582149SEric Auger its_send_mapc(col, true); 861*de582149SEric Auger its_send_invall(col); 862*de582149SEric Auger 863*de582149SEric Auger lpi_stats_expect(2, 8196); 864*de582149SEric Auger its_send_int(dev7, 255); 865*de582149SEric Auger check_lpi_stats("dev7/eventid= 255 triggered LPI 8196 on PE #2"); 866*de582149SEric Auger 867*de582149SEric Auger config = gicv3_lpi_get_config(8192); 868*de582149SEric Auger report(config == LPI_PROP_DEFAULT, 869*de582149SEric Auger "Config of LPI 8192 was properly migrated"); 870*de582149SEric Auger 871*de582149SEric Auger lpi_stats_expect(pe0, 8192); 872*de582149SEric Auger its_send_int(dev2, 0); 873*de582149SEric Auger check_lpi_stats("dev2/eventid = 0 triggered LPI 8192 on PE0"); 874*de582149SEric Auger } 875*de582149SEric Auger 876*de582149SEric Auger static void test_its_pending_migration(void) 877*de582149SEric Auger { 878*de582149SEric Auger struct its_device *dev; 879*de582149SEric Auger struct its_collection *collection[2]; 880*de582149SEric Auger int *expected = calloc(nr_cpus, sizeof(int)); 881*de582149SEric Auger int pe0 = nr_cpus - 1, pe1 = nr_cpus - 2; 882*de582149SEric Auger bool test_skipped = false; 883*de582149SEric Auger u64 pendbaser; 884*de582149SEric Auger void *ptr; 885*de582149SEric Auger int i; 886*de582149SEric Auger 887*de582149SEric Auger if (its_prerequisites(4)) { 888*de582149SEric Auger test_skipped = true; 889*de582149SEric Auger goto do_migrate; 890*de582149SEric Auger } 891*de582149SEric Auger 892*de582149SEric Auger dev = its_create_device(2 /* dev id */, 8 /* nb_ites */); 893*de582149SEric Auger its_send_mapd(dev, true); 894*de582149SEric Auger 895*de582149SEric Auger collection[0] = its_create_collection(pe0, pe0); 896*de582149SEric Auger collection[1] = its_create_collection(pe1, pe1); 897*de582149SEric Auger its_send_mapc(collection[0], true); 898*de582149SEric Auger its_send_mapc(collection[1], true); 899*de582149SEric Auger 900*de582149SEric Auger /* disable lpi at redist level */ 901*de582149SEric Auger gicv3_lpi_rdist_disable(pe0); 902*de582149SEric Auger gicv3_lpi_rdist_disable(pe1); 903*de582149SEric Auger 904*de582149SEric Auger /* lpis are interleaved inbetween the 2 PEs */ 905*de582149SEric Auger for (i = 0; i < 256; i++) { 906*de582149SEric Auger struct its_collection *col = i % 2 ? collection[0] : 907*de582149SEric Auger collection[1]; 908*de582149SEric Auger int vcpu = col->target_address >> 16; 909*de582149SEric Auger 910*de582149SEric Auger its_send_mapti(dev, LPI(i), i, col); 911*de582149SEric Auger gicv3_lpi_set_config(LPI(i), LPI_PROP_DEFAULT); 912*de582149SEric Auger gicv3_lpi_set_clr_pending(vcpu, LPI(i), true); 913*de582149SEric Auger } 914*de582149SEric Auger its_send_invall(collection[0]); 915*de582149SEric Auger its_send_invall(collection[1]); 916*de582149SEric Auger 917*de582149SEric Auger /* Clear the PTZ bit on each pendbaser */ 918*de582149SEric Auger 919*de582149SEric Auger expected[pe0] = 128; 920*de582149SEric Auger expected[pe1] = 128; 921*de582149SEric Auger 922*de582149SEric Auger ptr = gicv3_data.redist_base[pe0] + GICR_PENDBASER; 923*de582149SEric Auger pendbaser = readq(ptr); 924*de582149SEric Auger writeq(pendbaser & ~GICR_PENDBASER_PTZ, ptr); 925*de582149SEric Auger 926*de582149SEric Auger ptr = gicv3_data.redist_base[pe1] + GICR_PENDBASER; 927*de582149SEric Auger pendbaser = readq(ptr); 928*de582149SEric Auger writeq(pendbaser & ~GICR_PENDBASER_PTZ, ptr); 929*de582149SEric Auger 930*de582149SEric Auger gicv3_lpi_rdist_enable(pe0); 931*de582149SEric Auger gicv3_lpi_rdist_enable(pe1); 932*de582149SEric Auger 933*de582149SEric Auger do_migrate: 934*de582149SEric Auger puts("Now migrate the VM, then press a key to continue...\n"); 935*de582149SEric Auger (void)getchar(); 936*de582149SEric Auger report_info("Migration complete"); 937*de582149SEric Auger if (test_skipped) 938*de582149SEric Auger return; 939*de582149SEric Auger 940*de582149SEric Auger /* let's wait for the 256 LPIs to be handled */ 941*de582149SEric Auger mdelay(1000); 942*de582149SEric Auger 943*de582149SEric Auger check_lpi_hits(expected, "128 LPIs on both PE0 and PE1 after migration"); 944*de582149SEric Auger } 945ba74b106SEric Auger #endif 946ba74b106SEric Auger 947ac4a67b6SAndrew Jones int main(int argc, char **argv) 948ac4a67b6SAndrew Jones { 9492e2d471dSAndrew Jones if (!gic_init()) { 950ac4a67b6SAndrew Jones printf("No supported gic present, skipping tests...\n"); 951ac4a67b6SAndrew Jones return report_summary(); 952ac4a67b6SAndrew Jones } 953ac4a67b6SAndrew Jones 9542b19b829SAndrew Jones report_prefix_pushf("gicv%d", gic_version()); 955ac4a67b6SAndrew Jones 9562e2d471dSAndrew Jones switch (gic_version()) { 9572e2d471dSAndrew Jones case 2: 9582e2d471dSAndrew Jones gic = &gicv2; 9592e2d471dSAndrew Jones break; 9602e2d471dSAndrew Jones case 3: 9612e2d471dSAndrew Jones gic = &gicv3; 9622e2d471dSAndrew Jones break; 9632e2d471dSAndrew Jones } 9642e2d471dSAndrew Jones 965ac4a67b6SAndrew Jones if (argc < 2) 966ac4a67b6SAndrew Jones report_abort("no test specified"); 967ac4a67b6SAndrew Jones 968ac4a67b6SAndrew Jones if (strcmp(argv[1], "ipi") == 0) { 969ac4a67b6SAndrew Jones report_prefix_push(argv[1]); 970ac4a67b6SAndrew Jones nr_cpu_check(2); 97100b34f56SAndrew Jones on_cpus(ipi_test, NULL); 972c152d8bcSChristoffer Dall } else if (strcmp(argv[1], "active") == 0) { 973c152d8bcSChristoffer Dall run_active_clear_test(); 97478ad7e95SAndre Przywara } else if (strcmp(argv[1], "mmio") == 0) { 97578ad7e95SAndre Przywara report_prefix_push(argv[1]); 97678ad7e95SAndre Przywara gic_test_mmio(); 97778ad7e95SAndre Przywara report_prefix_pop(); 9780ef02cd6SEric Auger } else if (!strcmp(argv[1], "its-trigger")) { 9790ef02cd6SEric Auger report_prefix_push(argv[1]); 9800ef02cd6SEric Auger test_its_trigger(); 9810ef02cd6SEric Auger report_prefix_pop(); 98264260a5fSEric Auger } else if (!strcmp(argv[1], "its-migration")) { 98364260a5fSEric Auger report_prefix_push(argv[1]); 98464260a5fSEric Auger test_its_migration(); 98564260a5fSEric Auger report_prefix_pop(); 986*de582149SEric Auger } else if (!strcmp(argv[1], "its-pending-migration")) { 987*de582149SEric Auger report_prefix_push(argv[1]); 988*de582149SEric Auger test_its_pending_migration(); 989*de582149SEric Auger report_prefix_pop(); 990*de582149SEric Auger } else if (!strcmp(argv[1], "its-migrate-unmapped-collection")) { 991*de582149SEric Auger report_prefix_push(argv[1]); 992*de582149SEric Auger test_migrate_unmapped_collection(); 993*de582149SEric Auger report_prefix_pop(); 994ba74b106SEric Auger } else if (strcmp(argv[1], "its-introspection") == 0) { 995ba74b106SEric Auger report_prefix_push(argv[1]); 996ba74b106SEric Auger test_its_introspection(); 997ba74b106SEric Auger report_prefix_pop(); 998ac4a67b6SAndrew Jones } else { 999ac4a67b6SAndrew Jones report_abort("Unknown subtest '%s'", argv[1]); 1000ac4a67b6SAndrew Jones } 1001ac4a67b6SAndrew Jones 1002ac4a67b6SAndrew Jones return report_summary(); 1003ac4a67b6SAndrew Jones } 1004