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

[PATCH v5 12/22] xen/arm: vsmmuv3: Add support for event queue and global error


  • To: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Milan Djokic <milan_djokic@xxxxxxxx>
  • Date: Tue, 3 Nov 2026 17:30:32 +0000
  • Accept-language: en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=epam.com; dmarc=pass action=none header.from=epam.com; dkim=pass header.d=epam.com; arc=none
  • 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=sUXhi2FmOcD1qpvabmQIRGtPrND2M2ONfxDnBn4m6VU=; b=XdKgOXV9nYDTo1zzi4afqWpL7ZxgWayQltZCuxevgCACN7TVVqzDzy3/zom6Xc8gRmPi9ibMh4bIIGgmiZ7IV/OONFzlBXv3ruI2wKtQwsG9ajZnywSIX2NfjbxjyZrE5IUnYfmnJFjvNJOr/EOogzzyDT1RmlRtjFS54lLcm/S5n36oxbsTr49AN4MccIpclULxQIoXxamwm9slziXbKOVhOjgrA/tfU/nX/nDas27sv6RF8NY0SCvSDonGG94NceZ0e9cLXYLfRDLI5/5n4a9Hh4JGM7CbVz9Ih21m/lOfSTZnWdZJcNTTz8u9PfIY2675XTuv0FUla88KhB7iFQ==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=JmB0OawuMNHPtDKsb0hox4fYgyDgia5r1xbv+nbknovn6DYPqZ5/HQYqaskOXxADbq5U6SlkzRSUcYfJPJzGu2q+efW9pBsA70xGofkWdGvgGoXpuO3diKeXfPmSELVBMafSdHdYxbzKFVg+OEPT85Vb8K+eJ2Q6e2nRUTdzRnOSFfwYsq4Y5leQcWn0m3vbLU/vINoxcWVFHojAg0zN1FJ9Fo/SFrG6kZOO/kPCzrChGXdp4CR67QPlQnME1i2xbu5Vzs2Jo9KR0DasWDR5KG5F521lPY0th/NA4+op8HqpvoZciGK/E09081flsUCgptRCl20/j3XIPZPElefivQ==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=epam.com header.i="@epam.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:x-ms-exchange-senderadcheck"
  • Authentication-results: mx.microsoft.com 1; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=epam.com;
  • Cc: Rahul Singh <rahul.singh@xxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Milan Djokic <milan_djokic@xxxxxxxx>
  • Delivery-date: Tue, 03 Nov 2026 17:30:37 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHda7kHIstkwkoHG0iW7e6KNO1jCg==
  • Thread-topic: [PATCH v5 12/22] xen/arm: vsmmuv3: Add support for event queue and global error

From: Rahul Singh <rahul.singh@xxxxxxx>

Event queue is used to send the events to guest when there is an events/
faults. Add support for event queue to send events to guest.

Global error in SMMUv3 hw will be updated in smmu_gerror and
smmu_gerrorn register. Add support for global error registers to send
global error to guest.

Add architectural error handling to the emulated command queue,
updating the global error register and stopping command consumption
on error.

Signed-off-by: Rahul Singh <rahul.singh@xxxxxxx>
Signed-off-by: Milan Djokic <milan_djokic@xxxxxxxx>
---
 xen/arch/arm/dom0less-build.c          |  50 +++--
 xen/drivers/passthrough/arm/smmu-v3.h  |  20 ++
 xen/drivers/passthrough/arm/vsmmu-v3.c | 246 +++++++++++++++++++++++--
 xen/include/public/arch-arm.h          |   2 +
 4 files changed, 295 insertions(+), 23 deletions(-)

diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c
index b55218d920..6ad2a1b745 100644
--- a/xen/arch/arm/dom0less-build.c
+++ b/xen/arch/arm/dom0less-build.c
@@ -386,34 +386,60 @@ int __init arch_parse_dom0less_node(struct dt_device_node 
*node,
     if ( !dt_property_read_u32(node, "nr_spis", &d_cfg->arch.nr_spis) )
     {
         int vpl011_virq = GUEST_VPL011_SPI;
+        int vsmmu_virq = GUEST_VSMMU_SPI;
 
         d_cfg->arch.nr_spis = vgic_def_nr_spis();
 
         /*
-         * The VPL011 virq is GUEST_VPL011_SPI, unless direct-map is
-         * set, in which case it'll match the hardware.
-         *
-         * Since the domain is not yet created, we can't use
-         * d->arch.vpl011.irq. So the logic to find the vIRQ has to
-         * be hardcoded.
-         * The logic here shall be consistent with the one in
-         * domain_vpl011_init().
+         * The VPL011 and VSMMU interrupts use predefined virtual SPIs,
+         * unless direct-map is set, in which case they match the
+         * corresponding hardware interrupts.
          */
         if ( flags & CDF_directmap )
         {
+#ifdef CONFIG_ARM_VIRTUAL_IOMMU
+            struct host_iommu *hw_iommu;
+#endif
+            /*
+             * Since the domain is not yet created, we can't use
+             * d->arch.vpl011.irq. So the logic to find the vIRQ has to
+             * be hardcoded.
+             * The logic here shall be consistent with the one in
+             * domain_vpl011_init().
+             */
             vpl011_virq = serial_irq(SERHND_DTUART);
             if ( vpl011_virq < 0 )
                 panic("Error getting IRQ number for this serial port %d\n",
                         SERHND_DTUART);
-        }
 
+#ifdef CONFIG_ARM_VIRTUAL_IOMMU
+            /*
+             * The host SMMU list is already populated during SMMUv3 driver
+             * probe, so we can determine the highest SMMU interrupt ID
+             * from this list.
+             */
+            vsmmu_virq = 0;
+            list_for_each_entry(hw_iommu, &host_iommu_list, entry)
+            {
+                vsmmu_virq = MAX(vsmmu_virq, hw_iommu->irq);
+            }
+#endif
+        }
         /*
-            * vpl011 uses one emulated SPI. If vpl011 is requested, make
-            * sure that we allocate enough SPIs for it.
-            */
+         * vpl011 uses one emulated SPI. If vpl011 is requested, make
+         * sure that we allocate enough SPIs for it.
+         */
         if ( dt_property_read_bool(node, "vpl011") )
             d_cfg->arch.nr_spis = MAX(d_cfg->arch.nr_spis,
                                       vpl011_virq - 32 + 1);
+
+        /*
+         * vsmmu uses one emulated SPI. If vsmmu is enabled, make
+         * sure that we allocate enough SPIs for it.
+         */
+        if ( d_cfg->arch.viommu_type == XEN_DOMCTL_CONFIG_VIOMMU_SMMUV3 )
+            d_cfg->arch.nr_spis = MAX(d_cfg->arch.nr_spis,
+                                      vsmmu_virq - 32 + 1);
     }
     else if ( flags & CDF_hardware )
         panic("nr_spis cannot be specified for hardware domain\n");
diff --git a/xen/drivers/passthrough/arm/smmu-v3.h 
b/xen/drivers/passthrough/arm/smmu-v3.h
index 4a912be740..44ecb5d89c 100644
--- a/xen/drivers/passthrough/arm/smmu-v3.h
+++ b/xen/drivers/passthrough/arm/smmu-v3.h
@@ -358,6 +358,26 @@
 
 #define EVTQ_0_ID                      GENMASK_ULL(7, 0)
 
+#define EVT_ID_BAD_STREAMID            0x02
+#define EVT_ID_BAD_STE                 0x04
+#define EVT_ID_TRANSLATION_FAULT       0x10
+#define EVT_ID_ADDR_SIZE_FAULT         0x11
+#define EVT_ID_ACCESS_FAULT            0x12
+#define EVT_ID_PERMISSION_FAULT                0x13
+
+#define EVTQ_0_SSV                     (1UL << 11)
+#define EVTQ_0_SSID                    GENMASK_ULL(31, 12)
+#define EVTQ_0_SID                     GENMASK_ULL(63, 32)
+#define EVTQ_1_STAG                    GENMASK_ULL(15, 0)
+#define EVTQ_1_STALL                   (1UL << 31)
+#define EVTQ_1_PnU                     (1UL << 33)
+#define EVTQ_1_InD                     (1UL << 34)
+#define EVTQ_1_RnW                     (1UL << 35)
+#define EVTQ_1_S2                      (1UL << 39)
+#define EVTQ_1_CLASS                   GENMASK_ULL(41, 40)
+#define EVTQ_1_TT_READ                 (1UL << 44)
+#define EVTQ_2_ADDR                    GENMASK_ULL(63, 0)
+#define EVTQ_3_IPA                     GENMASK_ULL(51, 12)
 /* PRI queue */
 #define PRIQ_ENT_SZ_SHIFT              4
 #define PRIQ_ENT_DWORDS                        ((1 << PRIQ_ENT_SZ_SHIFT) >> 3)
