@@ -132,6 +132,29 @@ void kvm_rtc_irq_restore(struct kvm_vcpu *vcpu)
spin_unlock(&ioapic->lock);
}
+static void rtc_irq_ack_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu,
+ int irq)
+{
+ if (irq != RTC_GSI)
+ return;
+
+ if (test_and_clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map))
+ --ioapic->rtc_status.pending_eoi;
+
+ WARN_ON(ioapic->rtc_status.pending_eoi < 0);
+}
+
+static bool rtc_irq_check(struct kvm_ioapic *ioapic, int irq, bool line_status)
+{
+ if (irq != RTC_GSI || !line_status)
+ return false;
+
+ if (ioapic->rtc_status.pending_eoi > 0)
+ return true; /* coalesced */
+
+ return false;
+}
+
static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx,
bool line_status)
{
@@ -248,6 +271,7 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq, bool line_status)
{
union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
struct kvm_lapic_irq irqe;
+ int ret;
ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
"vector=%x trig_mode=%x\n",
@@ -263,7 +287,14 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq, bool line_status)
irqe.level = 1;
irqe.shorthand = 0;
- return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, NULL);
+ if (irq == RTC_GSI && line_status) {
+ ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe,
+ ioapic->rtc_status.dest_map);
+ ioapic->rtc_status.pending_eoi = ret;
+ } else
+ ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, NULL);
+
+ return ret;
}
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
@@ -287,6 +318,11 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
ret = 1;
} else {
int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG);
+
+ if (rtc_irq_check(ioapic, irq, line_status)) {
+ ret = 0; /* coalesced */
+ goto out;
+ }
ioapic->irr |= mask;
if ((edge && old_irr != ioapic->irr) ||
(!edge && !entry.fields.remote_irr))
@@ -294,6 +330,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
else
ret = 0; /* report coalesced interrupt */
}
+out:
trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0);
spin_unlock(&ioapic->lock);
@@ -321,6 +358,7 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
if (ent->fields.vector != vector)
continue;
+ rtc_irq_ack_eoi(ioapic, vcpu, i);
/*
* We are dropping lock while calling ack notifiers because ack
* notifier callbacks for assigned devices call into IOAPIC