diff mbox series

[v3,2/6] x86/vioapic: issue EOI to dpci when switching pin to edge trigger mode

Message ID 20210126134521.25784-3-roger.pau@citrix.com (mailing list archive)
State New
Headers show
Series x86/intr: HVM guest interrupt handling fixes/cleanup | expand

Commit Message

Roger Pau Monné Jan. 26, 2021, 1:45 p.m. UTC
When an IO-APIC pin is switched from level to edge trigger mode the
IRR bit is cleared, so it can be used as a way to EOI an interrupt at
the IO-APIC level.

Such EOI however does not get forwarded to the dpci code like it's
done for the local APIC initiated EOI. This change adds the code in
order to notify dpci of such EOI, so that dpci and the interrupt
controller are in sync.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Changes since v2:
 - Fix comment message missing 'edge'.
 - Add asserts that previous triggering mode was level and it's not a
   top word write.
---
 xen/arch/x86/hvm/vioapic.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

Comments

Jan Beulich Jan. 26, 2021, 3:25 p.m. UTC | #1
On 26.01.2021 14:45, Roger Pau Monne wrote:
> When an IO-APIC pin is switched from level to edge trigger mode the
> IRR bit is cleared, so it can be used as a way to EOI an interrupt at
> the IO-APIC level.
> 
> Such EOI however does not get forwarded to the dpci code like it's
> done for the local APIC initiated EOI. This change adds the code in
> order to notify dpci of such EOI, so that dpci and the interrupt
> controller are in sync.
> 
> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>

Reviewed-by: Jan Beulich <jbeulich@suse.com>
diff mbox series

Patch

diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c
index e3ee747b7d..87370dd417 100644
--- a/xen/arch/x86/hvm/vioapic.c
+++ b/xen/arch/x86/hvm/vioapic.c
@@ -219,6 +219,7 @@  static void vioapic_write_redirent(
     struct domain *d = vioapic_domain(vioapic);
     struct hvm_irq *hvm_irq = hvm_domain_irq(d);
     union vioapic_redir_entry *pent, ent;
+    bool prev_level;
     int unmasked = 0;
     unsigned int gsi;
 
@@ -234,6 +235,7 @@  static void vioapic_write_redirent(
 
     pent = &vioapic->redirtbl[idx];
     ent  = *pent;
+    prev_level = ent.fields.trig_mode == VIOAPIC_LEVEL_TRIG;
 
     if ( top_word )
     {
@@ -270,6 +272,21 @@  static void vioapic_write_redirent(
 
     spin_unlock(&d->arch.hvm.irq_lock);
 
+    if ( ent.fields.trig_mode == VIOAPIC_EDGE_TRIG &&
+         ent.fields.remote_irr && is_iommu_enabled(d) )
+    {
+            /*
+             * Since IRR has been cleared and further interrupts can be
+             * injected also attempt to deassert any virtual line of passed
+             * through devices using this pin. Switching a pin from level to
+             * edge trigger mode can be used as a way to EOI an interrupt at
+             * the IO-APIC level.
+             */
+            ASSERT(prev_level);
+            ASSERT(!top_word);
+            hvm_dpci_eoi(d, gsi);
+    }
+
     if ( is_hardware_domain(d) && unmasked )
     {
         /*