diff options
| -rw-r--r-- | include/kvm/arm_arch_timer.h | 23 | ||||
| -rw-r--r-- | virt/kvm/arm/arch_timer.c | 295 | ||||
| -rw-r--r-- | virt/kvm/arm/trace.h | 105 |
3 files changed, 278 insertions, 145 deletions
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h index 6d4a33a9c45a..05a18dd265b5 100644 --- a/include/kvm/arm_arch_timer.h +++ b/include/kvm/arm_arch_timer.h | |||
| @@ -51,11 +51,24 @@ struct arch_timer_context { | |||
| 51 | /* Emulated Timer (may be unused) */ | 51 | /* Emulated Timer (may be unused) */ |
| 52 | struct hrtimer hrtimer; | 52 | struct hrtimer hrtimer; |
| 53 | 53 | ||
| 54 | /* | ||
| 55 | * We have multiple paths which can save/restore the timer state onto | ||
| 56 | * the hardware, so we need some way of keeping track of where the | ||
| 57 | * latest state is. | ||
| 58 | */ | ||
| 59 | bool loaded; | ||
| 60 | |||
| 54 | /* Duplicated state from arch_timer.c for convenience */ | 61 | /* Duplicated state from arch_timer.c for convenience */ |
| 55 | u32 host_timer_irq; | 62 | u32 host_timer_irq; |
| 56 | u32 host_timer_irq_flags; | 63 | u32 host_timer_irq_flags; |
| 57 | }; | 64 | }; |
| 58 | 65 | ||
| 66 | struct timer_map { | ||
| 67 | struct arch_timer_context *direct_vtimer; | ||
| 68 | struct arch_timer_context *direct_ptimer; | ||
| 69 | struct arch_timer_context *emul_ptimer; | ||
| 70 | }; | ||
| 71 | |||
| 59 | struct arch_timer_cpu { | 72 | struct arch_timer_cpu { |
| 60 | struct arch_timer_context timers[NR_KVM_TIMERS]; | 73 | struct arch_timer_context timers[NR_KVM_TIMERS]; |
| 61 | 74 | ||
| @@ -64,16 +77,6 @@ struct arch_timer_cpu { | |||
| 64 | 77 | ||
| 65 | /* Is the timer enabled */ | 78 | /* Is the timer enabled */ |
| 66 | bool enabled; | 79 | bool enabled; |
| 67 | |||
| 68 | /* | ||
| 69 | * We have multiple paths which can save/restore the timer state | ||
| 70 | * onto the hardware, so we need some way of keeping track of | ||
| 71 | * where the latest state is. | ||
| 72 | * | ||
| 73 | * loaded == true: State is loaded on the hardware registers. | ||
| 74 | * loaded == false: State is stored in memory. | ||
| 75 | */ | ||
| 76 | bool loaded; | ||
| 77 | }; | 80 | }; |
| 78 | 81 | ||
| 79 | int kvm_timer_hyp_init(bool); | 82 | int kvm_timer_hyp_init(bool); |
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; |