diff --git a/xen/drivers/passthrough/arm/vsmmu-v3.c 
b/xen/drivers/passthrough/arm/vsmmu-v3.c
index 72f8075e0a..17e83dcb1a 100644
--- a/xen/drivers/passthrough/arm/vsmmu-v3.c
+++ b/xen/drivers/passthrough/arm/vsmmu-v3.c
@@ -86,6 +86,35 @@
 #define smmu_get_ste_s1ctxptr(x)    FIELD_PREP(STRTAB_STE_0_S1CTXPTR_MASK, \
                                     FIELD_GET(STRTAB_STE_0_S1CTXPTR_MASK, x))
 
+/* event queue entry */
+struct arm_smmu_evtq_ent {
+    /* Common fields */
+    uint8_t     opcode;
+    uint32_t    sid;
+
+    /* Event-specific fields */
+    union {
+        struct {
+            uint32_t ssid;
+            bool ssv;
+        } c_bad_ste_streamid;
+
+        struct {
+            bool stall;
+            uint16_t stag;
+            uint32_t ssid;
+            bool ssv;
+            bool s2;
+            uint64_t addr;
+            bool rnw;
+            bool pnu;
+            bool ind;
+            uint8_t class;
+            uint64_t addr2;
+        } f_translation;
+    };
+};
+
 /* stage-1 translation configuration */
 struct arm_vsmmu_s1_trans_cfg {
     paddr_t s1ctxptr;
@@ -116,6 +145,7 @@ struct virt_smmu {
     uint32_t    strtab_base_cfg;
     uint64_t    strtab_base;
     uint32_t    irq_ctrl;
+    uint32_t    virq;
     uint64_t    gerror_irq_cfg0;
     uint64_t    evtq_irq_cfg0;
     struct      arm_vsmmu_queue evtq, cmdq;
@@ -161,9 +191,15 @@ static inline bool smmu_get_evtq_enabled(struct virt_smmu 
*smmu)
     spin_unlock(&smmu->cr0_lock);
 
     return enabled;
-};
+}
 
 /* Queue manipulation functions */
+static bool queue_full(struct arm_vsmmu_queue *q)
+{
+    return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) &&
+           Q_WRP(q, q->prod) != Q_WRP(q, q->cons);
+}
+
 static bool queue_empty(struct arm_vsmmu_queue *q)
 {
     return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) &&
@@ -176,12 +212,141 @@ static void queue_inc_cons(struct arm_vsmmu_queue *q)
     q->cons = Q_OVF(q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons);
 }
 
+static void queue_inc_prod(struct arm_vsmmu_queue *q)
+{
+    u32 prod = (Q_WRP(q, q->prod) | Q_IDX(q, q->prod)) + 1;
+    q->prod = Q_OVF(q->prod) | Q_WRP(q, prod) | Q_IDX(q, prod);
+}
+
 static void dump_smmu_command(uint64_t *command)
 {
     gprintk(XENLOG_ERR, "cmd 0x%02llx: %016"PRIx64" %016"PRIx64"\n",
              smmu_cmd_get_command(command[0]), command[0], command[1]);
 }
 
