KVM/ARM Architected Timers support
Subsystems (2)
v5 cover KVM/ARM Architected Timers support
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
PATCH v5 1/4 ARM: arch_timers: switch to physical timers if HYP mode is available
From: Marc Zyngier <[email protected]>
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.
--- arch/arm/kernel/arch_timer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/arm/kernel/arch_timer.c +6 -1
@@ -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] ||
PATCH v5 2/4 ARM: KVM: arch_timers: Add guest timer core support
In reply to Christoffer DallFrom: Marc Zyngier <[email protected]>
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
--- 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
arch/arm/include/asm/kvm_arch_timer.h new file +85 -0
@@ -0,0 +1,85 @@ +/* +* Copyright (C) 2012 ARM Ltd. +* Author: Marc Zyngier <[email protected]> +* +* 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
arch/arm/include/asm/kvm_host.h +5 -0
@@ -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
arch/arm/kvm/arch_timer.c new file +257 -0
257 lines not on this page · raw message
arch/arm/kvm/interrupts.S +2 -0
@@ -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
arch/arm/kvm/interrupts_head.S +31 -0
@@ -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
Re: [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support
Quoted 11 lines · Christoffer Dall
From: Marc Zyngier <[email protected]>
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
[...]
Quoted 29 lines
arch/arm/kvm/arch_timer.c new file +29
-0+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) { +/*
arch/arm/kvm/arch_timer.c line 142
Quoted 10 lines
arch/arm/kvm/arch_timer.c new file +10
-0+* 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
Re: [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support
Quoted 48 lines · Will Deacon
Quoted 11 lines · Christoffer Dall
From: Marc Zyngier <[email protected]>
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[...]
Quoted 33 lines
(quoted diff) +33
-0+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);
Quoted 9 lines
Review
Quoted 6 lines
(quoted diff) +6
-0+ 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 <[email protected]> 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.
arch/arm/include/asm/kvm_vgic.h +2 -2
@@ -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);
arch/arm/kvm/arm.c +0 -0
@@ -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);
}
arch/arm/kvm/vgic.c +1 -1
@@ -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 <[email protected]> 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.
(quoted diff) +0 -0
b/arch/arm/include/asm/kvm_arch_timer.h
index aed1c42..2af5096 100644
arch/arm/include/asm/kvm_arch_timer.h +2 -2
@@ -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 )
arch/arm/kvm/arch_timer.c +0 -0
@@ -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;
arch/arm/kvm/arm.c +0 -0
@@ -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
Re: [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support
Quoted 60 lines · Christoffer Dall
Quoted 48 lines · Will Deacon
Quoted 11 lines · Christoffer Dall
From: Marc Zyngier <[email protected]>
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[...]
Quoted 33 lines
(quoted diff) +33
-0+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);Quoted 9 lines
Review
Quoted 6 lines
(quoted diff) +6
-0+ 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:
Quoted 8 lines
commit
1b68f39459dbc797f6766c103edf2c1053984161Author: Christoffer Dall <[email protected]> Date: Mon Jan 14 14:16:31 2013 -0500KVM: 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.
Signature · 1 line
Jazz is not dead. It just smells funny...
Re: [PATCH v5 2/4] ARM: KVM: arch_timers: Add guest timer core support
Quoted 65 lines · Marc Zyngier
Quoted 64 lines · Christoffer Dall
Quoted 48 lines · Will Deacon
Quoted 11 lines · Christoffer Dall
From: Marc Zyngier <[email protected]>
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[...]
Quoted 33 lines
(quoted diff) +33
-0+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);Quoted 9 lines
Review
Quoted 6 lines
(quoted diff) +6
-0+ 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
1b68f39459dbc797f6766c103edf2c1053984161Author: Christoffer Dall <[email protected]> Date: Mon Jan 14 14:16:31 2013 -0500
Quoted 8 lines
Quoted 4 lines
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
PATCH v5 3/4 ARM: KVM: arch_timers: Add timer world switch
In reply to Christoffer DallFrom: Marc Zyngier <[email protected]>
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.
--- 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(-)
arch/arm/include/asm/kvm_asm.h +2 -1
@@ -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
arch/arm/kernel/asm-offsets.c +6 -0
@@ -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));
arch/arm/kvm/arm.c +3 -0
@@ -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);
arch/arm/kvm/coproc.c +4 -0
@@ -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 */
arch/arm/kvm/interrupts_head.S +62 -0
94 lines not on this page · raw message
Re: [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch
Quoted 5 lines · Christoffer Dall
From: Marc Zyngier <[email protected]>
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.
[...]
Quoted 24 lines
arch/arm/kvm/interrupts_head.S +13
-0@@ -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 +
arch/arm/kvm/interrupts_head.S vcpu .req r0 @ vcpu pointer always in r0 · line 546
Quoted 10 lines
arch/arm/kvm/interrupts_head.S +10
-0+ 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
Re: [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch
Quoted 40 lines · Will Deacon
Quoted 5 lines · Christoffer Dall
From: Marc Zyngier <[email protected]>
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.[...]
Quoted 31 lines
arch/arm/kvm/interrupts_head.S +20
-0@@ -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]
Quoted 8 lines
arch/arm/kvm/interrupts_head.S vcpu .req r0 @ vcpu pointer always in r0 · line 546
Quoted 3 lines
arch/arm/kvm/interrupts_head.S +3
-0+ and r2, r2, #3 + mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL + isbHow 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.
Signature · 1 line
Jazz is not dead. It just smells funny...
Re: [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch
Quoted 50 lines · Marc Zyngier
Quoted 40 lines · Will Deacon
Quoted 5 lines · Christoffer Dall
From: Marc Zyngier <[email protected]>
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.[...]
Quoted 31 lines
(quoted diff) +20
-0@@ -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]Quoted 8 lines
Review vcpu .req r0 @ vcpu pointer always in r0 · line 546
Quoted 3 lines
(quoted diff) +3
-0+ and r2, r2, #3 + mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL + isbHow 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!
Quoted 6 lines
CNTVOFF directly influences whether or not
CNTV_CVALwill trigger or not. Maybe I'm just being paranoid and moving the isb afterCNTV_CVALis 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:
arch/arm/kvm/interrupts_head.S +1 -3
@@ -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
Re: [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch
arch/arm/kvm/interrupts_head.S vcpu .req r0 @ vcpu pointer always in r0 · line 495
Quoted 13 lines · Christoffer Dall
can't we also get rid of the isb on the return path then?
do you agree with this patch:
arch/arm/kvm/interrupts_head.S +0
-1@@ -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.
Quoted 9 lines
arch/arm/kvm/interrupts_head.S +0
-1mrrc 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
arch/arm/kvm/interrupts_head.S vcpu .req r0 @ vcpu pointer always in r0 · line 546
Quoted 10 lines
arch/arm/kvm/interrupts_head.S +1
-1add 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
Re: [PATCH v5 3/4] ARM: KVM: arch_timers: Add timer world switch
In reply to Christoffer DallQuoted 67 lines · Christoffer Dall
Quoted 50 lines · Marc Zyngier
Quoted 40 lines · Will Deacon
Quoted 5 lines · Christoffer Dall
From: Marc Zyngier <[email protected]>
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.[...]
Quoted 31 lines
(quoted diff) +20
-0@@ -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]Quoted 8 lines
Review vcpu .req r0 @ vcpu pointer always in r0 · line 546
Quoted 3 lines
(quoted diff) +3
-0+ and r2, r2, #3 + mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL + isbHow 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!Quoted 6 lines
CNTVOFF directly influences whether or not
CNTV_CVALwill trigger or not. Maybe I'm just being paranoid and moving the isb afterCNTV_CVALis 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:
arch/arm/kvm/interrupts_head.S +0
-0
arch/arm/kvm/interrupts_head.S vcpu .req r0 @ vcpu pointer always in r0 · line 495
Quoted 4 lines
arch/arm/kvm/interrupts_head.S +0
-1@@ -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).
Quoted 12 lines
arch/arm/kvm/interrupts_head.S +0
-1mrrc 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
arch/arm/kvm/interrupts_head.S vcpu .req r0 @ vcpu pointer always in r0 · line 547
Quoted 10 lines
arch/arm/kvm/interrupts_head.S +1
-1mcrr 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.
Signature · 1 line
Jazz is not dead. It just smells funny...
PATCH v5 4/4 ARM: KVM: arch_timers: Wire the init code and config option
In reply to Christoffer DallFrom: Marc Zyngier <[email protected]>
It is now possible to select CONFIG_KVM_ARM_TIMER to enable the KVM architected timer support.
--- 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(+)
arch/arm/kvm/Kconfig +8 -0
@@ -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
arch/arm/kvm/Makefile +1 -0
@@ -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
arch/arm/kvm/arm.c +11 -0
@@ -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:
arch/arm/kvm/vgic.c +1 -0
@@ -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);