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

[xen master] pci/rcar: implement OSID configuration for Renesas RCar Gen4 PCIe host



commit 114c01ebf38e423bc92e709a25c25fae1e94b7a4
Author:     Mykyta Poturai <Mykyta_Poturai@xxxxxxxx>
AuthorDate: Mon Jul 14 08:51:48 2025 +0000
Commit:     Stefano Stabellini <stefano.stabellini@xxxxxxx>
CommitDate: Wed Aug 20 18:11:12 2025 -0700

    pci/rcar: implement OSID configuration for Renesas RCar Gen4 PCIe host
    
    For IPMMU to be able to associate a specific PCI device with it's TLB
    the BDF to OSID mapping needs to be set up in the host bridge. The
    configured OSID is then emmited as a sideband data on the AXI bus during
    PCI DMA transactions. OSID configuration registers are located in the
    "app" region of the host bridge.
    
    Map the "app" region on init and implement methods for setting up
    BDF->OSID mappings
    
    Signed-off-by: Mykyta Poturai <mykyta_poturai@xxxxxxxx>
    Acked-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>
---
 xen/arch/arm/pci/pci-host-rcar4.c | 148 ++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/pci/pci-host-rcar4.h |  18 +++++
 2 files changed, 166 insertions(+)

diff --git a/xen/arch/arm/pci/pci-host-rcar4.c 
b/xen/arch/arm/pci/pci-host-rcar4.c
index 62d2130a63..9290c6cac5 100644
--- a/xen/arch/arm/pci/pci-host-rcar4.c
+++ b/xen/arch/arm/pci/pci-host-rcar4.c
@@ -16,6 +16,32 @@
 
 #define RCAR4_DWC_VERSION       0x520A
 
+/* PCIE BDF-OSID assignment */
+#define CNVID(n)             (0x700 + ((n) * 4))
+#define CNVID_CNV_EN         (1U << 31)
+#define CNVID_OSID_MASK      (0x0F << 16)
+#define CNVID_OSID_SHIFT     16
+#define CNVID_BDF_MASK       (0xFFFF << 0)
+#define CNVID_BDF_SHIFT      0
+
+#define CNVIDMSK(n)                (0x780 + ((n) * 4))
+#define CNVIDMSK_BDF_MSK_MASK      (0xFFFF << 0)
+#define CNVIDMSK_BDF_MSK_SHIFT     0
+
+#define CNVOSIDCTRL                0x800
+#define CNVOSIDCTRL_OSID_MASK      (0x0F << 16)
+#define CNVOSIDCTRL_OSID_SHIFT     16
+
+#define DEFAULT_OSID    0
+
+#define NUM_OSID_REGS    16
+
+struct rcar4_pcie_priv {
+    bool init_done;
+    void __iomem *app_base;
+    DECLARE_BITMAP(osid_regs, NUM_OSID_REGS);
+};
+
 /*
  * PCI host bridges often have different ways to access the root and child
  * bus config spaces:
@@ -65,17 +91,139 @@ static const struct dt_device_match __initconstrel 
rcar4_pcie_dt_match[] = {
     {},
 };
 
+static void rcar4_pcie_writel_app(struct rcar4_pcie_priv *pci, uint32_t reg,
+                                  uint32_t val)
+{
+    writel(val, pci->app_base + reg);
+}
+
+static uint32_t rcar4_pcie_readl_app(struct rcar4_pcie_priv *pci, uint32_t reg)
+{
+    return readl(pci->app_base + reg);
+}
+
+int rcar4_pcie_osid_regs_init(struct pci_host_bridge *bridge)
+{
+    struct rcar4_pcie_priv *priv = dw_pcie_get_priv(bridge);
+    uint32_t val = rcar4_pcie_readl_app(priv, CNVOSIDCTRL);
+
+    if ( priv->init_done )
+        return 0;
+    priv->init_done = true;
+
+    val = (val & ~CNVOSIDCTRL_OSID_MASK) |
+          (DEFAULT_OSID << CNVOSIDCTRL_OSID_SHIFT);
+    rcar4_pcie_writel_app(priv, CNVOSIDCTRL, val);
+    bitmap_zero(priv->osid_regs, NUM_OSID_REGS);
+
+    printk("%s: Initialized OSID regs (default OSID %u)\n",
+           bridge->dt_node->full_name, DEFAULT_OSID);
+
+    return 0;
+}
+
+int rcar4_pcie_osid_reg_alloc(struct pci_host_bridge *bridge)
+{
+    struct rcar4_pcie_priv *priv = dw_pcie_get_priv(bridge);
+    int ret;
+
+    ret = find_first_zero_bit(priv->osid_regs, NUM_OSID_REGS);
+    if ( ret != NUM_OSID_REGS )
+        set_bit(ret, priv->osid_regs);
+    else
+        ret = -EBUSY;
+
+    return ret;
+}
+
+void rcar4_pcie_osid_reg_free(struct pci_host_bridge *bridge,
+                              unsigned int reg_id)
+{
+    struct rcar4_pcie_priv *priv = dw_pcie_get_priv(bridge);
+
+    clear_bit(reg_id, priv->osid_regs);
+}
+
+void rcar4_pcie_osid_bdf_set(struct pci_host_bridge *bridge,
+                             unsigned int reg_id, uint32_t osid, uint32_t bdf)
+{
+    struct rcar4_pcie_priv *priv = dw_pcie_get_priv(bridge);
+    uint32_t data = rcar4_pcie_readl_app(priv, CNVID(reg_id));
+
+    data &= ~(CNVID_OSID_MASK | CNVID_BDF_MASK);
+    data |= CNVID_CNV_EN | (osid << CNVID_OSID_SHIFT) |
+            (bdf << CNVID_BDF_SHIFT);
+    rcar4_pcie_writel_app(priv, CNVID(reg_id), data);
+}
+
+void rcar4_pcie_osid_bdf_clear(struct pci_host_bridge *bridge,
+                               unsigned int reg_id)
+{
+    struct rcar4_pcie_priv *priv = dw_pcie_get_priv(bridge);
+    uint32_t data = rcar4_pcie_readl_app(priv, CNVID(reg_id));
+
+    data &= ~CNVID_CNV_EN;
+    rcar4_pcie_writel_app(priv, CNVID(reg_id), data);
+}
+
+void rcar4_pcie_bdf_msk_set(struct pci_host_bridge *bridge, unsigned int 
reg_id,
+                            uint32_t data)
+{
+    struct rcar4_pcie_priv *priv = dw_pcie_get_priv(bridge);
+
+    uint32_t val = rcar4_pcie_readl_app(priv, CNVIDMSK(reg_id));
+
+    val = (val & ~CNVIDMSK_BDF_MSK_MASK) | (data << CNVIDMSK_BDF_MSK_SHIFT);
+
+    rcar4_pcie_writel_app(priv, CNVIDMSK(reg_id), val);
+}
+
 static int __init pci_host_rcar4_probe(struct dt_device_node *dev,
                                        const void *data)
 {
     struct pci_host_bridge *bridge;
+    paddr_t app_phys_addr;
+    paddr_t app_size;
+    int app_idx, ret;
+
+    struct rcar4_pcie_priv *priv = xzalloc(struct rcar4_pcie_priv);
+    if ( !priv )
+        return -ENOMEM;
 
     bridge = dw_pcie_host_probe(dev, data, &rcar4_pcie_ops,
                                 &rcar4_pcie_child_ops);
 
+    app_idx = dt_property_match_string(dev, "reg-names", "app");
+    if ( app_idx < 0 )
+    {
+        printk(XENLOG_ERR "Cannot find \"app\" range index in device tree\n");
+        ret = app_idx;
+        goto err;
+    }
+    ret = dt_device_get_address(dev, app_idx, &app_phys_addr, &app_size);
+    if ( ret )
+    {
+        printk(XENLOG_ERR "Cannot find \"app\" range in device tree\n");
+        goto err;
+    }
+
+    priv->app_base = ioremap_nocache(app_phys_addr, app_size);
+    if ( !priv->app_base )
+    {
+        printk(XENLOG_ERR "APP ioremap failed\n");
+        ret = -ENXIO;
+        goto err;
+    }
+    printk("APP at [mem 0x%" PRIpaddr "-0x%" PRIpaddr "]\n", app_phys_addr,
+           app_phys_addr + app_size - 1);
+
+    dw_pcie_set_priv(bridge, priv);
     dw_pcie_set_version(bridge, RCAR4_DWC_VERSION);
 
     return 0;
+err:
+    xfree(priv);
+    return ret;
 }
 
 DT_DEVICE_START(pci_gen, "PCI HOST R-CAR GEN4", DEVICE_PCI_HOSTBRIDGE)
diff --git a/xen/arch/arm/pci/pci-host-rcar4.h 
b/xen/arch/arm/pci/pci-host-rcar4.h
new file mode 100644
index 0000000000..8ac6626a22
--- /dev/null
+++ b/xen/arch/arm/pci/pci-host-rcar4.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <asm/pci.h>
+
+#ifndef __PCI_HOST_RCAR4_H__
+#define __PCI_HOST_RCAR4_H__
+
+void rcar4_pcie_osid_bdf_set(struct pci_host_bridge *bridge,
+                             unsigned int reg_id, uint32_t osid, uint32_t bdf);
+void rcar4_pcie_osid_bdf_clear(struct pci_host_bridge *bridge,
+                               unsigned int reg_id);
+void rcar4_pcie_bdf_msk_set(struct pci_host_bridge *bridge, unsigned int 
reg_id,
+                            uint32_t data);
+int rcar4_pcie_osid_reg_alloc(struct pci_host_bridge *bridge);
+void rcar4_pcie_osid_reg_free(struct pci_host_bridge *bridge,
+                              unsigned int reg_id);
+int rcar4_pcie_osid_regs_init(struct pci_host_bridge *bridge);
+
+#endif /* __PCI_HOST_RCAR4_H__ */
--
generated by git-patchbot for /home/xen/git/xen.git#master



 


Rackspace

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