diff options
author | Ricardo Koller <ricarkol@google.com> | 2021-11-09 05:38:57 +0300 |
---|---|---|
committer | Marc Zyngier <maz@kernel.org> | 2021-12-28 22:24:06 +0300 |
commit | e5410ee2806d74a749fa39ca6fdb73be2f88611f (patch) | |
tree | ae9cd9cfb1d3b0dc3d8134e3fb8c3243baf2c901 /tools/testing/selftests/kvm/aarch64/vgic_irq.c | |
parent | e1cb399eed1eda29568b17bdb75d16cee1fc3da4 (diff) | |
download | linux-e5410ee2806d74a749fa39ca6fdb73be2f88611f.tar.xz |
KVM: selftests: aarch64: Cmdline arg to set number of IRQs in vgic_irq test
Add the ability to specify the number of vIRQs exposed by KVM (arg
defaults to 64). Then extend the KVM_IRQ_LINE test by injecting all
available SPIs at once (specified by the nr-irqs arg). As a bonus,
inject all SGIs at once as well.
Signed-off-by: Ricardo Koller <ricarkol@google.com>
Acked-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20211109023906.1091208-9-ricarkol@google.com
Diffstat (limited to 'tools/testing/selftests/kvm/aarch64/vgic_irq.c')
-rw-r--r-- | tools/testing/selftests/kvm/aarch64/vgic_irq.c | 149 |
1 files changed, 117 insertions, 32 deletions
diff --git a/tools/testing/selftests/kvm/aarch64/vgic_irq.c b/tools/testing/selftests/kvm/aarch64/vgic_irq.c index f5d76fef22f0..0b89a29dfe79 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_irq.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_irq.c @@ -24,6 +24,14 @@ #define VCPU_ID 0 /* + * Stores the user specified args; it's passed to the guest and to every test + * function. + */ +struct test_args { + uint32_t nr_irqs; /* number of KVM supported IRQs. */ +}; + +/* * KVM implements 32 priority levels: * 0x00 (highest priority) - 0xF8 (lowest priority), in steps of 8 * @@ -51,14 +59,18 @@ typedef enum { struct kvm_inject_args { kvm_inject_cmd cmd; - uint32_t intid; + uint32_t first_intid; + uint32_t num; }; /* Used on the guest side to perform the hypercall. */ -static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t intid); +static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, uint32_t num); #define KVM_INJECT(cmd, intid) \ - kvm_inject_call(cmd, intid) + kvm_inject_call(cmd, intid, 1) + +#define KVM_INJECT_MULTI(cmd, intid, num) \ + kvm_inject_call(cmd, intid, num) /* Used on the host side to get the hypercall info. */ static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc, @@ -122,11 +134,12 @@ static void guest_irq_handler(struct ex_regs *regs) GUEST_ASSERT(!gic_irq_get_pending(intid)); } -static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t intid) +static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, uint32_t num) { struct kvm_inject_args args = { .cmd = cmd, - .intid = intid, + .first_intid = first_intid, + .num = num, }; GUEST_SYNC(&args); } @@ -138,14 +151,30 @@ do { \ GUEST_ASSERT(_intid == 0 || _intid == IAR_SPURIOUS); \ } while (0) -static void guest_inject(uint32_t intid, kvm_inject_cmd cmd) +static void reset_priorities(struct test_args *args) +{ + int i; + + for (i = 0; i < args->nr_irqs; i++) + gic_set_priority(i, IRQ_DEFAULT_PRIO_REG); +} + +static void guest_inject(struct test_args *args, + uint32_t first_intid, uint32_t num, + kvm_inject_cmd cmd) { + uint32_t i; + reset_stats(); + /* Cycle over all priorities to make things more interesting. */ + for (i = first_intid; i < num + first_intid; i++) + gic_set_priority(i, (i % (KVM_NUM_PRIOS - 1)) << 3); + asm volatile("msr daifset, #2" : : : "memory"); - KVM_INJECT(cmd, intid); + KVM_INJECT_MULTI(cmd, first_intid, num); - while (irq_handled < 1) { + while (irq_handled < num) { asm volatile("wfi\n" "msr daifclr, #2\n" /* handle IRQ */ @@ -154,57 +183,72 @@ static void guest_inject(uint32_t intid, kvm_inject_cmd cmd) } asm volatile("msr daifclr, #2" : : : "memory"); - GUEST_ASSERT_EQ(irq_handled, 1); - GUEST_ASSERT_EQ(irqnr_received[intid], 1); + GUEST_ASSERT_EQ(irq_handled, num); + for (i = first_intid; i < num + first_intid; i++) + GUEST_ASSERT_EQ(irqnr_received[i], 1); GUEST_ASSERT_IAR_EMPTY(); + + reset_priorities(args); } -static void test_injection(struct kvm_inject_desc *f) +static void test_injection(struct test_args *args, struct kvm_inject_desc *f) { - if (f->sgi) - guest_inject(MIN_SGI, f->cmd); + uint32_t nr_irqs = args->nr_irqs; + + if (f->sgi) { + guest_inject(args, MIN_SGI, 1, f->cmd); + guest_inject(args, 0, 16, f->cmd); + } if (f->ppi) - guest_inject(MIN_PPI, f->cmd); + guest_inject(args, MIN_PPI, 1, f->cmd); - if (f->spi) - guest_inject(MIN_SPI, f->cmd); + if (f->spi) { + guest_inject(args, MIN_SPI, 1, f->cmd); + guest_inject(args, nr_irqs - 1, 1, f->cmd); + guest_inject(args, MIN_SPI, nr_irqs - MIN_SPI, f->cmd); + } } -static void guest_code(void) +static void guest_code(struct test_args args) { - uint32_t i; - uint32_t nr_irqs = 64; /* absolute minimum number of IRQs supported. */ + uint32_t i, nr_irqs = args.nr_irqs; struct kvm_inject_desc *f; gic_init(GIC_V3, 1, dist, redist); - for (i = 0; i < nr_irqs; i++) { + for (i = 0; i < nr_irqs; i++) gic_irq_enable(i); - gic_set_priority(i, IRQ_DEFAULT_PRIO_REG); - } + reset_priorities(&args); gic_set_priority_mask(CPU_PRIO_MASK); local_irq_enable(); /* Start the tests. */ for_each_inject_fn(inject_edge_fns, f) - test_injection(f); + test_injection(&args, f); GUEST_DONE(); } static void run_guest_cmd(struct kvm_vm *vm, int gic_fd, - struct kvm_inject_args *inject_args) + struct kvm_inject_args *inject_args, + struct test_args *test_args) { kvm_inject_cmd cmd = inject_args->cmd; - uint32_t intid = inject_args->intid; + uint32_t intid = inject_args->first_intid; + uint32_t num = inject_args->num; + uint32_t i; + + assert(intid < UINT_MAX - num); switch (cmd) { case KVM_INJECT_EDGE_IRQ_LINE: - kvm_arm_irq_line(vm, intid, 1); - kvm_arm_irq_line(vm, intid, 0); + for (i = intid; i < intid + num; i++) + kvm_arm_irq_line(vm, i, 1); + for (i = intid; i < intid + num; i++) + kvm_arm_irq_line(vm, i, 0); break; default: break; @@ -222,21 +266,35 @@ static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc, memcpy(args, kvm_args_hva, sizeof(struct kvm_inject_args)); } +static void print_args(struct test_args *args) +{ + printf("nr-irqs=%d\n", args->nr_irqs); +} -static void test_vgic(void) +static void test_vgic(uint32_t nr_irqs) { struct ucall uc; int gic_fd; struct kvm_vm *vm; struct kvm_inject_args inject_args; + struct test_args args = { + .nr_irqs = nr_irqs, + }; + + print_args(&args); + vm = vm_create_default(VCPU_ID, 0, guest_code); ucall_init(vm, NULL); vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vm, VCPU_ID); - gic_fd = vgic_v3_setup(vm, 1, GICD_BASE_GPA, GICR_BASE_GPA); + /* Setup the guest args page (so it gets the args). */ + vcpu_args_set(vm, 0, 1, args); + + gic_fd = vgic_v3_setup(vm, 1, nr_irqs, + GICD_BASE_GPA, GICR_BASE_GPA); vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT, guest_irq_handler); @@ -247,7 +305,7 @@ static void test_vgic(void) switch (get_ucall(vm, VCPU_ID, &uc)) { case UCALL_SYNC: kvm_inject_get_call(vm, &uc, &inject_args); - run_guest_cmd(vm, gic_fd, &inject_args); + run_guest_cmd(vm, gic_fd, &inject_args, &args); break; case UCALL_ABORT: TEST_FAIL("%s at %s:%ld\n\tvalues: %#lx, %#lx", @@ -266,12 +324,39 @@ done: kvm_vm_free(vm); } -int main(int ac, char **av) +static void help(const char *name) { + printf( + "\n" + "usage: %s [-n num_irqs]\n", name); + printf(" -n: specify the number of IRQs to configure the vgic with.\n"); + puts(""); + exit(1); +} + +int main(int argc, char **argv) +{ + uint32_t nr_irqs = 64; + int opt; + /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); - test_vgic(); + while ((opt = getopt(argc, argv, "hg:n:")) != -1) { + switch (opt) { + case 'n': + nr_irqs = atoi(optarg); + if (nr_irqs > 1024 || nr_irqs % 32) + help(argv[0]); + break; + case 'h': + default: + help(argv[0]); + break; + } + } + + test_vgic(nr_irqs); return 0; } |