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

[PATCH v1 3/3] iommu/ipmmu-vmsa: Implement basic PCIE-IPMMU OSID support


  • To: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Mykyta Poturai <Mykyta_Poturai@xxxxxxxx>
  • Date: Mon, 7 Jul 2025 09:20:40 +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=pxPvfOAsSigagv3rXTs+CLLre8x64/UR3pi98i0F9fU=; b=bWjMMTYLsTT3yW93xFTPzimP1e7T9yONbEa59mAuUYHfqAr9iyO0e02taIx0suNX63xczLLCc2qa26UJHI4m3dtL4+shV4VXLXDrQd5jJalW6bw82TgIXafJ+B73rpNIjddMxhfzcomlI1XPQRgh6Z0XZFCX2n1J3tlgGAn4/NY5vJlvfna/BvS19Ut81XJ6lAITuYCdun2vDZH0pkqFHDx48weIrcoFzPchdqSrJ4K3YXGnrdN+Tk5PwBN/mNCYnvcT6X87Xqm6Ghd3oA4o7gFLuJvqFa6wrnNrRcdm8SU1BhbN0YNvxaXsxH0kSIj8QUQUdZdNJKfHfJYWJ3saXA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=vty0tZDHERkr1kCvfmlUSh8+mDtQAsEF+W8s7NeXboJ6s5YFeUDoQjh33n17x4ohCQZgtlVJru+etb+F8D//7IqI79KAwuNrrhmz4u3naYp6d7dtpRVqKMKHXh/3Q/fAqKmgAHzChFMmzcKyMpxFMkVVjVcvPfjb5Ji6bSVHQ/+/i6zJLK8f1bA3QF87yA/YhKWvqoCQgETv3TtdPDfQ41skc5FvEJ+pNvzknOm02HGWhHB8+GOxR2mG6aIRwrBcz3D12h6bNUXWYLNEKnJMH/RJkOo1y4OiCWgh4dWZcSzEMbwnQSoK7hDEV39Y9VNV/baSSRitAFiEaUFzUSj/ig==
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=epam.com;
  • Cc: Oleksandr Tyshchenko <Oleksandr_Tyshchenko@xxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Mykyta Poturai <Mykyta_Poturai@xxxxxxxx>
  • Delivery-date: Mon, 07 Jul 2025 09:20:59 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHb7yBofin73T46RkmI40PJapT1qQ==
  • Thread-topic: [PATCH v1 3/3] iommu/ipmmu-vmsa: Implement basic PCIE-IPMMU OSID support

From: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>

Program PCIE BDF-OSID assignment according to the S4_PCIe_IPMMU-OSID
when adding PCI device to the IOMMU in ipmmu_add_device callback.
This is needed for being able to assign PCI devices to different
domains at the same time. Programmed OSID is emmited as sideband data on
the AXI bus during PCI DMA transactions and then used by IPMMU to match
the transaction to the corresponding uTLB.

Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>
Signed-off-by: Mykyta Poturai <mykyta_poturai@xxxxxxxx>
---
 xen/drivers/passthrough/arm/ipmmu-vmsa.c | 141 +++++++++++++++++++++--
 1 file changed, 133 insertions(+), 8 deletions(-)

diff --git a/xen/drivers/passthrough/arm/ipmmu-vmsa.c 
b/xen/drivers/passthrough/arm/ipmmu-vmsa.c
index d828d9cf6a..14ddabb30e 100644
--- a/xen/drivers/passthrough/arm/ipmmu-vmsa.c
+++ b/xen/drivers/passthrough/arm/ipmmu-vmsa.c
@@ -51,12 +51,25 @@
 #include <asm/device.h>
 #include <asm/io.h>
 #include <asm/iommu_fwspec.h>
+#include "../arch/arm/pci/pci-host-rcar4.h"
 
 #define dev_name(dev) dt_node_full_name(dev_to_dt(dev))
 
 /* Device logger functions */
