[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
> 



 


Rackspace

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