From patchwork Thu Jul 13 19:20:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoffer Dall X-Patchwork-Id: 9839469 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 968F160909 for ; Thu, 13 Jul 2017 18:02:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9016127FE4 for ; Thu, 13 Jul 2017 20:58:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8EDBB2879C; Thu, 13 Jul 2017 20:58:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 53004287EE for ; Thu, 13 Jul 2017 20:58:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753239AbdGMTU1 (ORCPT ); Thu, 13 Jul 2017 15:20:27 -0400 Received: from mail-wm0-f46.google.com ([74.125.82.46]:35070 "EHLO mail-wm0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753206AbdGMTUZ (ORCPT ); Thu, 13 Jul 2017 15:20:25 -0400 Received: by mail-wm0-f46.google.com with SMTP id w126so1940236wme.0 for ; Thu, 13 Jul 2017 12:20:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=JjLKNIjLgTP65h9IdbRI2+KaspcXlAmT2qCwOqA5/rU=; b=UNmyt+o8S3rXQVktSuiqio8w+7kislAQ/FEc2KPiPCxiQA6wLbgZQ0C5wOKVu0JNiq Uav5Mwdhl0glnUZUn6OowoDbAm7bZhFNxCyGwBPkq+59fXW8lG3KeSDmIpDAI5cMFPUQ ZA0Ly5ETKmBqlyMEOgP5uo61FKz9ITjXGP+7w= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=JjLKNIjLgTP65h9IdbRI2+KaspcXlAmT2qCwOqA5/rU=; b=nhJRmb1tPJg4gkS3O8lVPUMrdEenN7hr95cfyFbL6ZujCiknbVjH3Go8prSAn0TDnX y+QRm5lHVUErI7shJgFz+Q33m/t2UnuiGFNP2JE9wk/TtkYSjJfvLN6K+0yFS9cljqpO gOWOIm38835tUUcXUohilMuJIboPvwb6UzBkjYEg25luHCfguqVQab9G2bhvLMpLQadr XPBifKqgB3eRgei1qXwGBsMpOZh21fZDpSRVavaYENlnmnI2QivMEgDkoAmYZ4dGeAlp O85mpy8DfC7uUeKuMmlw4eVxbZg7Lese3V7PFUKiMndVCdx7cF9Y/IY9hIXaxi0MpQWk X35g== X-Gm-Message-State: AIVw113ErxjuFijFpoKMoeHR4Z9M2TY5F/O/E3sZ3BNK+bDYNB1gZo7i bj2EiJqbaGzGzM7AEy2rEw== X-Received: by 10.80.177.109 with SMTP id l42mr3984189edd.45.1499973623322; Thu, 13 Jul 2017 12:20:23 -0700 (PDT) Received: from localhost.localdomain (xd93ddc2d.cust.hiper.dk. [217.61.220.45]) by smtp.gmail.com with ESMTPSA id x51sm3612824edd.49.2017.07.13.12.20.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 13 Jul 2017 12:20:22 -0700 (PDT) From: Christoffer Dall To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Andrew Jones , Alexander Graf , Paolo Bonzini , =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= , Jintack Lim , Marc Zyngier , Christoffer Dall Subject: [PATCH kvm-unit-tests 3/3] arm64: timer: Add support for phys timer testing Date: Thu, 13 Jul 2017 21:20:09 +0200 Message-Id: <20170713192009.10069-4-cdall@linaro.org> X-Mailer: git-send-email 2.9.0 In-Reply-To: <20170713192009.10069-1-cdall@linaro.org> References: <20170713192009.10069-1-cdall@linaro.org> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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 #include -#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