From: Christoffer Dall <cdall@linaro.org>
To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu
Cc: Christoffer Dall <cdall@linaro.org>,
Marc Zyngier <marc.zyngier@arm.com>,
Paolo Bonzini <pbonzini@redhat.com>
Subject: [PATCH kvm-unit-tests 3/3] arm64: timer: Add support for phys timer testing
Date: Thu, 13 Jul 2017 21:20:09 +0200 [thread overview]
Message-ID: <20170713192009.10069-4-cdall@linaro.org> (raw)
In-Reply-To: <20170713192009.10069-1-cdall@linaro.org>
Rearrange the code to be able to reuse as much as posible and add
support for testing the physical timer as well.
Also change the default unittests configuration to run a separate vtimer
and ptimer test so that older kernels without ptimer support just show a
failure.
Signed-off-by: Christoffer Dall <cdall@linaro.org>
---
arm/timer.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++--------
arm/unittests.cfg | 9 ++-
2 files changed, 177 insertions(+), 31 deletions(-)
diff --git a/arm/timer.c b/arm/timer.c
index 77d257c..33dfc6f 100644
--- a/arm/timer.c
+++ b/arm/timer.c
@@ -11,34 +11,119 @@
#include <asm/gic.h>
#include <asm/io.h>
-#define CNTV_CTL_ENABLE (1 << 0)
-#define CNTV_CTL_IMASK (1 << 1)
-#define CNTV_CTL_ISTATUS (1 << 2)
+#define ARCH_TIMER_CTL_ENABLE (1 << 0)
+#define ARCH_TIMER_CTL_IMASK (1 << 1)
+#define ARCH_TIMER_CTL_ISTATUS (1 << 2)
-static u32 vtimer_irq, vtimer_irq_flags;
static void *gic_ispendr;
-static bool vtimer_irq_received;
+
+static u64 read_vtimer_counter(void)
+{
+ return read_sysreg(cntvct_el0);
+}
+
+static u64 read_vtimer_cval(void)
+{
+ return read_sysreg(cntv_cval_el0);
+}
+
+static void write_vtimer_cval(u64 val)
+{
+ write_sysreg(val, cntv_cval_el0);
+}
+
+static u64 read_vtimer_ctl(void)
+{
+ return read_sysreg(cntv_ctl_el0);
+}
+
+static void write_vtimer_ctl(u64 val)
+{
+ write_sysreg(val, cntv_ctl_el0);
+}
+
+static u64 read_ptimer_counter(void)
+{
+ return read_sysreg(cntpct_el0);
+}
+
+static u64 read_ptimer_cval(void)
+{
+ return read_sysreg(cntp_cval_el0);
+}
+
+static void write_ptimer_cval(u64 val)
+{
+ write_sysreg(val, cntp_cval_el0);
+}
+
+static u64 read_ptimer_ctl(void)
+{
+ return read_sysreg(cntp_ctl_el0);
+}
+
+static void write_ptimer_ctl(u64 val)
+{
+ write_sysreg(val, cntp_ctl_el0);
+}
+
+struct timer_info {
+ u32 irq;
+ u32 irq_flags;
+ bool irq_received;
+ u64 (*read_counter)(void);
+ u64 (*read_cval)(void);
+ void (*write_cval)(u64);
+ u64 (*read_ctl)(void);
+ void (*write_ctl)(u64);
+};
+
+static struct timer_info vtimer_info = {
+ .irq_received = false,
+ .read_counter = read_vtimer_counter,
+ .read_cval = read_vtimer_cval,
+ .write_cval = write_vtimer_cval,
+ .read_ctl = read_vtimer_ctl,
+ .write_ctl = write_vtimer_ctl,
+};
+
+static struct timer_info ptimer_info = {
+ .irq_received = false,
+ .read_counter = read_ptimer_counter,
+ .read_cval = read_ptimer_cval,
+ .write_cval = write_ptimer_cval,
+ .read_ctl = read_ptimer_ctl,
+ .write_ctl = write_ptimer_ctl,
+};
static void irq_handler(struct pt_regs *regs)
{
+ struct timer_info *info;
u32 irqstat = gic_read_iar();
u32 irqnr = gic_iar_irqnr(irqstat);
if (irqnr != GICC_INT_SPURIOUS)
gic_write_eoir(irqstat);
- if (irqnr == PPI(vtimer_irq)) {
- write_sysreg(CNTV_CTL_IMASK | CNTV_CTL_ENABLE, cntv_ctl_el0);
- ++vtimer_irq_received;
+ if (irqnr == PPI(vtimer_info.irq)) {
+ info = &vtimer_info;
+ } else if (irqnr == PPI(ptimer_info.irq)) {
+ info = &ptimer_info;
+ } else {
+ report_info("Unexpected interrupt: %d\n", irqnr);
+ return;
}
+
+ info->write_ctl(ARCH_TIMER_CTL_IMASK | ARCH_TIMER_CTL_ENABLE);
+ info->irq_received = true;
}
-static bool gic_vtimer_pending(void)
+static bool gic_timer_pending(struct timer_info *info)
{
- return readl(gic_ispendr) & (1 << PPI(vtimer_irq));
+ return readl(gic_ispendr) & (1 << PPI(info->irq));
}
-static bool test_cval_10msec(void)
+static bool test_cval_10msec(struct timer_info *info)
{
u64 time_10ms = read_sysreg(cntfrq_el0) / 100;
u64 time_1us = time_10ms / 10000;
@@ -46,15 +131,15 @@ static bool test_cval_10msec(void)
s64 difference;
/* Program timer to fire in 10 ms */
- before_timer = read_sysreg(cntvct_el0);
- write_sysreg(before_timer + time_10ms, cntv_cval_el0);
+ before_timer = info->read_counter();
+ info->write_cval(before_timer + time_10ms);
/* Wait for the timer to fire */
- while (!(read_sysreg(cntv_ctl_el0) & CNTV_CTL_ISTATUS))
+ while (!(info->read_ctl() & ARCH_TIMER_CTL_ISTATUS))
;
/* It fired, check how long it took */
- after_timer = read_sysreg(cntvct_el0);
+ after_timer = info->read_counter();
difference = after_timer - (before_timer + time_10ms);
report_info("After timer: 0x%016lx", after_timer);
@@ -62,32 +147,43 @@ static bool test_cval_10msec(void)
report_info("Difference : %ld us", difference / time_1us);
if (difference < 0) {
- printf("CNTV_CTL_EL0.ISTATUS set too early\n");
+ printf("ISTATUS set too early\n");
return false;
}
return difference < time_10ms;
}
-static void test_vtimer(void)
+static void test_timer(struct timer_info *info)
{
u64 now = read_sysreg(cntvct_el0);
u64 time_10s = read_sysreg(cntfrq_el0) * 10;
u64 later = now + time_10s;
- report_prefix_push("vtimer-busy-loop");
/* Enable the timer, but schedule it for much later*/
- write_sysreg(later, cntv_cval_el0);
+ info->write_cval(later);
isb();
- write_sysreg(CNTV_CTL_ENABLE, cntv_ctl_el0);
+ info->write_ctl(ARCH_TIMER_CTL_ENABLE);
- report("not pending before", !gic_vtimer_pending());
- report("latency within 10 ms", test_cval_10msec());
- report("interrupt received", vtimer_irq_received);
+ report("not pending before", !gic_timer_pending(info));
+ report("latency within 10 ms", test_cval_10msec(info));
+ report("interrupt received", info->irq_received);
/* Disable the timer again */
- write_sysreg(0, cntv_ctl_el0);
+ info->write_ctl(0);
+}
+
+static void test_vtimer(void)
+{
+ report_prefix_push("vtimer-busy-loop");
+ test_timer(&vtimer_info);
+ report_prefix_pop();
+}
+static void test_ptimer(void)
+{
+ report_prefix_push("ptimer-busy-loop");
+ test_timer(&ptimer_info);
report_prefix_pop();
}
@@ -102,20 +198,26 @@ static void test_init(void)
assert(node >= 0);
prop = fdt_get_property(fdt, node, "interrupts", &len);
assert(prop && len == (4 * 3 * sizeof(u32)));
+
data = (u32 *)prop->data;
+ assert(fdt32_to_cpu(data[3]) == 1);
+ ptimer_info.irq = fdt32_to_cpu(data[4]);
+ ptimer_info.irq_flags = fdt32_to_cpu(data[5]);
assert(fdt32_to_cpu(data[6]) == 1);
- vtimer_irq = fdt32_to_cpu(data[7]);
- vtimer_irq_flags = fdt32_to_cpu(data[8]);
+ vtimer_info.irq = fdt32_to_cpu(data[7]);
+ vtimer_info.irq_flags = fdt32_to_cpu(data[8]);
gic_enable_defaults();
switch (gic_version()) {
case 2:
- writel(1 << PPI(vtimer_irq), gicv2_dist_base() + GICD_ISENABLER + 0);
+ writel(1 << PPI(vtimer_info.irq), gicv2_dist_base() + GICD_ISENABLER + 0);
+ writel(1 << PPI(ptimer_info.irq), gicv2_dist_base() + GICD_ISENABLER + 0);
gic_ispendr = gicv2_dist_base() + GICD_ISPENDR;
break;
case 3:
- writel(1 << PPI(vtimer_irq), gicv3_sgi_base() + GICR_ISENABLER0);
+ writel(1 << PPI(vtimer_info.irq), gicv3_sgi_base() + GICR_ISENABLER0);
+ writel(1 << PPI(ptimer_info.irq), gicv3_sgi_base() + GICR_ISENABLER0);
gic_ispendr = gicv3_sgi_base() + GICD_ISPENDR;
break;
}
@@ -124,15 +226,52 @@ static void test_init(void)
local_irq_enable();
}
-int main(void)
+static void print_vtimer_info(void)
{
printf("CNTFRQ_EL0 : 0x%016lx\n", read_sysreg(cntfrq_el0));
printf("CNTVCT_EL0 : 0x%016lx\n", read_sysreg(cntvct_el0));
printf("CNTV_CTL_EL0 : 0x%016lx\n", read_sysreg(cntv_ctl_el0));
printf("CNTV_CVAL_EL0: 0x%016lx\n", read_sysreg(cntv_cval_el0));
+}
+
+static void print_ptimer_info(void)
+{
+ printf("CNTPCT_EL0 : 0x%016lx\n", read_sysreg(cntpct_el0));
+ printf("CNTP_CTL_EL0 : 0x%016lx\n", read_sysreg(cntp_ctl_el0));
+ printf("CNTP_CVAL_EL0: 0x%016lx\n", read_sysreg(cntp_cval_el0));
+}
+
+
+int main(int argc, char **argv)
+{
+ bool run_ptimer_test = false;
+ bool run_vtimer_test = false;
+
+ /* Check if we should also check the physical timer */
+ if (argc > 1) {
+ if (strcmp(argv[1], "vtimer") == 0) {
+ run_vtimer_test = true;
+ } else if (strcmp(argv[1], "ptimer") == 0) {
+ run_ptimer_test = true;
+ } else {
+ report_abort("Unknown option '%s'", argv[1]);
+ }
+ } else {
+ run_vtimer_test = true;
+ }
+
+ if (run_vtimer_test)
+ print_vtimer_info();
+ else if (run_ptimer_test)
+ print_ptimer_info();
test_init();
- test_vtimer();
+
+ if (run_vtimer_test)
+ test_vtimer();
+ else if (run_ptimer_test)
+ test_ptimer();
+
return report_summary();
}
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index bdfedf8..d55e52e 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -111,7 +111,14 @@ smp = $MAX_SMP
groups = psci
# Timer tests
-[timer]
+[vtimer]
file = timer.flat
+extra_params = -append 'vtimer'
+groups = timer
+timeout = 2s
+
+[ptimer]
+file = timer.flat
+extra_params = -append 'ptimer'
groups = timer
timeout = 2s
--
2.9.0
next prev parent reply other threads:[~2017-07-13 19:20 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-07-13 19:20 [PATCH kvm-unit-tests 0/3] Add physical timer test Christoffer Dall
2017-07-13 19:20 ` [PATCH kvm-unit-tests 1/3] arm64: timer: Fix vtimer interrupt test Christoffer Dall
2017-07-14 7:55 ` Marc Zyngier
2017-07-14 15:43 ` Christoffer Dall
2017-07-14 15:54 ` Marc Zyngier
2017-07-13 19:20 ` [PATCH kvm-unit-tests 2/3] arm64: timer: Fix test on APM X-Gene Christoffer Dall
2017-07-14 8:04 ` Marc Zyngier
2017-07-14 15:45 ` Christoffer Dall
2017-07-18 10:05 ` Andrew Jones
2017-07-18 10:35 ` Christoffer Dall
2017-07-18 12:15 ` Andrew Jones
2017-07-24 17:13 ` Paolo Bonzini
2017-07-24 21:25 ` Christoffer Dall
2017-07-26 11:38 ` Christoffer Dall
2017-07-13 19:20 ` Christoffer Dall [this message]
2017-07-18 12:09 ` [PATCH kvm-unit-tests 3/3] arm64: timer: Add support for phys timer testing Andrew Jones
2017-07-18 13:01 ` Christoffer Dall
2017-07-18 13:23 ` Andrew Jones
2017-07-18 13:31 ` Christoffer Dall
2017-07-18 13:50 ` Andrew Jones
2017-07-18 14:15 ` Christoffer Dall
2017-07-18 14:29 ` Andrew Jones
2017-07-18 14:37 ` Christoffer Dall
2017-07-18 10:17 ` [PATCH kvm-unit-tests 0/3] Add physical timer test Andrew Jones
2017-07-18 10:42 ` Christoffer Dall
2017-07-18 12:20 ` Andrew Jones
2017-07-24 17:16 ` Paolo Bonzini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170713192009.10069-4-cdall@linaro.org \
--to=cdall@linaro.org \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=marc.zyngier@arm.com \
--cc=pbonzini@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox