diff options
Diffstat (limited to 'virt/kvm/ioapic.c')
-rw-r--r-- | virt/kvm/ioapic.c | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index a49fcd55b378..97c67a50f904 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c | |||
@@ -147,6 +147,22 @@ static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic) | |||
147 | __rtc_irq_eoi_tracking_restore_one(vcpu); | 147 | __rtc_irq_eoi_tracking_restore_one(vcpu); |
148 | } | 148 | } |
149 | 149 | ||
150 | static void rtc_irq_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu) | ||
151 | { | ||
152 | if (test_and_clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map)) | ||
153 | --ioapic->rtc_status.pending_eoi; | ||
154 | |||
155 | WARN_ON(ioapic->rtc_status.pending_eoi < 0); | ||
156 | } | ||
157 | |||
158 | static bool rtc_irq_check_coalesced(struct kvm_ioapic *ioapic) | ||
159 | { | ||
160 | if (ioapic->rtc_status.pending_eoi > 0) | ||
161 | return true; /* coalesced */ | ||
162 | |||
163 | return false; | ||
164 | } | ||
165 | |||
150 | static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx, | 166 | static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx, |
151 | bool line_status) | 167 | bool line_status) |
152 | { | 168 | { |
@@ -260,6 +276,7 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq, bool line_status) | |||
260 | { | 276 | { |
261 | union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq]; | 277 | union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq]; |
262 | struct kvm_lapic_irq irqe; | 278 | struct kvm_lapic_irq irqe; |
279 | int ret; | ||
263 | 280 | ||
264 | ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " | 281 | ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " |
265 | "vector=%x trig_mode=%x\n", | 282 | "vector=%x trig_mode=%x\n", |
@@ -275,7 +292,15 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq, bool line_status) | |||
275 | irqe.level = 1; | 292 | irqe.level = 1; |
276 | irqe.shorthand = 0; | 293 | irqe.shorthand = 0; |
277 | 294 | ||
278 | return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, NULL); | 295 | if (irq == RTC_GSI && line_status) { |
296 | BUG_ON(ioapic->rtc_status.pending_eoi != 0); | ||
297 | ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, | ||
298 | ioapic->rtc_status.dest_map); | ||
299 | ioapic->rtc_status.pending_eoi = ret; | ||
300 | } else | ||
301 | ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, NULL); | ||
302 | |||
303 | return ret; | ||
279 | } | 304 | } |
280 | 305 | ||
281 | int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id, | 306 | int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id, |
@@ -299,6 +324,12 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id, | |||
299 | ret = 1; | 324 | ret = 1; |
300 | } else { | 325 | } else { |
301 | int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); | 326 | int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); |
327 | |||
328 | if (irq == RTC_GSI && line_status && | ||
329 | rtc_irq_check_coalesced(ioapic)) { | ||
330 | ret = 0; /* coalesced */ | ||
331 | goto out; | ||
332 | } | ||
302 | ioapic->irr |= mask; | 333 | ioapic->irr |= mask; |
303 | if ((edge && old_irr != ioapic->irr) || | 334 | if ((edge && old_irr != ioapic->irr) || |
304 | (!edge && !entry.fields.remote_irr)) | 335 | (!edge && !entry.fields.remote_irr)) |
@@ -306,6 +337,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id, | |||
306 | else | 337 | else |
307 | ret = 0; /* report coalesced interrupt */ | 338 | ret = 0; /* report coalesced interrupt */ |
308 | } | 339 | } |
340 | out: | ||
309 | trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0); | 341 | trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0); |
310 | spin_unlock(&ioapic->lock); | 342 | spin_unlock(&ioapic->lock); |
311 | 343 | ||
@@ -333,6 +365,8 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, | |||
333 | if (ent->fields.vector != vector) | 365 | if (ent->fields.vector != vector) |
334 | continue; | 366 | continue; |
335 | 367 | ||
368 | if (i == RTC_GSI) | ||
369 | rtc_irq_eoi(ioapic, vcpu); | ||
336 | /* | 370 | /* |
337 | * We are dropping lock while calling ack notifiers because ack | 371 | * We are dropping lock while calling ack notifiers because ack |
338 | * notifier callbacks for assigned devices call into IOAPIC | 372 | * notifier callbacks for assigned devices call into IOAPIC |