Skip to content

Commit

Permalink
KVM: selftests: aarch64: Add preemption tests in vgic_irq
Browse files Browse the repository at this point in the history
Add tests for IRQ preemption (having more than one activated IRQ at the
same time).  This test injects multiple concurrent IRQs and handles them
without handling the actual exceptions.  This is done by masking
interrupts for the whole test.

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-11-ricarkol@google.com
  • Loading branch information
Ricardo Koller authored and Marc Zyngier committed Dec 28, 2021
1 parent 8a35b28 commit 0ad3ff4
Showing 1 changed file with 90 additions and 1 deletion.
91 changes: 90 additions & 1 deletion tools/testing/selftests/kvm/aarch64/vgic_irq.c
Expand Up @@ -41,6 +41,7 @@ struct test_args {
*/
#define KVM_NUM_PRIOS 32
#define KVM_PRIO_SHIFT 3 /* steps of 8 = 1 << 3 */
#define KVM_PRIO_STEPS (1 << KVM_PRIO_SHIFT) /* 8 */
#define LOWEST_PRIO (KVM_NUM_PRIOS - 1)
#define CPU_PRIO_MASK (LOWEST_PRIO << KVM_PRIO_SHIFT) /* 0xf8 */
#define IRQ_DEFAULT_PRIO (LOWEST_PRIO - 1)
Expand Down Expand Up @@ -212,6 +213,74 @@ static void guest_inject(struct test_args *args,
reset_priorities(args);
}

/*
* Polls the IAR until it's not a spurious interrupt.
*
* This function should only be used in test_inject_preemption (with IRQs
* masked).
*/
static uint32_t wait_for_and_activate_irq(void)
{
uint32_t intid;

do {
asm volatile("wfi" : : : "memory");
intid = gic_get_and_ack_irq();
} while (intid == IAR_SPURIOUS);

return intid;
}

/*
* Inject multiple concurrent IRQs (num IRQs starting at first_intid) and
* handle them without handling the actual exceptions. This is done by masking
* interrupts for the whole test.
*/
static void test_inject_preemption(struct test_args *args,
uint32_t first_intid, int num,
kvm_inject_cmd cmd)
{
uint32_t intid, prio, step = KVM_PRIO_STEPS;
int i;

/* Set the priorities of the first (KVM_NUM_PRIOS - 1) IRQs
* in descending order, so intid+1 can preempt intid.
*/
for (i = 0, prio = (num - 1) * step; i < num; i++, prio -= step) {
GUEST_ASSERT(prio >= 0);
intid = i + first_intid;
gic_set_priority(intid, prio);
}

local_irq_disable();

for (i = 0; i < num; i++) {
uint32_t tmp;
intid = i + first_intid;
kvm_inject_call(cmd, intid, 1);
/* Each successive IRQ will preempt the previous one. */
tmp = wait_for_and_activate_irq();
GUEST_ASSERT_EQ(tmp, intid);
}

/* finish handling the IRQs starting with the highest priority one. */
for (i = 0; i < num; i++) {
intid = num - i - 1 + first_intid;
gic_set_eoi(intid);
if (args->eoi_split)
gic_set_dir(intid);
}

local_irq_enable();

for (i = 0; i < num; i++)
GUEST_ASSERT(!gic_irq_get_active(i + first_intid));
GUEST_ASSERT_EQ(gic_read_ap1r0(), 0);
GUEST_ASSERT_IAR_EMPTY();

reset_priorities(args);
}

static void test_injection(struct test_args *args, struct kvm_inject_desc *f)
{
uint32_t nr_irqs = args->nr_irqs;
Expand All @@ -231,6 +300,24 @@ static void test_injection(struct test_args *args, struct kvm_inject_desc *f)
}
}

static void test_preemption(struct test_args *args, struct kvm_inject_desc *f)
{
/*
* Test up to 4 levels of preemption. The reason is that KVM doesn't
* currently implement the ability to have more than the number-of-LRs
* number of concurrently active IRQs. The number of LRs implemented is
* IMPLEMENTATION DEFINED, however, it seems that most implement 4.
*/
if (f->sgi)
test_inject_preemption(args, MIN_SGI, 4, f->cmd);

if (f->ppi)
test_inject_preemption(args, MIN_PPI, 4, f->cmd);

if (f->spi)
test_inject_preemption(args, MIN_SPI, 4, f->cmd);
}

static void guest_code(struct test_args args)
{
uint32_t i, nr_irqs = args.nr_irqs;
Expand All @@ -249,8 +336,10 @@ static void guest_code(struct test_args args)
local_irq_enable();

/* Start the tests. */
for_each_inject_fn(inject_edge_fns, f)
for_each_inject_fn(inject_edge_fns, f) {
test_injection(&args, f);
test_preemption(&args, f);
}

GUEST_DONE();
}
Expand Down

0 comments on commit 0ad3ff4

Please sign in to comment.