+static void arm_vsmmu_update_irq(struct virt_smmu *smmu)
+{
+    bool evt_pending = false;
+    bool gerr_pending = false;
+    uint32_t irq_ctrl;
+
+    spin_lock(&smmu->irq_cfg_lock);
+    irq_ctrl = smmu->irq_ctrl;
+    spin_unlock(&smmu->irq_cfg_lock);
+
+    spin_lock(&smmu->evt_queue_lock);
+    evt_pending = !queue_empty(&smmu->evtq);
+    spin_unlock(&smmu->evt_queue_lock);
+
+    spin_lock(&smmu->gerror_lock);
+    gerr_pending = (smmu->gerror ^ smmu->gerrorn) != 0;
+    spin_unlock(&smmu->gerror_lock);
+
+    vgic_inject_irq(smmu->d, NULL, smmu->virq,
+                    ((irq_ctrl & IRQ_CTRL_EVTQ_IRQEN) && evt_pending) ||
+                    ((irq_ctrl & IRQ_CTRL_GERROR_IRQEN) && gerr_pending));
+}
+
+static void arm_vsmmu_set_gerror(struct virt_smmu *smmu, uint32_t gerror_err)
+{
+    uint32_t pending, new_gerrors;
+
+    spin_lock(&smmu->gerror_lock);
+
+    pending = smmu->gerror ^ smmu->gerrorn;
+    new_gerrors = ~pending & gerror_err;
+
+    if ( new_gerrors )
+        smmu->gerror ^= new_gerrors;
+
+    spin_unlock(&smmu->gerror_lock);
+
+    arm_vsmmu_update_irq(smmu);
+}
+
+static int arm_vsmmu_write_evtq(struct virt_smmu *smmu, uint64_t *evt)
+{
+    struct arm_vsmmu_queue *q = &smmu->evtq;
+    struct domain *d = smmu->d;
+    paddr_t addr;
+    int ret;
+
+    if ( !smmu_get_evtq_enabled(smmu) )
+        return 0;
+
+    spin_lock(&smmu->evt_queue_lock);
+
+    if ( queue_full(q) )
+    {
+        /*
+        * Toggle OVFLG only if the previous overflow
+        * has already been acknowledged.
+        */
+        if ( Q_OVF(smmu->evtq.prod) ==
+             Q_OVF(smmu->evtq.cons) )
+            smmu->evtq.prod ^= Q_OVERFLOW_FLAG;
+
+        spin_unlock(&smmu->evt_queue_lock);
+        return 0;
+    }
+
+    addr = Q_PROD_ENT(q);
+
+    ret = access_guest_memory_by_gpa(d, addr, evt,
+                                     sizeof(*evt) * EVTQ_ENT_DWORDS, true);
+    if ( ret )
+    {
+        spin_unlock(&smmu->evt_queue_lock);
+        return ret;
+    }
+
+    queue_inc_prod(q);
+
+    spin_unlock(&smmu->evt_queue_lock);
+
+    arm_vsmmu_update_irq(smmu);
+
+    return 0;
+}
+
+static void arm_vsmmu_send_event(struct virt_smmu *smmu,
+                                 struct arm_smmu_evtq_ent *ent)
+{
+    uint64_t evt[EVTQ_ENT_DWORDS];
+    int ret;
+
+    memset(evt, 0, 1 << EVTQ_ENT_SZ_SHIFT);
+
+    if ( !smmu_get_evtq_enabled(smmu) )
+        return;
+
+    evt[0] |= FIELD_PREP(EVTQ_0_ID, ent->opcode);
+    evt[0] |= FIELD_PREP(EVTQ_0_SID, ent->sid);
+
+    switch ( ent->opcode )
+    {
+    case EVT_ID_BAD_STREAMID:
+    case EVT_ID_BAD_STE:
+        evt[0] |= FIELD_PREP(EVTQ_0_SSID, ent->c_bad_ste_streamid.ssid);
+        evt[0] |= FIELD_PREP(EVTQ_0_SSV, ent->c_bad_ste_streamid.ssv);
+        break;
+    case EVT_ID_TRANSLATION_FAULT:
+    case EVT_ID_ADDR_SIZE_FAULT:
+    case EVT_ID_ACCESS_FAULT:
+    case EVT_ID_PERMISSION_FAULT:
+        break;
+    default:
+        gdprintk(XENLOG_WARNING, "vSMMUv3: event opcode is bad\n");
+        break;
+    }
+
+    ret = arm_vsmmu_write_evtq(smmu, evt);
+    if ( ret )
+        arm_vsmmu_set_gerror(smmu, GERROR_EVTQ_ABT_ERR);
+
+    return;
+}
+
 static int arm_vsmmu_find_ste(struct virt_smmu *smmu, uint32_t sid,
                               uint64_t *ste)
 {
@@ -190,6 +355,14 @@ static int arm_vsmmu_find_ste(struct virt_smmu *smmu, 
uint32_t sid,
     uint32_t log2size;
     int strtab_size_shift;
     int ret;
+    struct arm_smmu_evtq_ent ent = {
+        .opcode = EVT_ID_BAD_STREAMID,
+        .sid = sid,
+        .c_bad_ste_streamid = {
+            .ssid = 0,
+            .ssv = false,
+        },
+    };
 
     spin_lock(&smmu->strtab_cfg_lock);
     log2size = MIN(FIELD_GET(STRTAB_BASE_CFG_LOG2SIZE, smmu->strtab_base_cfg),
@@ -197,7 +370,10 @@ static int arm_vsmmu_find_ste(struct virt_smmu *smmu, 
uint32_t sid,
     spin_unlock(&smmu->strtab_cfg_lock);
 
     if ( sid >= (1U << log2size) )
+    {
+        arm_vsmmu_send_event(smmu, &ent);
         return -EINVAL;
+    }
 
     spin_lock(&smmu->strtab_cfg_lock);
     if ( FIELD_GET(STRTAB_BASE_CFG_FMT, smmu->strtab_base_cfg) ==
@@ -250,6 +426,7 @@ static int arm_vsmmu_find_ste(struct virt_smmu *smmu, 
uint32_t sid,
         {
             gdprintk(XENLOG_ERR, "idx=%d > max_l2_ste=%d\n",
                      idx, max_l2_ste);
+            arm_vsmmu_send_event(smmu, &ent);
             return -EINVAL;
         }
         addr = l2ptr + idx * sizeof(*ste) * STRTAB_STE_DWORDS;
@@ -278,6 +455,14 @@ static int arm_vsmmu_decode_ste(struct virt_smmu *smmu, 
uint32_t sid,
                                 uint64_t *ste)
 {
     uint64_t val = ste[0];
+    struct arm_smmu_evtq_ent ent = {
+        .opcode = EVT_ID_BAD_STE,
+        .sid = sid,
+        .c_bad_ste_streamid = {
+            .ssid = 0,
+            .ssv = false,
+        },
+    };
 
     if ( !(val & STRTAB_STE_0_V) )
     {
@@ -316,6 +501,7 @@ static int arm_vsmmu_decode_ste(struct virt_smmu *smmu, 
uint32_t sid,
     return 0;
 
  bad_ste:
+    arm_vsmmu_send_event(smmu, &ent);
     return -EINVAL;
 }
 
@@ -373,16 +559,19 @@ static int arm_vsmmu_handle_cmds(struct virt_smmu *smmu)
      * monopolizing CPU time. Implement commands rescheduling and asynchronous
      * execution as outlined in the design.
      */
-    while ( !queue_empty(q) )
+    while ( !queue_empty(q) &&
+          ((smmu->gerror ^ smmu->gerrorn) & (GERROR_CMDQ_ERR)) == 0 )
     {
-        int ret;
-
         addr = Q_CONS_ENT(q);
         ret = access_guest_memory_by_gpa(d, addr, command,
                                          sizeof(command), false);
-        if ( ret ) {
-            queue_inc_cons(q);
-            return ret;
+        if ( ret )
+        {
+            smmu->cmdq.cons &= ~CMDQ_CONS_ERR;
+            smmu->cmdq.cons |= FIELD_PREP(CMDQ_CONS_ERR,
+                                        CMDQ_ERR_CERROR_ABT_IDX);
+            arm_vsmmu_set_gerror(smmu, GERROR_CMDQ_ERR);
+            break;
         }
 
         switch ( smmu_cmd_get_command(command[0]) )
@@ -406,6 +595,10 @@ static int arm_vsmmu_handle_cmds(struct virt_smmu *smmu)
         default:
             gdprintk(XENLOG_ERR, "vSMMUv3: unhandled command\n");
             dump_smmu_command(command);
+            smmu->cmdq.cons &= ~CMDQ_CONS_ERR;
+            smmu->cmdq.cons |= FIELD_PREP(CMDQ_CONS_ERR,
+                                          CMDQ_ERR_CERROR_ILL_IDX);
+            arm_vsmmu_set_gerror(smmu, GERROR_CMDQ_ERR);
             break;
         }
 
@@ -416,6 +609,15 @@ static int arm_vsmmu_handle_cmds(struct virt_smmu *smmu)
                      ret);
             dump_smmu_command(command);
         }
+
+        /*
+        * Stop consuming the command queue if a command error occurred.
+        * CMDQ_CONS continues to point at the offending command until the
+        * error is acknowledged.
+        */
+        if ( (smmu->gerror ^ smmu->gerrorn) & GERROR_CMDQ_ERR )
+            break;
+
         queue_inc_cons(q);
     }
 
@@ -454,6 +656,7 @@ static int vsmmuv3_mmio_write(struct vcpu *v, mmio_info_t 
*info,
             vreg_reg32_update(&reg32, r, info);
             smmu->evtq.cons = reg32;
             spin_unlock(&smmu->evt_queue_lock);
+            arm_vsmmu_update_irq(smmu);
             break;
         default:
             printk(XENLOG_G_ERR
@@ -584,6 +787,7 @@ static int vsmmuv3_mmio_write(struct vcpu *v, mmio_info_t 
*info,
             vreg_reg32_update(&reg32, r, info);
             smmu->irq_ctrl = reg32;
             spin_unlock(&smmu->irq_cfg_lock);
+            arm_vsmmu_update_irq(smmu);
             break;
 
         case VREG64(ARM_SMMU_GERROR_IRQ_CFG0):
@@ -608,11 +812,20 @@ static int vsmmuv3_mmio_write(struct vcpu *v, mmio_info_t 
*info,
 
         case VREG32(ARM_SMMU_GERRORN):
             if ( dabt.size != DABT_WORD ) goto bad_width;
+            /*
+             * Acquire cmd_queue_lock before updating GERRORN to serialize 
error
+             * acknowledgement with command processing and ensure that repaired
+             * commands are not skipped.
+             */
+            spin_lock(&smmu->cmd_queue_lock);
             spin_lock(&smmu->gerror_lock);
             reg32 = smmu->gerrorn;
             vreg_reg32_update(&reg32, r, info);
             smmu->gerrorn = reg32;
             spin_unlock(&smmu->gerror_lock);
+            arm_vsmmu_update_irq(smmu);
+            arm_vsmmu_handle_cmds(smmu);
+            spin_unlock(&smmu->cmd_queue_lock);
             break;
 
         default:
@@ -916,9 +1129,10 @@ static const struct mmio_handler_ops vsmmuv3_mmio_handler 
= {
     .write = vsmmuv3_mmio_write,
 };
 
-static int vsmmuv3_init_single(struct domain *d, paddr_t addr, paddr_t size,
-                               uint32_t features)
+static int vsmmuv3_init_single(struct domain *d, paddr_t addr,
+                               paddr_t size, uint32_t virq, uint32_t features)
 {
+    int ret;
     struct virt_smmu *smmu;
 
     smmu = xzalloc(struct virt_smmu);
@@ -927,6 +1141,7 @@ static int vsmmuv3_init_single(struct domain *d, paddr_t 
addr, paddr_t size,
 
     smmu->d = d;
     smmu->features = features;
+    smmu->virq = virq;
     smmu->cmdq.ent_size = CMDQ_ENT_DWORDS * DWORDS_BYTES;
     smmu->evtq.ent_size = EVTQ_ENT_DWORDS * DWORDS_BYTES;
 
@@ -939,6 +1154,15 @@ static int vsmmuv3_init_single(struct domain *d, paddr_t 
addr, paddr_t size,
     spin_lock_init(&smmu->strtab_cfg_lock);
     spin_lock_init(&smmu->irq_cfg_lock);
 
+    ret = vgic_reserve_virq(d, virq);
+    if ( !ret )
+    {
+        printk(XENLOG_G_ERR
+                 "vSMMUv3: Failed to reserve domain vIRQ %u\n", virq);
+        xfree(smmu);
+        return -EINVAL;
+    }
+
     register_mmio_handler(d, &vsmmuv3_mmio_handler, addr, size, smmu);
 
     /* Register the vIOMMU to be able to clean it up later. */
@@ -990,7 +1214,7 @@ static int domain_vsmmuv3_init(struct domain *d)
         {
             smmu = (const struct arm_smmu_device *) hw_iommu->iommu;
             ret = vsmmuv3_init_single(d, hw_iommu->addr, hw_iommu->size,
-                                      smmu->features);
+                                      hw_iommu->irq, smmu->features);
             if ( ret )
                 return ret;
         }
@@ -1033,7 +1257,7 @@ static int domain_vsmmuv3_init(struct domain *d)
         }
 
         ret = vsmmuv3_init_single(d, GUEST_VSMMUV3_BASE, GUEST_VSMMUV3_SIZE,
-                                  features);
+                                  GUEST_VSMMU_SPI, features);
         if ( ret )
             return ret;
     }
diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
index 7c76f2afd4..35cdbbb867 100644
--- a/xen/include/public/arch-arm.h
+++ b/xen/include/public/arch-arm.h
@@ -524,6 +524,8 @@ typedef uint64_t xen_callback_t;
 #define GUEST_VIRTIO_MMIO_SPI_FIRST   33
 #define GUEST_VIRTIO_MMIO_SPI_LAST    43
 
+#define GUEST_VSMMU_SPI         44
+
 /*
  * SGI is the preferred delivery mechanism of FF-A pending notifications or
  * schedule recveive interrupt. SGIs 8-15 are normally not used by a guest
-- 
2.43.0



 


Rackspace

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