[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v8 21/26] emul/ns16x50: implement IRQ emulation via vIOAPIC


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: dmukhin@xxxxxxxx
  • Date: Wed, 11 Nov 2026 11:47:55 -0800
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 148.163.138.245) smtp.rcpttodomain=lists.xenproject.org smtp.mailfrom=ford.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=ford.com; dkim=pass (signature was verified) header.d=saarlouis.ford.com; dkim=pass (signature was verified) header.d=ford.com; arc=none (0)
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=3x1ONJUanBGvzivg5LMO4ZoRVWTSyHrt3t7m5UtrGIM=; b=LGp3mKe9Pu0u477LVFPPAnnL48z4MMNfiZIZ3JJ1Qh/355K8udRJDskt/dUSbVaVDqSZTQstaYYFqAH6QhQaCoTfAxVMOan4tF0ZgKMveBb8xUyRXhjhsqut1fmnNx5pKVf8wMYzrRj8+x5tgEK/gzey8V3BBPFJM8bFFjEoaJvuwEpnslBgX+bkQezM8B0G6/3YPbt7eiElkAtKj1pha4J86NSt0Z+HnNXzdm37woPdUavmp2szcbYvKxLbGG+fSV+xY/YEmO0nbeEqXDQQrm1Ks9LaAMyxfOYN8kZjf1NzQCZTp773noGAeRqmCCRZvypgugbGCOerudmNeXx1fg==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=He7gYk7vZ8m192IlehwucYf4Srktuq4IkTCjp8i0x5VFeGl7VRWCcMi6CYQYg5Fx65eoO/gi+KpuMlyvl7PXhGP9i99zg6pdW2BHFri1mT54DbqFTu9dcgu/v+yThRhN2iW6SfvslwoDYvc53cQUo3LCSuiZcB1jKJbYLFtsRWyTq0+l8WE+qVJi+Vf3AZ2B5hGQjjVJDTk4VGP+SJnXWAcVhUj2RffyBK2Stz20Cz4Wv6rwJOgxSFIJINXWv2wf0v7RzAwZQm94NGG2A59bQoCs5wma30rld8DVDSxVuMr+vok8/3b3/2mdiJ3h+gPFrDm5hj8CHY4obSqNDFzYnQ==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=ppford header.d=ford.com header.i="@ford.com" header.h="Cc:Content-Transfer-Encoding:Content-Type:Date:From:In-Reply-To:Message-ID:MIME-Version:References:Subject:To"; dkim=pass header.s=selector2-azureford-onmicrosoft-com header.d=azureford.onmicrosoft.com header.i="@azureford.onmicrosoft.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"; dkim=pass header.s=ppserprodsaar header.d=saarlouis.ford.com header.i="@saarlouis.ford.com" header.h="Cc:Content-Transfer-Encoding:Date:From:In-Reply-To:Message-ID:MIME-Version:References:Subject:To"; dkim=pass header.s=ppfserpocford header.d=ford.com header.i="@ford.com" header.h="Cc:Content-Transfer-Encoding:Date:From:In-Reply-To:Message-ID:MIME-Version:References:Subject:To"
  • Cc: andrew.cooper3@xxxxxxxxxx, anthony.perard@xxxxxxxxxx, jbeulich@xxxxxxxx, julien@xxxxxxx, michal.orzel@xxxxxxx, roger@xxxxxxxxxxxxxx, sstabellini@xxxxxxxxxx, xakep.amatop@xxxxxxxxx, dmukhin@xxxxxxx, Denis Mukhin <dmukhin@xxxxxxxx>
  • Delivery-date: Wed, 11 Nov 2026 19:49:23 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Pser-m365-app: SER-APP

From: Denis Mukhin <dmukhin@xxxxxxxx>

PVH domains use vIOAPIC, not vPIC and NS16550 emulates ISA IRQs which
cannot be asserted on vIOAPIC.

