diff options
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/arm/arch_timer.c | 45 |
1 files changed, 36 insertions, 9 deletions
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); |