|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v1 2/3] pci/rcar: implement OSID configuration for Renesas RCar Gen4 PCIe host
On Mon, 7 Jul 2025, Mykyta Poturai wrote:
> 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(+)
> create mode 100644 xen/arch/arm/pci/pci-host-rcar4.h
>
> 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__ */
> --
> 2.34.1
>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |