Skip to content

Commit 92f2cc4

Browse files
Ricardo KollerMarc Zyngier
authored andcommitted
KVM: selftests: aarch64: Level-sensitive interrupts tests in vgic_irq
Add a cmdline arg for using level-sensitive interrupts (vs the default edge-triggered). Then move the handler into a generic handler function that takes the type of interrupt (level vs. edge) as an arg. When handling line-sensitive interrupts it sets the line to low after acknowledging the IRQ. Signed-off-by: Ricardo Koller <[email protected]> Acked-by: Andrew Jones <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 0ad3ff4 commit 92f2cc4

File tree

1 file changed

+86
-32
lines changed

1 file changed

+86
-32
lines changed

tools/testing/selftests/kvm/aarch64/vgic_irq.c

Lines changed: 86 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
struct test_args {
3131
uint32_t nr_irqs; /* number of KVM supported IRQs. */
3232
bool eoi_split; /* 1 is eoir+dir, 0 is eoir only */
33+
bool level_sensitive; /* 1 is level, 0 is edge */
3334
};
3435

3536
/*
@@ -57,27 +58,31 @@ static void *redist = (void *)GICR_BASE_GPA;
5758

5859
typedef enum {
5960
KVM_INJECT_EDGE_IRQ_LINE = 1,
61+
KVM_SET_IRQ_LINE,
62+
KVM_SET_IRQ_LINE_HIGH,
6063
} kvm_inject_cmd;
6164

6265
struct kvm_inject_args {
6366
kvm_inject_cmd cmd;
6467
uint32_t first_intid;
6568
uint32_t num;
69+
int level;
6670
};
6771

6872
/* Used on the guest side to perform the hypercall. */
69-
static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, uint32_t num);
70-
71-
#define KVM_INJECT(cmd, intid) \
72-
kvm_inject_call(cmd, intid, 1)
73-
74-
#define KVM_INJECT_MULTI(cmd, intid, num) \
75-
kvm_inject_call(cmd, intid, num)
73+
static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid,
74+
uint32_t num, int level);
7675

7776
/* Used on the host side to get the hypercall info. */
7877
static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,
7978
struct kvm_inject_args *args);
8079

80+
#define KVM_INJECT(cmd, intid) \
81+
kvm_inject_call(cmd, intid, 1, -1 /* not used */)
82+
83+
#define KVM_INJECT_MULTI(cmd, intid, num) \
84+
kvm_inject_call(cmd, intid, num, -1 /* not used */)
85+
8186
struct kvm_inject_desc {
8287
kvm_inject_cmd cmd;
8388
/* can inject PPIs, PPIs, and/or SPIs. */
@@ -90,6 +95,12 @@ static struct kvm_inject_desc inject_edge_fns[] = {
9095
{ 0, },
9196
};
9297

98+
static struct kvm_inject_desc inject_level_fns[] = {
99+
/* sgi ppi spi */
100+
{ KVM_SET_IRQ_LINE_HIGH, false, true, true },
101+
{ 0, },
102+
};
103+
93104
#define for_each_inject_fn(t, f) \
94105
for ((f) = (t); (f)->cmd; (f)++)
95106

@@ -114,7 +125,9 @@ static uint64_t gic_read_ap1r0(void)
114125
return reg;
115126
}
116127

117-
static void guest_irq_generic_handler(bool eoi_split)
128+
static void guest_set_irq_line(uint32_t intid, uint32_t level);
129+
130+
static void guest_irq_generic_handler(bool eoi_split, bool level_sensitive)
118131
{
119132
uint32_t intid = gic_get_and_ack_irq();
120133

@@ -123,7 +136,11 @@ static void guest_irq_generic_handler(bool eoi_split)
123136

124137
GUEST_ASSERT(gic_irq_get_active(intid));
125138

126-
GUEST_ASSERT(!gic_irq_get_pending(intid));
139+
if (!level_sensitive)
140+
GUEST_ASSERT(!gic_irq_get_pending(intid));
141+
142+
if (level_sensitive)
143+
guest_set_irq_line(intid, 0);
127144

128145
GUEST_ASSERT(intid < MAX_SPI);
129146
irqnr_received[intid] += 1;
@@ -138,12 +155,14 @@ static void guest_irq_generic_handler(bool eoi_split)
138155
GUEST_ASSERT(!gic_irq_get_pending(intid));
139156
}
140157

