* [PATCH v5 0/4] KVM/ARM Architected Timers support
@ 2013-01-08 18:43 Christoffer Dall
2013-01-08 18:43 ` [PATCH v5 1/4] ARM: arch_timers: switch to physical timers if HYP mode is available Christoffer Dall
` (3 more replies)
0 siblings, 4 replies; 14+ messages in thread
From: Christoffer Dall @ 2013-01-08 18:43 UTC (permalink / raw)
To: linux-arm-kernel
The following series implements support for the architected generic
timers for KVM/ARM.
This patch series can also be pulled from:
git://github.com/virtualopensystems/linux-kvm-arm.git
branch: kvm-arm-v15-vgic-timers
Changes since v1-v4:
- Get virtual IRQ number from DT
- Simplify access to cntvoff and cntv_cval
- Remove extraneous bit clearing
- Abstract timer arming/disarming to improve code readability
- Context switch CNTKCTL across world-switches
- Add CPU hotplug notifier
---
Marc Zyngier (4):
ARM: arch_timers: switch to physical timers if HYP mode is available
ARM: KVM: arch_timers: Add guest timer core support
ARM: KVM: arch_timers: Add timer world switch
ARM: KVM: arch_timers: Wire the init code and config option
arch/arm/include/asm/kvm_arch_timer.h | 85 +++++++++++
arch/arm/include/asm/kvm_asm.h | 3
arch/arm/include/asm/kvm_host.h | 5 +
arch/arm/kernel/arch_timer.c | 7 +
arch/arm/kernel/asm-offsets.c | 6 +
arch/arm/kvm/Kconfig | 8 +
arch/arm/kvm/Makefile | 1
arch/arm/kvm/arch_timer.c | 257 +++++++++++++++++++++++++++++++++
arch/arm/kvm/arm.c | 14 ++
arch/arm/kvm/coproc.c | 4 +
arch/arm/kvm/interrupts.S | 2
arch/arm/kvm/interrupts_head.S | 93 ++++++++++++
arch/arm/kvm/vgic.c | 1
13 files changed, 484 insertions(+), 2 deletions(-)
create mode 100644 arch/arm/include/asm/kvm_arch_timer.h
create mode 100644 arch/arm/kvm/arch_timer.c
--
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v5 1/4] ARM: arch_timers: switch to physical timers if HYP mode is available
2013-01-08 18:43 [PATCH v5 0/4] KVM/ARM Architected Timers support Christoffer Dall
@ 2013-01-08 18:43 ` Christoffer Dall
2013-01-08 18:43 ` [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support Christoffer Dall
` (2 subsequent siblings)
3 siblings, 0 replies; 14+ messages in thread
From: Christoffer Dall @ 2013-01-08 18:43 UTC (permalink / raw)
To: linux-arm-kernel
From: Marc Zyngier <marc.zyngier@arm.com>
If we're booted in HYP mode, it is possible that we'll run some
kind of virtualized environment. In this case, it is a better to
switch to the physical timers, and leave the virtual timers to
guests.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm/kernel/arch_timer.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index c8ef207..8adcd04 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -26,6 +26,7 @@
#include <asm/arch_timer.h>
#include <asm/system_info.h>
#include <asm/sched_clock.h>
+#include <asm/virt.h>
static unsigned long arch_timer_rate;
@@ -489,10 +490,14 @@ int __init arch_timer_of_register(void)
arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
/*
+ * If HYP mode is available, we know that the physical timer
+ * has been configured to be accessible from PL1. Use it, so
+ * that a guest can use the virtual timer instead.
+ *
* If no interrupt provided for virtual timer, we'll have to
* stick to the physical timer. It'd better be accessible...
*/
- if (!arch_timer_ppi[VIRT_PPI]) {
+ if (is_hyp_mode_available() || !arch_timer_ppi[VIRT_PPI]) {
arch_timer_use_virtual = false;
if (!arch_timer_ppi[PHYS_SECURE_PPI] ||
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support
2013-01-08 18:43 [PATCH v5 0/4] KVM/ARM Architected Timers support Christoffer Dall
2013-01-08 18:43 ` [PATCH v5 1/4] ARM: arch_timers: switch to physical timers if HYP mode is available Christoffer Dall
@ 2013-01-08 18:43 ` Christoffer Dall
2013-01-14 15:18 ` Will Deacon
2013-01-08 18:43 ` [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch Christoffer Dall
2013-01-08 18:43 ` [PATCH v5 4/4] ARM: KVM: arch_timers: Wire the init code and config option Christoffer Dall
3 siblings, 1 reply; 14+ messages in thread
From: Christoffer Dall @ 2013-01-08 18:43 UTC (permalink / raw)
To: linux-arm-kernel
From: Marc Zyngier <marc.zyngier@arm.com>
Add some the architected timer related infrastructure, and support timer
interrupt injection, which can happen as a resultof three possible
events:
- The virtual timer interrupt has fired while we were still
executing the guest
- The timer interrupt hasn't fired, but it expired while we
were doing the world switch
- A hrtimer we programmed earlier has fired
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
---
arch/arm/include/asm/kvm_arch_timer.h | 85 +++++++++++
arch/arm/include/asm/kvm_host.h | 5 +
arch/arm/kvm/arch_timer.c | 257 +++++++++++++++++++++++++++++++++
arch/arm/kvm/interrupts.S | 2
arch/arm/kvm/interrupts_head.S | 31 ++++
5 files changed, 380 insertions(+)
create mode 100644 arch/arm/include/asm/kvm_arch_timer.h
create mode 100644 arch/arm/kvm/arch_timer.c
diff --git a/arch/arm/include/asm/kvm_arch_timer.h b/arch/arm/include/asm/kvm_arch_timer.h
new file mode 100644
index 0000000..aed1c42
--- /dev/null
+++ b/arch/arm/include/asm/kvm_arch_timer.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_ARM_KVM_ARCH_TIMER_H
+#define __ASM_ARM_KVM_ARCH_TIMER_H
+
+#include <linux/clocksource.h>
+#include <linux/hrtimer.h>
+#include <linux/workqueue.h>
+
+struct arch_timer_kvm {
+#ifdef CONFIG_KVM_ARM_TIMER
+ /* Is the timer enabled */
+ bool enabled;
+
+ /* Virtual offset */
+ cycle_t cntvoff;
+#endif
+};
+
+struct arch_timer_cpu {
+#ifdef CONFIG_KVM_ARM_TIMER
+ /* Registers: control register, timer value */
+ u32 cntv_ctl; /* Saved/restored */
+ cycle_t cntv_cval; /* Saved/restored */
+
+ /*
+ * Anything that is not used directly from assembly code goes
+ * here.
+ */
+
+ /* Background timer used when the guest is not running */
+ struct hrtimer timer;
+
+ /* Work queued with the above timer expires */
+ struct work_struct expired;
+
+ /* Background timer active */
+ bool armed;
+
+ /* Timer IRQ */
+ const struct kvm_irq_level *irq;
+#endif
+};
+
+#ifdef CONFIG_KVM_ARM_TIMER
+int kvm_timer_hyp_init(void);
+int kvm_timer_init(struct kvm *kvm);
+void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu);
+void kvm_timer_sync_to_cpu(struct kvm_vcpu *vcpu);
+void kvm_timer_sync_from_cpu(struct kvm_vcpu *vcpu);
+void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu);
+#else
+static inline int kvm_timer_hyp_init(void)
+{
+ return 0;
+};
+
+static inline int kvm_timer_init(struct kvm *kvm)
+{
+ return 0;
+}
+
+static inline void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) {}
+static inline void kvm_timer_sync_to_cpu(struct kvm_vcpu *vcpu) {}
+static inline void kvm_timer_sync_from_cpu(struct kvm_vcpu *vcpu) {}
+static inline void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu) {}
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 149d62b..334b81d 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -23,6 +23,7 @@
#include <asm/kvm_asm.h>
#include <asm/fpstate.h>
#include <asm/kvm_decode.h>
+#include <asm/kvm_arch_timer.h>
#define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS
#define KVM_USER_MEM_SLOTS 32
@@ -49,6 +50,9 @@ struct kvm_arch {
/* VTTBR value associated with below pgd and vmid */
u64 vttbr;
+ /* Timer */
+ struct arch_timer_kvm timer;
+
/*
* Anything that is not used directly from assembly code goes
* here.
@@ -99,6 +103,7 @@ struct kvm_vcpu_arch {
/* VGIC state */
struct vgic_cpu vgic_cpu;
+ struct arch_timer_cpu timer_cpu;
/*
* Anything that is not used directly from assembly code goes
diff --git a/arch/arm/kvm/arch_timer.c b/arch/arm/kvm/arch_timer.c
new file mode 100644
index 0000000..6cb9aa3
--- /dev/null
+++ b/arch/arm/kvm/arch_timer.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/cpu.h>
+#include <linux/of_irq.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/interrupt.h>
+
+#include <asm/arch_timer.h>
+
+#include <asm/kvm_vgic.h>
+#include <asm/kvm_arch_timer.h>
+
+static struct timecounter *timecounter;
+static struct workqueue_struct *wqueue;
+static struct kvm_irq_level timer_irq = {
+ .level = 1,
+};
+
+static cycle_t kvm_phys_timer_read(void)
+{
+ return timecounter->cc->read(timecounter->cc);
+}
+
+static bool timer_is_armed(struct arch_timer_cpu *timer)
+{
+ return timer->armed;
+}
+
+/* timer_arm: as in "arm the timer", not as in ARM the company */
+static void timer_arm(struct arch_timer_cpu *timer, u64 ns)
+{
+ timer->armed = true;
+ hrtimer_start(&timer->timer, ktime_add_ns(ktime_get(), ns),
+ HRTIMER_MODE_ABS);
+}
+
+static void timer_disarm(struct arch_timer_cpu *timer)
+{
+ if (timer_is_armed(timer)) {
+ hrtimer_cancel(&timer->timer);
+ cancel_work_sync(&timer->expired);
+ timer->armed = false;
+ }
+}
+
+static void kvm_timer_inject_irq(struct kvm_vcpu *vcpu)
+{
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+
+ timer->cntv_ctl |= 1 << 1; /* Mask the interrupt in the guest */
+ kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
+ vcpu->arch.timer_cpu.irq->irq,
+ vcpu->arch.timer_cpu.irq->level);
+}
+
+static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
+{
+ struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id;
+
+ /*
+ * We disable the timer in the world switch and let it be
+ * handled by kvm_timer_sync_from_cpu(). Getting a timer
+ * interrupt at this point is a sure sign of some major
+ * breakage.
+ */
+ pr_warn("Unexpected interrupt %d on vcpu %p\n", irq, vcpu);
+ return IRQ_HANDLED;
+}
+
+static void kvm_timer_inject_irq_work(struct work_struct *work)
+{
+ struct kvm_vcpu *vcpu;
+
+ vcpu = container_of(work, struct kvm_vcpu, arch.timer_cpu.expired);
+ vcpu->arch.timer_cpu.armed = false;
+ kvm_timer_inject_irq(vcpu);
+}
+
+static enum hrtimer_restart kvm_timer_expire(struct hrtimer *hrt)
+{
+ struct arch_timer_cpu *timer;
+ timer = container_of(hrt, struct arch_timer_cpu, timer);
+ queue_work(wqueue, &timer->expired);
+ return HRTIMER_NORESTART;
+}
+
+void kvm_timer_sync_to_cpu(struct kvm_vcpu *vcpu)
+{
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+
+ /*
+ * We're about to run this vcpu again, so there is no need to
+ * keep the background timer running, as we're about to
+ * populate the CPU timer again.
+ */
+ timer_disarm(timer);
+}
+
+void kvm_timer_sync_from_cpu(struct kvm_vcpu *vcpu)
+{
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+ cycle_t cval, now;
+ u64 ns;
+
+ /* Check if the timer is enabled and unmasked first */
+ if ((timer->cntv_ctl & 3) != 1)
+ return;
+
+ cval = timer->cntv_cval;
+ now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;
+
+ BUG_ON(timer_is_armed(timer));
+
+ if (cval <= now) {
+ /*
+ * Timer has already expired while we were not
+ * looking. Inject the interrupt and carry on.
+ */
+ kvm_timer_inject_irq(vcpu);
+ return;
+ }
+
+ ns = cyclecounter_cyc2ns(timecounter->cc, cval - now);
+ timer_arm(timer, ns);
+}
+
+void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
+{
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+
+ INIT_WORK(&timer->expired, kvm_timer_inject_irq_work);
+ hrtimer_init(&timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ timer->timer.function = kvm_timer_expire;
+ timer->irq = &timer_irq;
+}
+
+static void kvm_timer_init_interrupt(void *info)
+{
+ enable_percpu_irq(timer_irq.irq, 0);
+}
+
+
+static int kvm_timer_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *cpu)
+{
+ switch (action) {
+ case CPU_STARTING:
+ case CPU_STARTING_FROZEN:
+ kvm_timer_init_interrupt(NULL);
+ break;
+ case CPU_DYING:
+ case CPU_DYING_FROZEN:
+ disable_percpu_irq(timer_irq.irq);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block kvm_timer_cpu_nb = {
+ .notifier_call = kvm_timer_cpu_notify,
+};
+
+static const struct of_device_id arch_timer_of_match[] = {
+ { .compatible = "arm,armv7-timer", },
+ {},
+};
+
+int kvm_timer_hyp_init(void)
+{
+ struct device_node *np;
+ unsigned int ppi;
+ int err;
+
+ timecounter = arch_timer_get_timecounter();
+ if (!timecounter)
+ return -ENODEV;
+
+ np = of_find_matching_node(NULL, arch_timer_of_match);
+ if (!np) {
+ kvm_err("kvm_arch_timer: can't find DT node\n");
+ return -ENODEV;
+ }
+
+ ppi = irq_of_parse_and_map(np, 2);
+ if (!ppi) {
+ kvm_err("kvm_arch_timer: no virtual timer interrupt\n");
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = request_percpu_irq(ppi, kvm_arch_timer_handler,
+ "kvm guest timer", kvm_get_running_vcpus());
+ if (err) {
+ kvm_err("kvm_arch_timer: can't request interrupt %d (%d)\n",
+ ppi, err);
+ goto out;
+ }
+
+ timer_irq.irq = ppi;
+
+ err = register_cpu_notifier(&kvm_timer_cpu_nb);
+ if (err) {
+ kvm_err("Cannot register timer CPU notifier\n");
+ goto out_free;
+ }
+
+ wqueue = create_singlethread_workqueue("kvm_arch_timer");
+ if (!wqueue) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ kvm_info("%s IRQ%d\n", np->name, ppi);
+ on_each_cpu(kvm_timer_init_interrupt, NULL, 1);
+
+ goto out;
+out_free:
+ free_percpu_irq(ppi, kvm_get_running_vcpus());
+out:
+ of_node_put(np);
+ return err;
+}
+
+void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
+{
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+
+ timer_disarm(timer);
+}
+
+int kvm_timer_init(struct kvm *kvm)
+{
+ if (timecounter && wqueue) {
+ kvm->arch.timer.cntvoff = kvm_phys_timer_read();
+ kvm->arch.timer.enabled = 1;
+ }
+
+ return 0;
+}
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
index 9ff7904..64a3e06 100644
--- a/arch/arm/kvm/interrupts.S
+++ b/arch/arm/kvm/interrupts.S
@@ -95,6 +95,7 @@ ENTRY(__kvm_vcpu_run)
save_host_regs
restore_vgic_state
+ restore_timer_state
@ Store hardware CP15 state and load guest state
read_cp15_state store_to_vcpu = 0
@@ -189,6 +190,7 @@ after_vfp_restore:
read_cp15_state store_to_vcpu = 1
write_cp15_state read_from_vcpu = 0
+ save_timer_state
save_vgic_state
restore_host_regs
diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
index b4276ed..dde5f8d 100644
--- a/arch/arm/kvm/interrupts_head.S
+++ b/arch/arm/kvm/interrupts_head.S
@@ -455,6 +455,37 @@ vcpu .req r0 @ vcpu pointer always in r0
#endif
.endm
+#define CNTHCTL_PL1PCTEN (1 << 0)
+#define CNTHCTL_PL1PCEN (1 << 1)
+
+/*
+ * Save the timer state onto the VCPU and allow physical timer/counter access
+ * for the host.
+ *
+ * Assumes vcpu pointer in vcpu reg
+ */
+.macro save_timer_state
+ @ Allow physical timer/counter access for the host
+ mrc p15, 4, r2, c14, c1, 0 @ CNTHCTL
+ orr r2, r2, #(CNTHCTL_PL1PCEN | CNTHCTL_PL1PCTEN)
+ mcr p15, 4, r2, c14, c1, 0 @ CNTHCTL
+.endm
+
+/*
+ * Load the timer state from the VCPU and deny physical timer/counter access
+ * for the host.
+ *
+ * Assumes vcpu pointer in vcpu reg
+ */
+.macro restore_timer_state
+ @ Disallow physical timer access for the guest
+ @ Physical counter access is allowed
+ mrc p15, 4, r2, c14, c1, 0 @ CNTHCTL
+ orr r2, r2, #CNTHCTL_PL1PCTEN
+ bic r2, r2, #CNTHCTL_PL1PCEN
+ mcr p15, 4, r2, c14, c1, 0 @ CNTHCTL
+.endm
+
.equ vmentry, 0
.equ vmexit, 1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch
2013-01-08 18:43 [PATCH v5 0/4] KVM/ARM Architected Timers support Christoffer Dall
2013-01-08 18:43 ` [PATCH v5 1/4] ARM: arch_timers: switch to physical timers if HYP mode is available Christoffer Dall
2013-01-08 18:43 ` [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support Christoffer Dall
@ 2013-01-08 18:43 ` Christoffer Dall
2013-01-14 15:21 ` Will Deacon
2013-01-08 18:43 ` [PATCH v5 4/4] ARM: KVM: arch_timers: Wire the init code and config option Christoffer Dall
3 siblings, 1 reply; 14+ messages in thread
From: Christoffer Dall @ 2013-01-08 18:43 UTC (permalink / raw)
To: linux-arm-kernel
From: Marc Zyngier <marc.zyngier@arm.com>
Do the necessary save/restore dance for the timers in the world
switch code. In the process, allow the guest to read the physical
counter, which is useful for its own clock_event_device.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
---
arch/arm/include/asm/kvm_asm.h | 3 +-
arch/arm/kernel/asm-offsets.c | 6 ++++
arch/arm/kvm/arm.c | 3 ++
arch/arm/kvm/coproc.c | 4 +++
arch/arm/kvm/interrupts_head.S | 62 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 77 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 58d787b..8a60ed8 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -45,7 +45,8 @@
#define c13_TID_URW 23 /* Thread ID, User R/W */
#define c13_TID_URO 24 /* Thread ID, User R/O */
#define c13_TID_PRIV 25 /* Thread ID, Privileged */
-#define NR_CP15_REGS 26 /* Number of regs (incl. invalid) */
+#define c14_CNTKCTL 26 /* Timer Control Register (PL1) */
+#define NR_CP15_REGS 27 /* Number of regs (incl. invalid) */
#define ARM_EXCEPTION_RESET 0
#define ARM_EXCEPTION_UNDEFINED 1
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 17cea2e..5ce738b 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -179,6 +179,12 @@ int main(void)
DEFINE(VGIC_CPU_APR, offsetof(struct vgic_cpu, vgic_apr));
DEFINE(VGIC_CPU_LR, offsetof(struct vgic_cpu, vgic_lr));
DEFINE(VGIC_CPU_NR_LR, offsetof(struct vgic_cpu, nr_lr));
+#ifdef CONFIG_KVM_ARM_TIMER
+ DEFINE(VCPU_TIMER_CNTV_CTL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl));
+ DEFINE(VCPU_TIMER_CNTV_CVAL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_cval));
+ DEFINE(KVM_TIMER_CNTVOFF, offsetof(struct kvm, arch.timer.cntvoff));
+ DEFINE(KVM_TIMER_ENABLED, offsetof(struct kvm, arch.timer.enabled));
+#endif
DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base));
#endif
DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr));
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index ac72a8f..22f39d6 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -690,6 +690,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
update_vttbr(vcpu->kvm);
kvm_vgic_sync_to_cpu(vcpu);
+ kvm_timer_sync_to_cpu(vcpu);
local_irq_disable();
@@ -703,6 +704,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
if (ret <= 0 || need_new_vmid_gen(vcpu->kvm)) {
local_irq_enable();
+ kvm_timer_sync_from_cpu(vcpu);
kvm_vgic_sync_from_cpu(vcpu);
continue;
}
@@ -742,6 +744,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
* Back from guest
*************************************************************/
+ kvm_timer_sync_from_cpu(vcpu);
kvm_vgic_sync_from_cpu(vcpu);
ret = handle_exit(vcpu, run, ret);
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index d782638..4ea9a98 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -222,6 +222,10 @@ static const struct coproc_reg cp15_regs[] = {
NULL, reset_unknown, c13_TID_URO },
{ CRn(13), CRm( 0), Op1( 0), Op2( 4), is32,
NULL, reset_unknown, c13_TID_PRIV },
+
+ /* CNTKCTL: swapped by interrupt.S. */
+ { CRn(14), CRm( 1), Op1( 0), Op2( 0), is32,
+ NULL, reset_val, c14_CNTKCTL, 0x00000000 },
};
/* Target specific emulation tables */
diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
index dde5f8d..57cfa84 100644
--- a/arch/arm/kvm/interrupts_head.S
+++ b/arch/arm/kvm/interrupts_head.S
@@ -301,6 +301,14 @@ vcpu .req r0 @ vcpu pointer always in r0
str r11, [vcpu, #CP15_OFFSET(c6_IFAR)]
str r12, [vcpu, #CP15_OFFSET(c12_VBAR)]
.endif
+
+ mrc p15, 0, r2, c14, c1, 0 @ CNTKCTL
+
+ .if \store_to_vcpu == 0
+ push {r2}
+ .else
+ str r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
+ .endif
.endm
/*
@@ -312,6 +320,14 @@ vcpu .req r0 @ vcpu pointer always in r0
*/
.macro write_cp15_state read_from_vcpu
.if \read_from_vcpu == 0
+ pop {r2}
+ .else
+ ldr r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
+ .endif
+
+ mcr p15, 0, r2, c14, c1, 0 @ CNTKCTL
+
+ .if \read_from_vcpu == 0
pop {r2-r12}
.else
ldr r2, [vcpu, #CP15_OFFSET(c13_CID)]
@@ -463,8 +479,29 @@ vcpu .req r0 @ vcpu pointer always in r0
* for the host.
*
* Assumes vcpu pointer in vcpu reg
+ * Clobbers r2-r4
*/
.macro save_timer_state
+#ifdef CONFIG_KVM_ARM_TIMER
+ ldr r4, [vcpu, #VCPU_KVM]
+ ldr r2, [r4, #KVM_TIMER_ENABLED]
+ cmp r2, #0
+ beq 1f
+
+ mrc p15, 0, r2, c14, c3, 1 @ CNTV_CTL
+ str r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
+ bic r2, #1 @ Clear ENABLE
+ mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
+ isb
+
+ mrrc p15, 3, r2, r3, c14 @ CNTV_CVAL
+ ldr r4, =VCPU_TIMER_CNTV_CVAL
+ add vcpu, vcpu, r4
+ strd r2, r3, [vcpu]
+ sub vcpu, vcpu, r4
+
+1:
+#endif
@ Allow physical timer/counter access for the host
mrc p15, 4, r2, c14, c1, 0 @ CNTHCTL
orr r2, r2, #(CNTHCTL_PL1PCEN | CNTHCTL_PL1PCTEN)
@@ -476,6 +513,7 @@ vcpu .req r0 @ vcpu pointer always in r0
* for the host.
*
* Assumes vcpu pointer in vcpu reg
+ * Clobbers r2-r4
*/
.macro restore_timer_state
@ Disallow physical timer access for the guest
@@ -484,6 +522,30 @@ vcpu .req r0 @ vcpu pointer always in r0
orr r2, r2, #CNTHCTL_PL1PCTEN
bic r2, r2, #CNTHCTL_PL1PCEN
mcr p15, 4, r2, c14, c1, 0 @ CNTHCTL
+
+#ifdef CONFIG_KVM_ARM_TIMER
+ ldr r4, [vcpu, #VCPU_KVM]
+ ldr r2, [r4, #KVM_TIMER_ENABLED]
+ cmp r2, #0
+ beq 1f
+
+ ldr r2, [r4, #KVM_TIMER_CNTVOFF]
+ ldr r3, [r4, #(KVM_TIMER_CNTVOFF + 4)]
+ mcrr p15, 4, r2, r3, c14 @ CNTVOFF
+ isb
+
+ ldr r4, =VCPU_TIMER_CNTV_CVAL
+ add vcpu, vcpu, r4
+ ldrd r2, r3, [vcpu]
+ sub vcpu, vcpu, r4
+ mcrr p15, 3, r2, r3, c14 @ CNTV_CVAL
+
+ ldr r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
+ and r2, r2, #3
+ mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
+ isb
+1:
+#endif
.endm
.equ vmentry, 0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 4/4] ARM: KVM: arch_timers: Wire the init code and config option
2013-01-08 18:43 [PATCH v5 0/4] KVM/ARM Architected Timers support Christoffer Dall
` (2 preceding siblings ...)
2013-01-08 18:43 ` [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch Christoffer Dall
@ 2013-01-08 18:43 ` Christoffer Dall
3 siblings, 0 replies; 14+ messages in thread
From: Christoffer Dall @ 2013-01-08 18:43 UTC (permalink / raw)
To: linux-arm-kernel
From: Marc Zyngier <marc.zyngier@arm.com>
It is now possible to select CONFIG_KVM_ARM_TIMER to enable the
KVM architected timer support.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
---
arch/arm/kvm/Kconfig | 8 ++++++++
arch/arm/kvm/Makefile | 1 +
arch/arm/kvm/arm.c | 11 +++++++++++
arch/arm/kvm/vgic.c | 1 +
4 files changed, 21 insertions(+)
diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
index d32e33f..739500b 100644
--- a/arch/arm/kvm/Kconfig
+++ b/arch/arm/kvm/Kconfig
@@ -59,6 +59,14 @@ config KVM_ARM_VGIC
---help---
Adds support for a hardware assisted, in-kernel GIC emulation.
+config KVM_ARM_TIMER
+ bool "KVM support for Architected Timers"
+ depends on KVM_ARM_VGIC && ARM_ARCH_TIMER
+ select HAVE_KVM_IRQCHIP
+ default y
+ ---help---
+ Adds support for the Architected Timers in virtual machines
+
source drivers/virtio/Kconfig
endif # VIRTUALIZATION
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index 3c6620c..43c4cad 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -20,3 +20,4 @@ obj-y += kvm-arm.o init.o interrupts.o
obj-y += arm.o guest.o mmu.o emulate.o reset.o
obj-y += coproc.o coproc_a15.o mmio.o decode.o
obj-$(CONFIG_KVM_ARM_VGIC) += vgic.o
+obj-$(CONFIG_KVM_ARM_TIMER) += arch_timer.o
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 22f39d6..38ad78a 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -287,6 +287,7 @@ int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
{
kvm_mmu_free_memory_caches(vcpu);
+ kvm_timer_vcpu_terminate(vcpu);
kmem_cache_free(kvm_vcpu_cache, vcpu);
}
@@ -328,6 +329,9 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
if (ret)
return ret;
+ /* Set up the timer */
+ kvm_timer_vcpu_init(vcpu);
+
return 0;
}
@@ -1084,6 +1088,13 @@ static int init_hyp_mode(void)
vgic_present = true;
#endif
+ /*
+ * Init HYP architected timer support
+ */
+ err = kvm_timer_hyp_init();
+ if (err)
+ goto out_free_mappings;
+
kvm_info("Hyp mode initialized successfully\n");
return 0;
out_free_vfp:
diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
index 083639b..7eb94fa 100644
--- a/arch/arm/kvm/vgic.c
+++ b/arch/arm/kvm/vgic.c
@@ -1405,6 +1405,7 @@ int kvm_vgic_init(struct kvm *kvm)
for (i = VGIC_NR_PRIVATE_IRQS; i < VGIC_NR_IRQS; i += 4)
vgic_set_target_reg(kvm, 0, i);
+ kvm_timer_init(kvm);
kvm->arch.vgic.ready = true;
out:
mutex_unlock(&kvm->lock);
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support
2013-01-08 18:43 ` [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support Christoffer Dall
@ 2013-01-14 15:18 ` Will Deacon
2013-01-14 19:19 ` Christoffer Dall
0 siblings, 1 reply; 14+ messages in thread
From: Will Deacon @ 2013-01-14 15:18 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jan 08, 2013 at 06:43:20PM +0000, Christoffer Dall wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
>
> Add some the architected timer related infrastructure, and support timer
> interrupt injection, which can happen as a resultof three possible
> events:
>
> - The virtual timer interrupt has fired while we were still
> executing the guest
> - The timer interrupt hasn't fired, but it expired while we
> were doing the world switch
> - A hrtimer we programmed earlier has fired
[...]
> +void kvm_timer_sync_to_cpu(struct kvm_vcpu *vcpu)
> +{
> + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +
> + /*
> + * We're about to run this vcpu again, so there is no need to
> + * keep the background timer running, as we're about to
> + * populate the CPU timer again.
> + */
> + timer_disarm(timer);
> +}
> +
> +void kvm_timer_sync_from_cpu(struct kvm_vcpu *vcpu)
> +{
> + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> + cycle_t cval, now;
> + u64 ns;
> +
> + /* Check if the timer is enabled and unmasked first */
> + if ((timer->cntv_ctl & 3) != 1)
> + return;
> +
> + cval = timer->cntv_cval;
> + now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;
> +
> + BUG_ON(timer_is_armed(timer));
> +
> + if (cval <= now) {
> + /*
> + * Timer has already expired while we were not
> + * looking. Inject the interrupt and carry on.
> + */
> + kvm_timer_inject_irq(vcpu);
> + return;
> + }
> +
> + ns = cyclecounter_cyc2ns(timecounter->cc, cval - now);
> + timer_arm(timer, ns);
> +}
Please use flush/sync terminology to match the rest of arch/arm/.
Will
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch
2013-01-08 18:43 ` [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch Christoffer Dall
@ 2013-01-14 15:21 ` Will Deacon
2013-01-14 17:51 ` Marc Zyngier
0 siblings, 1 reply; 14+ messages in thread
From: Will Deacon @ 2013-01-14 15:21 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jan 08, 2013 at 06:43:27PM +0000, Christoffer Dall wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
>
> Do the necessary save/restore dance for the timers in the world
> switch code. In the process, allow the guest to read the physical
> counter, which is useful for its own clock_event_device.
[...]
> @@ -476,6 +513,7 @@ vcpu .req r0 @ vcpu pointer always in r0
> * for the host.
> *
> * Assumes vcpu pointer in vcpu reg
> + * Clobbers r2-r4
> */
> .macro restore_timer_state
> @ Disallow physical timer access for the guest
> @@ -484,6 +522,30 @@ vcpu .req r0 @ vcpu pointer always in r0
> orr r2, r2, #CNTHCTL_PL1PCTEN
> bic r2, r2, #CNTHCTL_PL1PCEN
> mcr p15, 4, r2, c14, c1, 0 @ CNTHCTL
> +
> +#ifdef CONFIG_KVM_ARM_TIMER
> + ldr r4, [vcpu, #VCPU_KVM]
> + ldr r2, [r4, #KVM_TIMER_ENABLED]
> + cmp r2, #0
> + beq 1f
> +
> + ldr r2, [r4, #KVM_TIMER_CNTVOFF]
> + ldr r3, [r4, #(KVM_TIMER_CNTVOFF + 4)]
> + mcrr p15, 4, r2, r3, c14 @ CNTVOFF
> + isb
> +
> + ldr r4, =VCPU_TIMER_CNTV_CVAL
> + add vcpu, vcpu, r4
> + ldrd r2, r3, [vcpu]
> + sub vcpu, vcpu, r4
> + mcrr p15, 3, r2, r3, c14 @ CNTV_CVAL
> +
> + ldr r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
> + and r2, r2, #3
> + mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
> + isb
How many of these isbs are actually needed, given that we're going to make
an exception return to the guest? The last one certainly looks redundant and
I can't see the need for ordering CNTVOFF vs CNTV_CVAL. I can see an
argument to putting one *before* CNTV_CTL, but you don't have one there!
Will
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch
2013-01-14 15:21 ` Will Deacon
@ 2013-01-14 17:51 ` Marc Zyngier
2013-01-14 22:08 ` Christoffer Dall
0 siblings, 1 reply; 14+ messages in thread
From: Marc Zyngier @ 2013-01-14 17:51 UTC (permalink / raw)
To: linux-arm-kernel
On 14/01/13 15:21, Will Deacon wrote:
> On Tue, Jan 08, 2013 at 06:43:27PM +0000, Christoffer Dall wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Do the necessary save/restore dance for the timers in the world
>> switch code. In the process, allow the guest to read the physical
>> counter, which is useful for its own clock_event_device.
>
> [...]
>
>> @@ -476,6 +513,7 @@ vcpu .req r0 @ vcpu pointer always in r0
>> * for the host.
>> *
>> * Assumes vcpu pointer in vcpu reg
>> + * Clobbers r2-r4
>> */
>> .macro restore_timer_state
>> @ Disallow physical timer access for the guest
>> @@ -484,6 +522,30 @@ vcpu .req r0 @ vcpu pointer always in r0
>> orr r2, r2, #CNTHCTL_PL1PCTEN
>> bic r2, r2, #CNTHCTL_PL1PCEN
>> mcr p15, 4, r2, c14, c1, 0 @ CNTHCTL
>> +
>> +#ifdef CONFIG_KVM_ARM_TIMER
>> + ldr r4, [vcpu, #VCPU_KVM]
>> + ldr r2, [r4, #KVM_TIMER_ENABLED]
>> + cmp r2, #0
>> + beq 1f
>> +
>> + ldr r2, [r4, #KVM_TIMER_CNTVOFF]
>> + ldr r3, [r4, #(KVM_TIMER_CNTVOFF + 4)]
>> + mcrr p15, 4, r2, r3, c14 @ CNTVOFF
>> + isb
>> +
>> + ldr r4, =VCPU_TIMER_CNTV_CVAL
>> + add vcpu, vcpu, r4
>> + ldrd r2, r3, [vcpu]
>> + sub vcpu, vcpu, r4
>> + mcrr p15, 3, r2, r3, c14 @ CNTV_CVAL
>> +
>> + ldr r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
>> + and r2, r2, #3
>> + mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
>> + isb
>
> How many of these isbs are actually needed, given that we're going to make
> an exception return to the guest? The last one certainly looks redundant and
> I can't see the need for ordering CNTVOFF vs CNTV_CVAL. I can see an
> argument to putting one *before* CNTV_CTL, but you don't have one there!
CNTVOFF directly influences whether or not CNTV_CVAL will trigger or
not. Maybe I'm just being paranoid and moving the isb after CNTV_CVAL is
enough.
The last one is definitively superfluous.
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support
2013-01-14 15:18 ` Will Deacon
@ 2013-01-14 19:19 ` Christoffer Dall
2013-01-15 11:07 ` Marc Zyngier
0 siblings, 1 reply; 14+ messages in thread
From: Christoffer Dall @ 2013-01-14 19:19 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jan 14, 2013 at 10:18 AM, Will Deacon <will.deacon@arm.com> wrote:
> On Tue, Jan 08, 2013 at 06:43:20PM +0000, Christoffer Dall wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Add some the architected timer related infrastructure, and support timer
>> interrupt injection, which can happen as a resultof three possible
>> events:
>>
>> - The virtual timer interrupt has fired while we were still
>> executing the guest
>> - The timer interrupt hasn't fired, but it expired while we
>> were doing the world switch
>> - A hrtimer we programmed earlier has fired
>
> [...]
>
>> +void kvm_timer_sync_to_cpu(struct kvm_vcpu *vcpu)
>> +{
>> + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>> +
>> + /*
>> + * We're about to run this vcpu again, so there is no need to
>> + * keep the background timer running, as we're about to
>> + * populate the CPU timer again.
>> + */
>> + timer_disarm(timer);
>> +}
>> +
>> +void kvm_timer_sync_from_cpu(struct kvm_vcpu *vcpu)
>> +{
>> + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>> + cycle_t cval, now;
>> + u64 ns;
>> +
>> + /* Check if the timer is enabled and unmasked first */
>> + if ((timer->cntv_ctl & 3) != 1)
>> + return;
>> +
>> + cval = timer->cntv_cval;
>> + now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;
>> +
>> + BUG_ON(timer_is_armed(timer));
>> +
>> + if (cval <= now) {
>> + /*
>> + * Timer has already expired while we were not
>> + * looking. Inject the interrupt and carry on.
>> + */
>> + kvm_timer_inject_irq(vcpu);
>> + return;
>> + }
>> +
>> + ns = cyclecounter_cyc2ns(timecounter->cc, cval - now);
>> + timer_arm(timer, ns);
>> +}
>
> Please use flush/sync terminology to match the rest of arch/arm/.
>
ok, the following fixes this for both timers and the vgic:
commit 1b68f39459dbc797f6766c103edf2c1053984161
Author: Christoffer Dall <c.dall@virtualopensystems.com>
Date: Mon Jan 14 14:16:31 2013 -0500
KVM: ARM: vgic: use sync/flush terminology
Use sync/flush for saving state to/from CPUs to be consistent with
other uses in arch/arm.
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
diff --git a/arch/arm/include/asm/kvm_vgic.h b/arch/arm/include/asm/kvm_vgic.h
index 5e81e28..f5f270b 100644
--- a/arch/arm/include/asm/kvm_vgic.h
+++ b/arch/arm/include/asm/kvm_vgic.h
@@ -149,8 +149,8 @@ int kvm_vgic_hyp_init(void);
int kvm_vgic_init(struct kvm *kvm);
int kvm_vgic_create(struct kvm *kvm);
int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu);
-void kvm_vgic_sync_to_cpu(struct kvm_vcpu *vcpu);
-void kvm_vgic_sync_from_cpu(struct kvm_vcpu *vcpu);
+void kvm_vgic_flush(struct kvm_vcpu *vcpu);
+void kvm_vgic_sync(struct kvm_vcpu *vcpu);
int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
bool level);
int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index f986718..7921bc4 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -714,7 +714,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu,
struct kvm_run *run)
update_vttbr(vcpu->kvm);
- kvm_vgic_sync_to_cpu(vcpu);
+ kvm_vgic_flush(vcpu);
kvm_timer_flush(vcpu);
local_irq_disable();
@@ -730,7 +730,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu,
struct kvm_run *run)
if (ret <= 0 || need_new_vmid_gen(vcpu->kvm)) {
local_irq_enable();
kvm_timer_sync(vcpu);
- kvm_vgic_sync_from_cpu(vcpu);
+ kvm_vgic_sync(vcpu);
continue;
}
@@ -770,7 +770,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu,
struct kvm_run *run)
*************************************************************/
kvm_timer_sync(vcpu);
- kvm_vgic_sync_from_cpu(vcpu);
+ kvm_vgic_sync(vcpu);
ret = handle_exit(vcpu, run, ret);
}
diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
index 7eb94fa..25daa07 100644
--- a/arch/arm/kvm/vgic.c
+++ b/arch/arm/kvm/vgic.c
@@ -946,7 +946,7 @@ static bool vgic_queue_hwirq(struct kvm_vcpu *vcpu, int irq)
* Fill the list registers with pending interrupts before running the
* guest.
*/
-static void __kvm_vgic_sync_to_cpu(struct kvm_vcpu *vcpu)
+static void __kvm_vgic_flush(struct kvm_vcpu *vcpu)
{
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
@@ -1009,7 +1009,7 @@ static bool vgic_process_maintenance(struct
kvm_vcpu *vcpu)
* We do not need to take the distributor lock here, since the only
* action we perform is clearing the irq_active_bit for an EOIed
* level interrupt. There is a potential race with
- * the queuing of an interrupt in __kvm_sync_to_cpu(), where we check
+ * the queuing of an interrupt in __kvm_vgic_flush(), where we check
* if the interrupt is already active. Two possibilities:
*
* - The queuing is occurring on the same vcpu: cannot happen,
@@ -1055,7 +1055,7 @@ static bool vgic_process_maintenance(struct
kvm_vcpu *vcpu)
* the distributor here (the irq_pending_on_cpu bit is safe to set),
* so there is no need for taking its lock.
*/
-static void __kvm_vgic_sync_from_cpu(struct kvm_vcpu *vcpu)
+static void __kvm_vgic_sync(struct kvm_vcpu *vcpu)
{
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
@@ -1085,7 +1085,7 @@ static void __kvm_vgic_sync_from_cpu(struct
kvm_vcpu *vcpu)
set_bit(vcpu->vcpu_id, &dist->irq_pending_on_cpu);
}
-void kvm_vgic_sync_to_cpu(struct kvm_vcpu *vcpu)
+void kvm_vgic_flush(struct kvm_vcpu *vcpu)
{
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
@@ -1093,16 +1093,16 @@ void kvm_vgic_sync_to_cpu(struct kvm_vcpu *vcpu)
return;
spin_lock(&dist->lock);
- __kvm_vgic_sync_to_cpu(vcpu);
+ __kvm_vgic_flush(vcpu);
spin_unlock(&dist->lock);
}
-void kvm_vgic_sync_from_cpu(struct kvm_vcpu *vcpu)
+void kvm_vgic_sync(struct kvm_vcpu *vcpu)
{
if (!irqchip_in_kernel(vcpu->kvm))
return;
- __kvm_vgic_sync_from_cpu(vcpu);
+ __kvm_vgic_sync(vcpu);
}
int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
--
commit b9e08fdd32b7f3da3ad0b287c4da575b3b6c23d7
Author: Christoffer Dall <c.dall@virtualopensystems.com>
Date: Mon Jan 14 14:15:31 2013 -0500
KVM: ARM: timers: use sync/flush terminology
Use sync/flush for saving state to/from CPUs to be consistent with other
uses in arch/arm.
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
diff --git a/arch/arm/include/asm/kvm_arch_timer.h
b/arch/arm/include/asm/kvm_arch_timer.h
index aed1c42..2af5096 100644
--- a/arch/arm/include/asm/kvm_arch_timer.h
+++ b/arch/arm/include/asm/kvm_arch_timer.h
@@ -62,8 +62,8 @@ struct arch_timer_cpu {
int kvm_timer_hyp_init(void);
int kvm_timer_init(struct kvm *kvm);
void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu);
-void kvm_timer_sync_to_cpu(struct kvm_vcpu *vcpu);
-void kvm_timer_sync_from_cpu(struct kvm_vcpu *vcpu);
+void kvm_timer_flush(struct kvm_vcpu *vcpu);
+void kvm_timer_sync(struct kvm_vcpu *vcpu);
void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu);
#else
static inline int kvm_timer_hyp_init(void)
diff --git a/arch/arm/kvm/arch_timer.c b/arch/arm/kvm/arch_timer.c
index 6cb9aa3..3f2580f 100644
--- a/arch/arm/kvm/arch_timer.c
+++ b/arch/arm/kvm/arch_timer.c
@@ -101,7 +101,14 @@ static enum hrtimer_restart
kvm_timer_expire(struct hrtimer *hrt)
return HRTIMER_NORESTART;
}
-void kvm_timer_sync_to_cpu(struct kvm_vcpu *vcpu)
+/**
+ * kvm_timer_flush - prepare to move the virt timer to the cpu
+ * @vcpu: The vcpu pointer
+ *
+ * Disarm any pending soft timers, since the world-switch code will write the
+ * virtual timer state back to the physical CPU.
+ */
+void kvm_timer_flush(struct kvm_vcpu *vcpu)
{
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
@@ -113,7 +120,14 @@ void kvm_timer_sync_to_cpu(struct kvm_vcpu *vcpu)
timer_disarm(timer);
}
-void kvm_timer_sync_from_cpu(struct kvm_vcpu *vcpu)
+/**
+ * kvm_timer_sync - sync timer state from cpu
+ * @vcpu: The vcpu pointer
+ *
+ * Check if the virtual timer was armed and either schedule a corresponding
+ * soft timer or inject directly if already expired.
+ */
+void kvm_timer_sync(struct kvm_vcpu *vcpu)
{
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
cycle_t cval, now;
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index fdd4a7c..f986718 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -715,7 +715,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu,
struct kvm_run *run)
update_vttbr(vcpu->kvm);
kvm_vgic_sync_to_cpu(vcpu);
- kvm_timer_sync_to_cpu(vcpu);
+ kvm_timer_flush(vcpu);
local_irq_disable();
@@ -729,7 +729,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu,
struct kvm_run *run)
if (ret <= 0 || need_new_vmid_gen(vcpu->kvm)) {
local_irq_enable();
- kvm_timer_sync_from_cpu(vcpu);
+ kvm_timer_sync(vcpu);
kvm_vgic_sync_from_cpu(vcpu);
continue;
}
@@ -769,7 +769,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu,
struct kvm_run *run)
* Back from guest
*************************************************************/
- kvm_timer_sync_from_cpu(vcpu);
+ kvm_timer_sync(vcpu);
kvm_vgic_sync_from_cpu(vcpu);
ret = handle_exit(vcpu, run, ret);
--
Thanks,
-Christoffer
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch
2013-01-14 17:51 ` Marc Zyngier
@ 2013-01-14 22:08 ` Christoffer Dall
2013-01-14 22:25 ` Will Deacon
2013-01-15 11:10 ` Marc Zyngier
0 siblings, 2 replies; 14+ messages in thread
From: Christoffer Dall @ 2013-01-14 22:08 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jan 14, 2013 at 12:51 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 14/01/13 15:21, Will Deacon wrote:
>> On Tue, Jan 08, 2013 at 06:43:27PM +0000, Christoffer Dall wrote:
>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>
>>> Do the necessary save/restore dance for the timers in the world
>>> switch code. In the process, allow the guest to read the physical
>>> counter, which is useful for its own clock_event_device.
>>
>> [...]
>>
>>> @@ -476,6 +513,7 @@ vcpu .req r0 @ vcpu pointer always in r0
>>> * for the host.
>>> *
>>> * Assumes vcpu pointer in vcpu reg
>>> + * Clobbers r2-r4
>>> */
>>> .macro restore_timer_state
>>> @ Disallow physical timer access for the guest
>>> @@ -484,6 +522,30 @@ vcpu .req r0 @ vcpu pointer always in r0
>>> orr r2, r2, #CNTHCTL_PL1PCTEN
>>> bic r2, r2, #CNTHCTL_PL1PCEN
>>> mcr p15, 4, r2, c14, c1, 0 @ CNTHCTL
>>> +
>>> +#ifdef CONFIG_KVM_ARM_TIMER
>>> + ldr r4, [vcpu, #VCPU_KVM]
>>> + ldr r2, [r4, #KVM_TIMER_ENABLED]
>>> + cmp r2, #0
>>> + beq 1f
>>> +
>>> + ldr r2, [r4, #KVM_TIMER_CNTVOFF]
>>> + ldr r3, [r4, #(KVM_TIMER_CNTVOFF + 4)]
>>> + mcrr p15, 4, r2, r3, c14 @ CNTVOFF
>>> + isb
>>> +
>>> + ldr r4, =VCPU_TIMER_CNTV_CVAL
>>> + add vcpu, vcpu, r4
>>> + ldrd r2, r3, [vcpu]
>>> + sub vcpu, vcpu, r4
>>> + mcrr p15, 3, r2, r3, c14 @ CNTV_CVAL
>>> +
>>> + ldr r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
>>> + and r2, r2, #3
>>> + mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
>>> + isb
>>
>> How many of these isbs are actually needed, given that we're going to make
>> an exception return to the guest? The last one certainly looks redundant and
>> I can't see the need for ordering CNTVOFF vs CNTV_CVAL. I can see an
>> argument to putting one *before* CNTV_CTL, but you don't have one there!
>
> CNTVOFF directly influences whether or not CNTV_CVAL will trigger or
> not. Maybe I'm just being paranoid and moving the isb after CNTV_CVAL is
> enough.
>
> The last one is definitively superfluous.
>
can't we also get rid of the isb on the return path then?
do you agree with this patch:
diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
index 57cfa84..7e6eedf 100644
--- a/arch/arm/kvm/interrupts_head.S
+++ b/arch/arm/kvm/interrupts_head.S
@@ -492,7 +492,6 @@ vcpu .req r0 @ vcpu pointer always in r0
str r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
bic r2, #1 @ Clear ENABLE
mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
- isb
mrrc p15, 3, r2, r3, c14 @ CNTV_CVAL
ldr r4, =VCPU_TIMER_CNTV_CVAL
@@ -532,18 +531,17 @@ vcpu .req r0 @ vcpu pointer always in r0
ldr r2, [r4, #KVM_TIMER_CNTVOFF]
ldr r3, [r4, #(KVM_TIMER_CNTVOFF + 4)]
mcrr p15, 4, r2, r3, c14 @ CNTVOFF
- isb
ldr r4, =VCPU_TIMER_CNTV_CVAL
add vcpu, vcpu, r4
ldrd r2, r3, [vcpu]
sub vcpu, vcpu, r4
mcrr p15, 3, r2, r3, c14 @ CNTV_CVAL
+ isb
ldr r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
and r2, r2, #3
mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
- isb
1:
#endif
.endm
--
Thanks,
-Christoffer
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch
2013-01-14 22:08 ` Christoffer Dall
@ 2013-01-14 22:25 ` Will Deacon
2013-01-15 11:10 ` Marc Zyngier
1 sibling, 0 replies; 14+ messages in thread
From: Will Deacon @ 2013-01-14 22:25 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jan 14, 2013 at 10:08:39PM +0000, Christoffer Dall wrote:
> can't we also get rid of the isb on the return path then?
>
> do you agree with this patch:
>
> diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
> index 57cfa84..7e6eedf 100644
> --- a/arch/arm/kvm/interrupts_head.S
> +++ b/arch/arm/kvm/interrupts_head.S
> @@ -492,7 +492,6 @@ vcpu .req r0 @ vcpu pointer always in r0
> str r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
> bic r2, #1 @ Clear ENABLE
> mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
> - isb
I'd keep this one as it stops speculation of CVAL until the timer is
disabled.
> mrrc p15, 3, r2, r3, c14 @ CNTV_CVAL
> ldr r4, =VCPU_TIMER_CNTV_CVAL
> @@ -532,18 +531,17 @@ vcpu .req r0 @ vcpu pointer always in r0
> ldr r2, [r4, #KVM_TIMER_CNTVOFF]
> ldr r3, [r4, #(KVM_TIMER_CNTVOFF + 4)]
> mcrr p15, 4, r2, r3, c14 @ CNTVOFF
> - isb
>
> ldr r4, =VCPU_TIMER_CNTV_CVAL
> add vcpu, vcpu, r4
> ldrd r2, r3, [vcpu]
> sub vcpu, vcpu, r4
> mcrr p15, 3, r2, r3, c14 @ CNTV_CVAL
> + isb
>
> ldr r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
> and r2, r2, #3
> mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
> - isb
Looks ok to me, but I'll let Marc decide as it's his code.
Will
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support
2013-01-14 19:19 ` Christoffer Dall
@ 2013-01-15 11:07 ` Marc Zyngier
2013-01-15 14:32 ` Christoffer Dall
0 siblings, 1 reply; 14+ messages in thread
From: Marc Zyngier @ 2013-01-15 11:07 UTC (permalink / raw)
To: linux-arm-kernel
On 14/01/13 19:19, Christoffer Dall wrote:
> On Mon, Jan 14, 2013 at 10:18 AM, Will Deacon <will.deacon@arm.com> wrote:
>> On Tue, Jan 08, 2013 at 06:43:20PM +0000, Christoffer Dall wrote:
>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>
>>> Add some the architected timer related infrastructure, and support timer
>>> interrupt injection, which can happen as a resultof three possible
>>> events:
>>>
>>> - The virtual timer interrupt has fired while we were still
>>> executing the guest
>>> - The timer interrupt hasn't fired, but it expired while we
>>> were doing the world switch
>>> - A hrtimer we programmed earlier has fired
>>
>> [...]
>>
>>> +void kvm_timer_sync_to_cpu(struct kvm_vcpu *vcpu)
>>> +{
>>> + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>>> +
>>> + /*
>>> + * We're about to run this vcpu again, so there is no need to
>>> + * keep the background timer running, as we're about to
>>> + * populate the CPU timer again.
>>> + */
>>> + timer_disarm(timer);
>>> +}
>>> +
>>> +void kvm_timer_sync_from_cpu(struct kvm_vcpu *vcpu)
>>> +{
>>> + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>>> + cycle_t cval, now;
>>> + u64 ns;
>>> +
>>> + /* Check if the timer is enabled and unmasked first */
>>> + if ((timer->cntv_ctl & 3) != 1)
>>> + return;
>>> +
>>> + cval = timer->cntv_cval;
>>> + now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;
>>> +
>>> + BUG_ON(timer_is_armed(timer));
>>> +
>>> + if (cval <= now) {
>>> + /*
>>> + * Timer has already expired while we were not
>>> + * looking. Inject the interrupt and carry on.
>>> + */
>>> + kvm_timer_inject_irq(vcpu);
>>> + return;
>>> + }
>>> +
>>> + ns = cyclecounter_cyc2ns(timecounter->cc, cval - now);
>>> + timer_arm(timer, ns);
>>> +}
>>
>> Please use flush/sync terminology to match the rest of arch/arm/.
>>
> ok, the following fixes this for both timers and the vgic:
>
> commit 1b68f39459dbc797f6766c103edf2c1053984161
> Author: Christoffer Dall <c.dall@virtualopensystems.com>
> Date: Mon Jan 14 14:16:31 2013 -0500
>
> KVM: ARM: vgic: use sync/flush terminology
>
> Use sync/flush for saving state to/from CPUs to be consistent with
> other uses in arch/arm.
Sync and flush on their own are pretty inexpressive. Consider changing
it to {flush,sync}_hwstate, so we're consistent with what VFP does.
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch
2013-01-14 22:08 ` Christoffer Dall
2013-01-14 22:25 ` Will Deacon
@ 2013-01-15 11:10 ` Marc Zyngier
1 sibling, 0 replies; 14+ messages in thread
From: Marc Zyngier @ 2013-01-15 11:10 UTC (permalink / raw)
To: linux-arm-kernel
On 14/01/13 22:08, Christoffer Dall wrote:
> On Mon, Jan 14, 2013 at 12:51 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> On 14/01/13 15:21, Will Deacon wrote:
>>> On Tue, Jan 08, 2013 at 06:43:27PM +0000, Christoffer Dall wrote:
>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>
>>>> Do the necessary save/restore dance for the timers in the world
>>>> switch code. In the process, allow the guest to read the physical
>>>> counter, which is useful for its own clock_event_device.
>>>
>>> [...]
>>>
>>>> @@ -476,6 +513,7 @@ vcpu .req r0 @ vcpu pointer always in r0
>>>> * for the host.
>>>> *
>>>> * Assumes vcpu pointer in vcpu reg
>>>> + * Clobbers r2-r4
>>>> */
>>>> .macro restore_timer_state
>>>> @ Disallow physical timer access for the guest
>>>> @@ -484,6 +522,30 @@ vcpu .req r0 @ vcpu pointer always in r0
>>>> orr r2, r2, #CNTHCTL_PL1PCTEN
>>>> bic r2, r2, #CNTHCTL_PL1PCEN
>>>> mcr p15, 4, r2, c14, c1, 0 @ CNTHCTL
>>>> +
>>>> +#ifdef CONFIG_KVM_ARM_TIMER
>>>> + ldr r4, [vcpu, #VCPU_KVM]
>>>> + ldr r2, [r4, #KVM_TIMER_ENABLED]
>>>> + cmp r2, #0
>>>> + beq 1f
>>>> +
>>>> + ldr r2, [r4, #KVM_TIMER_CNTVOFF]
>>>> + ldr r3, [r4, #(KVM_TIMER_CNTVOFF + 4)]
>>>> + mcrr p15, 4, r2, r3, c14 @ CNTVOFF
>>>> + isb
>>>> +
>>>> + ldr r4, =VCPU_TIMER_CNTV_CVAL
>>>> + add vcpu, vcpu, r4
>>>> + ldrd r2, r3, [vcpu]
>>>> + sub vcpu, vcpu, r4
>>>> + mcrr p15, 3, r2, r3, c14 @ CNTV_CVAL
>>>> +
>>>> + ldr r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
>>>> + and r2, r2, #3
>>>> + mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
>>>> + isb
>>>
>>> How many of these isbs are actually needed, given that we're going to make
>>> an exception return to the guest? The last one certainly looks redundant and
>>> I can't see the need for ordering CNTVOFF vs CNTV_CVAL. I can see an
>>> argument to putting one *before* CNTV_CTL, but you don't have one there!
>>
>> CNTVOFF directly influences whether or not CNTV_CVAL will trigger or
>> not. Maybe I'm just being paranoid and moving the isb after CNTV_CVAL is
>> enough.
>>
>> The last one is definitively superfluous.
>>
>
> can't we also get rid of the isb on the return path then?
>
> do you agree with this patch:
>
> diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
> index 57cfa84..7e6eedf 100644
> --- a/arch/arm/kvm/interrupts_head.S
> +++ b/arch/arm/kvm/interrupts_head.S
> @@ -492,7 +492,6 @@ vcpu .req r0 @ vcpu pointer always in r0
> str r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
> bic r2, #1 @ Clear ENABLE
> mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
> - isb
This isb is required. Otherwise you have no guarantee about how recent
the next CNTV_CVAL read is (could be speculated).
> mrrc p15, 3, r2, r3, c14 @ CNTV_CVAL
> ldr r4, =VCPU_TIMER_CNTV_CVAL
> @@ -532,18 +531,17 @@ vcpu .req r0 @ vcpu pointer always in r0
> ldr r2, [r4, #KVM_TIMER_CNTVOFF]
> ldr r3, [r4, #(KVM_TIMER_CNTVOFF + 4)]
> mcrr p15, 4, r2, r3, c14 @ CNTVOFF
> - isb
>
> ldr r4, =VCPU_TIMER_CNTV_CVAL
> add vcpu, vcpu, r4
> ldrd r2, r3, [vcpu]
> sub vcpu, vcpu, r4
> mcrr p15, 3, r2, r3, c14 @ CNTV_CVAL
> + isb
>
> ldr r2, [vcpu, #VCPU_TIMER_CNTV_CTL]
> and r2, r2, #3
> mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
> - isb
> 1:
> #endif
> .endm
This part is OK.
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support
2013-01-15 11:07 ` Marc Zyngier
@ 2013-01-15 14:32 ` Christoffer Dall
0 siblings, 0 replies; 14+ messages in thread
From: Christoffer Dall @ 2013-01-15 14:32 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jan 15, 2013 at 6:07 AM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 14/01/13 19:19, Christoffer Dall wrote:
>> On Mon, Jan 14, 2013 at 10:18 AM, Will Deacon <will.deacon@arm.com> wrote:
>>> On Tue, Jan 08, 2013 at 06:43:20PM +0000, Christoffer Dall wrote:
>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>
>>>> Add some the architected timer related infrastructure, and support timer
>>>> interrupt injection, which can happen as a resultof three possible
>>>> events:
>>>>
>>>> - The virtual timer interrupt has fired while we were still
>>>> executing the guest
>>>> - The timer interrupt hasn't fired, but it expired while we
>>>> were doing the world switch
>>>> - A hrtimer we programmed earlier has fired
>>>
>>> [...]
>>>
>>>> +void kvm_timer_sync_to_cpu(struct kvm_vcpu *vcpu)
>>>> +{
>>>> + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>>>> +
>>>> + /*
>>>> + * We're about to run this vcpu again, so there is no need to
>>>> + * keep the background timer running, as we're about to
>>>> + * populate the CPU timer again.
>>>> + */
>>>> + timer_disarm(timer);
>>>> +}
>>>> +
>>>> +void kvm_timer_sync_from_cpu(struct kvm_vcpu *vcpu)
>>>> +{
>>>> + struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>>>> + cycle_t cval, now;
>>>> + u64 ns;
>>>> +
>>>> + /* Check if the timer is enabled and unmasked first */
>>>> + if ((timer->cntv_ctl & 3) != 1)
>>>> + return;
>>>> +
>>>> + cval = timer->cntv_cval;
>>>> + now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;
>>>> +
>>>> + BUG_ON(timer_is_armed(timer));
>>>> +
>>>> + if (cval <= now) {
>>>> + /*
>>>> + * Timer has already expired while we were not
>>>> + * looking. Inject the interrupt and carry on.
>>>> + */
>>>> + kvm_timer_inject_irq(vcpu);
>>>> + return;
>>>> + }
>>>> +
>>>> + ns = cyclecounter_cyc2ns(timecounter->cc, cval - now);
>>>> + timer_arm(timer, ns);
>>>> +}
>>>
>>> Please use flush/sync terminology to match the rest of arch/arm/.
>>>
>> ok, the following fixes this for both timers and the vgic:
>>
>> commit 1b68f39459dbc797f6766c103edf2c1053984161
>> Author: Christoffer Dall <c.dall@virtualopensystems.com>
>> Date: Mon Jan 14 14:16:31 2013 -0500
>>
>> KVM: ARM: vgic: use sync/flush terminology
>>
>> Use sync/flush for saving state to/from CPUs to be consistent with
>> other uses in arch/arm.
>
> Sync and flush on their own are pretty inexpressive. Consider changing
> it to {flush,sync}_hwstate, so we're consistent with what VFP does.
>
sure
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2013-01-15 14:32 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-01-08 18:43 [PATCH v5 0/4] KVM/ARM Architected Timers support Christoffer Dall
2013-01-08 18:43 ` [PATCH v5 1/4] ARM: arch_timers: switch to physical timers if HYP mode is available Christoffer Dall
2013-01-08 18:43 ` [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support Christoffer Dall
2013-01-14 15:18 ` Will Deacon
2013-01-14 19:19 ` Christoffer Dall
2013-01-15 11:07 ` Marc Zyngier
2013-01-15 14:32 ` Christoffer Dall
2013-01-08 18:43 ` [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch Christoffer Dall
2013-01-14 15:21 ` Will Deacon
2013-01-14 17:51 ` Marc Zyngier
2013-01-14 22:08 ` Christoffer Dall
2013-01-14 22:25 ` Will Deacon
2013-01-15 11:10 ` Marc Zyngier
2013-01-08 18:43 ` [PATCH v5 4/4] ARM: KVM: arch_timers: Wire the init code and config option Christoffer Dall
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).