Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

cdx: add MSI support for CDX bus

Add CDX-MSI domain per CDX controller with gic-its domain as
a parent, to support MSI for CDX devices. CDX devices allocate
MSIs from the CDX domain. Also, introduce APIs to alloc and free
IRQs for CDX domain.

In CDX subsystem firmware is a controller for all devices and
their configuration. CDX bus controller sends all the write_msi_msg
commands to firmware running on RPU and the firmware interfaces with
actual devices to pass this information to devices

Since, CDX controller is the only way to communicate with the Firmware
for MSI write info, CDX domain per controller required in contrast to
having a CDX domain per device.

Co-developed-by: Nikhil Agarwal <nikhil.agarwal@amd.com>
Signed-off-by: Nikhil Agarwal <nikhil.agarwal@amd.com>
Co-developed-by: Abhijit Gangurde <abhijit.gangurde@amd.com>
Signed-off-by: Abhijit Gangurde <abhijit.gangurde@amd.com>
Signed-off-by: Nipun Gupta <nipun.gupta@amd.com>
Reviewed-by: Pieter Jansen van Vuuren <pieter.jansen-van-vuuren@amd.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Nikhil Agarwal <nikhil.agarwal@amd.com>
Link: https://lore.kernel.org/r/20240226082816.100872-1-nipun.gupta@amd.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Nipun Gupta and committed by
Greg Kroah-Hartman
0e439ba3 e3a59056

