aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/kvm/arm_arch_timer.h23
-rw-r--r--virt/kvm/arm/arch_timer.c295
-rw-r--r--virt/kvm/arm/trace.h105
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
66struct 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
59struct arch_timer_cpu { 72struct 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
79int kvm_timer_hyp_init(bool); 82int 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
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_sho