aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm/arm/arch_timer.c
diff options
context:
space:
mode:
authorChristoffer Dall <christoffer.dall@linaro.org>2015-08-30 09:01:27 -0400
committerChristoffer Dall <christoffer.dall@linaro.org>2015-10-22 17:01:44 -0400
commit4b4b4512da2a844b8da2585609b67fae1ce4f4db (patch)
tree6b5560b0c7d867a9c23f5aedcda5a8579a488803 /virt/kvm/arm/arch_timer.c
parent4cf1bc4c7cbf35983e565ab491142af59f03bb22 (diff)
arm/arm64: KVM: Rework the arch timer to use level-triggered semantics
The arch timer currently uses edge-triggered semantics in the sense that the line is never sampled by the vgic and lowering the line from the timer to the vgic doesn't have any effect on the pending state of virtual interrupts in the vgic. This means that we do not support a guest with the otherwise valid behavior of (1) disable interrupts (2) enable the timer (3) disable the timer (4) enable interrupts. Such a guest would validly not expect to see any interrupts on real hardware, but will see interrupts on KVM. This patch fixes this shortcoming through the following series of changes. First, we change the flow of the timer/vgic sync/flush operations. Now the timer is always flushed/synced before the vgic, because the vgic samples the state of the timer output. This has the implication that we move the timer operations in to non-preempible sections, but that is fine after the previous commit getting rid of hrtimer schedules on every entry/exit. Second, we change the internal behavior of the timer, letting the timer keep track of its previous output state, and only lower/raise the line to the vgic when the state changes. Note that in theory this could have been accomplished more simply by signalling the vgic every time the state *potentially* changed, but we don't want to be hitting the vgic more often than necessary. Third, we get rid of the use of the map->active field in the vgic and instead simply set the interrupt as active on the physical distributor whenever the input to the GIC is asserted and conversely clear the physical active state when the input to the GIC is deasserted. Fourth, and finally, we now initialize the timer PPIs (and all the other unused PPIs for now), to be level-triggered, and modify the sync code to sample the line state on HW sync and re-inject a new interrupt if it is still pending at that time. Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'virt/kvm/arm/arch_timer.c')
-rw-r--r--virt/kvm/arm/arch_timer.c81
1 files changed, 56 insertions, 25 deletions
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 32095fbb5d7c..523816d8c402 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -59,18 +59,6 @@ static void timer_disarm(struct arch_timer_cpu *timer)
59 } 59 }
60} 60}
61 61
62static void kvm_timer_inject_irq(struct kvm_vcpu *vcpu)
63{
64 int ret;
65 struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
66
67 kvm_vgic_set_phys_irq_active(timer->map, true);
68 ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
69 timer->map,
70 timer->irq->level);
71 WARN_ON(ret);
72}
73
74static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id) 62static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
75{ 63{
76 struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id; 64 struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id;
@@ -116,8 +104,7 @@ static bool kvm_timer_irq_can_fire(struct kvm_vcpu *vcpu)
116 struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; 104 struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
117 105
118 return !(timer->cntv_ctl & ARCH_TIMER_CTRL_IT_MASK) && 106 return !(timer->cntv_ctl & ARCH_TIMER_CTRL_IT_MASK) &&
119 (timer->cntv_ctl & ARCH_TIMER_CTRL_ENABLE) && 107 (timer->cntv_ctl & ARCH_TIMER_CTRL_ENABLE);
120 !kvm_vgic_get_phys_irq_active(timer->map);
121} 108}
122 109
123bool kvm_timer_should_fire(struct kvm_vcpu *vcpu) 110bool kvm_timer_should_fire(struct kvm_vcpu *vcpu)
@@ -134,6 +121,41 @@ bool kvm_timer_should_fire(struct kvm_vcpu *vcpu)
134 return cval <= now; 121 return cval <= now;
135} 122}
136 123
124static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
125{
126 int ret;
127 struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
128
129 BUG_ON(!vgic_initialized(vcpu->kvm));
130
131 timer->irq.level = new_level;
132 ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
133 timer->map,
134 timer->irq.level);
135 WARN_ON(ret);
136}
137
138/*
139 * Check if there was a change in the timer state (should we raise or lower
140 * the line level to the GIC).
141 */
142static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
143{
144 struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
145
146 /*
147 * If userspace modified the timer registers via SET_ONE_REG before
148 * the vgic was initialized, we mustn't set the timer->irq.level value
149 * because the guest would never see the interrupt. Instead wait
150 * until we call this function from kvm_timer_flush_hwstate.
151 */
152 if (!vgic_initialized(vcpu->kvm))
153 return;
154
155 if (kvm_timer_should_fire(vcpu) != timer->irq.level)
156 kvm_timer_update_irq(vcpu, !timer->irq.level);
157}
158
137/* 159/*
138 * Schedule the background timer before calling kvm_vcpu_block, so that this 160 * Schedule the background timer before calling kvm_vcpu_block, so that this
139 * thread is removed from its waitqueue and made runnable when there's a timer 161 * thread is removed from its waitqueue and made runnable when there's a timer
@@ -192,17 +214,20 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
192 bool phys_active; 214 bool phys_active;
193 int ret; 215 int ret;
194 216
195 if (kvm_timer_should_fire(vcpu)) 217 kvm_timer_update_state(vcpu);
196 kvm_timer_inject_irq(vcpu);
197 218
198 /* 219 /*
199 * We keep track of whether the edge-triggered interrupt has been 220 * If we enter the guest with the virtual input level to the VGIC
200 * signalled to the vgic/guest, and if so, we mask the interrupt and 221 * asserted, then we have already told the VGIC what we need to, and
201 * the physical distributor to prevent the timer from raising a 222 * we don't need to exit from the guest until the guest deactivates
202 * physical interrupt whenever we run a guest, preventing forward 223 * the already injected interrupt, so therefore we should set the
203 * VCPU progress. 224 * hardware active state to prevent unnecessary exits from the guest.
225 *
226 * Conversely, if the virtual input level is deasserted, then always
227 * clear the hardware active state to ensure that hardware interrupts
228 * from the timer triggers a guest exit.
204 */ 229 */
205 if (kvm_vgic_get_phys_irq_active(timer->map)) 230 if (timer->irq.level)
206 phys_active = true; 231 phys_active = true;
207 else 232 else
208 phys_active = false; 233 phys_active = false;
@@ -226,8 +251,11 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
226 251
227 BUG_ON(timer_is_armed(timer)); 252 BUG_ON(timer_is_armed(timer));
228 253
229 if (kvm_timer_should_fire(vcpu)) 254 /*
230 kvm_timer_inject_irq(vcpu); 255 * The guest could have modified the timer registers or the timer
256 * could have expired, update the timer state.
257 */
258 kvm_timer_update_state(vcpu);
231} 259}
232 260
233int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, 261int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
@@ -242,7 +270,7 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
242 * kvm_vcpu_set_target(). To handle this, we determine 270 * kvm_vcpu_set_target(). To handle this, we determine
243 * vcpu timer irq number when the vcpu is reset. 271 * vcpu timer irq number when the vcpu is reset.
244 */ 272 */
245 timer->irq = irq; 273 timer->irq.irq = irq->irq;
246 274
247 /* 275 /*
248 * The bits in CNTV_CTL are architecturally reset to UNKNOWN for ARMv8 276 * The bits in CNTV_CTL are architecturally reset to UNKNOWN for ARMv8
@@ -251,6 +279,7 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
251 * the ARMv7 architecture. 279 * the ARMv7 architecture.
252 */ 280 */
253 timer->cntv_ctl = 0; 281 timer->cntv_ctl = 0;
282 kvm_timer_update_state(vcpu);
254 283
255 /* 284 /*
256 * Tell the VGIC that the virtual interrupt is tied to a 285 * Tell the VGIC that the virtual interrupt is tied to a
@@ -295,6 +324,8 @@ int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
295 default: 324 default:
296 return -1; 325 return -1;
297 } 326 }
327
328 kvm_timer_update_state(vcpu);
298 return 0; 329 return 0;
299} 330}
300 331