[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] xen/arm: support the ARM generic virtual timer


  • To: xen-changelog@xxxxxxxxxxxxxxxxxxx
  • From: Xen patchbot-unstable <patchbot@xxxxxxx>
  • Date: Sat, 19 Jan 2013 01:33:10 +0000
  • Delivery-date: Sat, 19 Jan 2013 01:34:17 +0000
  • List-id: "Change log for Mercurial \(receive only\)" <xen-changelog.lists.xen.org>

# HG changeset patch
# User Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
# Date 1358441304 0
# Node ID adc707c1ebd509673b51c4d321adf7bd7fdd8354
# Parent  15a02be467b5ba2cc1dd0eb80e6355af5cb19567
xen/arm: support the ARM generic virtual timer

Save and restore the virtual timer registers during the context switch.
At save time initialize an internal Xen timer to make sure that Xen
schedules the guest vcpu at the time of the next virtual timer
interrupt.
Receive the virtual timer interrupt into the hypervisor and inject it
into the running guest.

Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
Committed-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---


diff -r 15a02be467b5 -r adc707c1ebd5 xen/arch/arm/domain.c
--- a/xen/arch/arm/domain.c     Thu Jan 17 16:48:23 2013 +0000
+++ b/xen/arch/arm/domain.c     Thu Jan 17 16:48:24 2013 +0000
@@ -51,9 +51,7 @@ static void ctxt_switch_from(struct vcpu
     p->arch.tpidrprw = READ_CP32(TPIDRPRW);
 
     /* Arch timer */
-    p->arch.cntvoff = READ_CP64(CNTVOFF);
-    p->arch.cntv_cval = READ_CP64(CNTV_CVAL);
-    p->arch.cntv_ctl = READ_CP32(CNTV_CTL);
+    virt_timer_save(p);
 
     /* XXX only save these if ThumbEE e.g. ID_PFR0.THUMB_EE_SUPPORT */
     p->arch.teecr = READ_CP32(TEECR);
@@ -134,11 +132,6 @@ static void ctxt_switch_to(struct vcpu *
     WRITE_CP32(n->arch.mair1, MAIR1);
     isb();
 
-    /* Arch timer */
-    WRITE_CP64(n->arch.cntvoff, CNTVOFF);
-    WRITE_CP64(n->arch.cntv_cval, CNTV_CVAL);
-    WRITE_CP32(n->arch.cntv_ctl, CNTV_CTL);
-
     /* Control Registers */
     WRITE_CP32(n->arch.actlr, ACTLR);
     WRITE_CP32(n->arch.sctlr, SCTLR);
@@ -165,6 +158,10 @@ static void ctxt_switch_to(struct vcpu *
 
     WRITE_CP32(hcr, HCR);
     isb();
+
+    /* This is could trigger an hardware interrupt from the virtual
+     * timer. The interrupt needs to be injected into the guest. */
+    virt_timer_restore(n);
 }
 
 static void schedule_tail(struct vcpu *prev)
diff -r 15a02be467b5 -r adc707c1ebd5 xen/arch/arm/gic.c
--- a/xen/arch/arm/gic.c        Thu Jan 17 16:48:23 2013 +0000
+++ b/xen/arch/arm/gic.c        Thu Jan 17 16:48:24 2013 +0000
@@ -379,7 +379,9 @@ void gic_route_ppis(void)
     gic_route_irq(25, 1, 1u << smp_processor_id(), 0xa0);
     /* Hypervisor Timer */
     gic_route_irq(26, 1, 1u << smp_processor_id(), 0xa0);
-    /* Timer */
+    /* Virtual Timer */
+    gic_route_irq(27, 1, 1u << smp_processor_id(), 0xa0);
+    /* Physical Timer */
     gic_route_irq(30, 1, 1u << smp_processor_id(), 0xa0);
 }
 
diff -r 15a02be467b5 -r adc707c1ebd5 xen/arch/arm/time.c
--- a/xen/arch/arm/time.c       Thu Jan 17 16:48:23 2013 +0000
+++ b/xen/arch/arm/time.c       Thu Jan 17 16:48:24 2013 +0000
@@ -24,10 +24,13 @@
 #include <xen/lib.h>
 #include <xen/mm.h>
 #include <xen/softirq.h>
+#include <xen/sched.h>
 #include <xen/time.h>
 #include <xen/sched.h>
 #include <xen/event.h>
 #include <asm/system.h>
+#include <asm/time.h>
+#include <asm/gic.h>
 
 /*
  * Unfortunately the hypervisor timer interrupt appears to be buggy in
@@ -36,10 +39,11 @@
  */
 #define USE_HYP_TIMER 1
 
+uint64_t __read_mostly boot_count;
+
 /* For fine-grained timekeeping, we use the ARM "Generic Timer", a
  * register-mapped time source in the SoC. */
 static uint32_t __read_mostly cntfrq;      /* Ticks per second */
-static uint64_t __read_mostly boot_count;  /* Counter value at boot time */
 
 /*static inline*/ s_time_t ticks_to_ns(uint64_t ticks)
 {
@@ -155,6 +159,13 @@ static void timer_interrupt(int irq, voi
     }
 }
 
+static void vtimer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
+{
+    current->arch.virt_timer.ctl = READ_CP32(CNTV_CTL);
+    WRITE_CP32(current->arch.virt_timer.ctl | CNTx_CTL_MASK, CNTV_CTL);
+    vgic_vcpu_inject_irq(current, irq, 1);
+}
+
 /* Set up the timer interrupt on this CPU */
 void __cpuinit init_timer_interrupt(void)
 {
@@ -174,6 +185,7 @@ void __cpuinit init_timer_interrupt(void
 
     /* XXX Need to find this IRQ number from devicetree? */
     request_irq(26, timer_interrupt, 0, "hyptimer", NULL);
+    request_irq(27, vtimer_interrupt, 0, "virtimer", NULL);
     request_irq(30, timer_interrupt, 0, "phytimer", NULL);
 }
 
diff -r 15a02be467b5 -r adc707c1ebd5 xen/arch/arm/vtimer.c
--- a/xen/arch/arm/vtimer.c     Thu Jan 17 16:48:23 2013 +0000
+++ b/xen/arch/arm/vtimer.c     Thu Jan 17 16:48:24 2013 +0000
@@ -21,31 +21,74 @@
 #include <xen/lib.h>
 #include <xen/timer.h>
 #include <xen/sched.h>
+#include <asm/irq.h>
+#include <asm/time.h>
 #include <asm/gic.h>
 #include <asm/regs.h>
 
 extern s_time_t ticks_to_ns(uint64_t ticks);
 extern uint64_t ns_to_ticks(s_time_t ns);
 
-static void vtimer_expired(void *data)
+static void phys_timer_expired(void *data)
 {
-    struct vcpu *v = data;
-    v->arch.vtimer.ctl |= CNTx_CTL_PENDING;
-    v->arch.vtimer.ctl &= ~CNTx_CTL_MASK;
-    vgic_vcpu_inject_irq(v, 30, 1);
+    struct vtimer *t = data;
+    t->ctl |= CNTx_CTL_PENDING;
+    t->ctl &= ~CNTx_CTL_MASK;
+    vgic_vcpu_inject_irq(t->v, 30, 1);
 }
 
+static void virt_timer_expired(void *data)
+{
+    struct vtimer *t = data;
+    vcpu_wake(t->v);
+}
+ 
 int vcpu_vtimer_init(struct vcpu *v)
 {
-    init_timer(&v->arch.vtimer.timer,
-               vtimer_expired, v,
-               smp_processor_id());
-    v->arch.vtimer.ctl = 0;
-    v->arch.vtimer.offset = NOW();
-    v->arch.vtimer.cval = NOW();
+    struct vtimer *t = &v->arch.phys_timer;
+
+    init_timer(&t->timer, phys_timer_expired, t, smp_processor_id());
+    t->ctl = 0;
+    t->offset = NOW();
+    t->cval = NOW();
+    t->irq = 30;
+    t->v = v;
+
+    t = &v->arch.virt_timer;
+    init_timer(&t->timer, virt_timer_expired, t, smp_processor_id());
+    t->ctl = 0;
+    t->offset = READ_CP64(CNTVCT) + READ_CP64(CNTVOFF);
+    t->cval = 0;
+    t->irq = 27;
+    t->v = v;
+
     return 0;
 }
 
+int virt_timer_save(struct vcpu *v)
+{
+    v->arch.virt_timer.ctl = READ_CP32(CNTV_CTL);
+    WRITE_CP32(v->arch.virt_timer.ctl & ~CNTx_CTL_ENABLE, CNTV_CTL);
+    v->arch.virt_timer.cval = READ_CP64(CNTV_CVAL);
+    if ( v->arch.virt_timer.ctl & CNTx_CTL_ENABLE )
+    {
+        set_timer(&v->arch.virt_timer.timer, 
ticks_to_ns(v->arch.virt_timer.cval +
+                  v->arch.virt_timer.offset - boot_count));
+    }
+    return 0;
+}
+
+int virt_timer_restore(struct vcpu *v)
+{
+    stop_timer(&v->arch.virt_timer.timer);
+
+    WRITE_CP32(v->arch.virt_timer.ctl & ~CNTx_CTL_ENABLE, CNTV_CTL);
+    WRITE_CP64(v->arch.virt_timer.offset, CNTVOFF);
+    WRITE_CP64(v->arch.virt_timer.cval, CNTV_CVAL);
+    WRITE_CP32(v->arch.virt_timer.ctl, CNTV_CTL);
+    return 0;
+}
+ 
 static int vtimer_emulate_32(struct cpu_user_regs *regs, union hsr hsr)
 {
     struct vcpu *v = current;
@@ -58,36 +101,36 @@ static int vtimer_emulate_32(struct cpu_
     case HSR_CPREG32(CNTP_CTL):
         if ( cp32.read )
         {
-            *r = v->arch.vtimer.ctl;
+            *r = v->arch.phys_timer.ctl;
         }
         else
         {
-            v->arch.vtimer.ctl = *r;
+            v->arch.phys_timer.ctl = *r;
 
-            if ( v->arch.vtimer.ctl & CNTx_CTL_ENABLE )
+            if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE )
             {
-                set_timer(&v->arch.vtimer.timer,
-                          v->arch.vtimer.cval + v->arch.vtimer.offset);
+                set_timer(&v->arch.phys_timer.timer,
+                          v->arch.phys_timer.cval + v->arch.phys_timer.offset);
             }
             else
-                stop_timer(&v->arch.vtimer.timer);
+                stop_timer(&v->arch.phys_timer.timer);
         }
 
         return 1;
 
     case HSR_CPREG32(CNTP_TVAL):
-        now = NOW() - v->arch.vtimer.offset;
+        now = NOW() - v->arch.phys_timer.offset;
         if ( cp32.read )
         {
-            *r = (uint32_t)(ns_to_ticks(v->arch.vtimer.cval - now) & 
0xffffffffull);
+            *r = (uint32_t)(ns_to_ticks(v->arch.phys_timer.cval - now) & 
0xffffffffull);
         }
         else
         {
-            v->arch.vtimer.cval = now + ticks_to_ns(*r);
-            if ( v->arch.vtimer.ctl & CNTx_CTL_ENABLE )
+            v->arch.phys_timer.cval = now + ticks_to_ns(*r);
+            if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE )
             {
-                set_timer(&v->arch.vtimer.timer,
-                          v->arch.vtimer.cval + v->arch.vtimer.offset);
+                set_timer(&v->arch.phys_timer.timer,
+                          v->arch.phys_timer.cval + v->arch.phys_timer.offset);
             }
         }
 
@@ -112,7 +155,7 @@ static int vtimer_emulate_64(struct cpu_
     case HSR_CPREG64(CNTPCT):
         if ( cp64.read )
         {
-            now = NOW() - v->arch.vtimer.offset;
+            now = NOW() - v->arch.phys_timer.offset;
             ticks = ns_to_ticks(now);
             *r1 = (uint32_t)(ticks & 0xffffffff);
             *r2 = (uint32_t)(ticks >> 32);
diff -r 15a02be467b5 -r adc707c1ebd5 xen/arch/arm/vtimer.h
--- a/xen/arch/arm/vtimer.h     Thu Jan 17 16:48:23 2013 +0000
+++ b/xen/arch/arm/vtimer.h     Thu Jan 17 16:48:24 2013 +0000
@@ -22,6 +22,8 @@
 
 extern int vcpu_vtimer_init(struct vcpu *v);
 extern int vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr);
+extern int virt_timer_save(struct vcpu *v);
+extern int virt_timer_restore(struct vcpu *v);
 
 #endif
 
diff -r 15a02be467b5 -r adc707c1ebd5 xen/include/asm-arm/domain.h
--- a/xen/include/asm-arm/domain.h      Thu Jan 17 16:48:23 2013 +0000
+++ b/xen/include/asm-arm/domain.h      Thu Jan 17 16:48:24 2013 +0000
@@ -3,6 +3,7 @@
 
 #include <xen/config.h>
 #include <xen/cache.h>
+#include <xen/sched.h>
 #include <asm/page.h>
 #include <asm/p2m.h>
 #include <public/hvm/params.h>
@@ -69,6 +70,15 @@ struct arch_domain
 
 }  __cacheline_aligned;
 
+struct vtimer {
+        struct vcpu *v;
+        int irq;
+        struct timer timer;
+        uint32_t ctl;
+        s_time_t offset;
+        s_time_t cval;
+};
+
 struct arch_vcpu
 {
     struct {
@@ -118,11 +128,6 @@ struct arch_vcpu
     uint32_t teecr, teehbr;
     uint32_t joscr, jmcr;
 
-    /* Arch timers */
-    uint64_t cntvoff;
-    uint64_t cntv_cval;
-    uint32_t cntv_ctl;
-
     /* CP 15 */
     uint32_t csselr;
 
@@ -157,12 +162,8 @@ struct arch_vcpu
         spinlock_t lock;
     } vgic;
 
-    struct {
-        struct timer timer;
-        uint32_t ctl;
-        s_time_t offset;
-        s_time_t cval;
-    } vtimer;
+    struct vtimer phys_timer;
+    struct vtimer virt_timer;
 }  __cacheline_aligned;
 
 void vcpu_show_execution_state(struct vcpu *);
diff -r 15a02be467b5 -r adc707c1ebd5 xen/include/asm-arm/time.h
--- a/xen/include/asm-arm/time.h        Thu Jan 17 16:48:23 2013 +0000
+++ b/xen/include/asm-arm/time.h        Thu Jan 17 16:48:24 2013 +0000
@@ -15,6 +15,9 @@ struct tm wallclock_time(void);
 /* Set up the timer interrupt on this CPU */
 extern void __cpuinit init_timer_interrupt(void);
 
+/* Counter value at boot time */
+extern uint64_t boot_count;
+
 #endif /* __ARM_TIME_H__ */
 /*
  * Local variables:

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.