141-
static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, uint32_t num)
158+
static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid,
159+
uint32_t num, int level)
142160
{
143161
struct kvm_inject_args args = {
144162
.cmd = cmd,
145163
.first_intid = first_intid,
146164
.num = num,
165+
.level = level,
147166
};
148167
GUEST_SYNC(&args);
149168
}
@@ -158,19 +177,21 @@ do { \
158177
#define CAT_HELPER(a, b) a ## b
159178
#define CAT(a, b) CAT_HELPER(a, b)
160179
#define PREFIX guest_irq_handler_
161-
#define GUEST_IRQ_HANDLER_NAME(split) CAT(PREFIX, split)
162-
#define GENERATE_GUEST_IRQ_HANDLER(split) \
163-
static void CAT(PREFIX, split)(struct ex_regs *regs) \
180+
#define GUEST_IRQ_HANDLER_NAME(split, lev) CAT(PREFIX, CAT(split, lev))
181+
#define GENERATE_GUEST_IRQ_HANDLER(split, lev) \
182+
static void CAT(PREFIX, CAT(split, lev))(struct ex_regs *regs) \
164183
{ \
165-
guest_irq_generic_handler(split); \
184+
guest_irq_generic_handler(split, lev); \
166185
}
167186

168-
GENERATE_GUEST_IRQ_HANDLER(0);
169-
GENERATE_GUEST_IRQ_HANDLER(1);
187+
GENERATE_GUEST_IRQ_HANDLER(0, 0);
188+
GENERATE_GUEST_IRQ_HANDLER(0, 1);
189+
GENERATE_GUEST_IRQ_HANDLER(1, 0);
190+
GENERATE_GUEST_IRQ_HANDLER(1, 1);
170191

171-
static void (*guest_irq_handlers[2])(struct ex_regs *) = {
172-
GUEST_IRQ_HANDLER_NAME(0),
173-
GUEST_IRQ_HANDLER_NAME(1),
192+
static void (*guest_irq_handlers[2][2])(struct ex_regs *) = {
193+
{GUEST_IRQ_HANDLER_NAME(0, 0), GUEST_IRQ_HANDLER_NAME(0, 1),},
194+
{GUEST_IRQ_HANDLER_NAME(1, 0), GUEST_IRQ_HANDLER_NAME(1, 1),},
174195
};
175196

176197
static void reset_priorities(struct test_args *args)
@@ -181,6 +202,11 @@ static void reset_priorities(struct test_args *args)
181202
gic_set_priority(i, IRQ_DEFAULT_PRIO_REG);
182203
}
183204

205+
static void guest_set_irq_line(uint32_t intid, uint32_t level)
206+
{
207+
kvm_inject_call(KVM_SET_IRQ_LINE, intid, 1, level);
208+
}
209+
184210
static void guest_inject(struct test_args *args,
185211
uint32_t first_intid, uint32_t num,
186212
kvm_inject_cmd cmd)
@@ -257,10 +283,12 @@ static void test_inject_preemption(struct test_args *args,
257283
for (i = 0; i < num; i++) {
258284
uint32_t tmp;
259285
intid = i + first_intid;
260-
kvm_inject_call(cmd, intid, 1);
286+
KVM_INJECT(cmd, intid);
261287
/* Each successive IRQ will preempt the previous one. */
262288
tmp = wait_for_and_activate_irq();
263289
GUEST_ASSERT_EQ(tmp, intid);
290+
if (args->level_sensitive)
291+
guest_set_irq_line(intid, 0);
264292
}
265293

266294
/* finish handling the IRQs starting with the highest priority one. */
@@ -321,22 +349,29 @@ static void test_preemption(struct test_args *args, struct kvm_inject_desc *f)
321349
static void guest_code(struct test_args args)
322350
{
323351
uint32_t i, nr_irqs = args.nr_irqs;
324-
struct kvm_inject_desc *f;
352+
bool level_sensitive = args.level_sensitive;
353+
struct kvm_inject_desc *f, *inject_fns;
325354

326355
gic_init(GIC_V3, 1, dist, redist);
327356

328357
for (i = 0; i < nr_irqs; i++)
329358
gic_irq_enable(i);
330359

360+
for (i = MIN_SPI; i < nr_irqs; i++)
361+
gic_irq_set_config(i, !args.level_sensitive);
362+
331363
gic_set_eoi_split(args.eoi_split);
332364

333365
reset_priorities(&args);
334366
gic_set_priority_mask(CPU_PRIO_MASK);
335367

368+
inject_fns = level_sensitive ? inject_level_fns
369+
: inject_edge_fns;
370+
336371
local_irq_enable();
337372

338373
/* Start the tests. */
339-
for_each_inject_fn(inject_edge_fns, f) {
374+
for_each_inject_fn(inject_fns, f) {
340375
test_injection(&args, f);
341376
test_preemption(&args, f);
342377
}
@@ -351,6 +386,7 @@ static void run_guest_cmd(struct kvm_vm *vm, int gic_fd,
351386
kvm_inject_cmd cmd = inject_args->cmd;
352387
uint32_t intid = inject_args->first_intid;
353388
uint32_t num = inject_args->num;
389+
int level = inject_args->level;
354390
uint32_t i;
355391

356392
assert(intid < UINT_MAX - num);
@@ -362,6 +398,14 @@ static void run_guest_cmd(struct kvm_vm *vm, int gic_fd,
362398
for (i = intid; i < intid + num; i++)
363399
kvm_arm_irq_line(vm, i, 0);
364400
break;
401+
case KVM_SET_IRQ_LINE:
402+
for (i = intid; i < intid + num; i++)
403+
kvm_arm_irq_line(vm, i, level);
404+
break;
405+
case KVM_SET_IRQ_LINE_HIGH:
406+
for (i = intid; i < intid + num; i++)
407+
kvm_arm_irq_line(vm, i, 1);
408+
break;
365409
default:
366410
break;
367411
}
@@ -380,11 +424,12 @@ static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,
380424

381425
static void print_args(struct test_args *args)
382426
{
383-
printf("nr-irqs=%d eoi-split=%d\n",
384-
args->nr_irqs, args->eoi_split);
427+
printf("nr-irqs=%d level-sensitive=%d eoi-split=%d\n",
428+
args->nr_irqs, args->level_sensitive,
429+
args->eoi_split);
385430
}
386431

387-
static void test_vgic(uint32_t nr_irqs, bool eoi_split)
432+
static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split)
388433
{
389434
struct ucall uc;
390435
int gic_fd;
@@ -393,6 +438,7 @@ static void test_vgic(uint32_t nr_irqs, bool eoi_split)
393438

394439
struct test_args args = {
395440
.nr_irqs = nr_irqs,
441+
.level_sensitive = level_sensitive,
396442
.eoi_split = eoi_split,
397443
};
398444

@@ -411,7 +457,7 @@ static void test_vgic(uint32_t nr_irqs, bool eoi_split)
411457
GICD_BASE_GPA, GICR_BASE_GPA);
412458

413459
vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT,
414-
guest_irq_handlers[args.eoi_split]);
460+
guest_irq_handlers[args.eoi_split][args.level_sensitive]);
415461

416462
while (1) {
417463
vcpu_run(vm, VCPU_ID);
@@ -442,11 +488,12 @@ static void help(const char *name)
442488
{
443489
printf(
444490
"\n"
445-
"usage: %s [-n num_irqs] [-e eoi_split]\n", name);
446-
printf(" -n: specify the number of IRQs to configure the vgic with. "
491+
"usage: %s [-n num_irqs] [-e eoi_split] [-l level_sensitive]\n", name);
492+
printf(" -n: specify number of IRQs to setup the vgic with. "
447493
"It has to be a multiple of 32 and between 64 and 1024.\n");
448494
printf(" -e: if 1 then EOI is split into a write to DIR on top "
449495
"of writing EOI.\n");
496+
printf(" -l: specify whether the IRQs are level-sensitive (1) or not (0).");
450497
puts("");
451498
exit(1);
452499
}
@@ -455,13 +502,14 @@ int main(int argc, char **argv)
455502
{
456503
uint32_t nr_irqs = 64;
457504
bool default_args = true;
505+
bool level_sensitive = false;
458506
int opt;
459507
bool eoi_split = false;
460508

461509
/* Tell stdout not to buffer its content */
462510
setbuf(stdout, NULL);
463511

464-
while ((opt = getopt(argc, argv, "hn:e:")) != -1) {
512+
while ((opt = getopt(argc, argv, "hn:e:l:")) != -1) {
465513
switch (opt) {
466514
case 'n':
467515
nr_irqs = atoi(optarg);
@@ -472,6 +520,10 @@ int main(int argc, char **argv)
472520
eoi_split = (bool)atoi(optarg);
473521
default_args = false;
474522
break;
523+
case 'l':
524+
level_sensitive = (bool)atoi(optarg);
525+
default_args = false;
526+
break;
475527
case 'h':
476528
default:
477529
help(argv[0]);
@@ -483,10 +535,12 @@ int main(int argc, char **argv)
483535
* combinations.
484536
*/
485537
if (default_args) {
486-
test_vgic(nr_irqs, false /* eoi_split */);
487-
test_vgic(nr_irqs, true /* eoi_split */);
538+
test_vgic(nr_irqs, false /* level */, false /* eoi_split */);
539+
test_vgic(nr_irqs, false /* level */, true /* eoi_split */);
540+
test_vgic(nr_irqs, true /* level */, false /* eoi_split */);
541+
test_vgic(nr_irqs, true /* level */, true /* eoi_split */);
488542
} else {
489-
test_vgic(nr_irqs, eoi_split);
543+
test_vgic(nr_irqs, level_sensitive, eoi_split);
490544
}
491545

492546
return 0;

0 commit comments

Comments
 (0)