aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm/ioapic.c
diff options
context:
space:
mode:
Diffstat (limited to 'virt/kvm/ioapic.c')
-rw-r--r--virt/kvm/ioapic.c36
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
150static 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
158static 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
150static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx, 166static 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
281int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id, 306int 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 }
340out:
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