diff options
| -rw-r--r-- | arch/arm/kvm/arm.c | 2 | ||||
| -rw-r--r-- | include/kvm/arm_arch_timer.h | 2 | ||||
| -rw-r--r-- | virt/kvm/arm/arch_timer.c | 45 |
3 files changed, 39 insertions, 10 deletions
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 9a5f057a97a3..e98370cd9969 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c | |||
| @@ -266,7 +266,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) | |||
| 266 | 266 | ||
| 267 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) | 267 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) |
| 268 | { | 268 | { |
| 269 | return 0; | 269 | return kvm_timer_should_fire(vcpu); |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) | 272 | int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) |
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h index a74e4c2bf188..e5966758c093 100644 --- a/include/kvm/arm_arch_timer.h +++ b/include/kvm/arm_arch_timer.h | |||
| @@ -67,4 +67,6 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu); | |||
| 67 | u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid); | 67 | u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid); |
| 68 | int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value); | 68 | int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value); |
| 69 | 69 | ||
| 70 | bool kvm_timer_should_fire(struct kvm_vcpu *vcpu); | ||
| 71 | |||
| 70 | #endif | 72 | #endif |
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index 6e54f3542126..98c95f2fcba4 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c | |||
| @@ -85,13 +85,22 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id) | |||
| 85 | return IRQ_HANDLED; | 85 | return IRQ_HANDLED; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | /* | ||
| 89 | * Work function for handling the backup timer that we schedule when a vcpu is | ||
| 90 | * no longer running, but had a timer programmed to fire in the future. | ||
| 91 | */ | ||
| 88 | static void kvm_timer_inject_irq_work(struct work_struct *work) | 92 | static void kvm_timer_inject_irq_work(struct work_struct *work) |
| 89 | { | 93 | { |
| 90 | struct kvm_vcpu *vcpu; | 94 | struct kvm_vcpu *vcpu; |
| 91 | 95 | ||
| 92 | vcpu = container_of(work, struct kvm_vcpu, arch.timer_cpu.expired); | 96 | vcpu = container_of(work, struct kvm_vcpu, arch.timer_cpu.expired); |
| 93 | vcpu->arch.timer_cpu.armed = false; | 97 | vcpu->arch.timer_cpu.armed = false; |
| 94 | kvm_timer_inject_irq(vcpu); | 98 | |
| 99 | /* | ||
| 100 | * If the vcpu is blocked we want to wake it up so that it will see | ||
| 101 | * the timer has expired when entering the guest. | ||
| 102 | */ | ||
| 103 | kvm_vcpu_kick(vcpu); | ||
| 95 | } | 104 | } |
| 96 | 105 | ||
| 97 | static enum hrtimer_restart kvm_timer_expire(struct hrtimer *hrt) | 106 | static enum hrtimer_restart kvm_timer_expire(struct hrtimer *hrt) |
| @@ -102,6 +111,21 @@ static enum hrtimer_restart kvm_timer_expire(struct hrtimer *hrt) | |||
| 102 | return HRTIMER_NORESTART; | 111 | return HRTIMER_NORESTART; |
| 103 | } | 112 | } |
| 104 | 113 | ||
| 114 | bool kvm_timer_should_fire(struct kvm_vcpu *vcpu) | ||
| 115 | { | ||
| 116 | struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; | ||
| 117 | cycle_t cval, now; | ||
| 118 | |||
| 119 | if ((timer->cntv_ctl & ARCH_TIMER_CTRL_IT_MASK) || | ||
| 120 | !(timer->cntv_ctl & ARCH_TIMER_CTRL_ENABLE)) | ||
| 121 | return false; | ||
| 122 | |||
| 123 | cval = timer->cntv_cval; | ||
| 124 | now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff; | ||
| 125 | |||
| 126 | return cval <= now; | ||
| 127 | } | ||
| 128 | |||
| 105 | /** | 129 | /** |
| 106 | * kvm_timer_flush_hwstate - prepare to move the virt timer to the cpu | 130 | * kvm_timer_flush_hwstate - prepare to move the virt timer to the cpu |
| 107 | * @vcpu: The vcpu pointer | 131 | * @vcpu: The vcpu pointer |
| @@ -119,6 +143,13 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu) | |||
| 119 | * populate the CPU timer again. | 143 | * populate the CPU timer again. |
| 120 | */ | 144 | */ |
| 121 | timer_disarm(timer); | 145 | timer_disarm(timer); |
| 146 | |||
| 147 | /* | ||
| 148 | * If the timer expired while we were not scheduled, now is the time | ||
| 149 | * to inject it. | ||
| 150 | */ | ||
| 151 | if (kvm_timer_should_fire(vcpu)) | ||
| 152 | kvm_timer_inject_irq(vcpu); | ||
| 122 | } | 153 | } |
| 123 | 154 | ||
| 124 | /** | 155 | /** |
| @@ -134,16 +165,9 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu) | |||
| 134 | cycle_t cval, now; | 165 | cycle_t cval, now; |
| 135 | u64 ns; | 166 | u64 ns; |
| 136 | 167 | ||
| 137 | if ((timer->cntv_ctl & ARCH_TIMER_CTRL_IT_MASK) || | ||
| 138 | !(timer->cntv_ctl & ARCH_TIMER_CTRL_ENABLE)) | ||
| 139 | return; | ||
| 140 | |||
| 141 | cval = timer->cntv_cval; | ||
| 142 | now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff; | ||
| 143 | |||
| 144 | BUG_ON(timer_is_armed(timer)); | 168 | BUG_ON(timer_is_armed(timer)); |
| 145 | 169 | ||
| 146 | if (cval <= now) { | 170 | if (kvm_timer_should_fire(vcpu)) { |
| 147 | /* | 171 | /* |
| 148 | * Timer has already expired while we were not | 172 | * Timer has already expired while we were not |
| 149 | * looking. Inject the interrupt and carry on. | 173 | * looking. Inject the interrupt and carry on. |
| @@ -152,6 +176,9 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu) | |||
| 152 | return; | 176 | return; |
| 153 | } | 177 | } |
| 154 | 178 | ||
| 179 | cval = timer->cntv_cval; | ||
| 180 | now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff; | ||
| 181 | |||
| 155 | ns = cyclecounter_cyc2ns(timecounter->cc, cval - now, timecounter->mask, | 182 | ns = cyclecounter_cyc2ns(timecounter->cc, cval - now, timecounter->mask, |
| 156 | &timecounter->frac); | 183 | &timecounter->frac); |
| 157 | timer_arm(timer, ns); | 184 | timer_arm(timer, ns); |
