diff options
| author | Christoffer Dall <christoffer.dall@arm.com> | 2019-01-04 07:31:22 -0500 |
|---|---|---|
| committer | Marc Zyngier <marc.zyngier@arm.com> | 2019-02-19 16:05:43 -0500 |
| commit | bee038a67487598ebbe995f85bf60c3a5b2e9099 (patch) | |
| tree | c0756ab3d7bc4822adff585a482c940135f4db6e /virt | |
| parent | 9e01dc76be6a3b5768cb02130d2ff0055a68809a (diff) | |
KVM: arm/arm64: Rework the timer code to use a timer_map
We are currently emulating two timers in two different ways. When we
add support for nested virtualization in the future, we are going to be
emulating either two timers in two diffferent ways, or four timers in a
single way.
We need a unified data structure to keep track of how we map virtual
state to physical state and we need to cleanup some of the timer code to
operate more independently on a struct arch_timer_context instead of
trying to consider the global state of the VCPU and recomputing all
state.
Co-written with Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
Diffstat (limited to 'virt')
| -rw-r--r-- | virt/kvm/arm/arch_timer.c | 295 | ||||
| -rw-r--r-- | virt/kvm/arm/trace.h | 105 |
2 files changed, 265 insertions, 135 deletions
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index 10c15151c87e..17f9de73cc8a 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c | |||
| @@ -68,6 +68,21 @@ u64 kvm_phys_timer_read(void) | |||
| 68 | return timecounter->cc->read(timecounter->cc); | 68 | return timecounter->cc->read(timecounter->cc); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | static void get_timer_map(struct kvm_vcpu *vcpu, struct timer_map *map) | ||
| 72 | { | ||
| 73 | if (has_vhe()) { | ||
| 74 | map->direct_vtimer = vcpu_vtimer(vcpu); | ||
| 75 | map->direct_ptimer = vcpu_ptimer(vcpu); | ||
| 76 | map->emul_ptimer = NULL; | ||
| 77 | } else { | ||
| 78 | map->direct_vtimer = vcpu_vtimer(vcpu); | ||
| 79 | map->direct_ptimer = NULL; | ||
| 80 | map->emul_ptimer = vcpu_ptimer(vcpu); | ||
| 81 | } | ||
| 82 | |||
| 83 | trace_kvm_get_timer_map(vcpu->vcpu_id, map); | ||
| 84 | } | ||
| 85 | |||
| 71 | static inline bool userspace_irqchip(struct kvm *kvm) | 86 | static inline bool userspace_irqchip(struct kvm *kvm) |
| 72 | { | 87 | { |
| 73 | return static_branch_unlikely(&userspace_irqchip_in_use) && | 88 | return static_branch_unlikely(&userspace_irqchip_in_use) && |
| @@ -89,6 +104,7 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id) | |||
| 89 | { | 104 | { |
| 90 | struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id; | 105 | struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id; |
| 91 | struct arch_timer_context *ctx; | 106 | struct arch_timer_context *ctx; |
| 107 | struct timer_map map; | ||
| 92 | 108 | ||
| 93 | /* | 109 | /* |
| 94 | * We may see a timer interrupt after vcpu_put() has been called which | 110 | * We may see a timer interrupt after vcpu_put() has been called which |
| @@ -99,10 +115,12 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id) | |||
| 99 | if (!vcpu) | 115 | if (!vcpu) |
| 100 | return IRQ_HANDLED; | 116 | return IRQ_HANDLED; |
| 101 | 117 | ||
| 118 | get_timer_map(vcpu, &map); | ||
| 119 | |||
| 102 | if (irq == host_vtimer_irq) | 120 | if (irq == host_vtimer_irq) |
| 103 | ctx = vcpu_vtimer(vcpu); | 121 | ctx = map.direct_vtimer; |
| 104 | else | 122 | else |
| 105 | ctx = vcpu_ptimer(vcpu); | 123 | ctx = map.direct_ptimer; |
| 106 | 124 | ||
| 107 | if (kvm_timer_should_fire(ctx)) | 125 | if (kvm_timer_should_fire(ctx)) |
| 108 | kvm_timer_update_irq(vcpu, true, ctx); | 126 | kvm_timer_update_irq(vcpu, true, ctx); |
| @@ -136,7 +154,9 @@ static u64 kvm_timer_compute_delta(struct arch_timer_context *timer_ctx) | |||
| 136 | 154 | ||
| 137 | static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx) | 155 | static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx) |
| 138 | { | 156 | { |
| 139 | return !(timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_IT_MASK) && | 157 | WARN_ON(timer_ctx && timer_ctx->loaded); |
| 158 | return timer_ctx && | ||
| 159 | !(timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_IT_MASK) && | ||
| 140 | (timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_ENABLE); | 160 | (timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_ENABLE); |
| 141 | } | 161 | } |
| 142 | 162 | ||
| @@ -146,21 +166,22 @@ static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx) | |||
| 146 | */ | 166 | */ |
| 147 | static u64 kvm_timer_earliest_exp(struct kvm_vcpu *vcpu) | 167 | static u64 kvm_timer_earliest_exp(struct kvm_vcpu *vcpu) |
| 148 | { | 168 | { |
| 149 | u64 min_virt = ULLONG_MAX, min_phys = ULLONG_MAX; | 169 | u64 min_delta = ULLONG_MAX; |
| 150 | struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); | 170 | int i; |
| 151 | struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); | ||
| 152 | 171 | ||
| 153 | if (kvm_timer_irq_can_fire(vtimer)) | 172 | for (i = 0; i < NR_KVM_TIMERS; i++) { |
| 154 | min_virt = kvm_timer_compute_delta(vtimer); | 173 | struct arch_timer_context *ctx = &vcpu->arch.timer_cpu.timers[i]; |
| 155 | 174 | ||
| 156 | if (kvm_timer_irq_can_fire(ptimer)) | 175 | WARN(ctx->loaded, "timer %d loaded\n", i); |
| 157 | min_phys = kvm_timer_compute_delta(ptimer); | 176 | if (kvm_timer_irq_can_fire(ctx)) |
| 177 | min_delta = min(min_delta, kvm_timer_compute_delta(ctx)); | ||
| 178 | } | ||
| 158 | 179 | ||
| 159 | /* If none of timers can fire, then return 0 */ | 180 | /* If none of timers can fire, then return 0 */ |
| 160 | if ((min_virt == ULLONG_MAX) && (min_phys == ULLONG_MAX)) | 181 | if (min_delta == ULLONG_MAX) |
| 161 | return 0; | 182 | return 0; |
| 162 | 183 | ||
| 163 | return min(min_virt, min_phys); | 184 | return min_delta; |
| 164 | } | 185 | } |
| 165 | 186 | ||
| 166 | static enum hrtimer_restart kvm_bg_timer_expire(struct hrtimer *hrt) | 187 | static enum hrtimer_restart kvm_bg_timer_expire(struct hrtimer *hrt) |
| @@ -187,37 +208,45 @@ static enum hrtimer_restart kvm_bg_timer_expire(struct hrtimer *hrt) | |||
| 187 | return HRTIMER_NORESTART; | 208 | return HRTIMER_NORESTART; |
| 188 | } | 209 | } |
| 189 | 210 | ||
| 190 | static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt) | 211 | static enum hrtimer_restart kvm_hrtimer_expire(struct hrtimer *hrt) |
| 191 | { | 212 | { |
| 192 | struct arch_timer_context *ptimer; | 213 | struct arch_timer_context *ctx; |
| 193 | struct kvm_vcpu *vcpu; | 214 | struct kvm_vcpu *vcpu; |
| 194 | u64 ns; | 215 | u64 ns; |
| 195 | 216 | ||
| 196 | ptimer = container_of(hrt, struct arch_timer_context, hrtimer); | 217 | ctx = container_of(hrt, struct arch_timer_context, hrtimer); |
| 197 | vcpu = ptimer->vcpu; | 218 | vcpu = ctx->vcpu; |
| 219 | |||
| 220 | trace_kvm_timer_hrtimer_expire(ctx); | ||
| 198 | 221 | ||
| 199 | /* | 222 | /* |
| 200 | * Check that the timer has really expired from the guest's | 223 | * Check that the timer has really expired from the guest's |
| 201 | * PoV (NTP on the host may have forced it to expire | 224 | * PoV (NTP on the host may have forced it to expire |
| 202 | * early). If not ready, schedule for a later time. | 225 | * early). If not ready, schedule for a later time. |
| 203 | */ | 226 | */ |
| 204 | ns = kvm_timer_compute_delta(ptimer); | 227 | ns = kvm_timer_compute_delta(ctx); |
| 205 | if (unlikely(ns)) { | 228 | if (unlikely(ns)) { |
| 206 | hrtimer_forward_now(hrt, ns_to_ktime(ns)); | 229 | hrtimer_forward_now(hrt, ns_to_ktime(ns)); |
| 207 | return HRTIMER_RESTART; | 230 | return HRTIMER_RESTART; |
| 208 | } | 231 | } |
| 209 | 232 | ||
| 210 | kvm_timer_update_irq(vcpu, true, ptimer); | 233 | kvm_timer_update_irq(vcpu, true, ctx); |
| 211 | return HRTIMER_NORESTART; | 234 | return HRTIMER_NORESTART; |
| 212 | } | 235 | } |
| 213 | 236 | ||
| 214 | static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx) | 237 | static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx) |
| 215 | { | 238 | { |
| 216 | struct arch_timer_cpu *timer = vcpu_timer(timer_ctx->vcpu); | 239 | struct arch_timer_cpu *timer; |
| 217 | enum kvm_arch_timers index = arch_timer_ctx_index(timer_ctx); | 240 | enum kvm_arch_timers index; |
| 218 | u64 cval, now; | 241 | u64 cval, now; |
| 219 | 242 | ||
| 220 | if (timer->loaded) { | 243 | if (!timer_ctx) |
| 244 | return false; | ||
| 245 | |||
| 246 | timer = vcpu_timer(timer_ctx->vcpu); | ||
| 247 | index = arch_timer_ctx_index(timer_ctx); | ||
| 248 | |||
| 249 | if (timer_ctx->loaded) { | ||
| 221 | u32 cnt_ctl = 0; | 250 | u32 cnt_ctl = 0; |
| 222 | 251 | ||
| 223 | switch (index) { | 252 | switch (index) { |
| @@ -249,13 +278,13 @@ static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx) | |||
| 249 | 278 | ||
| 250 | bool kvm_timer_is_pending(struct kvm_vcpu *vcpu) | 279 | bool kvm_timer_is_pending(struct kvm_vcpu *vcpu) |
| 251 | { | 280 | { |
| 252 | struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); | 281 | struct timer_map map; |
| 253 | struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); | ||
| 254 | 282 | ||
| 255 | if (kvm_timer_should_fire(vtimer)) | 283 | get_timer_map(vcpu, &map); |
| 256 | return true; | ||
| 257 | 284 | ||
| 258 | return kvm_timer_should_fire(ptimer); | 285 | return kvm_timer_should_fire(map.direct_vtimer) || |
| 286 | kvm_timer_should_fire(map.direct_ptimer) || | ||
| 287 | kvm_timer_should_fire(map.emul_ptimer); | ||
| 259 | } | 288 | } |
| 260 | 289 | ||
| 261 | /* | 290 | /* |
| @@ -294,60 +323,28 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level, | |||
| 294 | } | 323 | } |
| 295 | } | 324 | } |
| 296 | 325 | ||
| 297 | /* Schedule the background timer for the emulated timer. */ | 326 | static void timer_emulate(struct arch_timer_context *ctx) |
| 298 | static void phys_timer_emulate(struct kvm_vcpu *vcpu) | ||
| 299 | { | 327 | { |
| 300 | struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); | ||
