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> 15de582149SEric 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 } 63ca1b7a7bSAndrew Jones 64*7af008b1SAlexandru Elisei static void wait_for_interrupts(cpumask_t *mask) 65ac4a67b6SAndrew Jones { 66ac4a67b6SAndrew Jones int nr_pass, cpu, i; 67ac4a67b6SAndrew Jones 68ac4a67b6SAndrew Jones /* Wait up to 5s for all interrupts to be delivered */ 69*7af008b1SAlexandru Elisei for (i = 0; i < 50; i++) { 70ac4a67b6SAndrew Jones mdelay(100); 71ac4a67b6SAndrew Jones nr_pass = 0; 72ac4a67b6SAndrew Jones for_each_present_cpu(cpu) { 73*7af008b1SAlexandru Elisei /* 74*7af008b1SAlexandru Elisei * A CPU having received more than one interrupts will 75*7af008b1SAlexandru Elisei * show up in check_acked(), and no matter how long we 76*7af008b1SAlexandru Elisei * wait it cannot un-receive it. Consider at least one 77*7af008b1SAlexandru Elisei * interrupt as a pass. 78*7af008b1SAlexandru Elisei */ 79ac4a67b6SAndrew Jones nr_pass += cpumask_test_cpu(cpu, mask) ? 80*7af008b1SAlexandru Elisei acked[cpu] >= 1 : acked[cpu] == 0; 81ca1b7a7bSAndrew Jones } 82ca1b7a7bSAndrew Jones 83ac4a67b6SAndrew Jones if (nr_pass == nr_cpus) { 8496edb026SAndre Przywara if (i) 85*7af008b1SAlexandru Elisei report_info("interrupts took more than %d ms", i * 100); 86*7af008b1SAlexandru Elisei /* Wait for unexpected interrupts to fire */ 87*7af008b1SAlexandru Elisei mdelay(100); 88ac4a67b6SAndrew Jones return; 89ac4a67b6SAndrew Jones } 90ac4a67b6SAndrew Jones } 91ac4a67b6SAndrew Jones 92*7af008b1SAlexandru Elisei report_info("interrupts timed-out (5s)"); 93*7af008b1SAlexandru Elisei } 94*7af008b1SAlexandru Elisei 95*7af008b1SAlexandru Elisei static bool check_acked(cpumask_t *mask) 96*7af008b1SAlexandru Elisei { 97*7af008b1SAlexandru Elisei int missing = 0, extra = 0, unexpected = 0; 98*7af008b1SAlexandru Elisei bool pass = true; 99*7af008b1SAlexandru Elisei int cpu; 100*7af008b1SAlexandru Elisei 101ac4a67b6SAndrew Jones for_each_present_cpu(cpu) { 102ac4a67b6SAndrew Jones if (cpumask_test_cpu(cpu, mask)) { 103ac4a67b6SAndrew Jones if (!acked[cpu]) 104ac4a67b6SAndrew Jones ++missing; 105ac4a67b6SAndrew Jones else if (acked[cpu] > 1) 106ac4a67b6SAndrew Jones ++extra; 107ac4a67b6SAndrew Jones } else { 108ac4a67b6SAndrew Jones if (acked[cpu]) 109ac4a67b6SAndrew Jones ++unexpected; 110ac4a67b6SAndrew Jones } 111*7af008b1SAlexandru Elisei smp_rmb(); /* pairs with smp_wmb in ipi_handler */ 112*7af008b1SAlexandru Elisei 113*7af008b1SAlexandru Elisei if (bad_sender[cpu] != -1) { 114*7af008b1SAlexandru Elisei report_info("cpu%d received IPI from wrong sender %d", 115*7af008b1SAlexandru Elisei cpu, bad_sender[cpu]); 116*7af008b1SAlexandru Elisei pass = false; 117ac4a67b6SAndrew Jones } 118ac4a67b6SAndrew Jones 119*7af008b1SAlexandru Elisei if (bad_irq[cpu] != -1) { 120*7af008b1SAlexandru Elisei report_info("cpu%d received wrong irq %d", 121*7af008b1SAlexandru Elisei cpu, bad_irq[cpu]); 122*7af008b1SAlexandru Elisei pass = false; 123*7af008b1SAlexandru Elisei } 124*7af008b1SAlexandru Elisei } 125*7af008b1SAlexandru Elisei 126*7af008b1SAlexandru Elisei if (missing || extra || unexpected) { 127*7af008b1SAlexandru Elisei report_info("ACKS: missing=%d extra=%d unexpected=%d", 12896edb026SAndre Przywara missing, extra, unexpected); 129*7af008b1SAlexandru Elisei pass = false; 130*7af008b1SAlexandru Elisei } 131*7af008b1SAlexandru Elisei 132*7af008b1SAlexandru Elisei return pass; 133ac4a67b6SAndrew Jones } 134ac4a67b6SAndrew Jones 135ac4a67b6SAndrew Jones static void check_spurious(void) 136ac4a67b6SAndrew Jones { 137ac4a67b6SAndrew Jones int cpu; 138ac4a67b6SAndrew Jones 139ac4a67b6SAndrew Jones for_each_present_cpu(cpu) { 140ac4a67b6SAndrew Jones if (spurious[cpu]) 141ac4a67b6SAndrew Jones report_info("WARN: cpu%d got %d spurious interrupts", 142ac4a67b6SAndrew Jones cpu, spurious[cpu]); 143ac4a67b6SAndrew Jones } 144ac4a67b6SAndrew Jones } 145ac4a67b6SAndrew Jones 14664366016SAlexandru Elisei static void check_ipi_sender(u32 irqstat, int sender) 147ca1b7a7bSAndrew Jones { 148ca1b7a7bSAndrew Jones if (gic_version() == 2) { 149ca1b7a7bSAndrew Jones int src = (irqstat >> 10) & 7; 150ca1b7a7bSAndrew Jones 15164366016SAlexandru Elisei if (src != sender) 152ca1b7a7bSAndrew Jones bad_sender[smp_processor_id()] = src; 153ca1b7a7bSAndrew Jones } 154ca1b7a7bSAndrew Jones } 155ca1b7a7bSAndrew Jones 156ca1b7a7bSAndrew Jones static void check_irqnr(u32 irqnr) 157ca1b7a7bSAndrew Jones { 158ca1b7a7bSAndrew Jones if (irqnr != IPI_IRQ) 159ca1b7a7bSAndrew Jones bad_irq[smp_processor_id()] = irqnr; 160ca1b7a7bSAndrew Jones } 161ca1b7a7bSAndrew Jones 162ac4a67b6SAndrew Jones static void ipi_handler(struct pt_regs *regs __unused) 163ac4a67b6SAndrew Jones { 1642e2d471dSAndrew Jones u32 irqstat = gic_read_iar(); 1652e2d471dSAndrew Jones u32 irqnr = gic_iar_irqnr(irqstat); 166ac4a67b6SAndrew Jones 167ac4a67b6SAndrew Jones if (irqnr != GICC_INT_SPURIOUS) { 1682e2d471dSAndrew Jones gic_write_eoir(irqstat); 16964366016SAlexandru Elisei check_ipi_sender(irqstat, IPI_SENDER); 170ca1b7a7bSAndrew Jones check_irqnr(irqnr); 171718d77f1SAlexandru Elisei smp_wmb(); /* pairs with smp_rmb in check_acked */ 172718d77f1SAlexandru Elisei ++acked[smp_processor_id()]; 173ac4a67b6SAndrew Jones } else { 174ac4a67b6SAndrew Jones ++spurious[smp_processor_id()]; 175ac4a67b6SAndrew Jones } 176b3029e53SAlexandru Elisei 177b3029e53SAlexandru Elisei /* Wait for writes to acked/spurious to complete */ 178b3029e53SAlexandru Elisei dsb(ishst); 179ac4a67b6SAndrew Jones } 180ac4a67b6SAndrew Jones 1810ef02cd6SEric Auger static void setup_irq(irq_handler_fn handler) 1820ef02cd6SEric Auger { 1830ef02cd6SEric Auger gic_enable_defaults(); 1840ef02cd6SEric Auger #ifdef __arm__ 1850ef02cd6SEric Auger install_exception_handler(EXCPTN_IRQ, handler); 1860ef02cd6SEric Auger #else 1870ef02cd6SEric Auger install_irq_handler(EL1H_IRQ, handler); 1880ef02cd6SEric Auger #endif 1890ef02cd6SEric Auger local_irq_enable(); 1900ef02cd6SEric Auger } 1910ef02cd6SEric Auger 1920ef02cd6SEric Auger #if defined(__aarch64__) 1930ef02cd6SEric Auger struct its_event { 1940ef02cd6SEric Auger int cpu_id; 1950ef02cd6SEric Auger int lpi_id; 1960ef02cd6SEric Auger }; 1970ef02cd6SEric Auger 1980ef02cd6SEric Auger struct its_stats { 1990ef02cd6SEric Auger struct its_event expected; 2000ef02cd6SEric Auger struct its_event observed; 2010ef02cd6SEric Auger }; 2020ef02cd6SEric Auger 2030ef02cd6SEric Auger static struct its_stats lpi_stats; 2040ef02cd6SEric Auger 2050ef02cd6SEric Auger static void lpi_handler(struct pt_regs *regs __unused) 2060ef02cd6SEric Auger { 2070ef02cd6SEric Auger u32 irqstat = gic_read_iar(); 2080ef02cd6SEric Auger int irqnr = gic_iar_irqnr(irqstat); 2090ef02cd6SEric Auger 2100ef02cd6SEric Auger gic_write_eoir(irqstat); 2110ef02cd6SEric Auger assert(irqnr >= 8192); 2120ef02cd6SEric Auger smp_rmb(); /* pairs with wmb in lpi_stats_expect */ 2130ef02cd6SEric Auger lpi_stats.observed.cpu_id = smp_processor_id(); 2140ef02cd6SEric Auger lpi_stats.observed.lpi_id = irqnr; 215de582149SEric Auger acked[lpi_stats.observed.cpu_id]++; 2160ef02cd6SEric Auger smp_wmb(); /* pairs with rmb in check_lpi_stats */ 2170ef02cd6SEric Auger } 2180ef02cd6SEric Auger 2190ef02cd6SEric Auger static void lpi_stats_expect(int exp_cpu_id, int exp_lpi_id) 2200ef02cd6SEric Auger { 2210ef02cd6SEric Auger lpi_stats.expected.cpu_id = exp_cpu_id; 2220ef02cd6SEric Auger lpi_stats.expected.lpi_id = exp_lpi_id; 2230ef02cd6SEric Auger lpi_stats.observed.cpu_id = -1; 2240ef02cd6SEric Auger lpi_stats.observed.lpi_id = -1; 2250ef02cd6SEric Auger smp_wmb(); /* pairs with rmb in handler */ 2260ef02cd6SEric Auger } 2270ef02cd6SEric Auger 2280ef02cd6SEric Auger static void check_lpi_stats(const char *msg) 2290ef02cd6SEric Auger { 2300ef02cd6SEric Auger int i; 2310ef02cd6SEric Auger 2320ef02cd6SEric Auger for (i = 0; i < 50; i++) { 2330ef02cd6SEric Auger mdelay(100); 2340ef02cd6SEric Auger smp_rmb(); /* pairs with wmb in lpi_handler */ 2350ef02cd6SEric Auger if (lpi_stats.observed.cpu_id == lpi_stats.expected.cpu_id && 2360ef02cd6SEric Auger lpi_stats.observed.lpi_id == lpi_stats.expected.lpi_id) { 2370ef02cd6SEric Auger report(true, "%s", msg); 2380ef02cd6SEric Auger return; 2390ef02cd6SEric Auger } 2400ef02cd6SEric Auger } 2410ef02cd6SEric Auger 2420ef02cd6SEric Auger if (lpi_stats.observed.cpu_id == -1 && lpi_stats.observed.lpi_id == -1) { 2430ef02cd6SEric Auger report_info("No LPI received whereas (cpuid=%d, intid=%d) " 2440ef02cd6SEric Auger "was expected", lpi_stats.expected.cpu_id, 2450ef02cd6SEric Auger lpi_stats.expected.lpi_id); 2460ef02cd6SEric Auger } else { 2470ef02cd6SEric Auger report_info("Unexpected LPI (cpuid=%d, intid=%d)", 2480ef02cd6SEric Auger lpi_stats.observed.cpu_id, 2490ef02cd6SEric Auger lpi_stats.observed.lpi_id); 2500ef02cd6SEric Auger } 2510ef02cd6SEric Auger report(false, "%s", msg); 2520ef02cd6SEric Auger } 2530ef02cd6SEric Auger 2540ef02cd6SEric Auger static void secondary_lpi_test(void) 2550ef02cd6SEric Auger { 2560ef02cd6SEric Auger setup_irq(lpi_handler); 2570ef02cd6SEric Auger cpumask_set_cpu(smp_processor_id(), &ready); 2580ef02cd6SEric Auger while (1) 2590ef02cd6SEric Auger wfi(); 2600ef02cd6SEric Auger } 261de582149SEric Auger 262de582149SEric Auger static void check_lpi_hits(int *expected, const char *msg) 263de582149SEric Auger { 264de582149SEric Auger bool pass = true; 265de582149SEric Auger int i; 266de582149SEric Auger 267de582149SEric Auger for_each_present_cpu(i) { 268de582149SEric Auger if (acked[i] != expected[i]) { 269de582149SEric Auger report_info("expected %d LPIs on PE #%d, %d observed", 270de582149SEric Auger expected[i], i, acked[i]); 271de582149SEric Auger pass = false; 272de582149SEric Auger break; 273de582149SEric Auger } 274de582149SEric Auger } 275de582149SEric Auger report(pass, "%s", msg); 276de582149SEric Auger } 2770ef02cd6SEric Auger #endif 2780ef02cd6SEric Auger 2792e2d471dSAndrew Jones static void gicv2_ipi_send_self(void) 2802e2d471dSAndrew Jones { 28110e3685fSAlexandru Elisei /* 28210e3685fSAlexandru Elisei * The wmb() in writel and rmb() when acknowledging the interrupt are 28310e3685fSAlexandru Elisei * sufficient for ensuring that writes that happen in program order 28410e3685fSAlexandru Elisei * before the interrupt are observed in the interrupt handler after 28510e3685fSAlexandru Elisei * acknowledging the interrupt. 28610e3685fSAlexandru Elisei */ 287ca1b7a7bSAndrew Jones writel(2 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR); 2882e2d471dSAndrew Jones } 2892e2d471dSAndrew Jones 2902e2d471dSAndrew Jones static void gicv2_ipi_send_broadcast(void) 2912e2d471dSAndrew Jones { 29210e3685fSAlexandru Elisei /* No barriers are needed, same situation as gicv2_ipi_send_self() */ 293ca1b7a7bSAndrew Jones writel(1 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR); 2942e2d471dSAndrew Jones } 2952e2d471dSAndrew Jones 2962e2d471dSAndrew Jones static void gicv3_ipi_send_self(void) 2972e2d471dSAndrew Jones { 298ca1b7a7bSAndrew Jones gic_ipi_send_single(IPI_IRQ, smp_processor_id()); 2992e2d471dSAndrew Jones } 3002e2d471dSAndrew Jones 3012e2d471dSAndrew Jones static void gicv3_ipi_send_broadcast(void) 3022e2d471dSAndrew Jones { 3030c03f4b1SAlexandru Elisei /* 3040c03f4b1SAlexandru Elisei * Ensure stores to Normal memory are visible to other CPUs before 3050c03f4b1SAlexandru Elisei * sending the IPI 3060c03f4b1SAlexandru Elisei */ 3070c03f4b1SAlexandru Elisei wmb(); 308ca1b7a7bSAndrew Jones gicv3_write_sgi1r(1ULL << 40 | IPI_IRQ << 24); 3092e2d471dSAndrew Jones isb(); 3102e2d471dSAndrew Jones } 3112e2d471dSAndrew Jones 312ac4a67b6SAndrew Jones static void ipi_test_self(void) 313ac4a67b6SAndrew Jones { 314ac4a67b6SAndrew Jones cpumask_t mask; 315ac4a67b6SAndrew Jones 316ac4a67b6SAndrew Jones report_prefix_push("self"); 317ca1b7a7bSAndrew Jones stats_reset(); 318ac4a67b6SAndrew Jones cpumask_clear(&mask); 319ca1b7a7bSAndrew Jones cpumask_set_cpu(smp_processor_id(), &mask); 3202e2d471dSAndrew Jones gic->ipi.send_self(); 321*7af008b1SAlexandru Elisei wait_for_interrupts(&mask); 322*7af008b1SAlexandru Elisei report(check_acked(&mask), "Interrupts received"); 323ac4a67b6SAndrew Jones report_prefix_pop(); 324ac4a67b6SAndrew Jones } 325ac4a67b6SAndrew Jones 326ac4a67b6SAndrew Jones static void ipi_test_smp(void) 327ac4a67b6SAndrew Jones { 328ac4a67b6SAndrew Jones cpumask_t mask; 3292e2d471dSAndrew Jones int i; 330ac4a67b6SAndrew Jones 331ac4a67b6SAndrew Jones report_prefix_push("target-list"); 332ca1b7a7bSAndrew Jones stats_reset(); 3332e2d471dSAndrew Jones cpumask_copy(&mask, &cpu_present_mask); 334ca1b7a7bSAndrew Jones for (i = smp_processor_id() & 1; i < nr_cpus; i += 2) 3352e2d471dSAndrew Jones cpumask_clear_cpu(i, &mask); 336ca1b7a7bSAndrew Jones gic_ipi_send_mask(IPI_IRQ, &mask); 337*7af008b1SAlexandru Elisei wait_for_interrupts(&mask); 338*7af008b1SAlexandru Elisei report(check_acked(&mask), "Interrupts received"); 339ac4a67b6SAndrew Jones report_prefix_pop(); 340ac4a67b6SAndrew Jones 341ac4a67b6SAndrew Jones report_prefix_push("broadcast"); 342ca1b7a7bSAndrew Jones stats_reset(); 343ac4a67b6SAndrew Jones cpumask_copy(&mask, &cpu_present_mask); 344ca1b7a7bSAndrew Jones cpumask_clear_cpu(smp_processor_id(), &mask); 3452e2d471dSAndrew Jones gic->ipi.send_broadcast(); 346*7af008b1SAlexandru Elisei wait_for_interrupts(&mask); 347*7af008b1SAlexandru Elisei report(check_acked(&mask), "Interrupts received"); 348ac4a67b6SAndrew Jones report_prefix_pop(); 349ac4a67b6SAndrew Jones } 350ac4a67b6SAndrew Jones 351ca1b7a7bSAndrew Jones static void ipi_send(void) 352ca1b7a7bSAndrew Jones { 35325f66327SEric Auger setup_irq(ipi_handler); 354ca1b7a7bSAndrew Jones wait_on_ready(); 355ca1b7a7bSAndrew Jones ipi_test_self(); 356ca1b7a7bSAndrew Jones ipi_test_smp(); 357ca1b7a7bSAndrew Jones check_spurious(); 358ca1b7a7bSAndrew Jones exit(report_summary()); 359ca1b7a7bSAndrew Jones } 360ca1b7a7bSAndrew Jones 361ac4a67b6SAndrew Jones static void ipi_recv(void) 362ac4a67b6SAndrew Jones { 36325f66327SEric Auger setup_irq(ipi_handler); 364ac4a67b6SAndrew Jones cpumask_set_cpu(smp_processor_id(), &ready); 365ac4a67b6SAndrew Jones while (1) 366ac4a67b6SAndrew Jones wfi(); 367ac4a67b6SAndrew Jones } 368ac4a67b6SAndrew Jones 36900b34f56SAndrew Jones static void ipi_test(void *data __unused) 370bfd500b4SAndrew Jones { 371bfd500b4SAndrew Jones if (smp_processor_id() == IPI_SENDER) 372bfd500b4SAndrew Jones ipi_send(); 373bfd500b4SAndrew Jones else 374bfd500b4SAndrew Jones ipi_recv(); 375bfd500b4SAndrew Jones } 376bfd500b4SAndrew Jones 3772e2d471dSAndrew Jones static struct gic gicv2 = { 3782e2d471dSAndrew Jones .ipi = { 3792e2d471dSAndrew Jones .send_self = gicv2_ipi_send_self, 3802e2d471dSAndrew Jones .send_broadcast = gicv2_ipi_send_broadcast, 3812e2d471dSAndrew Jones }, 3822e2d471dSAndrew Jones }; 3832e2d471dSAndrew Jones 3842e2d471dSAndrew Jones static struct gic gicv3 = { 3852e2d471dSAndrew Jones .ipi = { 3862e2d471dSAndrew Jones .send_self = gicv3_ipi_send_self, 3872e2d471dSAndrew Jones .send_broadcast = gicv3_ipi_send_broadcast, 3882e2d471dSAndrew Jones }, 3892e2d471dSAndrew Jones }; 3902e2d471dSAndrew Jones 391680beae9SAlexandru Elisei /* Runs on the same CPU as the sender, no need for memory synchronization */ 392c152d8bcSChristoffer Dall static void ipi_clear_active_handler(struct pt_regs *regs __unused) 393c152d8bcSChristoffer Dall { 394c152d8bcSChristoffer Dall u32 irqstat = gic_read_iar(); 395c152d8bcSChristoffer Dall u32 irqnr = gic_iar_irqnr(irqstat); 396c152d8bcSChristoffer Dall 397c152d8bcSChristoffer Dall if (irqnr != GICC_INT_SPURIOUS) { 398c152d8bcSChristoffer Dall void *base; 399c152d8bcSChristoffer Dall u32 val = 1 << IPI_IRQ; 400c152d8bcSChristoffer Dall 401c152d8bcSChristoffer Dall if (gic_version() == 2) 402c152d8bcSChristoffer Dall base = gicv2_dist_base(); 403c152d8bcSChristoffer Dall else 4046d4d7c4bSAndrew Jones base = gicv3_sgi_base(); 405c152d8bcSChristoffer Dall 406c152d8bcSChristoffer Dall writel(val, base + GICD_ICACTIVER); 407c152d8bcSChristoffer Dall 40864366016SAlexandru Elisei check_ipi_sender(irqstat, smp_processor_id()); 409c152d8bcSChristoffer Dall check_irqnr(irqnr); 410718d77f1SAlexandru Elisei ++acked[smp_processor_id()]; 411c152d8bcSChristoffer Dall } else { 412c152d8bcSChristoffer Dall ++spurious[smp_processor_id()]; 413c152d8bcSChristoffer Dall } 414c152d8bcSChristoffer Dall } 415c152d8bcSChristoffer Dall 416c152d8bcSChristoffer Dall static void run_active_clear_test(void) 417c152d8bcSChristoffer Dall { 418c152d8bcSChristoffer Dall report_prefix_push("active"); 41925f66327SEric Auger setup_irq(ipi_clear_active_handler); 420c152d8bcSChristoffer Dall ipi_test_self(); 42164366016SAlexandru Elisei check_spurious(); 422c152d8bcSChristoffer Dall report_prefix_pop(); 423c152d8bcSChristoffer Dall } 424c152d8bcSChristoffer Dall 42578ad7e95SAndre Przywara static bool test_ro_pattern_32(void *address, u32 pattern, u32 orig) 42678ad7e95SAndre Przywara { 42778ad7e95SAndre Przywara u32 reg; 42878ad7e95SAndre Przywara 42978ad7e95SAndre Przywara writel(pattern, address); 43078ad7e95SAndre Przywara reg = readl(address); 43178ad7e95SAndre Przywara 43278ad7e95SAndre Przywara if (reg != orig) 43378ad7e95SAndre Przywara writel(orig, address); 43478ad7e95SAndre Przywara 43578ad7e95SAndre Przywara return reg == orig; 43678ad7e95SAndre Przywara } 43778ad7e95SAndre Przywara 43878ad7e95SAndre Przywara static bool test_readonly_32(void *address, bool razwi) 43978ad7e95SAndre Przywara { 44078ad7e95SAndre Przywara u32 orig, pattern; 44178ad7e95SAndre Przywara 44278ad7e95SAndre Przywara orig = readl(address); 44378ad7e95SAndre Przywara if (razwi && orig) 44478ad7e95SAndre Przywara return false; 44578ad7e95SAndre Przywara 44678ad7e95SAndre Przywara pattern = 0xffffffff; 44778ad7e95SAndre Przywara if (orig != pattern) { 44878ad7e95SAndre Przywara if (!test_ro_pattern_32(address, pattern, orig)) 44978ad7e95SAndre Przywara return false; 45078ad7e95SAndre Przywara } 45178ad7e95SAndre Przywara 45278ad7e95SAndre Przywara pattern = 0xa5a55a5a; 45378ad7e95SAndre Przywara if (orig != pattern) { 45478ad7e95SAndre Przywara if (!test_ro_pattern_32(address, pattern, orig)) 45578ad7e95SAndre Przywara return false; 45678ad7e95SAndre Przywara } 45778ad7e95SAndre Przywara 45878ad7e95SAndre Przywara pattern = 0; 45978ad7e95SAndre Przywara if (orig != pattern) { 46078ad7e95SAndre Przywara if (!test_ro_pattern_32(address, pattern, orig)) 46178ad7e95SAndre Przywara return false; 46278ad7e95SAndre Przywara } 46378ad7e95SAndre Przywara 46478ad7e95SAndre Przywara return true; 46578ad7e95SAndre Przywara } 46678ad7e95SAndre Przywara 46778ad7e95SAndre Przywara static void test_typer_v2(uint32_t reg) 46878ad7e95SAndre Przywara { 46978ad7e95SAndre Przywara int nr_gic_cpus = ((reg >> 5) & 0x7) + 1; 47078ad7e95SAndre Przywara 4718e0a4f41SAndre Przywara report_info("nr_cpus=%d", nr_cpus); 472a299895bSThomas Huth report(nr_cpus == nr_gic_cpus, "all CPUs have interrupts"); 47378ad7e95SAndre Przywara } 47478ad7e95SAndre Przywara 475ff31a1c4SAndre Przywara #define BYTE(reg32, byte) (((reg32) >> ((byte) * 8)) & 0xff) 476ff31a1c4SAndre Przywara #define REPLACE_BYTE(reg32, byte, new) (((reg32) & ~(0xff << ((byte) * 8))) |\ 477ff31a1c4SAndre Przywara ((new) << ((byte) * 8))) 478ff31a1c4SAndre Przywara 479ff31a1c4SAndre Przywara /* 480ff31a1c4SAndre Przywara * Some registers are byte accessible, do a byte-wide read and write of known 481ff31a1c4SAndre Przywara * content to check for this. 482ff31a1c4SAndre Przywara * Apply a @mask to cater for special register properties. 483ff31a1c4SAndre Przywara * @pattern contains the value already in the register. 484ff31a1c4SAndre Przywara */ 485ff31a1c4SAndre Przywara static void test_byte_access(void *base_addr, u32 pattern, u32 mask) 486ff31a1c4SAndre Przywara { 487ff31a1c4SAndre Przywara u32 reg = readb(base_addr + 1); 4888e0a4f41SAndre Przywara bool res; 489ff31a1c4SAndre Przywara 4908e0a4f41SAndre Przywara res = (reg == (BYTE(pattern, 1) & (mask >> 8))); 491a299895bSThomas Huth report(res, "byte reads successful"); 4928e0a4f41SAndre Przywara if (!res) 49346ca10f4SAlexandru Elisei report_info("byte 1 of 0x%08"PRIx32" => 0x%02"PRIx32, pattern & mask, reg); 494ff31a1c4SAndre Przywara 495ff31a1c4SAndre Przywara pattern = REPLACE_BYTE(pattern, 2, 0x1f); 496ff31a1c4SAndre Przywara writeb(BYTE(pattern, 2), base_addr + 2); 497ff31a1c4SAndre Przywara reg = readl(base_addr); 4988e0a4f41SAndre Przywara res = (reg == (pattern & mask)); 499a299895bSThomas Huth report(res, "byte writes successful"); 5008e0a4f41SAndre Przywara if (!res) 50146ca10f4SAlexandru Elisei report_info("writing 0x%02"PRIx32" into bytes 2 => 0x%08"PRIx32, 5028e0a4f41SAndre Przywara BYTE(pattern, 2), reg); 503ff31a1c4SAndre Przywara } 504ff31a1c4SAndre Przywara 505ff31a1c4SAndre Przywara static void test_priorities(int nr_irqs, void *priptr) 506ff31a1c4SAndre Przywara { 507ff31a1c4SAndre Przywara u32 orig_prio, reg, pri_bits; 508ff31a1c4SAndre Przywara u32 pri_mask, pattern; 509ff31a1c4SAndre Przywara void *first_spi = priptr + GIC_FIRST_SPI; 510ff31a1c4SAndre Przywara 511ff31a1c4SAndre Przywara orig_prio = readl(first_spi); 512ff31a1c4SAndre Przywara report_prefix_push("IPRIORITYR"); 513ff31a1c4SAndre Przywara 514ff31a1c4SAndre Przywara /* 515ff31a1c4SAndre Przywara * Determine implemented number of priority bits by writing all 1's 516ff31a1c4SAndre Przywara * and checking the number of cleared bits in the value read back. 517ff31a1c4SAndre Przywara */ 518ff31a1c4SAndre Przywara writel(0xffffffff, first_spi); 519ff31a1c4SAndre Przywara pri_mask = readl(first_spi); 520ff31a1c4SAndre Przywara 521ff31a1c4SAndre Przywara reg = ~pri_mask; 522a299895bSThomas Huth report((((reg >> 16) == (reg & 0xffff)) && 523a299895bSThomas Huth ((reg & 0xff) == ((reg >> 8) & 0xff))), 524a299895bSThomas Huth "consistent priority masking"); 52546ca10f4SAlexandru Elisei report_info("priority mask is 0x%08"PRIx32, pri_mask); 526ff31a1c4SAndre Przywara 527ff31a1c4SAndre Przywara reg = reg & 0xff; 528ff31a1c4SAndre Przywara for (pri_bits = 8; reg & 1; reg >>= 1, pri_bits--) 529ff31a1c4SAndre Przywara ; 530a299895bSThomas Huth report(pri_bits >= 4, "implements at least 4 priority bits"); 53146ca10f4SAlexandru Elisei report_info("%"PRIu32" priority bits implemented", pri_bits); 532ff31a1c4SAndre Przywara 533ff31a1c4SAndre Przywara pattern = 0; 534ff31a1c4SAndre Przywara writel(pattern, first_spi); 535a299895bSThomas Huth report(readl(first_spi) == pattern, "clearing priorities"); 536ff31a1c4SAndre Przywara 537ff31a1c4SAndre Przywara /* setting all priorities to their max valus was tested above */ 538ff31a1c4SAndre Przywara 539a299895bSThomas Huth report(test_readonly_32(priptr + nr_irqs, true), 540a299895bSThomas Huth "accesses beyond limit RAZ/WI"); 541ff31a1c4SAndre Przywara 542ff31a1c4SAndre Przywara writel(pattern, priptr + nr_irqs - 4); 543a299895bSThomas Huth report(readl(priptr + nr_irqs - 4) == (pattern & pri_mask), 544a299895bSThomas Huth "accessing last SPIs"); 545ff31a1c4SAndre Przywara 546ff31a1c4SAndre Przywara pattern = 0xff7fbf3f; 547ff31a1c4SAndre Przywara writel(pattern, first_spi); 548a299895bSThomas Huth report(readl(first_spi) == (pattern & pri_mask), 549a299895bSThomas Huth "priorities are preserved"); 550ff31a1c4SAndre Przywara 551ff31a1c4SAndre Przywara /* The PRIORITY registers are byte accessible. */ 552ff31a1c4SAndre Przywara test_byte_access(first_spi, pattern, pri_mask); 553ff31a1c4SAndre Przywara 554ff31a1c4SAndre Przywara report_prefix_pop(); 555ff31a1c4SAndre Przywara writel(orig_prio, first_spi); 556ff31a1c4SAndre Przywara } 557ff31a1c4SAndre Przywara 558fe572a5eSAndre Przywara /* GICD_ITARGETSR is only used by GICv2. */ 559fe572a5eSAndre Przywara static void test_targets(int nr_irqs) 560fe572a5eSAndre Przywara { 561fe572a5eSAndre Przywara void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR; 562fe572a5eSAndre Przywara u32 orig_targets; 563fe572a5eSAndre Przywara u32 cpu_mask; 564fe572a5eSAndre Przywara u32 pattern, reg; 565fe572a5eSAndre Przywara 566fe572a5eSAndre Przywara orig_targets = readl(targetsptr + GIC_FIRST_SPI); 567fe572a5eSAndre Przywara report_prefix_push("ITARGETSR"); 568fe572a5eSAndre Przywara 569fe572a5eSAndre Przywara cpu_mask = (1 << nr_cpus) - 1; 570fe572a5eSAndre Przywara cpu_mask |= cpu_mask << 8; 571fe572a5eSAndre Przywara cpu_mask |= cpu_mask << 16; 572fe572a5eSAndre Przywara 573fe572a5eSAndre Przywara /* Check that bits for non implemented CPUs are RAZ/WI. */ 574fe572a5eSAndre Przywara if (nr_cpus < 8) { 575fe572a5eSAndre Przywara writel(0xffffffff, targetsptr + GIC_FIRST_SPI); 576a299895bSThomas Huth report(!(readl(targetsptr + GIC_FIRST_SPI) & ~cpu_mask), 577a299895bSThomas Huth "bits for non-existent CPUs masked"); 5788e0a4f41SAndre Przywara report_info("%d non-existent CPUs", 8 - nr_cpus); 579fe572a5eSAndre Przywara } else { 580fe572a5eSAndre Przywara report_skip("CPU masking (all CPUs implemented)"); 581fe572a5eSAndre Przywara } 582fe572a5eSAndre Przywara 583a299895bSThomas Huth report(test_readonly_32(targetsptr + nr_irqs, true), 584a299895bSThomas Huth "accesses beyond limit RAZ/WI"); 585fe572a5eSAndre Przywara 586fe572a5eSAndre Przywara pattern = 0x0103020f; 587fe572a5eSAndre Przywara writel(pattern, targetsptr + GIC_FIRST_SPI); 588fe572a5eSAndre Przywara reg = readl(targetsptr + GIC_FIRST_SPI); 589a299895bSThomas Huth report(reg == (pattern & cpu_mask), "register content preserved"); 5908e0a4f41SAndre Przywara if (reg != (pattern & cpu_mask)) 59146ca10f4SAlexandru Elisei report_info("writing %08"PRIx32" reads back as %08"PRIx32, 5928e0a4f41SAndre Przywara pattern & cpu_mask, reg); 593fe572a5eSAndre Przywara 594fe572a5eSAndre Przywara /* The TARGETS registers are byte accessible. */ 595fe572a5eSAndre Przywara test_byte_access(targetsptr + GIC_FIRST_SPI, pattern, cpu_mask); 596fe572a5eSAndre Przywara 597fe572a5eSAndre Przywara writel(orig_targets, targetsptr + GIC_FIRST_SPI); 598da5b8576SAndre Przywara 599da5b8576SAndre Przywara report_prefix_pop(); 600fe572a5eSAndre Przywara } 601fe572a5eSAndre Przywara 60278ad7e95SAndre Przywara static void gic_test_mmio(void) 60378ad7e95SAndre Przywara { 60478ad7e95SAndre Przywara u32 reg; 60578ad7e95SAndre Przywara int nr_irqs; 60678ad7e95SAndre Przywara void *gic_dist_base, *idreg; 60778ad7e95SAndre Przywara 60878ad7e95SAndre Przywara switch(gic_version()) { 60978ad7e95SAndre Przywara case 0x2: 61078ad7e95SAndre Przywara gic_dist_base = gicv2_dist_base(); 61178ad7e95SAndre Przywara idreg = gic_dist_base + GICD_ICPIDR2; 61278ad7e95SAndre Przywara break; 61378ad7e95SAndre Przywara case 0x3: 61478ad7e95SAndre Przywara report_abort("GICv3 MMIO tests NYI"); 61578ad7e95SAndre Przywara default: 61678ad7e95SAndre Przywara report_abort("GIC version %d not supported", gic_version()); 61778ad7e95SAndre Przywara } 61878ad7e95SAndre Przywara 61978ad7e95SAndre Przywara reg = readl(gic_dist_base + GICD_TYPER); 62078ad7e95SAndre Przywara nr_irqs = GICD_TYPER_IRQS(reg); 62178ad7e95SAndre Przywara report_info("number of implemented SPIs: %d", nr_irqs - GIC_FIRST_SPI); 62278ad7e95SAndre Przywara 62378ad7e95SAndre Przywara test_typer_v2(reg); 62478ad7e95SAndre Przywara 62546ca10f4SAlexandru Elisei report_info("IIDR: 0x%08"PRIx32, readl(gic_dist_base + GICD_IIDR)); 62678ad7e95SAndre Przywara 627a299895bSThomas Huth report(test_readonly_32(gic_dist_base + GICD_TYPER, false), 628a299895bSThomas Huth "GICD_TYPER is read-only"); 629a299895bSThomas Huth report(test_readonly_32(gic_dist_base + GICD_IIDR, false), 630a299895bSThomas Huth "GICD_IIDR is read-only"); 63178ad7e95SAndre Przywara 63278ad7e95SAndre Przywara reg = readl(idreg); 633a299895bSThomas Huth report(test_readonly_32(idreg, false), "ICPIDR2 is read-only"); 63446ca10f4SAlexandru Elisei report_info("value of ICPIDR2: 0x%08"PRIx32, reg); 635ff31a1c4SAndre Przywara 636ff31a1c4SAndre Przywara test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR); 637fe572a5eSAndre Przywara 638fe572a5eSAndre Przywara if (gic_version() == 2) 639fe572a5eSAndre Przywara test_targets(nr_irqs); 64078ad7e95SAndre Przywara } 64178ad7e95SAndre Przywara 642ba74b106SEric Auger #if defined(__arm__) 643ba74b106SEric Auger 644ba74b106SEric Auger static void test_its_introspection(void) {} 6450ef02cd6SEric Auger static void test_its_trigger(void) {} 64664260a5fSEric Auger static void test_its_migration(void) {} 647de582149SEric Auger static void test_its_pending_migration(void) {} 648de582149SEric Auger static void test_migrate_unmapped_collection(void) {} 649ba74b106SEric Auger 650ba74b106SEric Auger #else /* __aarch64__ */ 651ba74b106SEric Auger 652ba74b106SEric Auger static void test_its_introspection(void) 653ba74b106SEric Auger { 654ba74b106SEric Auger struct its_baser *dev_baser = &its_data.device_baser; 655ba74b106SEric Auger struct its_baser *coll_baser = &its_data.coll_baser; 656ba74b106SEric Auger struct its_typer *typer = &its_data.typer; 657ba74b106SEric Auger 658ba74b106SEric Auger if (!gicv3_its_base()) { 659ba74b106SEric Auger report_skip("No ITS, skip ..."); 660ba74b106SEric Auger return; 661ba74b106SEric Auger } 662ba74b106SEric Auger 663ba74b106SEric Auger /* IIDR */ 664ba74b106SEric Auger report(test_readonly_32(gicv3_its_base() + GITS_IIDR, false), 665ba74b106SEric Auger "GITS_IIDR is read-only"), 666ba74b106SEric Auger 667ba74b106SEric Auger /* TYPER */ 668ba74b106SEric Auger report(test_readonly_32(gicv3_its_base() + GITS_TYPER, false), 669ba74b106SEric Auger "GITS_TYPER is read-only"); 670ba74b106SEric Auger 671ba74b106SEric Auger report(typer->phys_lpi, "ITS supports physical LPIs"); 672ba74b106SEric Auger report_info("vLPI support: %s", typer->virt_lpi ? "yes" : "no"); 673ba74b106SEric Auger report_info("ITT entry size = 0x%x", typer->ite_size); 674ba74b106SEric Auger report_info("Bit Count: EventID=%d DeviceId=%d CollId=%d", 675ba74b106SEric Auger typer->eventid_bits, typer->deviceid_bits, 676ba74b106SEric Auger typer->collid_bits); 677ba74b106SEric Auger report(typer->eventid_bits && typer->deviceid_bits && 678ba74b106SEric Auger typer->collid_bits, "ID spaces"); 679ba74b106SEric Auger report_info("Target address format %s", 680ba74b106SEric Auger typer->pta ? "Redist base address" : "PE #"); 681ba74b106SEric Auger 682ba74b106SEric Auger report(dev_baser && coll_baser, "detect device and collection BASER"); 683ba74b106SEric Auger report_info("device table entry_size = 0x%x", dev_baser->esz); 684ba74b106SEric Auger report_info("collection table entry_size = 0x%x", coll_baser->esz); 685ba74b106SEric Auger } 686ba74b106SEric Auger 6870ef02cd6SEric Auger static int its_prerequisites(int nb_cpus) 6880ef02cd6SEric Auger { 6890ef02cd6SEric Auger int cpu; 6900ef02cd6SEric Auger 6910ef02cd6SEric Auger if (!gicv3_its_base()) { 6920ef02cd6SEric Auger report_skip("No ITS, skip ..."); 6930ef02cd6SEric Auger return -1; 6940ef02cd6SEric Auger } 6950ef02cd6SEric Auger 6960ef02cd6SEric Auger if (nr_cpus < nb_cpus) { 6970ef02cd6SEric Auger report_skip("Test requires at least %d vcpus", nb_cpus); 6980ef02cd6SEric Auger return -1; 6990ef02cd6SEric Auger } 7000ef02cd6SEric Auger 7010ef02cd6SEric Auger stats_reset(); 7020ef02cd6SEric Auger 7030ef02cd6SEric Auger setup_irq(lpi_handler); 7040ef02cd6SEric Auger 7050ef02cd6SEric Auger for_each_present_cpu(cpu) { 7060ef02cd6SEric Auger if (cpu == 0) 7070ef02cd6SEric Auger continue; 7080ef02cd6SEric Auger smp_boot_secondary(cpu, secondary_lpi_test); 7090ef02cd6SEric Auger } 7100ef02cd6SEric Auger wait_on_ready(); 7110ef02cd6SEric Auger 7120ef02cd6SEric Auger its_enable_defaults(); 7130ef02cd6SEric Auger 7140ef02cd6SEric Auger return 0; 7150ef02cd6SEric Auger } 7160ef02cd6SEric Auger 71764260a5fSEric Auger /* 71864260a5fSEric Auger * Setup the configuration for those mappings: 71964260a5fSEric Auger * dev_id=2 event=20 -> vcpu 3, intid=8195 72064260a5fSEric Auger * dev_id=7 event=255 -> vcpu 2, intid=8196 72164260a5fSEric Auger * LPIs ready to hit 72264260a5fSEric Auger */ 72364260a5fSEric Auger static int its_setup1(void) 7240ef02cd6SEric Auger { 7250ef02cd6SEric Auger struct its_collection *col3, *col2; 7260ef02cd6SEric Auger struct its_device *dev2, *dev7; 7270ef02cd6SEric Auger 7280ef02cd6SEric Auger if (its_prerequisites(4)) 72964260a5fSEric Auger return -1; 7300ef02cd6SEric Auger 7310ef02cd6SEric Auger dev2 = its_create_device(2 /* dev id */, 8 /* nb_ites */); 7320ef02cd6SEric Auger dev7 = its_create_device(7 /* dev id */, 8 /* nb_ites */); 7330ef02cd6SEric Auger 7340ef02cd6SEric Auger col3 = its_create_collection(3 /* col id */, 3/* target PE */); 7350ef02cd6SEric Auger col2 = its_create_collection(2 /* col id */, 2/* target PE */); 7360ef02cd6SEric Auger 7370ef02cd6SEric Auger gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT); 7380ef02cd6SEric Auger gicv3_lpi_set_config(8196, LPI_PROP_DEFAULT); 7390ef02cd6SEric Auger 7400ef02cd6SEric Auger /* 7410ef02cd6SEric Auger * dev=2, eventid=20 -> lpi= 8195, col=3 7420ef02cd6SEric Auger * dev=7, eventid=255 -> lpi= 8196, col=2 7430ef02cd6SEric Auger */ 7440ef02cd6SEric Auger its_send_mapd(dev2, true); 7450ef02cd6SEric Auger its_send_mapd(dev7, true); 7460ef02cd6SEric Auger 7470ef02cd6SEric Auger its_send_mapc(col3, true); 7480ef02cd6SEric Auger its_send_mapc(col2, true); 7490ef02cd6SEric Auger 7500ef02cd6SEric Auger its_send_invall(col2); 7510ef02cd6SEric Auger its_send_invall(col3); 7520ef02cd6SEric Auger 7530ef02cd6SEric Auger its_send_mapti(dev2, 8195 /* lpi id */, 20 /* event id */, col3); 7540ef02cd6SEric Auger its_send_mapti(dev7, 8196 /* lpi id */, 255 /* event id */, col2); 75564260a5fSEric Auger return 0; 75664260a5fSEric Auger } 75764260a5fSEric Auger 75864260a5fSEric Auger static void test_its_trigger(void) 75964260a5fSEric Auger { 76064260a5fSEric Auger struct its_collection *col3; 76164260a5fSEric Auger struct its_device *dev2, *dev7; 76264260a5fSEric Auger 76364260a5fSEric Auger if (its_setup1()) 76464260a5fSEric Auger return; 76564260a5fSEric Auger 76664260a5fSEric Auger col3 = its_get_collection(3); 76764260a5fSEric Auger dev2 = its_get_device(2); 76864260a5fSEric Auger dev7 = its_get_device(7); 76964260a5fSEric Auger 77064260a5fSEric Auger report_prefix_push("int"); 7710ef02cd6SEric Auger 7720ef02cd6SEric Auger lpi_stats_expect(3, 8195); 7730ef02cd6SEric Auger its_send_int(dev2, 20); 7740ef02cd6SEric Auger check_lpi_stats("dev=2, eventid=20 -> lpi= 8195, col=3"); 7750ef02cd6SEric Auger 7760ef02cd6SEric Auger lpi_stats_expect(2, 8196); 7770ef02cd6SEric Auger its_send_int(dev7, 255); 7780ef02cd6SEric Auger check_lpi_stats("dev=7, eventid=255 -> lpi= 8196, col=2"); 7790ef02cd6SEric Auger 7800ef02cd6SEric Auger report_prefix_pop(); 7810ef02cd6SEric Auger 7820ef02cd6SEric Auger report_prefix_push("inv/invall"); 7830ef02cd6SEric Auger 7840ef02cd6SEric Auger /* 7850ef02cd6SEric Auger * disable 8195, check dev2/eventid=20 does not trigger the 7860ef02cd6SEric Auger * corresponding LPI 7870ef02cd6SEric Auger */ 7880ef02cd6SEric Auger gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT & ~LPI_PROP_ENABLED); 7890ef02cd6SEric Auger its_send_inv(dev2, 20); 7900ef02cd6SEric Auger 7910ef02cd6SEric Auger lpi_stats_expect(-1, -1); 7920ef02cd6SEric Auger its_send_int(dev2, 20); 7930ef02cd6SEric Auger check_lpi_stats("dev2/eventid=20 does not trigger any LPI"); 7940ef02cd6SEric Auger 7950ef02cd6SEric Auger /* 7960ef02cd6SEric Auger * re-enable the LPI but willingly do not call invall 7970ef02cd6SEric Auger * so the change in config is not taken into account. 7980ef02cd6SEric Auger * The LPI should not hit 7990ef02cd6SEric Auger */ 8000ef02cd6SEric Auger gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT); 8010ef02cd6SEric Auger lpi_stats_expect(-1, -1); 8020ef02cd6SEric Auger its_send_int(dev2, 20); 8030ef02cd6SEric Auger check_lpi_stats("dev2/eventid=20 still does not trigger any LPI"); 8040ef02cd6SEric Auger 8050ef02cd6SEric Auger /* Now call the invall and check the LPI hits */ 8060ef02cd6SEric Auger its_send_invall(col3); 8070ef02cd6SEric Auger lpi_stats_expect(3, 8195); 8080ef02cd6SEric Auger its_send_int(dev2, 20); 8090ef02cd6SEric Auger check_lpi_stats("dev2/eventid=20 now triggers an LPI"); 8100ef02cd6SEric Auger 8110ef02cd6SEric Auger report_prefix_pop(); 8120ef02cd6SEric Auger 8130ef02cd6SEric Auger report_prefix_push("mapd valid=false"); 8140ef02cd6SEric Auger /* 8150ef02cd6SEric Auger * Unmap device 2 and check the eventid 20 formerly 8160ef02cd6SEric Auger * attached to it does not hit anymore 8170ef02cd6SEric Auger */ 8180ef02cd6SEric Auger 8190ef02cd6SEric Auger its_send_mapd(dev2, false); 8200ef02cd6SEric Auger lpi_stats_expect(-1, -1); 8210ef02cd6SEric Auger its_send_int(dev2, 20); 8220ef02cd6SEric Auger check_lpi_stats("no LPI after device unmap"); 8230ef02cd6SEric Auger report_prefix_pop(); 8240ef02cd6SEric Auger } 82564260a5fSEric Auger 82664260a5fSEric Auger static void test_its_migration(void) 82764260a5fSEric Auger { 82864260a5fSEric Auger struct its_device *dev2, *dev7; 82964260a5fSEric Auger bool test_skipped = false; 83064260a5fSEric Auger 83164260a5fSEric Auger if (its_setup1()) { 83264260a5fSEric Auger test_skipped = true; 83364260a5fSEric Auger goto do_migrate; 83464260a5fSEric Auger } 83564260a5fSEric Auger 83664260a5fSEric Auger dev2 = its_get_device(2); 83764260a5fSEric Auger dev7 = its_get_device(7); 83864260a5fSEric Auger 83964260a5fSEric Auger do_migrate: 84064260a5fSEric Auger puts("Now migrate the VM, then press a key to continue...\n"); 84164260a5fSEric Auger (void)getchar(); 84264260a5fSEric Auger report_info("Migration complete"); 84364260a5fSEric Auger if (test_skipped) 84464260a5fSEric Auger return; 84564260a5fSEric Auger 84664260a5fSEric Auger lpi_stats_expect(3, 8195); 84764260a5fSEric Auger its_send_int(dev2, 20); 84864260a5fSEric Auger check_lpi_stats("dev2/eventid=20 triggers LPI 8195 on PE #3 after migration"); 84964260a5fSEric Auger 85064260a5fSEric Auger lpi_stats_expect(2, 8196); 85164260a5fSEric Auger its_send_int(dev7, 255); 85264260a5fSEric Auger check_lpi_stats("dev7/eventid=255 triggers LPI 8196 on PE #2 after migration"); 85364260a5fSEric Auger } 854de582149SEric Auger 855de582149SEric Auger #define ERRATA_UNMAPPED_COLLECTIONS "ERRATA_8c58be34494b" 856de582149SEric Auger 857de582149SEric Auger static void test_migrate_unmapped_collection(void) 858de582149SEric Auger { 859de582149SEric Auger struct its_collection *col = NULL; 860de582149SEric Auger struct its_device *dev2 = NULL, *dev7 = NULL; 861de582149SEric Auger bool test_skipped = false; 862de582149SEric Auger int pe0 = 0; 863de582149SEric Auger u8 config; 864de582149SEric Auger 865de582149SEric Auger if (its_setup1()) { 866de582149SEric Auger test_skipped = true; 867de582149SEric Auger goto do_migrate; 868de582149SEric Auger } 869de582149SEric Auger 870de582149SEric Auger if (!errata(ERRATA_UNMAPPED_COLLECTIONS)) { 871de582149SEric Auger report_skip("Skipping test, as this test hangs without the fix. " 872de582149SEric Auger "Set %s=y to enable.", ERRATA_UNMAPPED_COLLECTIONS); 873de582149SEric Auger test_skipped = true; 874de582149SEric Auger goto do_migrate; 875de582149SEric Auger } 876de582149SEric Auger 877de582149SEric Auger col = its_create_collection(pe0, pe0); 878de582149SEric Auger dev2 = its_get_device(2); 879de582149SEric Auger dev7 = its_get_device(7); 880de582149SEric Auger 881de582149SEric Auger /* MAPTI with the collection unmapped */ 882de582149SEric Auger its_send_mapti(dev2, 8192, 0, col); 883de582149SEric Auger gicv3_lpi_set_config(8192, LPI_PROP_DEFAULT); 884de582149SEric Auger 885de582149SEric Auger do_migrate: 886de582149SEric Auger puts("Now migrate the VM, then press a key to continue...\n"); 887de582149SEric Auger (void)getchar(); 888de582149SEric Auger report_info("Migration complete"); 889de582149SEric Auger if (test_skipped) 890de582149SEric Auger return; 891de582149SEric Auger 892de582149SEric Auger /* on the destination, map the collection */ 893de582149SEric Auger its_send_mapc(col, true); 894de582149SEric Auger its_send_invall(col); 895de582149SEric Auger 896de582149SEric Auger lpi_stats_expect(2, 8196); 897de582149SEric Auger its_send_int(dev7, 255); 898de582149SEric Auger check_lpi_stats("dev7/eventid= 255 triggered LPI 8196 on PE #2"); 899de582149SEric Auger 900de582149SEric Auger config = gicv3_lpi_get_config(8192); 901de582149SEric Auger report(config == LPI_PROP_DEFAULT, 902de582149SEric Auger "Config of LPI 8192 was properly migrated"); 903de582149SEric Auger 904de582149SEric Auger lpi_stats_expect(pe0, 8192); 905de582149SEric Auger its_send_int(dev2, 0); 906de582149SEric Auger check_lpi_stats("dev2/eventid = 0 triggered LPI 8192 on PE0"); 907de582149SEric Auger } 908de582149SEric Auger 909de582149SEric Auger static void test_its_pending_migration(void) 910de582149SEric Auger { 911de582149SEric Auger struct its_device *dev; 912de582149SEric Auger struct its_collection *collection[2]; 913de582149SEric Auger int *expected = calloc(nr_cpus, sizeof(int)); 914de582149SEric Auger int pe0 = nr_cpus - 1, pe1 = nr_cpus - 2; 915de582149SEric Auger bool test_skipped = false; 916de582149SEric Auger u64 pendbaser; 917de582149SEric Auger void *ptr; 918de582149SEric Auger int i; 919de582149SEric Auger 920de582149SEric Auger if (its_prerequisites(4)) { 921de582149SEric Auger test_skipped = true; 922de582149SEric Auger goto do_migrate; 923de582149SEric Auger } 924de582149SEric Auger 925de582149SEric Auger dev = its_create_device(2 /* dev id */, 8 /* nb_ites */); 926de582149SEric Auger its_send_mapd(dev, true); 927de582149SEric Auger 928de582149SEric Auger collection[0] = its_create_collection(pe0, pe0); 929de582149SEric Auger collection[1] = its_create_collection(pe1, pe1); 930de582149SEric Auger its_send_mapc(collection[0], true); 931de582149SEric Auger its_send_mapc(collection[1], true); 932de582149SEric Auger 933de582149SEric Auger /* disable lpi at redist level */ 934de582149SEric Auger gicv3_lpi_rdist_disable(pe0); 935de582149SEric Auger gicv3_lpi_rdist_disable(pe1); 936de582149SEric Auger 937de582149SEric Auger /* lpis are interleaved inbetween the 2 PEs */ 938de582149SEric Auger for (i = 0; i < 256; i++) { 939de582149SEric Auger struct its_collection *col = i % 2 ? collection[0] : 940de582149SEric Auger collection[1]; 941de582149SEric Auger int vcpu = col->target_address >> 16; 942de582149SEric Auger 943de582149SEric Auger its_send_mapti(dev, LPI(i), i, col); 944de582149SEric Auger gicv3_lpi_set_config(LPI(i), LPI_PROP_DEFAULT); 945de582149SEric Auger gicv3_lpi_set_clr_pending(vcpu, LPI(i), true); 946de582149SEric Auger } 947de582149SEric Auger its_send_invall(collection[0]); 948de582149SEric Auger its_send_invall(collection[1]); 949de582149SEric Auger 950de582149SEric Auger /* Clear the PTZ bit on each pendbaser */ 951de582149SEric Auger 952de582149SEric Auger expected[pe0] = 128; 953de582149SEric Auger expected[pe1] = 128; 954de582149SEric Auger 955de582149SEric Auger ptr = gicv3_data.redist_base[pe0] + GICR_PENDBASER; 956de582149SEric Auger pendbaser = readq(ptr); 957de582149SEric Auger writeq(pendbaser & ~GICR_PENDBASER_PTZ, ptr); 958de582149SEric Auger 959de582149SEric Auger ptr = gicv3_data.redist_base[pe1] + GICR_PENDBASER; 960de582149SEric Auger pendbaser = readq(ptr); 961de582149SEric Auger writeq(pendbaser & ~GICR_PENDBASER_PTZ, ptr); 962de582149SEric Auger 963de582149SEric Auger gicv3_lpi_rdist_enable(pe0); 964de582149SEric Auger gicv3_lpi_rdist_enable(pe1); 965de582149SEric Auger 966de582149SEric Auger do_migrate: 967de582149SEric Auger puts("Now migrate the VM, then press a key to continue...\n"); 968de582149SEric Auger (void)getchar(); 969de582149SEric Auger report_info("Migration complete"); 970de582149SEric Auger if (test_skipped) 971de582149SEric Auger return; 972de582149SEric Auger 973de582149SEric Auger /* let's wait for the 256 LPIs to be handled */ 974de582149SEric Auger mdelay(1000); 975de582149SEric Auger 976de582149SEric Auger check_lpi_hits(expected, "128 LPIs on both PE0 and PE1 after migration"); 977de582149SEric Auger } 978ba74b106SEric Auger #endif 979ba74b106SEric Auger 980ac4a67b6SAndrew Jones int main(int argc, char **argv) 981ac4a67b6SAndrew Jones { 9822e2d471dSAndrew Jones if (!gic_init()) { 983ac4a67b6SAndrew Jones printf("No supported gic present, skipping tests...\n"); 984ac4a67b6SAndrew Jones return report_summary(); 985ac4a67b6SAndrew Jones } 986ac4a67b6SAndrew Jones 9872b19b829SAndrew Jones report_prefix_pushf("gicv%d", gic_version()); 988ac4a67b6SAndrew Jones 9892e2d471dSAndrew Jones switch (gic_version()) { 9902e2d471dSAndrew Jones case 2: 9912e2d471dSAndrew Jones gic = &gicv2; 9922e2d471dSAndrew Jones break; 9932e2d471dSAndrew Jones case 3: 9942e2d471dSAndrew Jones gic = &gicv3; 9952e2d471dSAndrew Jones break; 9962e2d471dSAndrew Jones } 9972e2d471dSAndrew Jones 998ac4a67b6SAndrew Jones if (argc < 2) 999ac4a67b6SAndrew Jones report_abort("no test specified"); 1000ac4a67b6SAndrew Jones 1001ac4a67b6SAndrew Jones if (strcmp(argv[1], "ipi") == 0) { 1002ac4a67b6SAndrew Jones report_prefix_push(argv[1]); 1003ac4a67b6SAndrew Jones nr_cpu_check(2); 100400b34f56SAndrew Jones on_cpus(ipi_test, NULL); 1005c152d8bcSChristoffer Dall } else if (strcmp(argv[1], "active") == 0) { 1006c152d8bcSChristoffer Dall run_active_clear_test(); 100778ad7e95SAndre Przywara } else if (strcmp(argv[1], "mmio") == 0) { 100878ad7e95SAndre Przywara report_prefix_push(argv[1]); 100978ad7e95SAndre Przywara gic_test_mmio(); 101078ad7e95SAndre Przywara report_prefix_pop(); 10110ef02cd6SEric Auger } else if (!strcmp(argv[1], "its-trigger")) { 10120ef02cd6SEric Auger report_prefix_push(argv[1]); 10130ef02cd6SEric Auger test_its_trigger(); 10140ef02cd6SEric Auger report_prefix_pop(); 101564260a5fSEric Auger } else if (!strcmp(argv[1], "its-migration")) { 101664260a5fSEric Auger report_prefix_push(argv[1]); 101764260a5fSEric Auger test_its_migration(); 101864260a5fSEric Auger report_prefix_pop(); 1019de582149SEric Auger } else if (!strcmp(argv[1], "its-pending-migration")) { 1020de582149SEric Auger report_prefix_push(argv[1]); 1021de582149SEric Auger test_its_pending_migration(); 1022de582149SEric Auger report_prefix_pop(); 1023de582149SEric Auger } else if (!strcmp(argv[1], "its-migrate-unmapped-collection")) { 1024de582149SEric Auger report_prefix_push(argv[1]); 1025de582149SEric Auger test_migrate_unmapped_collection(); 1026de582149SEric Auger report_prefix_pop(); 1027ba74b106SEric Auger } else if (strcmp(argv[1], "its-introspection") == 0) { 1028ba74b106SEric Auger report_prefix_push(argv[1]); 1029ba74b106SEric Auger test_its_introspection(); 1030ba74b106SEric Auger report_prefix_pop(); 1031ac4a67b6SAndrew Jones } else { 1032ac4a67b6SAndrew Jones report_abort("Unknown subtest '%s'", argv[1]); 1033ac4a67b6SAndrew Jones } 1034ac4a67b6SAndrew Jones 1035ac4a67b6SAndrew Jones return report_summary(); 1036ac4a67b6SAndrew Jones } 1037