{map,unmap}_domain_pirq_emuirq() infrastructure is modified by adding
new type of interrupt resources 'IRQ_EMU' which means 'emulated device
IRQ' (similarly to IRQ_MSI_EMU). That relaxes ASSERT() in
map_domain_emuirq_pirq() to account for IRQ_EMU case.

This is necessary to for IOAPIC emulation code to skip IRQ->PIRQ mapping
(vioapic_hwdom_map_gsi()) when guest OS unmasks vIOAPIC pin
corresponding to virtual device's IRQ.

Also, hvm_gsi_eoi() is modified to trigger assertion in
hvm_gsi_deassert() path for ISA IRQs.

Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
 xen/arch/x86/hvm/vioapic.c        | 10 +++++++
 xen/arch/x86/include/asm/irq.h    |  6 ++++
 xen/arch/x86/irq.c                |  2 +-
 xen/common/emul/vuart/ns16x50.c   | 47 +++++++++++++++++++++++++++++++
 xen/drivers/passthrough/x86/hvm.c | 11 +++++++-
 5 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c
index 995fae7b3c0f..03a63c048ea6 100644
--- a/xen/arch/x86/hvm/vioapic.c
+++ b/xen/arch/x86/hvm/vioapic.c
@@ -178,6 +178,16 @@ static int vioapic_hwdom_map_gsi(unsigned int gsi, 
unsigned int trig,
 
     ASSERT(is_hardware_domain(currd));
 
+    /*
+     * Interrupt is claimed by one of the platform virtual devices (e.g.
+     * NS16550); do nothing.
+     */
+    write_lock(&currd->event_lock);
+    ret = is_domain_emuirq_claimed(currd, gsi);
+    write_unlock(&currd->event_lock);
+    if ( ret )
+        return 0;
+
     /* Interrupt has been unmasked, bind it now. */
     ret = mp_register_gsi(gsi, trig, pol);
     if ( ret == -EEXIST )
diff --git a/xen/arch/x86/include/asm/irq.h b/xen/arch/x86/include/asm/irq.h
index d26cb5c1daba..58f32026e033 100644
--- a/xen/arch/x86/include/asm/irq.h
+++ b/xen/arch/x86/include/asm/irq.h
@@ -169,6 +169,11 @@ void free_domain_pirqs(struct domain *d);
 int map_domain_emuirq_pirq(struct domain *d, int pirq, int emuirq);
 int unmap_domain_pirq_emuirq(struct domain *d, int pirq);
 
+#define domain_emuirq_claim(d, irq)     map_domain_emuirq_pirq(d, irq, IRQ_EMU)
+#define domain_emuirq_unclaim(d, irq)   unmap_domain_pirq_emuirq(d, irq)
+#define is_domain_emuirq_claimed(d, irq) \
+    (domain_pirq_to_emuirq(d, irq) != IRQ_UNBOUND)
+
 /* Evacuate interrupts assigned to CPUs not present in the CPU online map. */
 void fixup_irqs(void);
 void fixup_eoi(void);
@@ -222,6 +227,7 @@ void cleanup_domain_irq_mapping(struct domain *d);
 #define IRQ_UNBOUND (-1)
 #define IRQ_PT      (-2)
 #define IRQ_MSI_EMU (-3)
+#define IRQ_EMU     (-4)
 
 bool cpu_has_pending_apic_eoi(void);
 
diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c
index 3fcff671c27f..a1f0f3e05dac 100644
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -2814,7 +2814,7 @@ int map_domain_emuirq_pirq(struct domain *d, int pirq, 
int emuirq)
     if ( !is_hvm_domain(d) )
         return -EINVAL;
 
-    ASSERT(has_pirq(d));
+    ASSERT(has_pirq(d) || emuirq == IRQ_EMU);
 
     if ( pirq < 0 || pirq >= d->nr_pirqs ||
             emuirq == IRQ_UNBOUND || emuirq >= (int) nr_irqs )
diff --git a/xen/common/emul/vuart/ns16x50.c b/xen/common/emul/vuart/ns16x50.c
index 389c58f94198..17691dd2b5eb 100644
--- a/xen/common/emul/vuart/ns16x50.c
+++ b/xen/common/emul/vuart/ns16x50.c
@@ -353,6 +353,14 @@ static void ns16x50_irq_check(struct vuart_ns16x50 *vdev)
         else
             hvm_isa_irq_deassert(d, info->irq);
     }
