diff mbox

arm: Add simple arch timer test

Message ID 1474285480-215480-1-git-send-email-agraf@suse.de (mailing list archive)
State New, archived
Headers show

Commit Message

Alexander Graf Sept. 19, 2016, 11:44 a.m. UTC
All virtualization capable ARM cores support the ARM architected virtual timer.

This patch adds minimalistic checks whether we can fire a virtual timer event
using them. It does not actually trigger an interrupt yet, as infrastructure
for that is missing. However, it does check whether the timer pin is marked as
pending on the GIC.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 arm/Makefile.arm64 |   2 +-
 arm/vtimer-test.c  | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+), 1 deletion(-)
 create mode 100644 arm/vtimer-test.c

Comments

Andrew Jones Sept. 19, 2016, 2:52 p.m. UTC | #1
On Mon, Sep 19, 2016 at 01:44:40PM +0200, Alexander Graf wrote:
> All virtualization capable ARM cores support the ARM architected virtual timer.
> 
> This patch adds minimalistic checks whether we can fire a virtual timer event
> using them. It does not actually trigger an interrupt yet, as infrastructure
> for that is missing. However, it does check whether the timer pin is marked as
> pending on the GIC.
> 
> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
>  arm/Makefile.arm64 |   2 +-
>  arm/vtimer-test.c  | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 123 insertions(+), 1 deletion(-)
>  create mode 100644 arm/vtimer-test.c
> 
> diff --git a/arm/Makefile.arm64 b/arm/Makefile.arm64
> index 0b0761c..5b3fbe8 100644
> --- a/arm/Makefile.arm64
> +++ b/arm/Makefile.arm64
> @@ -12,7 +12,7 @@ cflatobjs += lib/arm64/processor.o
>  cflatobjs += lib/arm64/spinlock.o
>  
>  # arm64 specific tests
> -tests =
> +tests = $(TEST_DIR)/vtimer-test.flat
>  
>  include $(TEST_DIR)/Makefile.common
>  
> diff --git a/arm/vtimer-test.c b/arm/vtimer-test.c
> new file mode 100644
> index 0000000..a3e24ce
> --- /dev/null
> +++ b/arm/vtimer-test.c
> @@ -0,0 +1,122 @@
> +/*
> + * Unit tests for the virtual timer on the ARM virt machine
> + *
> + * Copyright (C) 2016, Alexander Graf <agraf@suse.de>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.
> + */
> +#include <libcflat.h>
> +#include <asm/io.h>
> +
> +#define VTIMER_CTL_ENABLE  (1 << 0)
> +#define VTIMER_CTL_IMASK   (1 << 1)
> +#define VTIMER_CTL_ISTATUS (1 << 2)
> +
> +#define VIRT_GIC_DIST_BASE 0x08000000
> +#define GIC_DIST_PENDING_SET            0x200
> +#define GIC_DIST_PENDING_CLEAR          0x280
> +#define GIC_DIST_ACTIVE_SET             0x300
> +#define GIC_DIST_ACTIVE_CLEAR           0x380
> +
> +#define VIRT_GIC_CPU_BASE  0x08010000

Once I get my arm/gic series in we won't need to hard code
the gic base addresses and these gic register offsets will
also be provided.

> +
> +#define ARCH_TIMER_VIRT_IRQ   11
> +#define ARCH_TIMER_S_EL1_IRQ  13
> +#define ARCH_TIMER_NS_EL1_IRQ 14
> +#define ARCH_TIMER_NS_EL2_IRQ 10

We can pull these out of the DT.

