diff options
Diffstat (limited to 'virt/kvm/arm/arch_timer.c')
| -rw-r--r-- | virt/kvm/arm/arch_timer.c | 43 | 
1 files changed, 24 insertions, 19 deletions
| diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index 4151250ce8da..cc29a8148328 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c @@ -92,16 +92,23 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)  {  	struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id;  	struct arch_timer_context *vtimer; +	u32 cnt_ctl; -	if (!vcpu) { -		pr_warn_once("Spurious arch timer IRQ on non-VCPU thread\n"); -		return IRQ_NONE; -	} -	vtimer = vcpu_vtimer(vcpu); +	/* +	 * We may see a timer interrupt after vcpu_put() has been called which +	 * sets the CPU's vcpu pointer to NULL, because even though the timer +	 * has been disabled in vtimer_save_state(), the hardware interrupt +	 * signal may not have been retired from the interrupt controller yet. +	 */ +	if (!vcpu) +		return IRQ_HANDLED; +	vtimer = vcpu_vtimer(vcpu);  	if (!vtimer->irq.level) { -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl); -		if (kvm_timer_irq_can_fire(vtimer)) +		cnt_ctl = read_sysreg_el0(cntv_ctl); +		cnt_ctl &= ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_STAT | +			   ARCH_TIMER_CTRL_IT_MASK; +		if (cnt_ctl == (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_STAT))  			kvm_timer_update_irq(vcpu, true, vtimer);  	} @@ -355,6 +362,7 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)  	/* Disable the virtual timer */  	write_sysreg_el0(0, cntv_ctl); +	isb();  	vtimer->loaded = false;  out: @@ -479,9 +487,6 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)  	vtimer_restore_state(vcpu); -	if (has_vhe()) -		disable_el1_phys_timer_access(); -  	/* Set the background timer for the physical timer emulation. */  	phys_timer_emulate(vcpu);  } @@ -510,9 +515,6 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)  	if (unlikely(!timer->enabled))  		return; -	if (has_vhe()) -		enable_el1_phys_timer_access(); -  	vtimer_save_state(vcpu);  	/* @@ -726,7 +728,7 @@ static int kvm_timer_dying_cpu(unsigned int cpu)  	return 0;  } -int kvm_timer_hyp_init(void) +int kvm_timer_hyp_init(bool has_gic)  {  	struct arch_timer_kvm_info *info;  	int err; @@ -762,10 +764,13 @@ int kvm_timer_hyp_init(void)  		return err;  	} -	err = irq_set_vcpu_affinity(host_vtimer_irq, kvm_get_running_vcpus()); -	if (err) { -		kvm_err("kvm_arch_timer: error setting vcpu affinity\n"); -		goto out_free_irq; +	if (has_gic) { +		err = irq_set_vcpu_affinity(host_vtimer_irq, +					    kvm_get_running_vcpus()); +		if (err) { +			kvm_err("kvm_arch_timer: error setting vcpu affinity\n"); +			goto out_free_irq; +		}  	}  	kvm_info("virtual timer IRQ%d\n", host_vtimer_irq); @@ -841,7 +846,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)  no_vgic:  	preempt_disable();  	timer->enabled = 1; -	kvm_timer_vcpu_load_vgic(vcpu); +	kvm_timer_vcpu_load(vcpu);  	preempt_enable();  	return 0; |