qemu-arm
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-arm] [Qemu-devel] [kvm-unit-tests PATCH v3 08/10] arm/arm64: g


From: Auger Eric
Subject: Re: [Qemu-arm] [Qemu-devel] [kvm-unit-tests PATCH v3 08/10] arm/arm64: gicv2: add an IPI test
Date: Thu, 1 Sep 2016 18:42:50 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.1.1

Hi Drew,

On 15/07/2016 15:00, Andrew Jones wrote:
> Signed-off-by: Andrew Jones <address@hidden>
> ---
> v2: add more details in the output if a test fails,
>     report spurious interrupts if we get them
> ---
>  arm/Makefile.common |   6 +-
>  arm/gic.c           | 194 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  arm/unittests.cfg   |   7 ++
>  3 files changed, 204 insertions(+), 3 deletions(-)
>  create mode 100644 arm/gic.c
> 
> diff --git a/arm/Makefile.common b/arm/Makefile.common
> index 41239c37e0920..bc38183ab86e0 100644
> --- a/arm/Makefile.common
> +++ b/arm/Makefile.common
> @@ -9,9 +9,9 @@ ifeq ($(LOADADDR),)
>       LOADADDR = 0x40000000
>  endif
>  
> -tests-common = \
> -     $(TEST_DIR)/selftest.flat \
> -     $(TEST_DIR)/spinlock-test.flat
> +tests-common  = $(TEST_DIR)/selftest.flat
> +tests-common += $(TEST_DIR)/spinlock-test.flat
> +tests-common += $(TEST_DIR)/gic.flat
>  
>  all: test_cases
>  
> diff --git a/arm/gic.c b/arm/gic.c
> new file mode 100644
> index 0000000000000..cf7ec1c90413c
> --- /dev/null
> +++ b/arm/gic.c
> @@ -0,0 +1,194 @@
> +/*
> + * GIC tests
> + *
> + * GICv2
> + *   . test sending/receiving IPIs
> + *
> + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.
> + */
> +#include <libcflat.h>
> +#include <asm/setup.h>
> +#include <asm/processor.h>
> +#include <asm/gic.h>
> +#include <asm/smp.h>
> +#include <asm/barrier.h>
> +#include <asm/io.h>
> +
> +static int gic_version;
> +static int acked[NR_CPUS], spurious[NR_CPUS];
> +static cpumask_t ready;
> +
> +static void nr_cpu_check(int nr)
> +{
> +     if (nr_cpus < nr)
> +             report_abort("At least %d cpus required", nr);
> +}
> +
> +static void wait_on_ready(void)
> +{
> +     cpumask_set_cpu(smp_processor_id(), &ready);
> +     while (!cpumask_full(&ready))
> +             cpu_relax();
> +}
> +
> +static void check_acked(cpumask_t *mask)
> +{
> +     int missing = 0, extra = 0, unexpected = 0;
> +     int nr_pass, cpu, i;
> +
> +     /* Wait up to 5s for all interrupts to be delivered */
> +     for (i = 0; i < 50; ++i) {
> +             mdelay(100);
> +             nr_pass = 0;
> +             for_each_present_cpu(cpu) {
Couldn't we use for_each_cpu(cpu, mask)?
> +                     smp_rmb();
> +                     nr_pass += cpumask_test_cpu(cpu, mask) ?
> +                             acked[cpu] == 1 : acked[cpu] == 0;
> +             }
> +             if (nr_pass == nr_cpus) {
> +                     report("Completed in %d ms", true, ++i * 100);
> +                     return;
> +             }
> +     }
> +
> +     for_each_present_cpu(cpu) {
> +             if (cpumask_test_cpu(cpu, mask)) {
here we can't since we count unexpected

> +                     if (!acked[cpu])
> +                             ++missing;
> +                     else if (acked[cpu] > 1)
> +                             ++extra;
> +             } else {
> +                     if (acked[cpu])
> +                             ++unexpected;
> +             }
> +     }
> +
> +     report("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d",
> +            false, missing, extra, unexpected);
> +}
> +
> +static void ipi_handler(struct pt_regs *regs __unused)
> +{
> +     u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> +
> +     if (iar != GICC_INT_SPURIOUS) {
> +             writel(iar, gicv2_cpu_base() + GIC_CPU_EOI);
if EOIMode is set may need to DIR as well.
> +             smp_rmb(); /* pairs with wmb in ipi_test functions */
> +             ++acked[smp_processor_id()];
> +             smp_wmb(); /* pairs with rmb in check_acked */
> +     } else {
> +             ++spurious[smp_processor_id()];
> +             smp_wmb();
> +     }
> +}
> +
> +static void ipi_test_self(void)
> +{
> +     cpumask_t mask;
> +
> +     report_prefix_push("self");
> +     memset(acked, 0, sizeof(acked));
> +     smp_wmb();
> +     cpumask_clear(&mask);
> +     cpumask_set_cpu(0, &mask);
> +     writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +     check_acked(&mask);
> +     report_prefix_pop();
> +}
> +
> +static void ipi_test_smp(void)
> +{
> +     cpumask_t mask;
> +     unsigned long tlist;
> +
> +     report_prefix_push("target-list");
> +     memset(acked, 0, sizeof(acked));
> +     smp_wmb();
> +     tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
> +     cpumask_bits(&mask)[0] = tlist;
> +     writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +     check_acked(&mask);
> +     report_prefix_pop();
> +
> +     report_prefix_push("broadcast");
> +     memset(acked, 0, sizeof(acked));
> +     smp_wmb();
> +     cpumask_copy(&mask, &cpu_present_mask);
> +     cpumask_clear_cpu(0, &mask);
> +     writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +     check_acked(&mask);
> +     report_prefix_pop();
> +}
> +
> +static void ipi_enable(void)
> +{
> +     gicv2_enable_defaults();
> +#ifdef __arm__
> +     install_exception_handler(EXCPTN_IRQ, ipi_handler);
> +#else
> +     install_irq_handler(EL1H_IRQ, ipi_handler);
> +#endif
> +     local_irq_enable();
> +}
> +
> +static void ipi_recv(void)
> +{
> +     ipi_enable();
> +     cpumask_set_cpu(smp_processor_id(), &ready);
> +     while (1)
> +             wfi();
> +}
> +
> +int main(int argc, char **argv)
> +{
> +     char pfx[8];
> +     int cpu;
> +
> +     gic_version = gic_init();
> +     if (!gic_version)
> +             report_abort("No gic present!");
> +
> +     snprintf(pfx, 8, "gicv%d", gic_version);
> +     report_prefix_push(pfx);
> +
> +     if (argc < 2) {
> +
spare void line
> +             report_prefix_push("ipi");
> +             ipi_enable();
> +             ipi_test_self();
> +             report_prefix_pop();
> +
same
> +     } else if (!strcmp(argv[1], "ipi")) {
> +
same or maybe this is just another style convention?
> +             report_prefix_push(argv[1]);
> +             nr_cpu_check(2);
> +             ipi_enable();
> +
> +             for_each_present_cpu(cpu) {
> +                     if (cpu == 0)
> +                             continue;
> +                     smp_boot_secondary(cpu, ipi_recv);
> +             }
> +             wait_on_ready();
> +             ipi_test_self();
> +             ipi_test_smp();
> +
> +             smp_rmb();
> +             for_each_present_cpu(cpu) {
> +                     if (spurious[cpu]) {
> +                             printf("ipi: WARN: cpu%d got %d spurious "
> +                                    "interrupts\n",
> +                                    spurious[cpu], smp_processor_id());
> +                     }
> +             }
> +
> +             report_prefix_pop();
> +
> +     } else {
> +             report_abort("Unknown subtest '%s'", argv[1]);
> +     }
> +
> +     return report_summary();
> +}
> diff --git a/arm/unittests.cfg b/arm/unittests.cfg
> index ffd12e5794aa0..bb364675043f0 100644
> --- a/arm/unittests.cfg
> +++ b/arm/unittests.cfg
> @@ -51,3 +51,10 @@ file = selftest.flat
>  smp = $MAX_SMP
>  extra_params = -append 'smp'
>  groups = selftest
> +
> +# Test GIC emulation
> +[gicv2-ipi]
> +file = gic.flat
> +smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
> +extra_params = -machine gic-version=2 -append 'ipi'
> +groups = gic
> 
Aside the minor comments above,
Reviewed-by: Eric Auger <address@hidden>

Thanks

Eric




reply via email to

[Prev in Thread] Current Thread [Next in Thread]