> +
> +static void write_vtimer_ctl(u64 val)
> +{
> +	asm volatile("msr cntv_ctl_el0, %0" : : "r" (val));
> +}
> +
> +static void write_vtimer_cval(u64 val)
> +{
> +	asm volatile("msr cntv_cval_el0, %0" : : "r" (val));
> +}
> +
> +static u64 read_vtimer_ctl(void)
> +{
> +	u64 val;
> +	asm volatile("mrs %0, cntv_ctl_el0" : "=r" (val));
> +	return val;
> +}
> +
> +static u64 read_vtimer_cval(void)
> +{
> +	u64 val;
> +	asm volatile("mrs %0, cntv_cval_el0" : "=r" (val));
> +	return val;
> +}
> +
> +static u64 read_vtimer_val(void)
> +{
> +	u64 val;
> +	asm volatile("mrs %0, cntvct_el0" : "=r" (val));
> +	return val;
> +}
> +
> +static u64 read_vtimer_freq(void)
> +{
> +	u64 val;
> +	asm volatile("mrs %0, cntfrq_el0" : "=r" (val));
> +	return val;
> +}
> +
> +static bool gic_vtimer_pending(void)
> +{
> +	u32 *pending = (u32*)(VIRT_GIC_DIST_BASE + GIC_DIST_PENDING_SET);
> +	return (readl(pending) & (1 << (ARCH_TIMER_VIRT_IRQ + 16)));

nit: don't need the outer ()

I think I'd like to add the PPI(irq) macro we added to QEMU for
the +16's.

> +}
> +
> +static bool test_cval_10msec(void)
> +{
> +	u64 time_10ms = read_vtimer_freq() / 100;
> +	u64 time_1us = time_10ms / 10000;
> +	u64 before_timer = read_vtimer_val();
> +	u64 after_timer, latency;
> +
> +	/* Program timer to fire in 10ms */
> +	write_vtimer_cval(before_timer + time_10ms);
> +
> +	/* Wait for the timer to fire */
> +	while (!(read_vtimer_ctl() & VTIMER_CTL_ISTATUS)) ;

If emulation fails to set the status bit then we'll spin forever.
That's OK if we set the test timeout (arm/unittests.cfg:timeout
for this test appropriately) Or, maybe can add a trial count here
that's sufficiently large?

> +
> +	/* It fired, check how long it took */
> +	after_timer = read_vtimer_val();
> +
> +	latency = (after_timer - (before_timer + time_10ms));

nit: don't need the outer ()

Shouldn't latency be signed so we can see if the status bit was
set too soon? Or just compare time_10ms with after - before?

> +	printf("After timer: 0x%lx\n", after_timer);
> +	printf("Expected   : 0x%lx\n", before_timer + time_10ms);
> +	printf("Latency    : %ld us\n", latency / time_1us);
> +
> +	return latency < time_10ms;

Does this mean that the threshold for success is 10ms? If so,
then that's not too large?

> +}
> +
> +static void test_vtimer(void)
> +{
> +	printf("\n=== vtimer with busy loop ===\n");

I guess this is a subtest header, i.e. this file will get
other subtests and headers like this one will divide up
the test output. That's fine, but new, at least for arm tests.
Currently we're dividing subtests with report prefixes. In
this case, instead of the above printf, we'd do

 report_prefix_push("busy-loop");

or whatever the prefix should be. At the end of the function
we'd pop the prefix. I prefer the prefix style as it makes
grepping test logs easier.

> +
> +	/* Enable the timer */
> +	write_vtimer_cval(-1);

nit: I prefer ~0

> +	write_vtimer_ctl(VTIMER_CTL_ENABLE);
> +
> +	report("timer is not pending before", !gic_vtimer_pending());
> +	report("latency is within 10ms", test_cval_10msec());
> +	report("timer is pending after", gic_vtimer_pending());
> +
> +	/* Disable the timer again */
> +	write_vtimer_ctl(0);
> +}
> +
> +int main(void)
> +{
> +	printf("vtimer ctl:  0x%lx\n", read_vtimer_ctl());
> +	printf("vtimer cval: 0x%lx\n", read_vtimer_cval());
> +	printf("vtimer val:  0x%lx\n", read_vtimer_val());
> +	printf("vtimer freq: 0x%lx\n", read_vtimer_freq());
> +
> +	test_vtimer();
> +
> +	return report_summary();
> +}
> -- 
> 1.8.5.6
>

Thanks for submitting this Alex. I'll bump the arm/gic patches up in my
priority queue.

