aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Jones <drjones@redhat.com>2020-02-11 13:29:56 +0100
committerAndrew Jones <drjones@redhat.com>2020-04-03 09:40:34 +0200
commit56145eb8f7f6aa66b26e1d1232a5f3dfa7cdd058 (patch)
tree4765ede291cfc4c8ee5eb57108dfbe7376f225db
parent450c579c669756588fb2edfcaad7d2e467eb8275 (diff)
downloadkvm-unit-tests-56145eb8f7f6aa66b26e1d1232a5f3dfa7cdd058.tar.gz
arm64: timer: Speed up gic-timer-state check
Let's bail out of the wait loop if we see the expected state to save over six seconds of run time. Make sure we wait a bit before reading the registers and double check again after, though, to somewhat mitigate the chance of seeing the expected state by accident. We also take this opportunity to push more IRQ state code to the library. Cc: Zenghui Yu <yuzenghui@huawei.com> Reviewed-by: Zenghui Yu <yuzenghui@huawei.com> Tested-by: Zenghui Yu <yuzenghui@huawei.com> Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com> Signed-off-by: Andrew Jones <drjones@redhat.com>
-rw-r--r--arm/timer.c36
-rw-r--r--lib/arm/asm/gic.h11
-rw-r--r--lib/arm/gic.c45
3 files changed, 63 insertions, 29 deletions
diff --git a/arm/timer.c b/arm/timer.c
index f5cf775..44621b4 100644
--- a/arm/timer.c
+++ b/arm/timer.c
@@ -17,8 +17,6 @@
#define ARCH_TIMER_CTL_IMASK (1 << 1)
#define ARCH_TIMER_CTL_ISTATUS (1 << 2)
-static void *gic_isactiver;
-static void *gic_ispendr;
static void *gic_isenabler;
static void *gic_icenabler;
@@ -183,28 +181,22 @@ static bool timer_pending(struct timer_info *info)
(info->read_ctl() & ARCH_TIMER_CTL_ISTATUS);
}
-static enum gic_state gic_timer_state(struct timer_info *info)
+static bool gic_timer_check_state(struct timer_info *info,
+ enum gic_irq_state expected_state)
{
- enum gic_state state = GIC_STATE_INACTIVE;
int i;
- bool pending, active;
/* Wait for up to 1s for the GIC to sample the interrupt. */
for (i = 0; i < 10; i++) {
- pending = readl(gic_ispendr) & (1 << PPI(info->irq));
- active = readl(gic_isactiver) & (1 << PPI(info->irq));
- if (!active && !pending)
- state = GIC_STATE_INACTIVE;
- if (pending)
- state = GIC_STATE_PENDING;
- if (active)
- state = GIC_STATE_ACTIVE;
- if (active && pending)
- state = GIC_STATE_ACTIVE_PENDING;
mdelay(100);
+ if (gic_irq_state(PPI(info->irq)) == expected_state) {
+ mdelay(100);
+ if (gic_irq_state(PPI(info->irq)) == expected_state)
+ return true;
+ }
}
- return state;
+ return false;
}
static bool test_cval_10msec(struct timer_info *info)
@@ -253,11 +245,11 @@ static void test_timer(struct timer_info *info)
/* Enable the timer, but schedule it for much later */
info->write_cval(later);
info->write_ctl(ARCH_TIMER_CTL_ENABLE);
- report(!timer_pending(info) && gic_timer_state(info) == GIC_STATE_INACTIVE,
+ report(!timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE),
"not pending before");
info->write_cval(now - 1);
- report(timer_pending(info) && gic_timer_state(info) == GIC_STATE_PENDING,
+ report(timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_PENDING),
"interrupt signal pending");
/* Disable the timer again and prepare to take interrupts */
@@ -265,12 +257,12 @@ static void test_timer(struct timer_info *info)
info->irq_received = false;
set_timer_irq_enabled(info, true);
report(!info->irq_received, "no interrupt when timer is disabled");
- report(!timer_pending(info) && gic_timer_state(info) == GIC_STATE_INACTIVE,
+ report(!timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE),
"interrupt signal no longer pending");
info->write_cval(now - 1);
info->write_ctl(ARCH_TIMER_CTL_ENABLE | ARCH_TIMER_CTL_IMASK);
- report(timer_pending(info) && gic_timer_state(info) == GIC_STATE_INACTIVE,
+ report(timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE),
"interrupt signal not pending");
report(test_cval_10msec(info), "latency within 10 ms");
@@ -345,14 +337,10 @@ static void test_init(void)
switch (gic_version()) {
case 2:
- gic_isactiver = gicv2_dist_base() + GICD_ISACTIVER;
- gic_ispendr = gicv2_dist_base() + GICD_ISPENDR;
gic_isenabler = gicv2_dist_base() + GICD_ISENABLER;
gic_icenabler = gicv2_dist_base() + GICD_ICENABLER;
break;
case 3:
- gic_isactiver = gicv3_sgi_base() + GICR_ISACTIVER0;
- gic_ispendr = gicv3_sgi_base() + GICR_ISPENDR0;
gic_isenabler = gicv3_sgi_base() + GICR_ISENABLER0;
gic_icenabler = gicv3_sgi_base() + GICR_ICENABLER0;
break;
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index a72e0cd..922cbe9 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -47,11 +47,11 @@
#ifndef __ASSEMBLY__
#include <asm/cpumask.h>
-enum gic_state {
- GIC_STATE_INACTIVE,
- GIC_STATE_PENDING,
- GIC_STATE_ACTIVE,
- GIC_STATE_ACTIVE_PENDING,
+enum gic_irq_state {
+ GIC_IRQ_STATE_INACTIVE,
+ GIC_IRQ_STATE_PENDING,
+ GIC_IRQ_STATE_ACTIVE,
+ GIC_IRQ_STATE_ACTIVE_PENDING,
};
/*
@@ -80,6 +80,7 @@ extern u32 gic_iar_irqnr(u32 iar);
extern void gic_write_eoir(u32 irqstat);
extern void gic_ipi_send_single(int irq, int cpu);
extern void gic_ipi_send_mask(int irq, const cpumask_t *dest);
+extern enum gic_irq_state gic_irq_state(int irq);
#endif /* !__ASSEMBLY__ */
#endif /* _ASMARM_GIC_H_ */
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
index 9430116..c3c5f6b 100644
--- a/lib/arm/gic.c
+++ b/lib/arm/gic.c
@@ -146,3 +146,48 @@ void gic_ipi_send_mask(int irq, const cpumask_t *dest)
assert(gic_common_ops && gic_common_ops->ipi_send_mask);
gic_common_ops->ipi_send_mask(irq, dest);
}
+
+enum gic_irq_state gic_irq_state(int irq)
+{
+ enum gic_irq_state state;
+ void *ispendr, *isactiver;
+ bool pending, active;
+ int offset, mask;
+
+ assert(gic_common_ops);
+ assert(irq < 1020);
+
+ switch (gic_version()) {
+ case 2:
+ ispendr = gicv2_dist_base() + GICD_ISPENDR;
+ isactiver = gicv2_dist_base() + GICD_ISACTIVER;
+ break;
+ case 3:
+ if (irq < GIC_NR_PRIVATE_IRQS) {
+ ispendr = gicv3_sgi_base() + GICR_ISPENDR0;
+ isactiver = gicv3_sgi_base() + GICR_ISACTIVER0;
+ } else {
+ ispendr = gicv3_dist_base() + GICD_ISPENDR;
+ isactiver = gicv3_dist_base() + GICD_ISACTIVER;
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ offset = irq / 32 * 4;
+ mask = 1 << (irq % 32);
+ pending = readl(ispendr + offset) & mask;
+ active = readl(isactiver + offset) & mask;
+
+ if (!active && !pending)
+ state = GIC_IRQ_STATE_INACTIVE;
+ if (pending)
+ state = GIC_IRQ_STATE_PENDING;
+ if (active)
+ state = GIC_IRQ_STATE_ACTIVE;
+ if (active && pending)
+ state = GIC_IRQ_STATE_ACTIVE_PENDING;
+
+ return state;
+}