+    else if ( has_vioapic(d) )
+    {
+        /*
+         * Inject the positive edge only on a low -> high transition.
+         */
+        if ( asserted )
+            hvm_ioapic_assert(d, info->irq, false);
+    }
     else
         ASSERT_UNREACHABLE();
 
@@ -896,6 +904,36 @@ static void ns16x50_reset(struct vuart_ns16x50 *vdev)
     vdev->regs[NS16X50_REGS_NUM + UART_DLM] = (divisor >> 8) & UINT8_MAX;
 }
 
+static int ns16x50_claim_irq(struct vuart_ns16x50 *vdev, unsigned int irq)
+{
+    struct domain *d = vdev->owner;
+    int rc = 0;
+
+    write_lock(&d->event_lock);
+    rc = domain_emuirq_claim(d, irq);
+    write_unlock(&d->event_lock);
+
+    if ( rc )
+        ns16x50_err(vdev, "virtual IRQ#%d: cannot claim: %d\n",
+                    irq, rc);
+
+    return rc;
+}
+
+static void ns16x50_unclaim_irq(struct vuart_ns16x50 *vdev, unsigned int irq)
+{
+    struct domain *d = vdev->owner;
+    int rc = 0;
+
+    write_lock(&d->event_lock);
+    rc = domain_emuirq_unclaim(d, irq);
+    write_unlock(&d->event_lock);
+
+    if ( rc )
+        ns16x50_err(vdev, "virtual IRQ#%d: cannot unclaim: %d\n",
+                    irq, rc);
+}
+
 static int ns16x50_init(void *arg)
 {
     struct vuart_ns16x50 *vdev = arg;
@@ -942,6 +980,11 @@ static int ns16x50_init(void *arg)
         return rc;
     }
 
+    /* Claim virtual IRQ */
+    rc = ns16x50_claim_irq(vdev, info->irq);
+    if ( rc )
+        return rc;
+
     ns16x50_reset(vdev);
 
     ns16x50_irq_check(vdev);
@@ -953,12 +996,16 @@ static void cf_check ns16x50_deinit(void *arg)
 {
     struct vuart_ns16x50 *vdev = arg;
     const struct vuart_info *info;
+    struct domain *d;
     unsigned long flags;
 
     ASSERT(vdev);
 
+    d = vdev->owner;
     info = vdev->info;
 
+    ns16x50_unclaim_irq(vdev, info->irq);
+
     ns16x50_lock(vdev, &flags);
     ns16x50_fifo_tx_flush(vdev);
     ns16x50_unlock(vdev, &flags);
diff --git a/xen/drivers/passthrough/x86/hvm.c 
b/xen/drivers/passthrough/x86/hvm.c
index 9f8e6c8cd50f..e108f2c69a33 100644
--- a/xen/drivers/passthrough/x86/hvm.c
+++ b/xen/drivers/passthrough/x86/hvm.c
@@ -934,7 +934,16 @@ static void __hvm_dpci_eoi(struct domain *d,
 
 static void hvm_gsi_eoi(struct domain *d, unsigned int gsi)
 {
-    struct pirq *pirq = pirq_info(d, gsi);
+    struct pirq *pirq;
+
+    /* Check if GSI is claimed by one of the virtual devices. */
+    if ( is_domain_emuirq_claimed(d, gsi) )
+    {
+        hvm_gsi_deassert(d, gsi);
+        return;
+    }
+
+    pirq = pirq_info(d, gsi);
 
     /* Check if GSI is actually mapped. */
     if ( !pirq_dpci(pirq) )
-- 
2.56.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.