drew
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andrew Jones Nov. 16, 2016, 3:54 p.m. UTC | #2
On Mon, Sep 19, 2016 at 04:52:01PM +0200, Andrew Jones wrote:
> On Mon, Sep 19, 2016 at 01:44:40PM +0200, Alexander Graf wrote:
> > All virtualization capable ARM cores support the ARM architected virtual timer.
> > 
> > This patch adds minimalistic checks whether we can fire a virtual timer event
> > using them. It does not actually trigger an interrupt yet, as infrastructure
> > for that is missing. However, it does check whether the timer pin is marked as
> > pending on the GIC.
> > 
> > Signed-off-by: Alexander Graf <agraf@suse.de>
> > ---
> >  arm/Makefile.arm64 |   2 +-
> >  arm/vtimer-test.c  | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 123 insertions(+), 1 deletion(-)
> >  create mode 100644 arm/vtimer-test.c
> > 
> > diff --git a/arm/Makefile.arm64 b/arm/Makefile.arm64
> > index 0b0761c..5b3fbe8 100644
> > --- a/arm/Makefile.arm64
> > +++ b/arm/Makefile.arm64
> > @@ -12,7 +12,7 @@ cflatobjs += lib/arm64/processor.o
> >  cflatobjs += lib/arm64/spinlock.o
> >  
> >  # arm64 specific tests
> > -tests =
> > +tests = $(TEST_DIR)/vtimer-test.flat
> >  
> >  include $(TEST_DIR)/Makefile.common
> >  
> > diff --git a/arm/vtimer-test.c b/arm/vtimer-test.c
> > new file mode 100644
> > index 0000000..a3e24ce
> > --- /dev/null
> > +++ b/arm/vtimer-test.c
> > @@ -0,0 +1,122 @@
> > +/*
> > + * Unit tests for the virtual timer on the ARM virt machine
> > + *
> > + * Copyright (C) 2016, Alexander Graf <agraf@suse.de>
> > + *
> > + * This work is licensed under the terms of the GNU LGPL, version 2.
> > + */
> > +#include <libcflat.h>
> > +#include <asm/io.h>
> > +
> > +#define VTIMER_CTL_ENABLE  (1 << 0)
> > +#define VTIMER_CTL_IMASK   (1 << 1)
> > +#define VTIMER_CTL_ISTATUS (1 << 2)
> > +
> > +#define VIRT_GIC_DIST_BASE 0x08000000
> > +#define GIC_DIST_PENDING_SET            0x200
> > +#define GIC_DIST_PENDING_CLEAR          0x280
> > +#define GIC_DIST_ACTIVE_SET             0x300
> > +#define GIC_DIST_ACTIVE_CLEAR           0x380
> > +
> > +#define VIRT_GIC_CPU_BASE  0x08010000
> 
> Once I get my arm/gic series in we won't need to hard code
> the gic base addresses and these gic register offsets will
> also be provided.
> 
> > +
> > +#define ARCH_TIMER_VIRT_IRQ   11
> > +#define ARCH_TIMER_S_EL1_IRQ  13
> > +#define ARCH_TIMER_NS_EL1_IRQ 14
> > +#define ARCH_TIMER_NS_EL2_IRQ 10
> 
> We can pull these out of the DT.
> 
> > +
> > +static void write_vtimer_ctl(u64 val)
> > +{
> > +	asm volatile("msr cntv_ctl_el0, %0" : : "r" (val));
> > +}
> > +
> > +static void write_vtimer_cval(u64 val)
> > +{
> > +	asm volatile("msr cntv_cval_el0, %0" : : "r" (val));
> > +}
> > +
> > +static u64 read_vtimer_ctl(void)
> > +{
> > +	u64 val;
> > +	asm volatile("mrs %0, cntv_ctl_el0" : "=r" (val));
> > +	return val;
> > +}
> > +
> > +static u64 read_vtimer_cval(void)
> > +{
> > +	u64 val;
> > +	asm volatile("mrs %0, cntv_cval_el0" : "=r" (val));
> > +	return val;
> > +}
> > +
> > +static u64 read_vtimer_val(void)
> > +{
> > +	u64 val;
> > +	asm volatile("mrs %0, cntvct_el0" : "=r" (val));
> > +	return val;
> > +}
> > +
> > +static u64 read_vtimer_freq(void)
> > +{
> > +	u64 val;
> > +	asm volatile("mrs %0, cntfrq_el0" : "=r" (val));
> > +	return val;
> > +}
> > +
> > +static bool gic_vtimer_pending(void)
> > +{
> > +	u32 *pending = (u32*)(VIRT_GIC_DIST_BASE + GIC_DIST_PENDING_SET);
> > +	return (readl(pending) & (1 << (ARCH_TIMER_VIRT_IRQ + 16)));
> 
> nit: don't need the outer ()
> 
> I think I'd like to add the PPI(irq) macro we added to QEMU for
> the +16's.
> 
> > +}
> > +
> > +static bool test_cval_10msec(void)
> > +{
> > +	u64 time_10ms = read_vtimer_freq() / 100;
> > +	u64 time_1us = time_10ms / 10000;
> > +	u64 before_timer = read_vtimer_val();
> > +	u64 after_timer, latency;
> > +
> > +	/* Program timer to fire in 10ms */
> > +	write_vtimer_cval(before_timer + time_10ms);
> > +
> > +	/* Wait for the timer to fire */
> > +	while (!(read_vtimer_ctl() & VTIMER_CTL_ISTATUS)) ;
> 
> If emulation fails to set the status bit then we'll spin forever.
> That's OK if we set the test timeout (arm/unittests.cfg:timeout
> for this test appropriately) Or, maybe can add a trial count here
> that's sufficiently large?
> 
> > +
> > +	/* It fired, check how long it took */
> > +	after_timer = read_vtimer_val();
> > +
> > +	latency = (after_timer - (before_timer + time_10ms));
> 
> nit: don't need the outer ()
> 
> Shouldn't latency be signed so we can see if the status bit was
> set too soon? Or just compare time_10ms with after - before?
> 
> > +	printf("After timer: 0x%lx\n", after_timer);
> > +	printf("Expected   : 0x%lx\n", before_timer + time_10ms);
> > +	printf("Latency    : %ld us\n", latency / time_1us);
> > +
> > +	return latency < time_10ms;
> 
> Does this mean that the threshold for success is 10ms? If so,
> then that's not too large?
> 
> > +}
> > +
> > +static void test_vtimer(void)
> > +{
> > +	printf("\n=== vtimer with busy loop ===\n");
> 
> I guess this is a subtest header, i.e. this file will get
> other subtests and headers like this one will divide up
> the test output. That's fine, but new, at least for arm tests.
> Currently we're dividing subtests with report prefixes. In
> this case, instead of the above printf, we'd do
> 
>  report_prefix_push("busy-loop");
> 
> or whatever the prefix should be. At the end of the function
> we'd pop the prefix. I prefer the prefix style as it makes
> grepping test logs easier.
> 
> > +
> > +	/* Enable the timer */
> > +	write_vtimer_cval(-1);
> 
> nit: I prefer ~0
> 
> > +	write_vtimer_ctl(VTIMER_CTL_ENABLE);
> > +
> > +	report("timer is not pending before", !gic_vtimer_pending());
> > +	report("latency is within 10ms", test_cval_10msec());
> > +	report("timer is pending after", gic_vtimer_pending());
> > +
> > +	/* Disable the timer again */
> > +	write_vtimer_ctl(0);
> > +}
> > +
> > +int main(void)
> > +{
> > +	printf("vtimer ctl:  0x%lx\n", read_vtimer_ctl());
> > +	printf("vtimer cval: 0x%lx\n", read_vtimer_cval());
> > +	printf("vtimer val:  0x%lx\n", read_vtimer_val());
> > +	printf("vtimer freq: 0x%lx\n", read_vtimer_freq());
> > +
> > +	test_vtimer();
> > +
> > +	return report_summary();
> > +}
> > -- 
> > 1.8.5.6
> >
> 
> Thanks for submitting this Alex. I'll bump the arm/gic patches up in my
> priority queue.
>

