Devices on cdx bus are dynamically detected and registered using platform_device_register API. As these devices are not linked to of node they need a separate MSI domain for handling device ID to be provided to the GIC ITS domain. Signed-off-by: Nipun Gupta <nipun.gupta@xxxxxxx> Signed-off-by: Nikhil Agarwal <nikhil.agarwal@xxxxxxx> --- drivers/bus/cdx/Makefile | 2 +- drivers/bus/cdx/cdx.c | 31 +++++++++++ drivers/bus/cdx/cdx.h | 16 ++++++ drivers/bus/cdx/cdx_msi_domain.c | 90 ++++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 drivers/bus/cdx/cdx_msi_domain.c diff --git a/drivers/bus/cdx/Makefile b/drivers/bus/cdx/Makefile index c9cee5b6fa8a..5dc7874530f5 100644 --- a/drivers/bus/cdx/Makefile +++ b/drivers/bus/cdx/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_CDX_BUS) += cdx-bus-device-driver.o -cdx-bus-device-driver-objs := cdx.o +cdx-bus-device-driver-objs := cdx.o cdx_msi_domain.o diff --git a/drivers/bus/cdx/cdx.c b/drivers/bus/cdx/cdx.c index f28329770af8..cd916ef5f2bc 100644 --- a/drivers/bus/cdx/cdx.c +++ b/drivers/bus/cdx/cdx.c @@ -15,7 +15,9 @@ #include <linux/of_platform.h> #include <linux/dma-mapping.h> #include <linux/property.h> +#include <linux/msi.h> #include <linux/cdx/cdx_bus.h> +#include "cdx.h" #include "cdx.h" @@ -47,6 +49,8 @@ static int cdx_populate_one(struct platform_device *pdev_parent, dev_data.bus_id = dev_params->bus_id; dev_data.func_id = dev_params->func_id; + dev_data.dev_id = dev_params->msi_device_id; + dev_data.num_msi = dev_params->num_msi; memset(&pdevinfo, 0, sizeof(pdevinfo)); pdevinfo.fwnode = swnode; @@ -76,6 +80,10 @@ static int cdx_populate_one(struct platform_device *pdev_parent, goto out; } + /* Set the MSI domain */ + dev_set_msi_domain(&new_pdev->dev, + irq_find_host(pdev_parent->dev.of_node)); + return 0; out: @@ -109,8 +117,22 @@ static int cdx_bus_device_discovery(struct platform_device *pdev) int num_cdx_bus = 0, num_cdx_func = 0; int bus_id = 0, func_id = 0; struct device_node *np = pdev->dev.of_node; + struct irq_domain *cdx_msi_domain; int ret; + /* If CDX MSI domain is not created, create one. */ + cdx_msi_domain = irq_find_host(pdev->dev.of_node); + if (!cdx_msi_domain) { + np = pdev->dev.of_node; + + ret = cdx_msi_domain_init(&pdev->dev, np->full_name); + if (ret != 0) { + dev_err(&pdev->dev, + "cdx_msi_domain_init() failed: %d", ret); + return ret; + } + } + /* TODO: Get number of busses from firmware */ num_cdx_bus = 1; @@ -144,7 +166,16 @@ static int cdx_bus_device_discovery(struct platform_device *pdev) ret); goto fail; } + ret = of_map_id(np, req_id, "msi-map", "msi-map-mask", + NULL, &dev_params.msi_device_id); + if (ret != 0) { + dev_err(&pdev->dev, + "of_map_id failed for MSI: %d\n", + ret); + goto fail; + } + dev_params.num_msi = 2; dev_params.dev_type_idx = 0; dev_params.res_cnt = 1; diff --git a/drivers/bus/cdx/cdx.h b/drivers/bus/cdx/cdx.h index 7db8b06de9cd..da2c282d4d93 100644 --- a/drivers/bus/cdx/cdx.h +++ b/drivers/bus/cdx/cdx.h @@ -19,6 +19,8 @@ struct cdx_dev_params_t { struct resource res[CDX_DEV_NUM_RESOURCES]; int res_cnt; u32 stream_id; + u32 msi_device_id; + u32 num_msi; }; /** @@ -26,10 +28,24 @@ struct cdx_dev_params_t { * CDX device. * @bus_id: Bus ID for reset * @func_id: Function ID for reset + * @dev_id: Device ID for MSI. + * @num_msi: Number of MSI supported by the device */ struct cdx_device_data { u32 bus_id; u32 func_id; + u32 dev_id; + u32 num_msi; }; +/** + * cdx_msi_domain_init - Init the CDX bus MSI domain. + * @cbus_dev: Device of the CDX bus + * @name: Name to be assigned to the newly created domain + * + * Return 0 on success, <0 on failure + */ +int cdx_msi_domain_init(struct device *cdev_bus, + const char *name); + #endif /* _CDX_H_ */ diff --git a/drivers/bus/cdx/cdx_msi_domain.c b/drivers/bus/cdx/cdx_msi_domain.c new file mode 100644 index 000000000000..44472ae02d1c --- /dev/null +++ b/drivers/bus/cdx/cdx_msi_domain.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CDX bus driver MSI support + * + * Copyright(c) 2022 Xilinx. + * + */ + +#include <linux/irq.h> +#include <linux/msi.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> + +#include "cdx.h" + +static struct irq_chip cdx_msi_irq_chip = { + .name = "CDX-MSI", + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_eoi = irq_chip_eoi_parent, + .irq_set_affinity = msi_domain_set_affinity +}; + +static int cdx_msi_prepare(struct irq_domain *msi_domain, + struct device *dev, + int nvec, msi_alloc_info_t *info) +{ + struct msi_domain_info *msi_info; + struct cdx_device_data *dev_data; + u32 dev_id; + + /* Retrieve device ID from platform data */ + dev_data = dev->platform_data; + dev_id = dev_data->dev_id; + + /* Set the device Id to be passed to the GIC-ITS */ + info->scratchpad[0].ul = dev_id; + + msi_info = msi_get_domain_info(msi_domain->parent); + + /* Allocate at least 32 MSIs, and always as a power of 2 */ + nvec = max_t(int, 32, roundup_pow_of_two(nvec)); + return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info); +} + +static struct msi_domain_ops cdx_msi_ops __ro_after_init = { + .msi_prepare = cdx_msi_prepare, +}; + +static struct msi_domain_info cdx_msi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), + .ops = &cdx_msi_ops, + .chip = &cdx_msi_irq_chip, +}; + +int cdx_msi_domain_init(struct device *cbus_dev, + const char *name) +{ + struct irq_domain *parent; + struct irq_domain *cdx_msi_domain; + struct fwnode_handle *fwnode_handle; + struct device_node *parent_node; + struct device_node *np; + + np = cbus_dev->of_node; + parent_node = of_parse_phandle(np, "msi-map", 1); + + parent = irq_find_matching_fwnode(of_node_to_fwnode(parent_node), + DOMAIN_BUS_NEXUS); + if (!parent || !msi_get_domain_info(parent)) { + dev_err(cbus_dev, "%s: unable to locate ITS domain\n", name); + return -ENODEV; + } + + fwnode_handle = of_node_to_fwnode(np); + cdx_msi_domain = platform_msi_create_irq_domain(fwnode_handle, + &cdx_msi_domain_info, + parent); + if (!cdx_msi_domain) { + dev_err(cbus_dev, "%s: unable to create cdx bus domain\n", + name); + return -1; + } + + dev_info(cbus_dev, "cdx bus MSI: %s domain created\n", name); + + return 0; +} -- 2.25.1