aboutsummaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorChristoffer Dall <christoffer.dall@arm.com>2019-01-04 07:31:22 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2019-02-19 16:05:43 -0500
commitbee038a67487598ebbe995f85bf60c3a5b2e9099 (patch)
treec0756ab3d7bc4822adff585a482c940135f4db6e /virt
parent9e01dc76be6a3b5768cb02130d2ff0055a68809a (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.c295
-rw-r--r--virt/kvm/arm/trace.h105
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
71static 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
71static inline bool userspace_irqchip(struct kvm *kvm) 86static 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
137static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx) 155static 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 */
147static u64 kvm_timer_earliest_exp(struct kvm_vcpu *vcpu) 167static 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
166static enum hrtimer_restart kvm_bg_timer_expire(struct hrtimer *hrt) 187static 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
190static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt) 211static 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
214static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx) 237static 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
250bool kvm_timer_is_pending(struct kvm_vcpu *vcpu) 279bool 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. */ 326static void timer_emulate(struct arch_timer_context *ctx)
298static void phys_timer_emulate(struct kvm_vcpu *vcpu)
299{ 327{
300 struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);