Hi Alex,

Just checking on this. Do you plan to resubmit based on the gic series?
If so, then you may want to grab v6[*], which is hopefully pretty much
the last revision, as your base.

[*] https://github.com/rhdrjones/kvm-unit-tests/commits/arm/gic-v6

Thanks,
drew
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alexander Graf Nov. 16, 2016, 3:56 p.m. UTC | #3
On 16/11/2016 16:54, Andrew Jones wrote:
> On Mon, Sep 19, 2016 at 04:52:01PM +0200, Andrew Jones wrote:
>> On Mon, Sep 19, 2016 at 01:44:40PM +0200, Alexander Graf wrote:
>>> All virtualization capable ARM cores support the ARM architected virtual timer.
>>>
>>> This patch adds minimalistic checks whether we can fire a virtual timer event
>>> using them. It does not actually trigger an interrupt yet, as infrastructure
>>> for that is missing. However, it does check whether the timer pin is marked as
>>> pending on the GIC.
>>>
>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>> ---
>>>  arm/Makefile.arm64 |   2 +-
>>>  arm/vtimer-test.c  | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  2 files changed, 123 insertions(+), 1 deletion(-)
>>>  create mode 100644 arm/vtimer-test.c
>>>
>>> diff --git a/arm/Makefile.arm64 b/arm/Makefile.arm64
>>> index 0b0761c..5b3fbe8 100644
>>> --- a/arm/Makefile.arm64
>>> +++ b/arm/Makefile.arm64
>>> @@ -12,7 +12,7 @@ cflatobjs += lib/arm64/processor.o
>>>  cflatobjs += lib/arm64/spinlock.o
>>>
>>>  # arm64 specific tests
>>> -tests =
>>> +tests = $(TEST_DIR)/vtimer-test.flat
>>>
>>>  include $(TEST_DIR)/Makefile.common
>>>
>>> diff --git a/arm/vtimer-test.c b/arm/vtimer-test.c
>>> new file mode 100644
>>> index 0000000..a3e24ce
>>> --- /dev/null
>>> +++ b/arm/vtimer-test.c
>>> @@ -0,0 +1,122 @@
>>> +/*
>>> + * Unit tests for the virtual timer on the ARM virt machine
>>> + *
>>> + * Copyright (C) 2016, Alexander Graf <agraf@suse.de>
>>> + *
>>> + * This work is licensed under the terms of the GNU LGPL, version 2.
>>> + */
>>> +#include <libcflat.h>
>>> +#include <asm/io.h>
>>> +
>>> +#define VTIMER_CTL_ENABLE  (1 << 0)
>>> +#define VTIMER_CTL_IMASK   (1 << 1)
>>> +#define VTIMER_CTL_ISTATUS (1 << 2)
>>> +
>>> +#define VIRT_GIC_DIST_BASE 0x08000000
>>> +#define GIC_DIST_PENDING_SET            0x200
>>> +#define GIC_DIST_PENDING_CLEAR          0x280
>>> +#define GIC_DIST_ACTIVE_SET             0x300
>>> +#define GIC_DIST_ACTIVE_CLEAR           0x380
>>> +
>>> +#define VIRT_GIC_CPU_BASE  0x08010000
>>
>> Once I get my arm/gic series in we won't need to hard code
>> the gic base addresses and these gic register offsets will
>> also be provided.
>>
>>> +
>>> +#define ARCH_TIMER_VIRT_IRQ   11
>>> +#define ARCH_TIMER_S_EL1_IRQ  13
>>> +#define ARCH_TIMER_NS_EL1_IRQ 14
>>> +#define ARCH_TIMER_NS_EL2_IRQ 10
>>
>> We can pull these out of the DT.
>>
>>> +
>>> +static void write_vtimer_ctl(u64 val)
>>> +{
>>> +	asm volatile("msr cntv_ctl_el0, %0" : : "r" (val));
>>> +}
>>> +
>>> +static void write_vtimer_cval(u64 val)
>>> +{
>>> +	asm volatile("msr cntv_cval_el0, %0" : : "r" (val));
>>> +}
>>> +
>>> +static u64 read_vtimer_ctl(void)
>>> +{
>>> +	u64 val;
>>> +	asm volatile("mrs %0, cntv_ctl_el0" : "=r" (val));
>>> +	return val;
>>> +}
>>> +
>>> +static u64 read_vtimer_cval(void)
>>> +{
>>> +	u64 val;
>>> +	asm volatile("mrs %0, cntv_cval_el0" : "=r" (val));
>>> +	return val;
>>> +}
>>> +
>>> +static u64 read_vtimer_val(void)
>>> +{
>>> +	u64 val;
>>> +	asm volatile("mrs %0, cntvct_el0" : "=r" (val));
>>> +	return val;
>>> +}
>>> +
>>> +static u64 read_vtimer_freq(void)
>>> +{
>>> +	u64 val;
>>> +	asm volatile("mrs %0, cntfrq_el0" : "=r" (val));
>>> +	return val;
>>> +}
>>> +
>>> +static bool gic_vtimer_pending(void)
>>> +{
>>> +	u32 *pending = (u32*)(VIRT_GIC_DIST_BASE + GIC_DIST_PENDING_SET);
>>> +	return (readl(pending) & (1 << (ARCH_TIMER_VIRT_IRQ + 16)));
>>
>> nit: don't need the outer ()
>>
>> I think I'd like to add the PPI(irq) macro we added to QEMU for
>> the +16's.
>>
>>> +}
>>> +
>>> +static bool test_cval_10msec(void)
>>> +{
>>> +	u64 time_10ms = read_vtimer_freq() / 100;
>>> +	u64 time_1us = time_10ms / 10000;
>>> +	u64 before_timer = read_vtimer_val();
>>> +	u64 after_timer, latency;
>>> +
>>> +	/* Program timer to fire in 10ms */
>>> +	write_vtimer_cval(before_timer + time_10ms);
>>> +
>>> +	/* Wait for the timer to fire */
>>> +	while (!(read_vtimer_ctl() & VTIMER_CTL_ISTATUS)) ;
>>
>> If emulation fails to set the status bit then we'll spin forever.
>> That's OK if we set the test timeout (arm/unittests.cfg:timeout
>> for this test appropriately) Or, maybe can add a trial count here
>> that's sufficiently large?
>>
>>> +
>>> +	/* It fired, check how long it took */
>>> +	after_timer = read_vtimer_val();
>>> +
>>> +	latency = (after_timer - (before_timer + time_10ms));
>>
>> nit: don't need the outer ()
>>
>> Shouldn't latency be signed so we can see if the status bit was
>> set too soon? Or just compare time_10ms with after - before?
>>
>>> +	printf("After timer: 0x%lx\n", after_timer);
>>> +	printf("Expected   : 0x%lx\n", before_timer + time_10ms);
>>> +	printf("Latency    : %ld us\n", latency / time_1us);
>>> +
>>> +	return latency < time_10ms;
>>
>> Does this mean that the threshold for success is 10ms? If so,
>> then that's not too large?
>>
>>> +}
>>> +
>>> +static void test_vtimer(void)
>>> +{
>>> +	printf("\n=== vtimer with busy loop ===\n");
>>
>> I guess this is a subtest header, i.e. this file will get
>> other subtests and headers like this one will divide up
>> the test output. That's fine, but new, at least for arm tests.
>> Currently we're dividing subtests with report prefixes. In
>> this case, instead of the above printf, we'd do
>>
>>  report_prefix_push("busy-loop");
>>
>> or whatever the prefix should be. At the end of the function
>> we'd pop the prefix. I prefer the prefix style as it makes
>> grepping test logs easier.
>>
>>> +
>>> +	/* Enable the timer */
>>> +	write_vtimer_cval(-1);
>>
>> nit: I prefer ~0
>>
>>> +	write_vtimer_ctl(VTIMER_CTL_ENABLE);
>>> +
>>> +	report("timer is not pending before", !gic_vtimer_pending());
>>> +	report("latency is within 10ms", test_cval_10msec());
>>> +	report("timer is pending after", gic_vtimer_pending());
>>> +
>>> +	/* Disable the timer again */
>>> +	write_vtimer_ctl(0);
>>> +}
>>> +
>>> +int main(void)
>>> +{
>>> +	printf("vtimer ctl:  0x%lx\n", read_vtimer_ctl());
>>> +	printf("vtimer cval: 0x%lx\n", read_vtimer_cval());
>>> +	printf("vtimer val:  0x%lx\n", read_vtimer_val());
>>> +	printf("vtimer freq: 0x%lx\n", read_vtimer_freq());
>>> +
>>> +	test_vtimer();
>>> +
>>> +	return report_summary();
>>> +}
>>> --
>>> 1.8.5.6
>>>
>>
>> Thanks for submitting this Alex. I'll bump the arm/gic patches up in my
>> priority queue.
>>
>
> Hi Alex,
>
> Just checking on this. Do you plan to resubmit based on the gic series?
> If so, then you may want to grab v6[*], which is hopefully pretty much
> the last revision, as your base.
>
> [*] https://github.com/rhdrjones/kvm-unit-tests/commits/arm/gic-v6