+#ifndef CONFIG_HAS_PCI
 #define dev_print(dev, lvl, fmt, ...)    \
     printk(lvl "ipmmu: %s: " fmt, dev_name(dev), ## __VA_ARGS__)
+#else
+#define dev_print(dev, lvl, fmt, ...) ({                                \
+    if ( !dev_is_pci((dev)) )                                           \
+        printk(lvl "ipmmu: %s: " fmt, dev_name((dev)), ## __VA_ARGS__);  \
+    else                                                                \
+    {                                                                   \
+        struct pci_dev *pdev = dev_to_pci((dev));                       \
+        printk(lvl "ipmmu: %pp: " fmt, &pdev->sbdf, ## __VA_ARGS__);     \
+    }                                                                   \
+})
+#endif
 
 #define dev_info(dev, fmt, ...)    \
     dev_print(dev, XENLOG_INFO, fmt, ## __VA_ARGS__)
@@ -1121,6 +1134,8 @@ static void ipmmu_free_root_domain(struct 
ipmmu_vmsa_domain *domain)
     xfree(domain);
 }
 
+static int ipmmu_deassign_device(struct domain *d, struct device *dev);
+
 static int ipmmu_assign_device(struct domain *d, u8 devfn, struct device *dev,
                                uint32_t flag)
 {
@@ -1134,8 +1149,43 @@ static int ipmmu_assign_device(struct domain *d, u8 
devfn, struct device *dev,
     if ( !to_ipmmu(dev) )
         return -ENODEV;
 
-    spin_lock(&xen_domain->lock);
+#ifdef CONFIG_HAS_PCI
+    if ( dev_is_pci(dev) )
+    {
+        struct pci_dev *pdev = dev_to_pci(dev);
+        struct domain *old_d = pdev->domain;
+
+        printk(XENLOG_INFO "Assigning device %04x:%02x:%02x.%u to dom%d\n",
+               pdev->seg, pdev->bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+               d->domain_id);
+
+        /*
+         * XXX What would be the proper behavior? This could happen if
+         * pdev->phantom_stride > 0
+         */
+        if ( devfn != pdev->devfn )
+            ASSERT_UNREACHABLE();
+
+        list_move(&pdev->domain_list, &d->pdev_list);
+        pdev->domain = d;
+
+        /* dom_io is used as a sentinel for quarantined devices */
+        if ( d == dom_io )
+        {
+            int ret;
+
+            /*
+             * Try to de-assign: do not return error if it was already
+             * de-assigned.
+             */
+            ret = ipmmu_deassign_device(old_d, dev);
+
+            return ret == -ESRCH ? 0 : ret;
+        }
+    }
+#endif
 
+    spin_lock(&xen_domain->lock);
     /*
      * The IPMMU context for the Xen domain is not allocated beforehand
      * (at the Xen domain creation time), but on demand only, when the first
@@ -1240,7 +1290,7 @@ static int ipmmu_reassign_device(struct domain *s, struct 
domain *t,
     int ret = 0;
 
     /* Don't allow remapping on other domain than hwdom */
-    if ( t && !is_hardware_domain(t) )
+    if ( t && !is_hardware_domain(t) && (t != dom_io) )
         return -EPERM;
 
     if ( t == s )
@@ -1288,20 +1338,95 @@ static int ipmmu_dt_xlate(struct device *dev,
 
 static int ipmmu_add_device(u8 devfn, struct device *dev)
 {
-    struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+    struct iommu_fwspec *fwspec;
+
+#ifdef CONFIG_HAS_PCI
+    if ( dev_is_pci(dev) )
+    {
+        struct pci_dev *pdev = dev_to_pci(dev);
+        int ret;
+
+        if ( devfn != pdev->devfn )
+            return 0;
+
+        ret = iommu_add_pci_sideband_ids(pdev);
+        if ( ret < 0 )
+            iommu_fwspec_free(dev);
+    }
+#endif
+
+    fwspec = dev_iommu_fwspec_get(dev);
 
     /* Only let through devices that have been verified in xlate(). */
     if ( !to_ipmmu(dev) )
         return -ENODEV;
 
-    if ( dt_device_is_protected(dev_to_dt(dev)) )
+    if ( !dev_is_pci(dev) )
     {
-        dev_err(dev, "Already added to IPMMU\n");
-        return -EEXIST;
+        if ( dt_device_is_protected(dev_to_dt(dev)) )
+        {
+            dev_err(dev, "Already added to IPMMU\n");
+            return -EEXIST;
+        }
+
+        /* Let Xen know that the master device is protected by an IOMMU. */
+        dt_device_set_protected(dev_to_dt(dev));
     }
+#ifdef CONFIG_HAS_PCI
+    if ( dev_is_pci(dev) )
+    {
+        struct pci_dev *pdev = dev_to_pci(dev);
+        unsigned int reg_id, osid;
+        struct pci_host_bridge *bridge;
+        struct iommu_fwspec *fwspec_bridge;
+        unsigned int utlb_osid0 = 0;
+        int ret;
+
+        bridge = pci_find_host_bridge(pdev->seg, pdev->bus);
+        if ( !bridge )
+        {
+            dev_err(dev, "Failed to find host bridge\n");
+            return -ENODEV;
+        }
+
+        fwspec_bridge = dev_iommu_fwspec_get(dt_to_dev(bridge->dt_node));
+        if ( fwspec_bridge->num_ids < 1 )
+        {
+            dev_err(dev, "Failed to find host bridge uTLB\n");
+            return -ENXIO;
+        }
+
+        if ( fwspec->num_ids < 1 )
+        {
+            dev_err(dev, "Failed to find uTLB");
+            return -ENXIO;
+        }
+
+        rcar4_pcie_osid_regs_init(bridge);
 
-    /* Let Xen know that the master device is protected by an IOMMU. */
-    dt_device_set_protected(dev_to_dt(dev));
+        ret = rcar4_pcie_osid_reg_alloc(bridge);
+        if ( ret < 0 )
+        {
+            dev_err(dev, "No unused OSID regs\n");
+            return ret;
+        }
+        reg_id = ret;
+
+        osid = fwspec->ids[0] - utlb_osid0;
+        rcar4_pcie_osid_bdf_set(bridge, reg_id, osid, pdev->sbdf.bdf);
+        rcar4_pcie_bdf_msk_set(bridge, reg_id, 0);
+
+        dev_info(dev, "Allocated OSID reg %u (OSID %u)\n", reg_id, osid);
+
+        ret = ipmmu_assign_device(pdev->domain, devfn, dev, 0);
+        if ( ret )
+        {
+            rcar4_pcie_osid_bdf_clear(bridge, reg_id);
+            rcar4_pcie_osid_reg_free(bridge, reg_id);
+            return ret;
+        }
+    }
+#endif
 
     dev_info(dev, "Added master device (IPMMU %s micro-TLBs %u)\n",
              dev_name(fwspec->iommu_dev), fwspec->num_ids);
-- 
2.34.1



 


Rackspace

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