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); 193