I don't think I'll get around to it this year, so feel free to pick it 
up and hack away :)


Alex
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arm/Makefile.arm64 b/arm/Makefile.arm64
index 0b0761c..5b3fbe8 100644
--- a/arm/Makefile.arm64
+++ b/arm/Makefile.arm64
@@ -12,7 +12,7 @@  cflatobjs += lib/arm64/processor.o
 cflatobjs += lib/arm64/spinlock.o
 
 # arm64 specific tests
-tests =
+tests = $(TEST_DIR)/vtimer-test.flat
 
 include $(TEST_DIR)/Makefile.common
 
diff --git a/arm/vtimer-test.c b/arm/vtimer-test.c
new file mode 100644
index 0000000..a3e24ce
--- /dev/null
+++ b/arm/vtimer-test.c
@@ -0,0 +1,122 @@ 
+/*
+ * Unit tests for the virtual timer on the ARM virt machine
+ *
+ * Copyright (C) 2016, Alexander Graf <agraf@suse.de>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <libcflat.h>
+#include <asm/io.h>
+
+#define VTIMER_CTL_ENABLE  (1 << 0)
+#define VTIMER_CTL_IMASK   (1 << 1)
+#define VTIMER_CTL_ISTATUS (1 << 2)
+
+#define VIRT_GIC_DIST_BASE 0x08000000
+#define GIC_DIST_PENDING_SET            0x200
+#define GIC_DIST_PENDING_CLEAR          0x280
+#define GIC_DIST_ACTIVE_SET             0x300
+#define GIC_DIST_ACTIVE_CLEAR           0x380
+
+#define VIRT_GIC_CPU_BASE  0x08010000
+
+#define ARCH_TIMER_VIRT_IRQ   11
+#define ARCH_TIMER_S_EL1_IRQ  13
+#define ARCH_TIMER_NS_EL1_IRQ 14
+#define ARCH_TIMER_NS_EL2_IRQ 10
+
+static void write_vtimer_ctl(u64 val)
+{
+	asm volatile("msr cntv_ctl_el0, %0" : : "r" (val));
+}
+
+static void write_vtimer_cval(u64 val)
+{
+	asm volatile("msr cntv_cval_el0, %0" : : "r" (val));
+}
+
+static u64 read_vtimer_ctl(void)
+{
+	u64 val;
+	asm volatile("mrs %0, cntv_ctl_el0" : "=r" (val));
+	return val;
+}
+
+static u64 read_vtimer_cval(void)
+{
+	u64 val;
+	asm volatile("mrs %0, cntv_cval_el0" : "=r" (val));
+	return val;
+}
+
+static u64 read_vtimer_val(void)
+{
+	u64 val;
+	asm volatile("mrs %0, cntvct_el0" : "=r" (val));
+	return val;
+}
+
+static u64 read_vtimer_freq(void)
+{
+	u64 val;
+	asm volatile("mrs %0, cntfrq_el0" : "=r" (val));
+	return val;
+}
+
+static bool gic_vtimer_pending(void)
+{
+	u32 *pending = (u32*)(VIRT_GIC_DIST_BASE + GIC_DIST_PENDING_SET);
+	return (readl(pending) & (1 << (ARCH_TIMER_VIRT_IRQ + 16)));
+}
+
+static bool test_cval_10msec(void)
+{
+	u64 time_10ms = read_vtimer_freq() / 100;
+	u64 time_1us = time_10ms / 10000;
+	u64 before_timer = read_vtimer_val();
+	u64 after_timer, latency;
+
+	/* Program timer to fire in 10ms */
+	write_vtimer_cval(before_timer + time_10ms);
+
+	/* Wait for the timer to fire */
+	while (!(read_vtimer_ctl() & VTIMER_CTL_ISTATUS)) ;
+
+	/* It fired, check how long it took */
+	after_timer = read_vtimer_val();
+
+	latency = (after_timer - (before_timer + time_10ms));
+	printf("After timer: 0x%lx\n", after_timer);
+	printf("Expected   : 0x%lx\n", before_timer + time_10ms);
+	printf("Latency    : %ld us\n", latency / time_1us);
+
+	return latency < time_10ms;
+}
+
+static void test_vtimer(void)
+{
+	printf("\n=== vtimer with busy loop ===\n");
+
+	/* Enable the timer */
+	write_vtimer_cval(-1);
+	write_vtimer_ctl(VTIMER_CTL_ENABLE);
+
+	report("timer is not pending before", !gic_vtimer_pending());
+	report("latency is within 10ms", test_cval_10msec());
+	report("timer is pending after", gic_vtimer_pending());
+
+	/* Disable the timer again */
+	write_vtimer_ctl(0);
+}
+
+int main(void)
+{
+	printf("vtimer ctl:  0x%lx\n", read_vtimer_ctl());
+	printf("vtimer cval: 0x%lx\n", read_vtimer_cval());
+	printf("vtimer val:  0x%lx\n", read_vtimer_val());
+	printf("vtimer freq: 0x%lx\n", read_vtimer_freq());
+
+	test_vtimer();
+
+	return report_summary();
+}