+434 -3
+4
drivers/cdx/Makefile
··· 8 8 ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CDX_BUS 9 9 10 10 obj-$(CONFIG_CDX_BUS) += cdx.o controller/ 11 + 12 + ifdef CONFIG_GENERIC_MSI_IRQ 13 + obj-$(CONFIG_CDX_BUS) += cdx_msi.o 14 + endif
+20
drivers/cdx/cdx.c
··· 56 56 */ 57 57 58 58 #include <linux/init.h> 59 + #include <linux/irqdomain.h> 59 60 #include <linux/kernel.h> 60 61 #include <linux/of.h> 61 62 #include <linux/of_device.h> ··· 303 302 { 304 303 struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); 305 304 struct cdx_device *cdx_dev = to_cdx_device(dev); 305 + struct cdx_controller *cdx = cdx_dev->cdx; 306 306 int error; 307 + 308 + /* 309 + * Setup MSI device data so that generic MSI alloc/free can 310 + * be used by the device driver. 311 + */ 312 + if (cdx->msi_domain) { 313 + error = msi_setup_device_data(&cdx_dev->dev); 314 + if (error) 315 + return error; 316 + } 307 317 308 318 error = cdx_drv->probe(cdx_dev); 309 319 if (error) { ··· 799 787 800 788 /* Populate CDX dev params */ 801 789 cdx_dev->req_id = dev_params->req_id; 790 + cdx_dev->msi_dev_id = dev_params->msi_dev_id; 802 791 cdx_dev->vendor = dev_params->vendor; 803 792 cdx_dev->device = dev_params->device; 804 793 cdx_dev->subsystem_vendor = dev_params->subsys_vendor; ··· 817 804 cdx_dev->dev.bus = &cdx_bus_type; 818 805 cdx_dev->dev.dma_mask = &cdx_dev->dma_mask; 819 806 cdx_dev->dev.release = cdx_device_release; 807 + cdx_dev->msi_write_pending = false; 808 + mutex_init(&cdx_dev->irqchip_lock); 820 809 821 810 /* Set Name */ 822 811 dev_set_name(&cdx_dev->dev, "cdx-%02x:%02x", 823 812 ((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (cdx_dev->bus_num & CDX_BUS_NUM_MASK)), 824 813 cdx_dev->dev_num); 814 + 815 + if (cdx->msi_domain) { 816 + cdx_dev->num_msi = dev_params->num_msi; 817 + dev_set_msi_domain(&cdx_dev->dev, cdx->msi_domain); 818 + } 825 819 826 820 ret = device_add(&cdx_dev->dev); 827 821 if (ret) {
+12
drivers/cdx/cdx.h
··· 25 25 * @req_id: Requestor ID associated with CDX device 26 26 * @class: Class of the CDX Device 27 27 * @revision: Revision of the CDX device 28 + * @msi_dev_id: MSI device ID associated with CDX device 29 + * @num_msi: Number of MSI's supported by the device 28 30 */ 29 31 struct cdx_dev_params { 30 32 struct cdx_controller *cdx; ··· 42 40 u32 req_id; 43 41 u32 class; 44 42 u8 revision; 43 + u32 msi_dev_id; 44 + u32 num_msi; 45 45 }; 46 46 47 47 /** ··· 82 78 * Return: associated Linux generic device pointer on success or NULL on failure. 83 79 */ 84 80 struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num); 81 + 82 + /** 83 + * cdx_msi_domain_init - Init the CDX bus MSI domain. 84 + * @dev: Device of the CDX bus controller 85 + * 86 + * Return: CDX MSI domain, NULL on failure 87 + */ 88 + struct irq_domain *cdx_msi_domain_init(struct device *dev); 85 89 86 90 #endif /* _CDX_H_ */
+192
drivers/cdx/cdx_msi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * AMD CDX bus driver MSI support 4 + * 5 + * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. 6 + */ 7 + 8 + #include <linux/of.h> 9 + #include <linux/of_device.h> 10 + #include <linux/of_address.h> 11 + #include <linux/of_irq.h> 12 + #include <linux/irq.h> 13 + #include <linux/irqdomain.h> 14 + #include <linux/msi.h> 15 + #include <linux/cdx/cdx_bus.h> 16 + 17 + #include "cdx.h" 18 + 19 + static void cdx_msi_write_msg(struct irq_data *irq_data, struct msi_msg *msg) 20 + { 21 + struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data); 22 + struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev); 23 + 24 + /* We would not operate on msg here rather we wait for irq_bus_sync_unlock() 25 + * to be called from preemptible task context. 26 + */ 27 + msi_desc->msg = *msg; 28 + cdx_dev->msi_write_pending = true; 29 + } 30 + 31 + static void cdx_msi_write_irq_lock(struct irq_data *irq_data) 32 + { 33 + struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data); 34 + struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev); 35 + 36 + mutex_lock(&cdx_dev->irqchip_lock); 37 + } 38 + 39 + static void cdx_msi_write_irq_unlock(struct irq_data *irq_data) 40 + { 41 + struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data); 42 + struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev); 43 + struct cdx_controller *cdx = cdx_dev->cdx; 44 + struct cdx_device_config dev_config; 45 + 46 + if (!cdx_dev->msi_write_pending) { 47 + mutex_unlock(&cdx_dev->irqchip_lock); 48 + return; 49 + } 50 + 51 + cdx_dev->msi_write_pending = false; 52 + mutex_unlock(&cdx_dev->irqchip_lock); 53 + 54 + dev_config.msi.msi_index = msi_desc->msi_index; 55 + dev_config.msi.data = msi_desc->msg.data; 56 + dev_config.msi.addr = ((u64)(msi_desc->msg.address_hi) << 32) | msi_desc->msg.address_lo; 57 + 58 + /* 59 + * dev_configure() is a controller callback which can interact with 60 + * Firmware or other entities, and can sleep, so invoke this function 61 + * outside of the mutex held region. 62 + */ 63 + dev_config.type = CDX_DEV_MSI_CONF; 64 + if (cdx->ops->dev_configure) 65 + cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config); 66 + } 67 + 68 + int cdx_enable_msi(struct cdx_device *cdx_dev) 69 + { 70 + struct cdx_controller *cdx = cdx_dev->cdx; 71 + struct cdx_device_config dev_config; 72 + 73 + dev_config.type = CDX_DEV_MSI_ENABLE; 74 + dev_config.msi_enable = true; 75 + if (cdx->ops->dev_configure) { 76 + return cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, 77 + &dev_config); 78 + } 79 + 80 + return -EOPNOTSUPP; 81 + } 82 + EXPORT_SYMBOL_GPL(cdx_enable_msi); 83 + 84 + void cdx_disable_msi(struct cdx_device *cdx_dev) 85 + { 86 + struct cdx_controller *cdx = cdx_dev->cdx; 87 + struct cdx_device_config dev_config; 88 + 89 + dev_config.type = CDX_DEV_MSI_ENABLE; 90 + dev_config.msi_enable = false; 91 + if (cdx->ops->dev_configure) 92 + cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config); 93 + } 94 + EXPORT_SYMBOL_GPL(cdx_disable_msi); 95 + 96 + static struct irq_chip cdx_msi_irq_chip = { 97 + .name = "CDX-MSI", 98 + .irq_mask = irq_chip_mask_parent, 99 + .irq_unmask = irq_chip_unmask_parent, 100 + .irq_eoi = irq_chip_eoi_parent, 101 + .irq_set_affinity = msi_domain_set_affinity, 102 + .irq_write_msi_msg = cdx_msi_write_msg, 103 + .irq_bus_lock = cdx_msi_write_irq_lock, 104 + .irq_bus_sync_unlock = cdx_msi_write_irq_unlock 105 + }; 106 + 107 + /* Convert an msi_desc to a unique identifier within the domain. */ 108 + static irq_hw_number_t cdx_domain_calc_hwirq(struct cdx_device *dev, 109 + struct msi_desc *desc) 110 + { 111 + return ((irq_hw_number_t)dev->msi_dev_id << 10) | desc->msi_index; 112 + } 113 + 114 + static void cdx_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) 115 + { 116 + arg->desc = desc; 117 + arg->hwirq = cdx_domain_calc_hwirq(to_cdx_device(desc->dev), desc); 118 + } 119 + 120 + static int cdx_msi_prepare(struct irq_domain *msi_domain, 121 + struct device *dev, 122 + int nvec, msi_alloc_info_t *info) 123 + { 124 + struct cdx_device *cdx_dev = to_cdx_device(dev); 125 + struct device *parent = cdx_dev->cdx->dev; 126 + struct msi_domain_info *msi_info; 127 + u32 dev_id; 128 + int ret; 129 + 130 + /* Retrieve device ID from requestor ID using parent device */ 131 + ret = of_map_id(parent->of_node, cdx_dev->msi_dev_id, "msi-map", "msi-map-mask", 132 + NULL, &dev_id); 133 + if (ret) { 134 + dev_err(dev, "of_map_id failed for MSI: %d\n", ret); 135 + return ret; 136 + } 137 + 138 + #ifdef GENERIC_MSI_DOMAIN_OPS 139 + /* Set the device Id to be passed to the GIC-ITS */ 140 + info->scratchpad[0].ul = dev_id; 141 + #endif 142 + 143 + msi_info = msi_get_domain_info(msi_domain->parent); 144 + 145 + return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info); 146 + } 147 + 148 + static struct msi_domain_ops cdx_msi_ops = { 149 + .msi_prepare = cdx_msi_prepare, 150 + .set_desc = cdx_msi_set_desc 151 + }; 152 + 153 + static struct msi_domain_info cdx_msi_domain_info = { 154 + .ops = &cdx_msi_ops, 155 + .chip = &cdx_msi_irq_chip, 156 + .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 157 + MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS 158 + }; 159 + 160 + struct irq_domain *cdx_msi_domain_init(struct device *dev) 161 + { 162 + struct device_node *np = dev->of_node; 163 + struct fwnode_handle *fwnode_handle; 164 + struct irq_domain *cdx_msi_domain; 165 + struct device_node *parent_node; 166 + struct irq_domain *parent; 167 + 168 + fwnode_handle = of_node_to_fwnode(np); 169 + 170 + parent_node = of_parse_phandle(np, "msi-map", 1); 171 + if (!parent_node) { 172 + dev_err(dev, "msi-map not present on cdx controller\n"); 173 + return NULL; 174 + } 175 + 176 + parent = irq_find_matching_fwnode(of_node_to_fwnode(parent_node), DOMAIN_BUS_NEXUS); 177 + if (!parent || !msi_get_domain_info(parent)) { 178 + dev_err(dev, "unable to locate ITS domain\n"); 179 + return NULL; 180 + } 181 + 182 + cdx_msi_domain = msi_create_irq_domain(fwnode_handle, &cdx_msi_domain_info, parent); 183 + if (!cdx_msi_domain) { 184 + dev_err(dev, "unable to create CDX-MSI domain\n"); 185 + return NULL; 186 + } 187 + 188 + dev_dbg(dev, "CDX-MSI domain created\n"); 189 + 190 + return cdx_msi_domain; 191 + } 192 + EXPORT_SYMBOL_NS_GPL(cdx_msi_domain_init, CDX_BUS_CONTROLLER);
+1
drivers/cdx/controller/Kconfig
··· 9 9 10 10 config CDX_CONTROLLER 11 11 tristate "CDX bus controller" 12 + select GENERIC_MSI_IRQ 12 13 select REMOTEPROC 13 14 select RPMSG 14 15 help
+25
drivers/cdx/controller/cdx_controller.c
··· 9 9 #include <linux/platform_device.h> 10 10 #include <linux/slab.h> 11 11 #include <linux/cdx/cdx_bus.h> 12 + #include <linux/irqdomain.h> 12 13 13 14 #include "cdx_controller.h" 14 15 #include "../cdx.h" ··· 61 60 u8 bus_num, u8 dev_num, 62 61 struct cdx_device_config *dev_config) 63 62 { 63 + u16 msi_index; 64 64 int ret = 0; 65 + u32 data; 66 + u64 addr; 65 67 66 68 switch (dev_config->type) { 69 + case CDX_DEV_MSI_CONF: 70 + msi_index = dev_config->msi.msi_index; 71 + data = dev_config->msi.data; 72 + addr = dev_config->msi.addr; 73 + 74 + ret = cdx_mcdi_write_msi(cdx->priv, bus_num, dev_num, msi_index, addr, data); 75 + break; 67 76 case CDX_DEV_RESET_CONF: 68 77 ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num); 69 78 break; 70 79 case CDX_DEV_BUS_MASTER_CONF: 71 80 ret = cdx_mcdi_bus_master_enable(cdx->priv, bus_num, dev_num, 72 81 dev_config->bus_master_enable); 82 + break; 83 + case CDX_DEV_MSI_ENABLE: 84 + ret = cdx_mcdi_msi_enable(cdx->priv, bus_num, dev_num, dev_config->msi_enable); 73 85 break; 74 86 default: 75 87 ret = -EINVAL; ··· 192 178 cdx->priv = cdx_mcdi; 193 179 cdx->ops = &cdx_ops; 194 180 181 + /* Create MSI domain */ 182 + cdx->msi_domain = cdx_msi_domain_init(&pdev->dev); 183 + if (!cdx->msi_domain) { 184 + dev_err(&pdev->dev, "cdx_msi_domain_init() failed"); 185 + ret = -ENODEV; 186 + goto cdx_msi_fail; 187 + } 188 + 195 189 ret = cdx_setup_rpmsg(pdev); 196 190 if (ret) { 197 191 if (ret != -EPROBE_DEFER) ··· 211 189 return 0; 212 190 213 191 cdx_rpmsg_fail: 192 + irq_domain_remove(cdx->msi_domain); 193 + cdx_msi_fail: 214 194 kfree(cdx); 215 195 cdx_alloc_fail: 216 196 cdx_mcdi_finish(cdx_mcdi); ··· 229 205 230 206 cdx_destroy_rpmsg(pdev); 231 207 208 + irq_domain_remove(cdx->msi_domain); 232 209 kfree(cdx); 233 210 234 211 cdx_mcdi_finish(cdx_mcdi);
+64
drivers/cdx/controller/mc_cdx_pcol.h
··· 455 455 #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_OFST 84 456 456 #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_LEN 4 457 457 458 + /* MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2 msgresponse */ 459 + #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN 92 460 + /* Requester ID used by device for GIC ITS DeviceID */ 461 + #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID_OFST 88 462 + #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID_LEN 4 463 + 458 464 /***********************************/ 459 465 /* 460 466 * MC_CMD_CDX_BUS_DOWN ··· 621 615 #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_OFST 0 622 616 #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_LBN 2 623 617 #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_WIDTH 1 618 + 619 + /***********************************/ 620 + /* 621 + * MC_CMD_CDX_DEVICE_WRITE_MSI_MSG 622 + * Populates the MSI message to be used by the hardware to raise the specified 623 + * interrupt vector. Versal-net implementation specific limitations are that 624 + * only 4 CDX devices with MSI interrupt capability are supported and all 625 + * vectors within a device must use the same write address. The command will 626 + * return EINVAL if any of these limitations is violated. 627 + */ 628 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG 0x9 629 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_MSGSET 0x9 630 + #undef MC_CMD_0x9_PRIVILEGE_CTG 631 + 632 + #define MC_CMD_0x9_PRIVILEGE_CTG SRIOV_CTG_ADMIN 633 + 634 + /* MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN msgrequest */ 635 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN 28 636 + /* Device bus number, in range 0 to BUS_COUNT-1 */ 637 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_BUS_OFST 0 638 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_BUS_LEN 4 639 + /* Device number relative to the bus, in range 0 to DEVICE_COUNT-1 for that bus */ 640 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE_OFST 4 641 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE_LEN 4 642 + /* 643 + * Device-relative MSI vector number. Must be < MSI_COUNT reported for the 644 + * device. 645 + */ 646 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR_OFST 8 647 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR_LEN 4 648 + /* Reserved (alignment) */ 649 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_RESERVED_OFST 12 650 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_RESERVED_LEN 4 651 + /* 652 + * MSI address to be used by the hardware. Typically, on ARM systems this 653 + * address is translated by the IOMMU (if enabled) and it is the responsibility 654 + * of the entity managing the IOMMU (APU kernel) to supply the correct IOVA 655 + * here. 656 + */ 657 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_OFST 16 658 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LEN 8 659 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_OFST 16 660 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_LEN 4 661 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_LBN 128 662 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_WIDTH 32 663 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_OFST 20 664 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_LEN 4 665 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_LBN 160 666 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_WIDTH 32 667 + /* 668 + * MSI data to be used by the hardware. On versal-net, only the lower 16-bits 669 + * are used, the remaining bits are ignored and should be set to zero. 670 + */ 671 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA_OFST 24 672 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA_LEN 4 673 + 674 + /* MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_OUT msgresponse */ 675 + #define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_OUT_LEN 0 624 676 625 677 /***********************************/ 626 678 /* MC_CMD_V2_EXTN - Encapsulation for a v2 extended command */
+31 -2
drivers/cdx/controller/mcdi_functions.c
··· 49 49 u8 bus_num, u8 dev_num, 50 50 struct cdx_dev_params *dev_params) 51 51 { 52 - MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN); 52 + MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN); 53 53 MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN); 54 54 struct resource *res = &dev_params->res[0]; 55 55 size_t outlen; ··· 64 64 if (ret) 65 65 return ret; 66 66 67 - if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN) 67 + if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN) 68 68 return -EIO; 69 69 70 70 dev_params->bus_num = bus_num; ··· 72 72 73 73 req_id = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID); 74 74 dev_params->req_id = req_id; 75 + 76 + dev_params->msi_dev_id = MCDI_DWORD(outbuf, 77 + CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID); 75 78 76 79 dev_params->res_count = 0; 77 80 if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) { ··· 130 127 dev_params->class = MCDI_DWORD(outbuf, 131 128 CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS) & 0xFFFFFF; 132 129 dev_params->revision = MCDI_BYTE(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION); 130 + dev_params->num_msi = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MSI_COUNT); 133 131 134 132 return 0; 135 133 } ··· 154 150 155 151 MCDI_SET_DWORD(inbuf, CDX_BUS_DOWN_IN_BUS, bus_num); 156 152 ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_DOWN, inbuf, sizeof(inbuf), 153 + NULL, 0, NULL); 154 + 155 + return ret; 156 + } 157 + 158 + int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, 159 + u32 msi_vector, u64 msi_address, u32 msi_data) 160 + { 161 + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN); 162 + int ret; 163 + 164 + MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_BUS, bus_num); 165 + MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE, dev_num); 166 + MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR, msi_vector); 167 + MCDI_SET_QWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS, msi_address); 168 + MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA, msi_data); 169 + 170 + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG, inbuf, sizeof(inbuf), 157 171 NULL, 0, NULL); 158 172 159 173 return ret; ··· 247 225 { 248 226 return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, 249 227 MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_LBN); 228 + } 229 + 230 + int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num, 231 + u8 dev_num, bool enable) 232 + { 233 + return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, 234 + MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MSI_ENABLE_LBN); 250 235 }
+33
drivers/cdx/controller/mcdi_functions.h
··· 66 66 int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num); 67 67 68 68 /** 69 + * cdx_mcdi_write_msi - Write MSI configuration for CDX device 70 + * @cdx: pointer to MCDI interface. 71 + * @bus_num: Bus number. 72 + * @dev_num: Device number. 73 + * @msi_vector: Device-relative MSI vector number. 74 + * Must be < MSI_COUNT reported for the device. 75 + * @msi_address: MSI address to be used by the hardware. Typically, on ARM 76 + * systems this address is translated by the IOMMU (if enabled) and 77 + * it is the responsibility of the entity managing the IOMMU (APU kernel) 78 + * to supply the correct IOVA here. 79 + * @msi_data: MSI data to be used by the hardware. On versal-net, only the 80 + * lower 16-bits are used, the remaining bits are ignored and should be 81 + * set to zero. 82 + * 83 + * Return: 0 on success, <0 on failure 84 + */ 85 + int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, 86 + u32 msi_vector, u64 msi_address, u32 msi_data); 87 + 88 + /** 69 89 * cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num 70 90 * @cdx: pointer to MCDI interface. 71 91 * @bus_num: Bus number. ··· 108 88 */ 109 89 int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num, 110 90 u8 dev_num, bool enable); 91 + 92 + /** 93 + * cdx_mcdi_msi_enable - Enable/Disable MSIs for cdx device represented 94 + * by bus_num:dev_num 95 + * @cdx: pointer to MCDI interface. 96 + * @bus_num: Bus number. 97 + * @dev_num: Device number. 98 + * @enable: Enable msi's if set, disable otherwise. 99 + * 100 + * Return: 0 on success, <0 on failure 101 + */ 102 + int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num, 103 + u8 dev_num, bool enable); 111 104 112 105 #endif /* CDX_MCDI_FUNCTIONS_H */
+52 -1
include/linux/cdx/cdx_bus.h
··· 12 12 #include <linux/device.h> 13 13 #include <linux/list.h> 14 14 #include <linux/mod_devicetable.h> 15 + #include <linux/msi.h> 15 16 16 17 #define MAX_CDX_DEV_RESOURCES 4 17 18 #define CDX_CONTROLLER_ID_SHIFT 4 ··· 22 21 struct cdx_controller; 23 22 24 23 enum { 24 + CDX_DEV_MSI_CONF, 25 25 CDX_DEV_BUS_MASTER_CONF, 26 26 CDX_DEV_RESET_CONF, 27 + CDX_DEV_MSI_ENABLE, 28 + }; 29 + 30 + struct cdx_msi_config { 31 + u64 addr; 32 + u32 data; 33 + u16 msi_index; 27 34 }; 28 35 29 36 struct cdx_device_config { 30 37 u8 type; 31 - bool bus_master_enable; 38 + union { 39 + struct cdx_msi_config msi; 40 + bool bus_master_enable; 41 + bool msi_enable; 42 + }; 32 43 }; 33 44 34 45 typedef int (*cdx_bus_enable_cb)(struct cdx_controller *cdx, u8 bus_num); ··· 100 87 * struct cdx_controller: CDX controller object 101 88 * @dev: Linux device associated with the CDX controller. 102 89 * @priv: private data 90 + * @msi_domain: MSI domain 103 91 * @id: Controller ID 104 92 * @controller_registered: controller registered with bus 105 93 * @ops: CDX controller ops ··· 108 94 struct cdx_controller { 109 95 struct device *dev; 110 96 void *priv; 97 + struct irq_domain *msi_domain; 111 98 u32 id; 112 99 bool controller_registered; 113 100 struct cdx_ops *ops; ··· 135 120 * @req_id: Requestor ID associated with CDX device 136 121 * @is_bus: Is this bus device 137 122 * @enabled: is this bus enabled 123 + * @msi_dev_id: MSI Device ID associated with CDX device 124 + * @num_msi: Number of MSI's supported by the device 138 125 * @driver_override: driver name to force a match; do not set directly, 139 126 * because core frees it; use driver_set_override() to 140 127 * set or clear it. 128 + * @irqchip_lock: lock to synchronize irq/msi configuration 129 + * @msi_write_pending: MSI write pending for this device 141 130 */ 142 131 struct cdx_device { 143 132 struct device dev; ··· 163 144 u32 req_id; 164 145 bool is_bus; 165 146 bool enabled; 147 + u32 msi_dev_id; 148 + u32 num_msi; 166 149 const char *driver_override; 150 + struct mutex irqchip_lock; 151 + bool msi_write_pending; 167 152 }; 168 153 169 154 #define to_cdx_device(_dev) \ ··· 259 236 * Return: 0 for success, -errno on failure 260 237 */ 261 238 int cdx_clear_master(struct cdx_device *cdx_dev); 239 + 240 + #ifdef CONFIG_GENERIC_MSI_IRQ 241 + /** 242 + * cdx_enable_msi - Enable MSI for the CDX device. 243 + * @cdx_dev: device pointer 244 + * 245 + * Return: 0 for success, -errno on failure 246 + */ 247 + int cdx_enable_msi(struct cdx_device *cdx_dev); 248 + 249 + /** 250 + * cdx_disable_msi - Disable MSI for the CDX device. 251 + * @cdx_dev: device pointer 252 + */ 253 + void cdx_disable_msi(struct cdx_device *cdx_dev); 254 + 255 + #else /* CONFIG_GENERIC_MSI_IRQ */ 256 + 257 + static inline int cdx_enable_msi(struct cdx_device *cdx_dev) 258 + { 259 + return -ENODEV; 260 + } 261 + 262 + static inline void cdx_disable_msi(struct cdx_device *cdx_dev) 263 + { 264 + } 265 + 266 + #endif /* CONFIG_GENERIC_MSI_IRQ */ 262 267 263 268 #endif /* _CDX_BUS_H_ */