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

Merge tag 'irq-msi-2024-07-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull MSI interrupt updates from Thomas Gleixner:
"Switch ARM/ARM64 over to the modern per device MSI domains.

This simplifies the handling of platform MSI and wire to MSI
controllers and removes about 500 lines of legacy code.

Aside of that it paves the way for ARM/ARM64 to utilize the dynamic
allocation of PCI/MSI interrupts and to support the upcoming non
standard IMS (Interrupt Message Store) mechanism on PCIe devices"

* tag 'irq-msi-2024-07-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (25 commits)
irqchip/gic-v3-its: Correctly fish out the DID for platform MSI
irqchip/gic-v3-its: Correctly honor the RID remapping
genirq/msi: Move msi_device_data to core
genirq/msi: Remove platform MSI leftovers
irqchip/irq-mvebu-icu: Remove platform MSI leftovers
irqchip/irq-mvebu-sei: Switch to MSI parent
irqchip/mvebu-odmi: Switch to parent MSI
irqchip/mvebu-gicp: Switch to MSI parent
irqchip/irq-mvebu-icu: Prepare for real per device MSI
irqchip/imx-mu-msi: Switch to MSI parent
irqchip/gic-v2m: Switch to device MSI
irqchip/gic_v3_mbi: Switch over to parent domain
genirq/msi: Remove platform_msi_create_device_domain()
irqchip/mbigen: Remove platform_msi_create_device_domain() fallback
irqchip/gic-v3-its: Switch platform MSI to MSI parent
irqchip/irq-msi-lib: Prepare for DOMAIN_BUS_WIRED_TO_MSI
irqchip/mbigen: Prepare for real per device MSI
irqchip/irq-msi-lib: Prepare for DEVICE MSI to replace platform MSI
irqchip/gic-v3-its: Provide MSI parent for PCI/MSI[-X]
irqchip/irq-msi-lib: Prepare for PCI MSI/MSIX
...

+756 -1313
+3 -347
drivers/base/platform-msi.c
··· 4 4 * 5 5 * Copyright (C) 2015 ARM Limited, All Rights Reserved. 6 6 * Author: Marc Zyngier <marc.zyngier@arm.com> 7 + * Copyright (C) 2022 Linutronix GmbH 7 8 */ 8 9 9 10 #include <linux/device.h> 10 - #include <linux/idr.h> 11 - #include <linux/irq.h> 12 11 #include <linux/irqdomain.h> 13 12 #include <linux/msi.h> 14 - #include <linux/slab.h> 15 - 16 - /* Begin of removal area. Once everything is converted over. Cleanup the includes too! */ 17 - 18 - #define DEV_ID_SHIFT 21 19 - #define MAX_DEV_MSIS (1 << (32 - DEV_ID_SHIFT)) 20 - 21 - /* 22 - * Internal data structure containing a (made up, but unique) devid 23 - * and the callback to write the MSI message. 24 - */ 25 - struct platform_msi_priv_data { 26 - struct device *dev; 27 - void *host_data; 28 - msi_alloc_info_t arg; 29 - irq_write_msi_msg_t write_msg; 30 - int devid; 31 - }; 32 - 33 - /* The devid allocator */ 34 - static DEFINE_IDA(platform_msi_devid_ida); 35 - 36 - #ifdef GENERIC_MSI_DOMAIN_OPS 37 - /* 38 - * Convert an msi_desc to a globaly unique identifier (per-device 39 - * devid + msi_desc position in the msi_list). 40 - */ 41 - static irq_hw_number_t platform_msi_calc_hwirq(struct msi_desc *desc) 42 - { 43 - u32 devid = desc->dev->msi.data->platform_data->devid; 44 - 45 - return (devid << (32 - DEV_ID_SHIFT)) | desc->msi_index; 46 - } 47 - 48 - static void platform_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) 49 - { 50 - arg->desc = desc; 51 - arg->hwirq = platform_msi_calc_hwirq(desc); 52 - } 53 - 54 - static int platform_msi_init(struct irq_domain *domain, 55 - struct msi_domain_info *info, 56 - unsigned int virq, irq_hw_number_t hwirq, 57 - msi_alloc_info_t *arg) 58 - { 59 - return irq_domain_set_hwirq_and_chip(domain, virq, hwirq, 60 - info->chip, info->chip_data); 61 - } 62 - 63 - static void platform_msi_set_proxy_dev(msi_alloc_info_t *arg) 64 - { 65 - arg->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE; 66 - } 67 - #else 68 - #define platform_msi_set_desc NULL 69 - #define platform_msi_init NULL 70 - #define platform_msi_set_proxy_dev(x) do {} while(0) 71 - #endif 72 - 73 - static void platform_msi_update_dom_ops(struct msi_domain_info *info) 74 - { 75 - struct msi_domain_ops *ops = info->ops; 76 - 77 - BUG_ON(!ops); 78 - 79 - if (ops->msi_init == NULL) 80 - ops->msi_init = platform_msi_init; 81 - if (ops->set_desc == NULL) 82 - ops->set_desc = platform_msi_set_desc; 83 - } 84 - 85 - static void platform_msi_write_msg(struct irq_data *data, struct msi_msg *msg) 86 - { 87 - struct msi_desc *desc = irq_data_get_msi_desc(data); 88 - 89 - desc->dev->msi.data->platform_data->write_msg(desc, msg); 90 - } 91 - 92 - static void platform_msi_update_chip_ops(struct msi_domain_info *info) 93 - { 94 - struct irq_chip *chip = info->chip; 95 - 96 - BUG_ON(!chip); 97 - if (!chip->irq_mask) 98 - chip->irq_mask = irq_chip_mask_parent; 99 - if (!chip->irq_unmask) 100 - chip->irq_unmask = irq_chip_unmask_parent; 101 - if (!chip->irq_eoi) 102 - chip->irq_eoi = irq_chip_eoi_parent; 103 - if (!chip->irq_set_affinity) 104 - chip->irq_set_affinity = msi_domain_set_affinity; 105 - if (!chip->irq_write_msi_msg) 106 - chip->irq_write_msi_msg = platform_msi_write_msg; 107 - if (WARN_ON((info->flags & MSI_FLAG_LEVEL_CAPABLE) && 108 - !(chip->flags & IRQCHIP_SUPPORTS_LEVEL_MSI))) 109 - info->flags &= ~MSI_FLAG_LEVEL_CAPABLE; 110 - } 111 - 112 - /** 113 - * platform_msi_create_irq_domain - Create a platform MSI interrupt domain 114 - * @fwnode: Optional fwnode of the interrupt controller 115 - * @info: MSI domain info 116 - * @parent: Parent irq domain 117 - * 118 - * Updates the domain and chip ops and creates a platform MSI 119 - * interrupt domain. 120 - * 121 - * Returns: 122 - * A domain pointer or NULL in case of failure. 123 - */ 124 - struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode, 125 - struct msi_domain_info *info, 126 - struct irq_domain *parent) 127 - { 128 - struct irq_domain *domain; 129 - 130 - if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) 131 - platform_msi_update_dom_ops(info); 132 - if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) 133 - platform_msi_update_chip_ops(info); 134 - info->flags |= MSI_FLAG_DEV_SYSFS | MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | 135 - MSI_FLAG_FREE_MSI_DESCS; 136 - 137 - domain = msi_create_irq_domain(fwnode, info, parent); 138 - if (domain) 139 - irq_domain_update_bus_token(domain, DOMAIN_BUS_PLATFORM_MSI); 140 - 141 - return domain; 142 - } 143 - EXPORT_SYMBOL_GPL(platform_msi_create_irq_domain); 144 - 145 - static int platform_msi_alloc_priv_data(struct device *dev, unsigned int nvec, 146 - irq_write_msi_msg_t write_msi_msg) 147 - { 148 - struct platform_msi_priv_data *datap; 149 - int err; 150 - 151 - /* 152 - * Limit the number of interrupts to 2048 per device. Should we 153 - * need to bump this up, DEV_ID_SHIFT should be adjusted 154 - * accordingly (which would impact the max number of MSI 155 - * capable devices). 156 - */ 157 - if (!dev->msi.domain || !write_msi_msg || !nvec || nvec > MAX_DEV_MSIS) 158 - return -EINVAL; 159 - 160 - if (dev->msi.domain->bus_token != DOMAIN_BUS_PLATFORM_MSI) { 161 - dev_err(dev, "Incompatible msi_domain, giving up\n"); 162 - return -EINVAL; 163 - } 164 - 165 - err = msi_setup_device_data(dev); 166 - if (err) 167 - return err; 168 - 169 - /* Already initialized? */ 170 - if (dev->msi.data->platform_data) 171 - return -EBUSY; 172 - 173 - datap = kzalloc(sizeof(*datap), GFP_KERNEL); 174 - if (!datap) 175 - return -ENOMEM; 176 - 177 - datap->devid = ida_alloc_max(&platform_msi_devid_ida, 178 - (1 << DEV_ID_SHIFT) - 1, GFP_KERNEL); 179 - if (datap->devid < 0) { 180 - err = datap->devid; 181 - kfree(datap); 182 - return err; 183 - } 184 - 185 - datap->write_msg = write_msi_msg; 186 - datap->dev = dev; 187 - dev->msi.data->platform_data = datap; 188 - return 0; 189 - } 190 - 191 - static void platform_msi_free_priv_data(struct device *dev) 192 - { 193 - struct platform_msi_priv_data *data = dev->msi.data->platform_data; 194 - 195 - dev->msi.data->platform_data = NULL; 196 - ida_free(&platform_msi_devid_ida, data->devid); 197 - kfree(data); 198 - } 199 - 200 - /** 201 - * platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev 202 - * @dev: The device for which to allocate interrupts 203 - * @nvec: The number of interrupts to allocate 204 - * @write_msi_msg: Callback to write an interrupt message for @dev 205 - * 206 - * Returns: 207 - * Zero for success, or an error code in case of failure 208 - */ 209 - static int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, 210 - irq_write_msi_msg_t write_msi_msg) 211 - { 212 - int err; 213 - 214 - err = platform_msi_alloc_priv_data(dev, nvec, write_msi_msg); 215 - if (err) 216 - return err; 217 - 218 - err = msi_domain_alloc_irqs_range(dev, MSI_DEFAULT_DOMAIN, 0, nvec - 1); 219 - if (err) 220 - platform_msi_free_priv_data(dev); 221 - 222 - return err; 223 - } 224 - 225 - /** 226 - * platform_msi_get_host_data - Query the private data associated with 227 - * a platform-msi domain 228 - * @domain: The platform-msi domain 229 - * 230 - * Return: The private data provided when calling 231 - * platform_msi_create_device_domain(). 232 - */ 233 - void *platform_msi_get_host_data(struct irq_domain *domain) 234 - { 235 - struct platform_msi_priv_data *data = domain->host_data; 236 - 237 - return data->host_data; 238 - } 239 - 240 - static struct lock_class_key platform_device_msi_lock_class; 241 - 242 - /** 243 - * __platform_msi_create_device_domain - Create a platform-msi device domain 244 - * 245 - * @dev: The device generating the MSIs 246 - * @nvec: The number of MSIs that need to be allocated 247 - * @is_tree: flag to indicate tree hierarchy 248 - * @write_msi_msg: Callback to write an interrupt message for @dev 249 - * @ops: The hierarchy domain operations to use 250 - * @host_data: Private data associated to this domain 251 - * 252 - * Return: An irqdomain for @nvec interrupts on success, NULL in case of error. 253 - * 254 - * This is for interrupt domains which stack on a platform-msi domain 255 - * created by platform_msi_create_irq_domain(). @dev->msi.domain points to 256 - * that platform-msi domain which is the parent for the new domain. 257 - */ 258 - struct irq_domain * 259 - __platform_msi_create_device_domain(struct device *dev, 260 - unsigned int nvec, 261 - bool is_tree, 262 - irq_write_msi_msg_t write_msi_msg, 263 - const struct irq_domain_ops *ops, 264 - void *host_data) 265 - { 266 - struct platform_msi_priv_data *data; 267 - struct irq_domain *domain; 268 - int err; 269 - 270 - err = platform_msi_alloc_priv_data(dev, nvec, write_msi_msg); 271 - if (err) 272 - return NULL; 273 - 274 - /* 275 - * Use a separate lock class for the MSI descriptor mutex on 276 - * platform MSI device domains because the descriptor mutex nests 277 - * into the domain mutex. See alloc/free below. 278 - */ 279 - lockdep_set_class(&dev->msi.data->mutex, &platform_device_msi_lock_class); 280 - 281 - data = dev->msi.data->platform_data; 282 - data->host_data = host_data; 283 - domain = irq_domain_create_hierarchy(dev->msi.domain, 0, 284 - is_tree ? 0 : nvec, 285 - dev->fwnode, ops, data); 286 - if (!domain) 287 - goto free_priv; 288 - 289 - platform_msi_set_proxy_dev(&data->arg); 290 - err = msi_domain_prepare_irqs(domain->parent, dev, nvec, &data->arg); 291 - if (err) 292 - goto free_domain; 293 - 294 - return domain; 295 - 296 - free_domain: 297 - irq_domain_remove(domain); 298 - free_priv: 299 - platform_msi_free_priv_data(dev); 300 - return NULL; 301 - } 302 - 303 - /** 304 - * platform_msi_device_domain_free - Free interrupts associated with a platform-msi 305 - * device domain 306 - * 307 - * @domain: The platform-msi device domain 308 - * @virq: The base irq from which to perform the free operation 309 - * @nr_irqs: How many interrupts to free from @virq 310 - */ 311 - void platform_msi_device_domain_free(struct irq_domain *domain, unsigned int virq, 312 - unsigned int nr_irqs) 313 - { 314 - struct platform_msi_priv_data *data = domain->host_data; 315 - 316 - msi_lock_descs(data->dev); 317 - msi_domain_depopulate_descs(data->dev, virq, nr_irqs); 318 - irq_domain_free_irqs_common(domain, virq, nr_irqs); 319 - msi_free_msi_descs_range(data->dev, virq, virq + nr_irqs - 1); 320 - msi_unlock_descs(data->dev); 321 - } 322 - 323 - /** 324 - * platform_msi_device_domain_alloc - Allocate interrupts associated with 325 - * a platform-msi device domain 326 - * 327 - * @domain: The platform-msi device domain 328 - * @virq: The base irq from which to perform the allocate operation 329 - * @nr_irqs: How many interrupts to allocate from @virq 330 - * 331 - * Return 0 on success, or an error code on failure. Must be called 332 - * with irq_domain_mutex held (which can only be done as part of a 333 - * top-level interrupt allocation). 334 - */ 335 - int platform_msi_device_domain_alloc(struct irq_domain *domain, unsigned int virq, 336 - unsigned int nr_irqs) 337 - { 338 - struct platform_msi_priv_data *data = domain->host_data; 339 - struct device *dev = data->dev; 340 - 341 - return msi_domain_populate_irqs(domain->parent, dev, virq, nr_irqs, &data->arg); 342 - } 343 - 344 - /* End of removal area */ 345 - 346 - /* Real per device domain interfaces */ 347 13 348 14 /* 349 15 * This indirection can go when platform_device_msi_init_and_alloc_irqs() ··· 23 357 cb(irq_data_get_msi_desc(d), msg); 24 358 } 25 359 26 - static void platform_msi_set_desc_byindex(msi_alloc_info_t *arg, struct msi_desc *desc) 360 + static void platform_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) 27 361 { 28 362 arg->desc = desc; 29 363 arg->hwirq = desc->msi_index; ··· 39 373 }, 40 374 41 375 .ops = { 42 - .set_desc = platform_msi_set_desc_byindex, 376 + .set_desc = platform_msi_set_desc, 43 377 }, 44 378 45 379 .info = { ··· 74 408 if (!domain || !write_msi_msg) 75 409 return -EINVAL; 76 410 77 - /* Migration support. Will go away once everything is converted */ 78 - if (!irq_domain_is_msi_parent(domain)) 79 - return platform_msi_domain_alloc_irqs(dev, nvec, write_msi_msg); 80 - 81 411 /* 82 412 * @write_msi_msg is stored in the resulting msi_domain_info::data. 83 413 * The underlying domain creation mechanism will assign that ··· 94 432 */ 95 433 void platform_device_msi_free_irqs_all(struct device *dev) 96 434 { 97 - struct irq_domain *domain = dev->msi.domain; 98 - 99 435 msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN); 100 - 101 - /* Migration support. Will go away once everything is converted */ 102 - if (!irq_domain_is_msi_parent(domain)) 103 - platform_msi_free_priv_data(dev); 104 436 } 105 437 EXPORT_SYMBOL_GPL(platform_device_msi_free_irqs_all);
+8
drivers/irqchip/Kconfig
··· 26 26 bool 27 27 depends on PCI 28 28 select ARM_GIC 29 + select IRQ_MSI_LIB 29 30 select PCI_MSI 30 31 31 32 config GIC_NON_BANKED ··· 42 41 config ARM_GIC_V3_ITS 43 42 bool 44 43 select GENERIC_MSI_IRQ 44 + select IRQ_MSI_LIB 45 45 default ARM_GIC_V3 46 46 47 47 config ARM_GIC_V3_ITS_PCI ··· 75 73 help 76 74 The maximum number of VICs available in the system, for 77 75 power management. 76 + 77 + config IRQ_MSI_LIB 78 + bool 78 79 79 80 config ARMADA_370_XP_IRQ 80 81 bool ··· 383 378 select GENERIC_IRQ_CHIP 384 379 385 380 config MVEBU_GICP 381 + select IRQ_MSI_LIB 386 382 bool 387 383 388 384 config MVEBU_ICU ··· 391 385 392 386 config MVEBU_ODMI 393 387 bool 388 + select IRQ_MSI_LIB 394 389 select GENERIC_MSI_IRQ 395 390 396 391 config MVEBU_PIC ··· 515 508 select IRQ_DOMAIN 516 509 select IRQ_DOMAIN_HIERARCHY 517 510 select GENERIC_MSI_IRQ 511 + select IRQ_MSI_LIB 518 512 help 519 513 Provide a driver for the i.MX Messaging Unit block used as a 520 514 CPU-to-CPU MSI controller. This requires a specially crafted DT
+2 -2
drivers/irqchip/Makefile
··· 29 29 obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o 30 30 obj-$(CONFIG_ARM_GIC_PM) += irq-gic-pm.o 31 31 obj-$(CONFIG_ARCH_REALVIEW) += irq-gic-realview.o 32 + obj-$(CONFIG_IRQ_MSI_LIB) += irq-msi-lib.o 32 33 obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o 33 34 obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-v3-mbi.o irq-gic-common.o 34 - obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-platform-msi.o irq-gic-v4.o 35 - obj-$(CONFIG_ARM_GIC_V3_ITS_PCI) += irq-gic-v3-its-pci-msi.o 35 + obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v4.o irq-gic-v3-its-msi-parent.o 36 36 obj-$(CONFIG_ARM_GIC_V3_ITS_FSL_MC) += irq-gic-v3-its-fsl-mc-msi.o 37 37 obj-$(CONFIG_PARTITION_PERCPU) += irq-partition-percpu.o 38 38 obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
+3
drivers/irqchip/irq-gic-common.h
··· 8 8 9 9 #include <linux/of.h> 10 10 #include <linux/irqdomain.h> 11 + #include <linux/msi.h> 11 12 #include <linux/irqchip/arm-gic-common.h> 12 13 13 14 struct gic_quirk { ··· 28 27 void *data); 29 28 void gic_enable_of_quirks(const struct device_node *np, 30 29 const struct gic_quirk *quirks, void *data); 30 + 31 + extern const struct msi_parent_ops gic_v3_its_msi_parent_ops; 31 32 32 33 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) 33 34 #define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1)
+25 -56
drivers/irqchip/irq-gic-v2m.c
··· 26 26 #include <linux/irqchip/arm-gic.h> 27 27 #include <linux/irqchip/arm-gic-common.h> 28 28 29 + #include "irq-msi-lib.h" 30 + 29 31 /* 30 32 * MSI_TYPER: 31 33 * [31:26] Reserved ··· 72 70 u32 spi_offset; /* offset to be subtracted from SPI number */ 73 71 unsigned long *bm; /* MSI vector bitmap */ 74 72 u32 flags; /* v2m flags for specific implementation */ 75 - }; 76 - 77 - static void gicv2m_mask_msi_irq(struct irq_data *d) 78 - { 79 - pci_msi_mask_irq(d); 80 - irq_chip_mask_parent(d); 81 - } 82 - 83 - static void gicv2m_unmask_msi_irq(struct irq_data *d) 84 - { 85 - pci_msi_unmask_irq(d); 86 - irq_chip_unmask_parent(d); 87 - } 88 - 89 - static struct irq_chip gicv2m_msi_irq_chip = { 90 - .name = "MSI", 91 - .irq_mask = gicv2m_mask_msi_irq, 92 - .irq_unmask = gicv2m_unmask_msi_irq, 93 - .irq_eoi = irq_chip_eoi_parent, 94 - }; 95 - 96 - static struct msi_domain_info gicv2m_msi_domain_info = { 97 - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 98 - MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI), 99 - .chip = &gicv2m_msi_irq_chip, 100 73 }; 101 74 102 75 static phys_addr_t gicv2m_get_msi_addr(struct v2m_data *v2m, int hwirq) ··· 207 230 } 208 231 209 232 static const struct irq_domain_ops gicv2m_domain_ops = { 233 + .select = msi_lib_irq_domain_select, 210 234 .alloc = gicv2m_irq_domain_alloc, 211 235 .free = gicv2m_irq_domain_free, 212 236 }; ··· 228 250 return true; 229 251 } 230 252 231 - static struct irq_chip gicv2m_pmsi_irq_chip = { 232 - .name = "pMSI", 233 - }; 234 - 235 - static struct msi_domain_ops gicv2m_pmsi_ops = { 236 - }; 237 - 238 - static struct msi_domain_info gicv2m_pmsi_domain_info = { 239 - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), 240 - .ops = &gicv2m_pmsi_ops, 241 - .chip = &gicv2m_pmsi_irq_chip, 242 - }; 243 - 244 253 static void __init gicv2m_teardown(void) 245 254 { 246 255 struct v2m_data *v2m, *tmp; ··· 243 278 } 244 279 } 245 280 281 + 282 + #define GICV2M_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ 283 + MSI_FLAG_USE_DEF_CHIP_OPS | \ 284 + MSI_FLAG_PCI_MSI_MASK_PARENT) 285 + 286 + #define GICV2M_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ 287 + MSI_FLAG_PCI_MSIX | \ 288 + MSI_FLAG_MULTI_PCI_MSI) 289 + 290 + static struct msi_parent_ops gicv2m_msi_parent_ops = { 291 + .supported_flags = GICV2M_MSI_FLAGS_SUPPORTED, 292 + .required_flags = GICV2M_MSI_FLAGS_REQUIRED, 293 + .bus_select_token = DOMAIN_BUS_NEXUS, 294 + .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI, 295 + .prefix = "GICv2m-", 296 + .init_dev_msi_info = msi_lib_init_dev_msi_info, 297 + }; 298 + 246 299 static __init int gicv2m_allocate_domains(struct irq_domain *parent) 247 300 { 248 - struct irq_domain *inner_domain, *pci_domain, *plat_domain; 301 + struct irq_domain *inner_domain; 249 302 struct v2m_data *v2m; 250 303 251 304 v2m = list_first_entry_or_null(&v2m_nodes, struct v2m_data, entry); ··· 278 295 } 279 296 280 297 irq_domain_update_bus_token(inner_domain, DOMAIN_BUS_NEXUS); 281 - pci_domain = pci_msi_create_irq_domain(v2m->fwnode, 282 - &gicv2m_msi_domain_info, 283 - inner_domain); 284 - plat_domain = platform_msi_create_irq_domain(v2m->fwnode, 285 - &gicv2m_pmsi_domain_info, 286 - inner_domain); 287 - if (!pci_domain || !plat_domain) { 288 - pr_err("Failed to create MSI domains\n"); 289 - if (plat_domain) 290 - irq_domain_remove(plat_domain); 291 - if (pci_domain) 292 - irq_domain_remove(pci_domain); 293 - irq_domain_remove(inner_domain); 294 - return -ENOMEM; 295 - } 296 - 298 + inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; 299 + inner_domain->msi_parent_ops = &gicv2m_msi_parent_ops; 297 300 return 0; 298 301 } 299 302 ··· 480 511 pr_info("applying Amazon Graviton quirk\n"); 481 512 res.end = res.start + SZ_8K - 1; 482 513 flags |= GICV2M_GRAVITON_ADDRESS_ONLY; 483 - gicv2m_msi_domain_info.flags &= ~MSI_FLAG_MULTI_PCI_MSI; 514 + gicv2m_msi_parent_ops.supported_flags &= ~MSI_FLAG_MULTI_PCI_MSI; 484 515 } 485 516 486 517 if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
+210
drivers/irqchip/irq-gic-v3-its-msi-parent.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + // Copyright (C) 2013-2015 ARM Limited, All Rights Reserved. 3 + // Author: Marc Zyngier <marc.zyngier@arm.com> 4 + // Copyright (C) 2022 Linutronix GmbH 5 + // Copyright (C) 2022 Intel 6 + 7 + #include <linux/acpi_iort.h> 8 + #include <linux/pci.h> 9 + 10 + #include "irq-gic-common.h" 11 + #include "irq-msi-lib.h" 12 + 13 + #define ITS_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ 14 + MSI_FLAG_USE_DEF_CHIP_OPS | \ 15 + MSI_FLAG_PCI_MSI_MASK_PARENT) 16 + 17 + #define ITS_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ 18 + MSI_FLAG_PCI_MSIX | \ 19 + MSI_FLAG_MULTI_PCI_MSI) 20 + 21 + #ifdef CONFIG_PCI_MSI 22 + static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data) 23 + { 24 + int msi, msix, *count = data; 25 + 26 + msi = max(pci_msi_vec_count(pdev), 0); 27 + msix = max(pci_msix_vec_count(pdev), 0); 28 + *count += max(msi, msix); 29 + 30 + return 0; 31 + } 32 + 33 + static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data) 34 + { 35 + struct pci_dev **alias_dev = data; 36 + 37 + *alias_dev = pdev; 38 + 39 + return 0; 40 + } 41 + 42 + static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, 43 + int nvec, msi_alloc_info_t *info) 44 + { 45 + struct pci_dev *pdev, *alias_dev; 46 + struct msi_domain_info *msi_info; 47 + int alias_count = 0, minnvec = 1; 48 + 49 + if (!dev_is_pci(dev)) 50 + return -EINVAL; 51 + 52 + pdev = to_pci_dev(dev); 53 + /* 54 + * If pdev is downstream of any aliasing bridges, take an upper 55 + * bound of how many other vectors could map to the same DevID. 56 + * Also tell the ITS that the signalling will come from a proxy 57 + * device, and that special allocation rules apply. 58 + */ 59 + pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev); 60 + if (alias_dev != pdev) { 61 + if (alias_dev->subordinate) 62 + pci_walk_bus(alias_dev->subordinate, 63 + its_pci_msi_vec_count, &alias_count); 64 + info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE; 65 + } 66 + 67 + /* ITS specific DeviceID, as the core ITS ignores dev. */ 68 + info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain->parent, pdev); 69 + 70 + /* 71 + * @domain->msi_domain_info->hwsize contains the size of the 72 + * MSI[-X] domain, but vector allocation happens one by one. This 73 + * needs some thought when MSI comes into play as the size of MSI 74 + * might be unknown at domain creation time and therefore set to 75 + * MSI_MAX_INDEX. 76 + */ 77 + msi_info = msi_get_domain_info(domain); 78 + if (msi_info->hwsize > nvec) 79 + nvec = msi_info->hwsize; 80 + 81 + /* 82 + * Always allocate a power of 2, and special case device 0 for 83 + * broken systems where the DevID is not wired (and all devices 84 + * appear as DevID 0). For that reason, we generously allocate a 85 + * minimum of 32 MSIs for DevID 0. If you want more because all 86 + * your devices are aliasing to DevID 0, consider fixing your HW. 87 + */ 88 + nvec = max(nvec, alias_count); 89 + if (!info->scratchpad[0].ul) 90 + minnvec = 32; 91 + nvec = max_t(int, minnvec, roundup_pow_of_two(nvec)); 92 + 93 + msi_info = msi_get_domain_info(domain->parent); 94 + return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info); 95 + } 96 + #else /* CONFIG_PCI_MSI */ 97 + #define its_pci_msi_prepare NULL 98 + #endif /* !CONFIG_PCI_MSI */ 99 + 100 + static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev, 101 + u32 *dev_id) 102 + { 103 + int ret, index = 0; 104 + 105 + /* Suck the DeviceID out of the msi-parent property */ 106 + do { 107 + struct of_phandle_args args; 108 + 109 + ret = of_parse_phandle_with_args(dev->of_node, 110 + "msi-parent", "#msi-cells", 111 + index, &args); 112 + if (args.np == irq_domain_get_of_node(domain)) { 113 + if (WARN_ON(args.args_count != 1)) 114 + return -EINVAL; 115 + *dev_id = args.args[0]; 116 + break; 117 + } 118 + index++; 119 + } while (!ret); 120 + 121 + return ret; 122 + } 123 + 124 + int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id) 125 + { 126 + return -1; 127 + } 128 + 129 + static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev, 130 + int nvec, msi_alloc_info_t *info) 131 + { 132 + struct msi_domain_info *msi_info; 133 + u32 dev_id; 134 + int ret; 135 + 136 + if (dev->of_node) 137 + ret = of_pmsi_get_dev_id(domain->parent, dev, &dev_id); 138 + else 139 + ret = iort_pmsi_get_dev_id(dev, &dev_id); 140 + if (ret) 141 + return ret; 142 + 143 + /* ITS specific DeviceID, as the core ITS ignores dev. */ 144 + info->scratchpad[0].ul = dev_id; 145 + 146 + /* 147 + * @domain->msi_domain_info->hwsize contains the size of the device 148 + * domain, but vector allocation happens one by one. 149 + */ 150 + msi_info = msi_get_domain_info(domain); 151 + if (msi_info->hwsize > nvec) 152 + nvec = msi_info->hwsize; 153 + 154 + /* Allocate at least 32 MSIs, and always as a power of 2 */ 155 + nvec = max_t(int, 32, roundup_pow_of_two(nvec)); 156 + 157 + msi_info = msi_get_domain_info(domain->parent); 158 + return msi_info->ops->msi_prepare(domain->parent, 159 + dev, nvec, info); 160 + } 161 + 162 + static bool its_init_dev_msi_info(struct device *dev, struct irq_domain *domain, 163 + struct irq_domain *real_parent, struct msi_domain_info *info) 164 + { 165 + if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info)) 166 + return false; 167 + 168 + switch(info->bus_token) { 169 + case DOMAIN_BUS_PCI_DEVICE_MSI: 170 + case DOMAIN_BUS_PCI_DEVICE_MSIX: 171 + /* 172 + * FIXME: This probably should be done after a (not yet 173 + * existing) post domain creation callback once to make 174 + * support for dynamic post-enable MSI-X allocations 175 + * work without having to reevaluate the domain size 176 + * over and over. It is known already at allocation 177 + * time via info->hwsize. 178 + * 179 + * That should work perfectly fine for MSI/MSI-X but needs 180 + * some thoughts for purely software managed MSI domains 181 + * where the index space is only limited artificially via 182 + * %MSI_MAX_INDEX. 183 + */ 184 + info->ops->msi_prepare = its_pci_msi_prepare; 185 + break; 186 + case DOMAIN_BUS_DEVICE_MSI: 187 + case DOMAIN_BUS_WIRED_TO_MSI: 188 + /* 189 + * FIXME: See the above PCI prepare comment. The domain 190 + * size is also known at domain creation time. 191 + */ 192 + info->ops->msi_prepare = its_pmsi_prepare; 193 + break; 194 + default: 195 + /* Confused. How did the lib return true? */ 196 + WARN_ON_ONCE(1); 197 + return false; 198 + } 199 + 200 + return true; 201 + } 202 + 203 + const struct msi_parent_ops gic_v3_its_msi_parent_ops = { 204 + .supported_flags = ITS_MSI_FLAGS_SUPPORTED, 205 + .required_flags = ITS_MSI_FLAGS_REQUIRED, 206 + .bus_select_token = DOMAIN_BUS_NEXUS, 207 + .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI, 208 + .prefix = "ITS-", 209 + .init_dev_msi_info = its_init_dev_msi_info, 210 + };
-202
drivers/irqchip/irq-gic-v3-its-pci-msi.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-only 2 - /* 3 - * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved. 4 - * Author: Marc Zyngier <marc.zyngier@arm.com> 5 - */ 6 - 7 - #include <linux/acpi_iort.h> 8 - #include <linux/pci.h> 9 - #include <linux/msi.h> 10 - #include <linux/of.h> 11 - #include <linux/of_irq.h> 12 - #include <linux/of_pci.h> 13 - 14 - static void its_mask_msi_irq(struct irq_data *d) 15 - { 16 - pci_msi_mask_irq(d); 17 - irq_chip_mask_parent(d); 18 - } 19 - 20 - static void its_unmask_msi_irq(struct irq_data *d) 21 - { 22 - pci_msi_unmask_irq(d); 23 - irq_chip_unmask_parent(d); 24 - } 25 - 26 - static struct irq_chip its_msi_irq_chip = { 27 - .name = "ITS-MSI", 28 - .irq_unmask = its_unmask_msi_irq, 29 - .irq_mask = its_mask_msi_irq, 30 - .irq_eoi = irq_chip_eoi_parent, 31 - }; 32 - 33 - static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data) 34 - { 35 - int msi, msix, *count = data; 36 - 37 - msi = max(pci_msi_vec_count(pdev), 0); 38 - msix = max(pci_msix_vec_count(pdev), 0); 39 - *count += max(msi, msix); 40 - 41 - return 0; 42 - } 43 - 44 - static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data) 45 - { 46 - struct pci_dev **alias_dev = data; 47 - 48 - *alias_dev = pdev; 49 - 50 - return 0; 51 - } 52 - 53 - static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, 54 - int nvec, msi_alloc_info_t *info) 55 - { 56 - struct pci_dev *pdev, *alias_dev; 57 - struct msi_domain_info *msi_info; 58 - int alias_count = 0, minnvec = 1; 59 - 60 - if (!dev_is_pci(dev)) 61 - return -EINVAL; 62 - 63 - msi_info = msi_get_domain_info(domain->parent); 64 - 65 - pdev = to_pci_dev(dev); 66 - /* 67 - * If pdev is downstream of any aliasing bridges, take an upper 68 - * bound of how many other vectors could map to the same DevID. 69 - * Also tell the ITS that the signalling will come from a proxy 70 - * device, and that special allocation rules apply. 71 - */ 72 - pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev); 73 - if (alias_dev != pdev) { 74 - if (alias_dev->subordinate) 75 - pci_walk_bus(alias_dev->subordinate, 76 - its_pci_msi_vec_count, &alias_count); 77 - info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE; 78 - } 79 - 80 - /* ITS specific DeviceID, as the core ITS ignores dev. */ 81 - info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain, pdev); 82 - 83 - /* 84 - * Always allocate a power of 2, and special case device 0 for 85 - * broken systems where the DevID is not wired (and all devices 86 - * appear as DevID 0). For that reason, we generously allocate a 87 - * minimum of 32 MSIs for DevID 0. If you want more because all 88 - * your devices are aliasing to DevID 0, consider fixing your HW. 89 - */ 90 - nvec = max(nvec, alias_count); 91 - if (!info->scratchpad[0].ul) 92 - minnvec = 32; 93 - nvec = max_t(int, minnvec, roundup_pow_of_two(nvec)); 94 - return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info); 95 - } 96 - 97 - static struct msi_domain_ops its_pci_msi_ops = { 98 - .msi_prepare = its_pci_msi_prepare, 99 - }; 100 - 101 - static struct msi_domain_info its_pci_msi_domain_info = { 102 - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 103 - MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), 104 - .ops = &its_pci_msi_ops, 105 - .chip = &its_msi_irq_chip, 106 - }; 107 - 108 - static struct of_device_id its_device_id[] = { 109 - { .compatible = "arm,gic-v3-its", }, 110 - {}, 111 - }; 112 - 113 - static int __init its_pci_msi_init_one(struct fwnode_handle *handle, 114 - const char *name) 115 - { 116 - struct irq_domain *parent; 117 - 118 - parent = irq_find_matching_fwnode(handle, DOMAIN_BUS_NEXUS); 119 - if (!parent || !msi_get_domain_info(parent)) { 120 - pr_err("%s: Unable to locate ITS domain\n", name); 121 - return -ENXIO; 122 - } 123 - 124 - if (!pci_msi_create_irq_domain(handle, &its_pci_msi_domain_info, 125 - parent)) { 126 - pr_err("%s: Unable to create PCI domain\n", name); 127 - return -ENOMEM; 128 - } 129 - 130 - return 0; 131 - } 132 - 133 - static int __init its_pci_of_msi_init(void) 134 - { 135 - struct device_node *np; 136 - 137 - for (np = of_find_matching_node(NULL, its_device_id); np; 138 - np = of_find_matching_node(np, its_device_id)) { 139 - if (!of_device_is_available(np)) 140 - continue; 141 - if (!of_property_read_bool(np, "msi-controller")) 142 - continue; 143 - 144 - if (its_pci_msi_init_one(of_node_to_fwnode(np), np->full_name)) 145 - continue; 146 - 147 - pr_info("PCI/MSI: %pOF domain created\n", np); 148 - } 149 - 150 - return 0; 151 - } 152 - 153 - #ifdef CONFIG_ACPI 154 - 155 - static int __init 156 - its_pci_msi_parse_madt(union acpi_subtable_headers *header, 157 - const unsigned long end) 158 - { 159 - struct acpi_madt_generic_translator *its_entry; 160 - struct fwnode_handle *dom_handle; 161 - const char *node_name; 162 - int err = -ENXIO; 163 - 164 - its_entry = (struct acpi_madt_generic_translator *)header; 165 - node_name = kasprintf(GFP_KERNEL, "ITS@0x%lx", 166 - (long)its_entry->base_address); 167 - dom_handle = iort_find_domain_token(its_entry->translation_id); 168 - if (!dom_handle) { 169 - pr_err("%s: Unable to locate ITS domain handle\n", node_name); 170 - goto out; 171 - } 172 - 173 - err = its_pci_msi_init_one(dom_handle, node_name); 174 - if (!err) 175 - pr_info("PCI/MSI: %s domain created\n", node_name); 176 - 177 - out: 178 - kfree(node_name); 179 - return err; 180 - } 181 - 182 - static int __init its_pci_acpi_msi_init(void) 183 - { 184 - acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR, 185 - its_pci_msi_parse_madt, 0); 186 - return 0; 187 - } 188 - #else 189 - static int __init its_pci_acpi_msi_init(void) 190 - { 191 - return 0; 192 - } 193 - #endif 194 - 195 - static int __init its_pci_msi_init(void) 196 - { 197 - its_pci_of_msi_init(); 198 - its_pci_acpi_msi_init(); 199 - 200 - return 0; 201 - } 202 - early_initcall(its_pci_msi_init);
-163
drivers/irqchip/irq-gic-v3-its-platform-msi.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-only 2 - /* 3 - * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved. 4 - * Author: Marc Zyngier <marc.zyngier@arm.com> 5 - */ 6 - 7 - #include <linux/acpi_iort.h> 8 - #include <linux/device.h> 9 - #include <linux/msi.h> 10 - #include <linux/of.h> 11 - #include <linux/of_irq.h> 12 - 13 - static struct irq_chip its_pmsi_irq_chip = { 14 - .name = "ITS-pMSI", 15 - }; 16 - 17 - static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev, 18 - u32 *dev_id) 19 - { 20 - int ret, index = 0; 21 - 22 - /* Suck the DeviceID out of the msi-parent property */ 23 - do { 24 - struct of_phandle_args args; 25 - 26 - ret = of_parse_phandle_with_args(dev->of_node, 27 - "msi-parent", "#msi-cells", 28 - index, &args); 29 - if (args.np == irq_domain_get_of_node(domain)) { 30 - if (WARN_ON(args.args_count != 1)) 31 - return -EINVAL; 32 - *dev_id = args.args[0]; 33 - break; 34 - } 35 - index++; 36 - } while (!ret); 37 - 38 - return ret; 39 - } 40 - 41 - int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id) 42 - { 43 - return -1; 44 - } 45 - 46 - static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev, 47 - int nvec, msi_alloc_info_t *info) 48 - { 49 - struct msi_domain_info *msi_info; 50 - u32 dev_id; 51 - int ret; 52 - 53 - msi_info = msi_get_domain_info(domain->parent); 54 - 55 - if (dev->of_node) 56 - ret = of_pmsi_get_dev_id(domain, dev, &dev_id); 57 - else 58 - ret = iort_pmsi_get_dev_id(dev, &dev_id); 59 - if (ret) 60 - return ret; 61 - 62 - /* ITS specific DeviceID, as the core ITS ignores dev. */ 63 - info->scratchpad[0].ul = dev_id; 64 - 65 - /* Allocate at least 32 MSIs, and always as a power of 2 */ 66 - nvec = max_t(int, 32, roundup_pow_of_two(nvec)); 67 - return msi_info->ops->msi_prepare(domain->parent, 68 - dev, nvec, info); 69 - } 70 - 71 - static struct msi_domain_ops its_pmsi_ops = { 72 - .msi_prepare = its_pmsi_prepare, 73 - }; 74 - 75 - static struct msi_domain_info its_pmsi_domain_info = { 76 - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), 77 - .ops = &its_pmsi_ops, 78 - .chip = &its_pmsi_irq_chip, 79 - }; 80 - 81 - static const struct of_device_id its_device_id[] = { 82 - { .compatible = "arm,gic-v3-its", }, 83 - {}, 84 - }; 85 - 86 - static int __init its_pmsi_init_one(struct fwnode_handle *fwnode, 87 - const char *name) 88 - { 89 - struct irq_domain *parent; 90 - 91 - parent = irq_find_matching_fwnode(fwnode, DOMAIN_BUS_NEXUS); 92 - if (!parent || !msi_get_domain_info(parent)) { 93 - pr_err("%s: unable to locate ITS domain\n", name); 94 - return -ENXIO; 95 - } 96 - 97 - if (!platform_msi_create_irq_domain(fwnode, &its_pmsi_domain_info, 98 - parent)) { 99 - pr_err("%s: unable to create platform domain\n", name); 100 - return -ENXIO; 101 - } 102 - 103 - pr_info("Platform MSI: %s domain created\n", name); 104 - return 0; 105 - } 106 - 107 - #ifdef CONFIG_ACPI 108 - static int __init 109 - its_pmsi_parse_madt(union acpi_subtable_headers *header, 110 - const unsigned long end) 111 - { 112 - struct acpi_madt_generic_translator *its_entry; 113 - struct fwnode_handle *domain_handle; 114 - const char *node_name; 115 - int err = -ENXIO; 116 - 117 - its_entry = (struct acpi_madt_generic_translator *)header; 118 - node_name = kasprintf(GFP_KERNEL, "ITS@0x%lx", 119 - (long)its_entry->base_address); 120 - domain_handle = iort_find_domain_token(its_entry->translation_id); 121 - if (!domain_handle) { 122 - pr_err("%s: Unable to locate ITS domain handle\n", node_name); 123 - goto out; 124 - } 125 - 126 - err = its_pmsi_init_one(domain_handle, node_name); 127 - 128 - out: 129 - kfree(node_name); 130 - return err; 131 - } 132 - 133 - static void __init its_pmsi_acpi_init(void) 134 - { 135 - acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR, 136 - its_pmsi_parse_madt, 0); 137 - } 138 - #else 139 - static inline void its_pmsi_acpi_init(void) { } 140 - #endif 141 - 142 - static void __init its_pmsi_of_init(void) 143 - { 144 - struct device_node *np; 145 - 146 - for (np = of_find_matching_node(NULL, its_device_id); np; 147 - np = of_find_matching_node(np, its_device_id)) { 148 - if (!of_device_is_available(np)) 149 - continue; 150 - if (!of_property_read_bool(np, "msi-controller")) 151 - continue; 152 - 153 - its_pmsi_init_one(of_node_to_fwnode(np), np->full_name); 154 - } 155 - } 156 - 157 - static int __init its_pmsi_init(void) 158 - { 159 - its_pmsi_of_init(); 160 - its_pmsi_acpi_init(); 161 - return 0; 162 - } 163 - early_initcall(its_pmsi_init);
+5
drivers/irqchip/irq-gic-v3-its.c
··· 38 38 #include <asm/exception.h> 39 39 40 40 #include "irq-gic-common.h" 41 + #include "irq-msi-lib.h" 41 42 42 43 #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0) 43 44 #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) ··· 3683 3682 } 3684 3683 3685 3684 static const struct irq_domain_ops its_domain_ops = { 3685 + .select = msi_lib_irq_domain_select, 3686 3686 .alloc = its_irq_domain_alloc, 3687 3687 .free = its_irq_domain_free, 3688 3688 .activate = its_irq_domain_activate, ··· 4990 4988 } 4991 4989 4992 4990 irq_domain_update_bus_token(inner_domain, DOMAIN_BUS_NEXUS); 4991 + 4992 + inner_domain->msi_parent_ops = &gic_v3_its_msi_parent_ops; 4993 + inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; 4993 4994 4994 4995 return 0; 4995 4996 }
+50 -86
drivers/irqchip/irq-gic-v3-mbi.c
··· 18 18 19 19 #include <linux/irqchip/arm-gic-v3.h> 20 20 21 + #include "irq-msi-lib.h" 22 + 21 23 struct mbi_range { 22 24 u32 spi_start; 23 25 u32 nr_spis; ··· 140 138 } 141 139 142 140 static const struct irq_domain_ops mbi_domain_ops = { 141 + .select = msi_lib_irq_domain_select, 143 142 .alloc = mbi_irq_domain_alloc, 144 143 .free = mbi_irq_domain_free, 145 144 }; ··· 154 151 iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg); 155 152 } 156 153 157 - #ifdef CONFIG_PCI_MSI 158 - /* PCI-specific irqchip */ 159 - static void mbi_mask_msi_irq(struct irq_data *d) 160 - { 161 - pci_msi_mask_irq(d); 162 - irq_chip_mask_parent(d); 163 - } 164 - 165 - static void mbi_unmask_msi_irq(struct irq_data *d) 166 - { 167 - pci_msi_unmask_irq(d); 168 - irq_chip_unmask_parent(d); 169 - } 170 - 171 - static struct irq_chip mbi_msi_irq_chip = { 172 - .name = "MSI", 173 - .irq_mask = mbi_mask_msi_irq, 174 - .irq_unmask = mbi_unmask_msi_irq, 175 - .irq_eoi = irq_chip_eoi_parent, 176 - .irq_compose_msi_msg = mbi_compose_msi_msg, 177 - }; 178 - 179 - static struct msi_domain_info mbi_msi_domain_info = { 180 - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 181 - MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI), 182 - .chip = &mbi_msi_irq_chip, 183 - }; 184 - 185 - static int mbi_allocate_pci_domain(struct irq_domain *nexus_domain, 186 - struct irq_domain **pci_domain) 187 - { 188 - *pci_domain = pci_msi_create_irq_domain(nexus_domain->parent->fwnode, 189 - &mbi_msi_domain_info, 190 - nexus_domain); 191 - if (!*pci_domain) 192 - return -ENOMEM; 193 - 194 - return 0; 195 - } 196 - #else 197 - static int mbi_allocate_pci_domain(struct irq_domain *nexus_domain, 198 - struct irq_domain **pci_domain) 199 - { 200 - *pci_domain = NULL; 201 - return 0; 202 - } 203 - #endif 204 - 205 154 static void mbi_compose_mbi_msg(struct irq_data *data, struct msi_msg *msg) 206 155 { 207 156 mbi_compose_msi_msg(data, msg); ··· 165 210 iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), &msg[1]); 166 211 } 167 212 168 - /* Platform-MSI specific irqchip */ 169 - static struct irq_chip mbi_pmsi_irq_chip = { 170 - .name = "pMSI", 171 - .irq_set_type = irq_chip_set_type_parent, 172 - .irq_compose_msi_msg = mbi_compose_mbi_msg, 173 - .flags = IRQCHIP_SUPPORTS_LEVEL_MSI, 174 - }; 175 - 176 - static struct msi_domain_ops mbi_pmsi_ops = { 177 - }; 178 - 179 - static struct msi_domain_info mbi_pmsi_domain_info = { 180 - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 181 - MSI_FLAG_LEVEL_CAPABLE), 182 - .ops = &mbi_pmsi_ops, 183 - .chip = &mbi_pmsi_irq_chip, 184 - }; 185 - 186 - static int mbi_allocate_domains(struct irq_domain *parent) 213 + static bool mbi_init_dev_msi_info(struct device *dev, struct irq_domain *domain, 214 + struct irq_domain *real_parent, struct msi_domain_info *info) 187 215 { 188 - struct irq_domain *nexus_domain, *pci_domain, *plat_domain; 189 - int err; 216 + if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info)) 217 + return false; 218 + 219 + switch (info->bus_token) { 220 + case DOMAIN_BUS_PCI_DEVICE_MSI: 221 + case DOMAIN_BUS_PCI_DEVICE_MSIX: 222 + info->chip->irq_compose_msi_msg = mbi_compose_msi_msg; 223 + return true; 224 + 225 + case DOMAIN_BUS_DEVICE_MSI: 226 + info->chip->irq_compose_msi_msg = mbi_compose_mbi_msg; 227 + info->chip->irq_set_type = irq_chip_set_type_parent; 228 + info->chip->flags |= IRQCHIP_SUPPORTS_LEVEL_MSI; 229 + info->flags |= MSI_FLAG_LEVEL_CAPABLE; 230 + return true; 231 + 232 + default: 233 + WARN_ON_ONCE(1); 234 + return false; 235 + } 236 + } 237 + 238 + #define MBI_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ 239 + MSI_FLAG_USE_DEF_CHIP_OPS | \ 240 + MSI_FLAG_PCI_MSI_MASK_PARENT) 241 + 242 + #define MBI_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ 243 + MSI_FLAG_PCI_MSIX | \ 244 + MSI_FLAG_MULTI_PCI_MSI) 245 + 246 + static const struct msi_parent_ops gic_v3_mbi_msi_parent_ops = { 247 + .supported_flags = MBI_MSI_FLAGS_SUPPORTED, 248 + .required_flags = MBI_MSI_FLAGS_REQUIRED, 249 + .bus_select_token = DOMAIN_BUS_NEXUS, 250 + .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI, 251 + .prefix = "MBI-", 252 + .init_dev_msi_info = mbi_init_dev_msi_info, 253 + }; 254 + 255 + static int mbi_allocate_domain(struct irq_domain *parent) 256 + { 257 + struct irq_domain *nexus_domain; 190 258 191 259 nexus_domain = irq_domain_create_hierarchy(parent, 0, 0, parent->fwnode, 192 260 &mbi_domain_ops, NULL); ··· 217 239 return -ENOMEM; 218 240 219 241 irq_domain_update_bus_token(nexus_domain, DOMAIN_BUS_NEXUS); 220 - 221 - err = mbi_allocate_pci_domain(nexus_domain, &pci_domain); 222 - 223 - plat_domain = platform_msi_create_irq_domain(parent->fwnode, 224 - &mbi_pmsi_domain_info, 225 - nexus_domain); 226 - 227 - if (err || !plat_domain) { 228 - if (plat_domain) 229 - irq_domain_remove(plat_domain); 230 - if (pci_domain) 231 - irq_domain_remove(pci_domain); 232 - irq_domain_remove(nexus_domain); 233 - return -ENOMEM; 234 - } 235 - 242 + nexus_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; 243 + nexus_domain->msi_parent_ops = &gic_v3_mbi_msi_parent_ops; 236 244 return 0; 237 245 } 238 246 ··· 281 317 282 318 pr_info("Using MBI frame %pa\n", &mbi_phys_base); 283 319 284 - ret = mbi_allocate_domains(parent); 320 + ret = mbi_allocate_domain(parent); 285 321 if (ret) 286 322 goto err_free_mbi; 287 323
+23 -31
drivers/irqchip/irq-imx-mu-msi.c
··· 24 24 #include <linux/pm_domain.h> 25 25 #include <linux/spinlock.h> 26 26 27 + #include "irq-msi-lib.h" 28 + 27 29 #define IMX_MU_CHANS 4 28 30 29 31 enum imx_mu_xcr { ··· 116 114 imx_mu_read(msi_data, msi_data->cfg->xRR + data->hwirq * 4); 117 115 } 118 116 119 - static struct irq_chip imx_mu_msi_irq_chip = { 120 - .name = "MU-MSI", 121 - .irq_ack = irq_chip_ack_parent, 122 - }; 123 - 124 - static struct msi_domain_ops imx_mu_msi_irq_ops = { 125 - }; 126 - 127 - static struct msi_domain_info imx_mu_msi_domain_info = { 128 - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), 129 - .ops = &imx_mu_msi_irq_ops, 130 - .chip = &imx_mu_msi_irq_chip, 131 - }; 132 - 133 117 static void imx_mu_msi_parent_compose_msg(struct irq_data *data, 134 118 struct msi_msg *msg) 135 119 { ··· 183 195 } 184 196 185 197 static const struct irq_domain_ops imx_mu_msi_domain_ops = { 198 + .select = msi_lib_irq_domain_select, 186 199 .alloc = imx_mu_msi_domain_irq_alloc, 187 200 .free = imx_mu_msi_domain_irq_free, 188 201 }; ··· 205 216 chained_irq_exit(chip, desc); 206 217 } 207 218 219 + #define IMX_MU_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ 220 + MSI_FLAG_USE_DEF_CHIP_OPS | \ 221 + MSI_FLAG_PARENT_PM_DEV) 222 + 223 + #define IMX_MU_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK) 224 + 225 + static const struct msi_parent_ops imx_mu_msi_parent_ops = { 226 + .supported_flags = IMX_MU_MSI_FLAGS_SUPPORTED, 227 + .required_flags = IMX_MU_MSI_FLAGS_REQUIRED, 228 + .bus_select_token = DOMAIN_BUS_NEXUS, 229 + .bus_select_mask = MATCH_PLATFORM_MSI, 230 + .prefix = "MU-MSI-", 231 + .init_dev_msi_info = msi_lib_init_dev_msi_info, 232 + }; 233 + 208 234 static int imx_mu_msi_domains_init(struct imx_mu_msi *msi_data, struct device *dev) 209 235 { 210 236 struct fwnode_handle *fwnodes = dev_fwnode(dev); 211 237 struct irq_domain *parent; 212 238 213 239 /* Initialize MSI domain parent */ 214 - parent = irq_domain_create_linear(fwnodes, 215 - IMX_MU_CHANS, 216 - &imx_mu_msi_domain_ops, 217 - msi_data); 240 + parent = irq_domain_create_linear(fwnodes, IMX_MU_CHANS, 241 + &imx_mu_msi_domain_ops, msi_data); 218 242 if (!parent) { 219 243 dev_err(dev, "failed to create IRQ domain\n"); 220 244 return -ENOMEM; 221 245 } 222 246 223 247 irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS); 224 - 225 - msi_data->msi_domain = platform_msi_create_irq_domain(fwnodes, 226 - &imx_mu_msi_domain_info, 227 - parent); 228 - 229 - if (!msi_data->msi_domain) { 230 - dev_err(dev, "failed to create MSI domain\n"); 231 - irq_domain_remove(parent); 232 - return -ENOMEM; 233 - } 234 - 235 - irq_domain_set_pm_device(msi_data->msi_domain, dev); 236 - 248 + parent->dev = parent->pm_dev = dev; 249 + parent->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; 250 + parent->msi_parent_ops = &imx_mu_msi_parent_ops; 237 251 return 0; 238 252 } 239 253
+38 -62
drivers/irqchip/irq-mbigen.c
··· 135 135 return 0; 136 136 } 137 137 138 - static struct irq_chip mbigen_irq_chip = { 139 - .name = "mbigen-v2", 140 - .irq_mask = irq_chip_mask_parent, 141 - .irq_unmask = irq_chip_unmask_parent, 142 - .irq_eoi = mbigen_eoi_irq, 143 - .irq_set_type = mbigen_set_type, 144 - .irq_set_affinity = irq_chip_set_affinity_parent, 145 - }; 146 - 147 - static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg) 138 + static void mbigen_write_msi_msg(struct irq_data *d, struct msi_msg *msg) 148 139 { 149 - struct irq_data *d = irq_get_irq_data(desc->irq); 150 140 void __iomem *base = d->chip_data; 151 141 u32 val; 152 142 153 143 if (!msg->address_lo && !msg->address_hi) 154 144 return; 155 - 145 + 156 146 base += get_mbigen_vec_reg(d->hwirq); 157 147 val = readl_relaxed(base); 158 148 ··· 155 165 writel_relaxed(val, base); 156 166 } 157 167 158 - static int mbigen_domain_translate(struct irq_domain *d, 159 - struct irq_fwspec *fwspec, 160 - unsigned long *hwirq, 161 - unsigned int *type) 168 + static int mbigen_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, 169 + unsigned long *hwirq, unsigned int *type) 162 170 { 163 171 if (is_of_node(fwspec->fwnode) || is_acpi_device_node(fwspec->fwnode)) { 164 172 if (fwspec->param_count != 2) ··· 180 192 return -EINVAL; 181 193 } 182 194 183 - static int mbigen_irq_domain_alloc(struct irq_domain *domain, 184 - unsigned int virq, 185 - unsigned int nr_irqs, 186 - void *args) 195 + static void mbigen_domain_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) 187 196 { 188 - struct irq_fwspec *fwspec = args; 189 - irq_hw_number_t hwirq; 190 - unsigned int type; 191 - struct mbigen_device *mgn_chip; 192 - int i, err; 193 - 194 - err = mbigen_domain_translate(domain, fwspec, &hwirq, &type); 195 - if (err) 196 - return err; 197 - 198 - err = platform_msi_device_domain_alloc(domain, virq, nr_irqs); 199 - if (err) 200 - return err; 201 - 202 - mgn_chip = platform_msi_get_host_data(domain); 203 - 204 - for (i = 0; i < nr_irqs; i++) 205 - irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, 206 - &mbigen_irq_chip, mgn_chip->base); 207 - 208 - return 0; 197 + arg->desc = desc; 198 + arg->hwirq = (u32)desc->data.icookie.value; 209 199 } 210 200 211 - static void mbigen_irq_domain_free(struct irq_domain *domain, unsigned int virq, 212 - unsigned int nr_irqs) 213 - { 214 - platform_msi_device_domain_free(domain, virq, nr_irqs); 215 - } 201 + static const struct msi_domain_template mbigen_msi_template = { 202 + .chip = { 203 + .name = "mbigen-v2", 204 + .irq_mask = irq_chip_mask_parent, 205 + .irq_unmask = irq_chip_unmask_parent, 206 + .irq_eoi = mbigen_eoi_irq, 207 + .irq_set_type = mbigen_set_type, 208 + .irq_write_msi_msg = mbigen_write_msi_msg, 209 + }, 216 210 217 - static const struct irq_domain_ops mbigen_domain_ops = { 218 - .translate = mbigen_domain_translate, 219 - .alloc = mbigen_irq_domain_alloc, 220 - .free = mbigen_irq_domain_free, 211 + .ops = { 212 + .set_desc = mbigen_domain_set_desc, 213 + .msi_translate = mbigen_domain_translate, 214 + }, 215 + 216 + .info = { 217 + .bus_token = DOMAIN_BUS_WIRED_TO_MSI, 218 + .flags = MSI_FLAG_USE_DEV_FWNODE, 219 + }, 221 220 }; 221 + 222 + static bool mbigen_create_device_domain(struct device *dev, unsigned int size, 223 + struct mbigen_device *mgn_chip) 224 + { 225 + if (WARN_ON_ONCE(!dev->msi.domain)) 226 + return false; 227 + 228 + return msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN, 229 + &mbigen_msi_template, size, 230 + NULL, mgn_chip->base); 231 + } 222 232 223 233 static int mbigen_of_create_domain(struct platform_device *pdev, 224 234 struct mbigen_device *mgn_chip) 225 235 { 226 236 struct platform_device *child; 227 - struct irq_domain *domain; 228 237 struct device_node *np; 229 238 u32 num_pins; 230 239 int ret = 0; ··· 243 258 break; 244 259 } 245 260 246 - domain = platform_msi_create_device_domain(&child->dev, num_pins, 247 - mbigen_write_msg, 248 - &mbigen_domain_ops, 249 - mgn_chip); 250 - if (!domain) { 261 + if (!mbigen_create_device_domain(&child->dev, num_pins, mgn_chip)) { 251 262 ret = -ENOMEM; 252 263 break; 253 264 } ··· 265 284 static int mbigen_acpi_create_domain(struct platform_device *pdev, 266 285 struct mbigen_device *mgn_chip) 267 286 { 268 - struct irq_domain *domain; 269 287 u32 num_pins = 0; 270 288 int ret; 271 289 ··· 295 315 if (ret || num_pins == 0) 296 316 return -EINVAL; 297 317 298 - domain = platform_msi_create_device_domain(&pdev->dev, num_pins, 299 - mbigen_write_msg, 300 - &mbigen_domain_ops, 301 - mgn_chip); 302 - if (!domain) 318 + if (!mbigen_create_device_domain(&pdev->dev, num_pins, mgn_chip)) 303 319 return -ENOMEM; 304 320 305 321 return 0;
+140
drivers/irqchip/irq-msi-lib.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + // Copyright (C) 2022 Linutronix GmbH 3 + // Copyright (C) 2022 Intel 4 + 5 + #include <linux/export.h> 6 + 7 + #include "irq-msi-lib.h" 8 + 9 + /** 10 + * msi_lib_init_dev_msi_info - Domain info setup for MSI domains 11 + * @dev: The device for which the domain is created for 12 + * @domain: The domain providing this callback 13 + * @real_parent: The real parent domain of the domain to be initialized 14 + * which might be a domain built on top of @domain or 15 + * @domain itself 16 + * @info: The domain info for the domain to be initialize 17 + * 18 + * This function is to be used for all types of MSI domains above the root 19 + * parent domain and any intermediates. The topmost parent domain specific 20 + * functionality is determined via @real_parent. 21 + * 22 + * All intermediate domains between the root and the device domain must 23 + * have either msi_parent_ops.init_dev_msi_info = msi_parent_init_dev_msi_info 24 + * or invoke it down the line. 25 + */ 26 + bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain, 27 + struct irq_domain *real_parent, 28 + struct msi_domain_info *info) 29 + { 30 + const struct msi_parent_ops *pops = real_parent->msi_parent_ops; 31 + u32 required_flags; 32 + 33 + /* Parent ops available? */ 34 + if (WARN_ON_ONCE(!pops)) 35 + return false; 36 + 37 + /* 38 + * MSI parent domain specific settings. For now there is only the 39 + * root parent domain, e.g. NEXUS, acting as a MSI parent, but it is 40 + * possible to stack MSI parents. See x86 vector -> irq remapping 41 + */ 42 + if (domain->bus_token == pops->bus_select_token) { 43 + if (WARN_ON_ONCE(domain != real_parent)) 44 + return false; 45 + } else { 46 + WARN_ON_ONCE(1); 47 + return false; 48 + } 49 + 50 + required_flags = pops->required_flags; 51 + 52 + /* Is the target domain bus token supported? */ 53 + switch(info->bus_token) { 54 + case DOMAIN_BUS_PCI_DEVICE_MSI: 55 + case DOMAIN_BUS_PCI_DEVICE_MSIX: 56 + if (WARN_ON_ONCE(!IS_ENABLED(CONFIG_PCI_MSI))) 57 + return false; 58 + 59 + break; 60 + case DOMAIN_BUS_DEVICE_MSI: 61 + /* 62 + * Per device MSI should never have any MSI feature bits 63 + * set. It's sole purpose is to create a dumb interrupt 64 + * chip which has a device specific irq_write_msi_msg() 65 + * callback. 66 + */ 67 + if (WARN_ON_ONCE(info->flags)) 68 + return false; 69 + 70 + /* Core managed MSI descriptors */ 71 + info->flags = MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS; 72 + fallthrough; 73 + case DOMAIN_BUS_WIRED_TO_MSI: 74 + /* Remove PCI specific flags */ 75 + required_flags &= ~MSI_FLAG_PCI_MSI_MASK_PARENT; 76 + break; 77 + default: 78 + /* 79 + * This should never be reached. See 80 + * msi_lib_irq_domain_select() 81 + */ 82 + WARN_ON_ONCE(1); 83 + return false; 84 + } 85 + 86 + /* 87 + * Mask out the domain specific MSI feature flags which are not 88 + * supported by the real parent. 89 + */ 90 + info->flags &= pops->supported_flags; 91 + /* Enforce the required flags */ 92 + info->flags |= required_flags; 93 + 94 + /* Chip updates for all child bus types */ 95 + if (!info->chip->irq_eoi) 96 + info->chip->irq_eoi = irq_chip_eoi_parent; 97 + if (!info->chip->irq_ack) 98 + info->chip->irq_ack = irq_chip_ack_parent; 99 + 100 + /* 101 + * The device MSI domain can never have a set affinity callback. It 102 + * always has to rely on the parent domain to handle affinity 103 + * settings. The device MSI domain just has to write the resulting 104 + * MSI message into the hardware which is the whole purpose of the 105 + * device MSI domain aside of mask/unmask which is provided e.g. by 106 + * PCI/MSI device domains. 107 + */ 108 + info->chip->irq_set_affinity = msi_domain_set_affinity; 109 + return true; 110 + } 111 + EXPORT_SYMBOL_GPL(msi_lib_init_dev_msi_info); 112 + 113 + /** 114 + * msi_lib_irq_domain_select - Shared select function for NEXUS domains 115 + * @d: Pointer to the irq domain on which select is invoked 116 + * @fwspec: Firmware spec describing what is searched 117 + * @bus_token: The bus token for which a matching irq domain is looked up 118 + * 119 + * Returns: %0 if @d is not what is being looked for 120 + * 121 + * %1 if @d is either the domain which is directly searched for or 122 + * if @d is providing the parent MSI domain for the functionality 123 + * requested with @bus_token. 124 + */ 125 + int msi_lib_irq_domain_select(struct irq_domain *d, struct irq_fwspec *fwspec, 126 + enum irq_domain_bus_token bus_token) 127 + { 128 + const struct msi_parent_ops *ops = d->msi_parent_ops; 129 + u32 busmask = BIT(bus_token); 130 + 131 + if (fwspec->fwnode != d->fwnode || fwspec->param_count != 0) 132 + return 0; 133 + 134 + /* Handle pure domain searches */ 135 + if (bus_token == ops->bus_select_token) 136 + return 1; 137 + 138 + return ops && !!(ops->bus_select_mask & busmask); 139 + } 140 + EXPORT_SYMBOL_GPL(msi_lib_irq_domain_select);
+27
drivers/irqchip/irq-msi-lib.h
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + // Copyright (C) 2022 Linutronix GmbH 3 + // Copyright (C) 2022 Intel 4 + 5 + #ifndef _DRIVERS_IRQCHIP_IRQ_MSI_LIB_H 6 + #define _DRIVERS_IRQCHIP_IRQ_MSI_LIB_H 7 + 8 + #include <linux/bits.h> 9 + #include <linux/irqdomain.h> 10 + #include <linux/msi.h> 11 + 12 + #ifdef CONFIG_PCI_MSI 13 + #define MATCH_PCI_MSI BIT(DOMAIN_BUS_PCI_MSI) 14 + #else 15 + #define MATCH_PCI_MSI (0) 16 + #endif 17 + 18 + #define MATCH_PLATFORM_MSI BIT(DOMAIN_BUS_PLATFORM_MSI) 19 + 20 + int msi_lib_irq_domain_select(struct irq_domain *d, struct irq_fwspec *fwspec, 21 + enum irq_domain_bus_token bus_token); 22 + 23 + bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain, 24 + struct irq_domain *real_parent, 25 + struct msi_domain_info *info); 26 + 27 + #endif /* _DRIVERS_IRQCHIP_IRQ_MSI_LIB_H */
+19 -25
drivers/irqchip/irq-mvebu-gicp.c
··· 17 17 #include <linux/of_platform.h> 18 18 #include <linux/platform_device.h> 19 19 20 + #include "irq-msi-lib.h" 21 + 20 22 #include <dt-bindings/interrupt-controller/arm-gic.h> 21 23 22 24 #define GICP_SETSPI_NSR_OFFSET 0x0 ··· 147 145 } 148 146 149 147 static const struct irq_domain_ops gicp_domain_ops = { 148 + .select = msi_lib_irq_domain_select, 150 149 .alloc = gicp_irq_domain_alloc, 151 150 .free = gicp_irq_domain_free, 152 151 }; 153 152 154 - static struct irq_chip gicp_msi_irq_chip = { 155 - .name = "GICP", 156 - .irq_set_type = irq_chip_set_type_parent, 157 - .flags = IRQCHIP_SUPPORTS_LEVEL_MSI, 158 - }; 153 + #define GICP_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ 154 + MSI_FLAG_USE_DEF_CHIP_OPS) 159 155 160 - static struct msi_domain_ops gicp_msi_ops = { 161 - }; 156 + #define GICP_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ 157 + MSI_FLAG_LEVEL_CAPABLE) 162 158 163 - static struct msi_domain_info gicp_msi_domain_info = { 164 - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 165 - MSI_FLAG_LEVEL_CAPABLE), 166 - .ops = &gicp_msi_ops, 167 - .chip = &gicp_msi_irq_chip, 159 + static const struct msi_parent_ops gicp_msi_parent_ops = { 160 + .supported_flags = GICP_MSI_FLAGS_SUPPORTED, 161 + .required_flags = GICP_MSI_FLAGS_REQUIRED, 162 + .bus_select_token = DOMAIN_BUS_GENERIC_MSI, 163 + .bus_select_mask = MATCH_PLATFORM_MSI, 164 + .prefix = "GICP-", 165 + .init_dev_msi_info = msi_lib_init_dev_msi_info, 168 166 }; 169 167 170 168 static int mvebu_gicp_probe(struct platform_device *pdev) 171 169 { 172 - struct mvebu_gicp *gicp; 173 - struct irq_domain *inner_domain, *plat_domain, *parent_domain; 170 + struct irq_domain *inner_domain, *parent_domain; 174 171 struct device_node *node = pdev->dev.of_node; 175 172 struct device_node *irq_parent_dn; 173 + struct mvebu_gicp *gicp; 176 174 int ret, i; 177 175 178 176 gicp = devm_kzalloc(&pdev->dev, sizeof(*gicp), GFP_KERNEL); ··· 236 234 if (!inner_domain) 237 235 return -ENOMEM; 238 236 239 - 240 - plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(node), 241 - &gicp_msi_domain_info, 242 - inner_domain); 243 - if (!plat_domain) { 244 - irq_domain_remove(inner_domain); 245 - return -ENOMEM; 246 - } 247 - 248 - platform_set_drvdata(pdev, gicp); 249 - 237 + irq_domain_update_bus_token(inner_domain, DOMAIN_BUS_GENERIC_MSI); 238 + inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; 239 + inner_domain->msi_parent_ops = &gicp_msi_parent_ops; 250 240 return 0; 251 241 } 252 242
+121 -162
drivers/irqchip/irq-mvebu-icu.c
··· 20 20 #include <linux/of_platform.h> 21 21 #include <linux/platform_device.h> 22 22 23 + #include "irq-msi-lib.h" 24 + 23 25 #include <dt-bindings/interrupt-controller/mvebu-icu.h> 24 26 25 27 /* ICU registers */ ··· 62 60 const struct mvebu_icu_subset_data *subset_data; 63 61 }; 64 62 65 - struct mvebu_icu_irq_data { 66 - struct mvebu_icu *icu; 67 - unsigned int icu_group; 68 - unsigned int type; 69 - }; 70 - 71 63 static DEFINE_STATIC_KEY_FALSE(legacy_bindings); 72 64 73 - static void mvebu_icu_init(struct mvebu_icu *icu, 74 - struct mvebu_icu_msi_data *msi_data, 75 - struct msi_msg *msg) 76 - { 77 - const struct mvebu_icu_subset_data *subset = msi_data->subset_data; 78 - 79 - if (atomic_cmpxchg(&msi_data->initialized, false, true)) 80 - return; 81 - 82 - /* Set 'SET' ICU SPI message address in AP */ 83 - writel_relaxed(msg[0].address_hi, icu->base + subset->offset_set_ah); 84 - writel_relaxed(msg[0].address_lo, icu->base + subset->offset_set_al); 85 - 86 - if (subset->icu_group != ICU_GRP_NSR) 87 - return; 88 - 89 - /* Set 'CLEAR' ICU SPI message address in AP (level-MSI only) */ 90 - writel_relaxed(msg[1].address_hi, icu->base + subset->offset_clr_ah); 91 - writel_relaxed(msg[1].address_lo, icu->base + subset->offset_clr_al); 92 - } 93 - 94 - static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) 95 - { 96 - struct irq_data *d = irq_get_irq_data(desc->irq); 97 - struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d->domain); 98 - struct mvebu_icu_irq_data *icu_irqd = d->chip_data; 99 - struct mvebu_icu *icu = icu_irqd->icu; 100 - unsigned int icu_int; 101 - 102 - if (msg->address_lo || msg->address_hi) { 103 - /* One off initialization per domain */ 104 - mvebu_icu_init(icu, msi_data, msg); 105 - /* Configure the ICU with irq number & type */ 106 - icu_int = msg->data | ICU_INT_ENABLE; 107 - if (icu_irqd->type & IRQ_TYPE_EDGE_RISING) 108 - icu_int |= ICU_IS_EDGE; 109 - icu_int |= icu_irqd->icu_group << ICU_GROUP_SHIFT; 110 - } else { 111 - /* De-configure the ICU */ 112 - icu_int = 0; 113 - } 114 - 115 - writel_relaxed(icu_int, icu->base + ICU_INT_CFG(d->hwirq)); 116 - 117 - /* 118 - * The SATA unit has 2 ports, and a dedicated ICU entry per 119 - * port. The ahci sata driver supports only one irq interrupt 120 - * per SATA unit. To solve this conflict, we configure the 2 121 - * SATA wired interrupts in the south bridge into 1 GIC 122 - * interrupt in the north bridge. Even if only a single port 123 - * is enabled, if sata node is enabled, both interrupts are 124 - * configured (regardless of which port is actually in use). 125 - */ 126 - if (d->hwirq == ICU_SATA0_ICU_ID || d->hwirq == ICU_SATA1_ICU_ID) { 127 - writel_relaxed(icu_int, 128 - icu->base + ICU_INT_CFG(ICU_SATA0_ICU_ID)); 129 - writel_relaxed(icu_int, 130 - icu->base + ICU_INT_CFG(ICU_SATA1_ICU_ID)); 131 - } 132 - } 133 - 134 - static struct irq_chip mvebu_icu_nsr_chip = { 135 - .name = "ICU-NSR", 136 - .irq_mask = irq_chip_mask_parent, 137 - .irq_unmask = irq_chip_unmask_parent, 138 - .irq_eoi = irq_chip_eoi_parent, 139 - .irq_set_type = irq_chip_set_type_parent, 140 - .irq_set_affinity = irq_chip_set_affinity_parent, 141 - }; 142 - 143 - static struct irq_chip mvebu_icu_sei_chip = { 144 - .name = "ICU-SEI", 145 - .irq_ack = irq_chip_ack_parent, 146 - .irq_mask = irq_chip_mask_parent, 147 - .irq_unmask = irq_chip_unmask_parent, 148 - .irq_set_type = irq_chip_set_type_parent, 149 - .irq_set_affinity = irq_chip_set_affinity_parent, 150 - }; 151 - 152 - static int 153 - mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, 65 + static int mvebu_icu_translate(struct irq_domain *d, struct irq_fwspec *fwspec, 154 66 unsigned long *hwirq, unsigned int *type) 155 67 { 156 68 unsigned int param_count = static_branch_unlikely(&legacy_bindings) ? 3 : 2; 157 - struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d); 69 + struct mvebu_icu_msi_data *msi_data = d->host_data; 158 70 struct mvebu_icu *icu = msi_data->icu; 159 71 160 72 /* Check the count of the parameters in dt */ ··· 108 192 return 0; 109 193 } 110 194 111 - static int 112 - mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, 113 - unsigned int nr_irqs, void *args) 195 + static void mvebu_icu_init(struct mvebu_icu *icu, 196 + struct mvebu_icu_msi_data *msi_data, 197 + struct msi_msg *msg) 114 198 { 115 - int err; 116 - unsigned long hwirq; 117 - struct irq_fwspec *fwspec = args; 118 - struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(domain); 199 + const struct mvebu_icu_subset_data *subset = msi_data->subset_data; 200 + 201 + if (atomic_cmpxchg(&msi_data->initialized, false, true)) 202 + return; 203 + 204 + /* Set 'SET' ICU SPI message address in AP */ 205 + writel_relaxed(msg[0].address_hi, icu->base + subset->offset_set_ah); 206 + writel_relaxed(msg[0].address_lo, icu->base + subset->offset_set_al); 207 + 208 + if (subset->icu_group != ICU_GRP_NSR) 209 + return; 210 + 211 + /* Set 'CLEAR' ICU SPI message address in AP (level-MSI only) */ 212 + writel_relaxed(msg[1].address_hi, icu->base + subset->offset_clr_ah); 213 + writel_relaxed(msg[1].address_lo, icu->base + subset->offset_clr_al); 214 + } 215 + 216 + static int mvebu_icu_msi_init(struct irq_domain *domain, struct msi_domain_info *info, 217 + unsigned int virq, irq_hw_number_t hwirq, msi_alloc_info_t *arg) 218 + { 219 + irq_domain_set_hwirq_and_chip(domain, virq, hwirq, info->chip, info->chip_data); 220 + return irq_set_irqchip_state(virq, IRQCHIP_STATE_PENDING, false); 221 + } 222 + 223 + static void mvebu_icu_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) 224 + { 225 + arg->desc = desc; 226 + arg->hwirq = (u32)desc->data.icookie.value; 227 + } 228 + 229 + static void mvebu_icu_write_msi_msg(struct irq_data *d, struct msi_msg *msg) 230 + { 231 + struct mvebu_icu_msi_data *msi_data = d->chip_data; 232 + unsigned int icu_group = msi_data->subset_data->icu_group; 233 + struct msi_desc *desc = irq_data_get_msi_desc(d); 119 234 struct mvebu_icu *icu = msi_data->icu; 120 - struct mvebu_icu_irq_data *icu_irqd; 121 - struct irq_chip *chip = &mvebu_icu_nsr_chip; 235 + unsigned int type; 236 + u32 icu_int; 122 237 123 - icu_irqd = kmalloc(sizeof(*icu_irqd), GFP_KERNEL); 124 - if (!icu_irqd) 125 - return -ENOMEM; 126 - 127 - err = mvebu_icu_irq_domain_translate(domain, fwspec, &hwirq, 128 - &icu_irqd->type); 129 - if (err) { 130 - dev_err(icu->dev, "failed to translate ICU parameters\n"); 131 - goto free_irqd; 238 + if (msg->address_lo || msg->address_hi) { 239 + /* One off initialization per domain */ 240 + mvebu_icu_init(icu, msi_data, msg); 241 + /* Configure the ICU with irq number & type */ 242 + icu_int = msg->data | ICU_INT_ENABLE; 243 + type = (unsigned int)(desc->data.icookie.value >> 32); 244 + if (type & IRQ_TYPE_EDGE_RISING) 245 + icu_int |= ICU_IS_EDGE; 246 + icu_int |= icu_group << ICU_GROUP_SHIFT; 247 + } else { 248 + /* De-configure the ICU */ 249 + icu_int = 0; 132 250 } 133 251 134 - if (static_branch_unlikely(&legacy_bindings)) 135 - icu_irqd->icu_group = fwspec->param[0]; 136 - else 137 - icu_irqd->icu_group = msi_data->subset_data->icu_group; 138 - icu_irqd->icu = icu; 252 + writel_relaxed(icu_int, icu->base + ICU_INT_CFG(d->hwirq)); 139 253 140 - err = platform_msi_device_domain_alloc(domain, virq, nr_irqs); 141 - if (err) { 142 - dev_err(icu->dev, "failed to allocate ICU interrupt in parent domain\n"); 143 - goto free_irqd; 254 + /* 255 + * The SATA unit has 2 ports, and a dedicated ICU entry per 256 + * port. The ahci sata driver supports only one irq interrupt 257 + * per SATA unit. To solve this conflict, we configure the 2 258 + * SATA wired interrupts in the south bridge into 1 GIC 259 + * interrupt in the north bridge. Even if only a single port 260 + * is enabled, if sata node is enabled, both interrupts are 261 + * configured (regardless of which port is actually in use). 262 + */ 263 + if (d->hwirq == ICU_SATA0_ICU_ID || d->hwirq == ICU_SATA1_ICU_ID) { 264 + writel_relaxed(icu_int, icu->base + ICU_INT_CFG(ICU_SATA0_ICU_ID)); 265 + writel_relaxed(icu_int, icu->base + ICU_INT_CFG(ICU_SATA1_ICU_ID)); 144 266 } 145 - 146 - /* Make sure there is no interrupt left pending by the firmware */ 147 - err = irq_set_irqchip_state(virq, IRQCHIP_STATE_PENDING, false); 148 - if (err) 149 - goto free_msi; 150 - 151 - if (icu_irqd->icu_group == ICU_GRP_SEI) 152 - chip = &mvebu_icu_sei_chip; 153 - 154 - err = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, 155 - chip, icu_irqd); 156 - if (err) { 157 - dev_err(icu->dev, "failed to set the data to IRQ domain\n"); 158 - goto free_msi; 159 - } 160 - 161 - return 0; 162 - 163 - free_msi: 164 - platform_msi_device_domain_free(domain, virq, nr_irqs); 165 - free_irqd: 166 - kfree(icu_irqd); 167 - return err; 168 267 } 169 268 170 - static void 171 - mvebu_icu_irq_domain_free(struct irq_domain *domain, unsigned int virq, 172 - unsigned int nr_irqs) 173 - { 174 - struct irq_data *d = irq_get_irq_data(virq); 175 - struct mvebu_icu_irq_data *icu_irqd = d->chip_data; 269 + static const struct msi_domain_template mvebu_icu_nsr_msi_template = { 270 + .chip = { 271 + .name = "ICU-NSR", 272 + .irq_mask = irq_chip_mask_parent, 273 + .irq_unmask = irq_chip_unmask_parent, 274 + .irq_eoi = irq_chip_eoi_parent, 275 + .irq_set_type = irq_chip_set_type_parent, 276 + .irq_write_msi_msg = mvebu_icu_write_msi_msg, 277 + .flags = IRQCHIP_SUPPORTS_LEVEL_MSI, 278 + }, 176 279 177 - kfree(icu_irqd); 280 + .ops = { 281 + .msi_translate = mvebu_icu_translate, 282 + .msi_init = mvebu_icu_msi_init, 283 + .set_desc = mvebu_icu_set_desc, 284 + }, 178 285 179 - platform_msi_device_domain_free(domain, virq, nr_irqs); 180 - } 286 + .info = { 287 + .bus_token = DOMAIN_BUS_WIRED_TO_MSI, 288 + .flags = MSI_FLAG_LEVEL_CAPABLE | 289 + MSI_FLAG_USE_DEV_FWNODE, 290 + }, 291 + }; 181 292 182 - static const struct irq_domain_ops mvebu_icu_domain_ops = { 183 - .translate = mvebu_icu_irq_domain_translate, 184 - .alloc = mvebu_icu_irq_domain_alloc, 185 - .free = mvebu_icu_irq_domain_free, 293 + static const struct msi_domain_template mvebu_icu_sei_msi_template = { 294 + .chip = { 295 + .name = "ICU-SEI", 296 + .irq_mask = irq_chip_mask_parent, 297 + .irq_unmask = irq_chip_unmask_parent, 298 + .irq_ack = irq_chip_ack_parent, 299 + .irq_set_type = irq_chip_set_type_parent, 300 + .irq_write_msi_msg = mvebu_icu_write_msi_msg, 301 + .flags = IRQCHIP_SUPPORTS_LEVEL_MSI, 302 + }, 303 + 304 + .ops = { 305 + .msi_translate = mvebu_icu_translate, 306 + .msi_init = mvebu_icu_msi_init, 307 + .set_desc = mvebu_icu_set_desc, 308 + }, 309 + 310 + .info = { 311 + .bus_token = DOMAIN_BUS_WIRED_TO_MSI, 312 + .flags = MSI_FLAG_LEVEL_CAPABLE | 313 + MSI_FLAG_USE_DEV_FWNODE, 314 + }, 186 315 }; 187 316 188 317 static const struct mvebu_icu_subset_data mvebu_icu_nsr_subset_data = { ··· 258 297 259 298 static int mvebu_icu_subset_probe(struct platform_device *pdev) 260 299 { 300 + const struct msi_domain_template *tmpl; 261 301 struct mvebu_icu_msi_data *msi_data; 262 - struct device_node *msi_parent_dn; 263 302 struct device *dev = &pdev->dev; 264 - struct irq_domain *irq_domain; 303 + bool sei; 265 304 266 305 msi_data = devm_kzalloc(dev, sizeof(*msi_data), GFP_KERNEL); 267 306 if (!msi_data) ··· 275 314 msi_data->subset_data = of_device_get_match_data(dev); 276 315 } 277 316 278 - dev->msi.domain = of_msi_get_domain(dev, dev->of_node, 279 - DOMAIN_BUS_PLATFORM_MSI); 317 + dev->msi.domain = of_msi_get_domain(dev, dev->of_node, DOMAIN_BUS_PLATFORM_MSI); 280 318 if (!dev->msi.domain) 281 319 return -EPROBE_DEFER; 282 320 283 - msi_parent_dn = irq_domain_get_of_node(dev->msi.domain); 284 - if (!msi_parent_dn) 321 + if (!irq_domain_get_of_node(dev->msi.domain)) 285 322 return -ENODEV; 286 323 287 - irq_domain = platform_msi_create_device_tree_domain(dev, ICU_MAX_IRQS, 288 - mvebu_icu_write_msg, 289 - &mvebu_icu_domain_ops, 290 - msi_data); 291 - if (!irq_domain) { 324 + sei = msi_data->subset_data->icu_group == ICU_GRP_SEI; 325 + tmpl = sei ? &mvebu_icu_sei_msi_template : &mvebu_icu_nsr_msi_template; 326 + 327 + if (!msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN, tmpl, 328 + ICU_MAX_IRQS, NULL, msi_data)) { 292 329 dev_err(dev, "Failed to create ICU MSI domain\n"); 293 330 return -ENOMEM; 294 331 }
+18 -19
drivers/irqchip/irq-mvebu-odmi.c
··· 17 17 #include <linux/msi.h> 18 18 #include <linux/of_address.h> 19 19 #include <linux/slab.h> 20 + 21 + #include "irq-msi-lib.h" 22 + 20 23 #include <dt-bindings/interrupt-controller/arm-gic.h> 21 24 22 25 #define GICP_ODMIN_SET 0x40 ··· 144 141 } 145 142 146 143 static const struct irq_domain_ops odmi_domain_ops = { 144 + .select = msi_lib_irq_domain_select, 147 145 .alloc = odmi_irq_domain_alloc, 148 146 .free = odmi_irq_domain_free, 149 147 }; 150 148 151 - static struct irq_chip odmi_msi_irq_chip = { 152 - .name = "ODMI", 153 - }; 149 + #define ODMI_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ 150 + MSI_FLAG_USE_DEF_CHIP_OPS) 154 151 155 - static struct msi_domain_ops odmi_msi_ops = { 156 - }; 152 + #define ODMI_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK) 157 153 158 - static struct msi_domain_info odmi_msi_domain_info = { 159 - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), 160 - .ops = &odmi_msi_ops, 161 - .chip = &odmi_msi_irq_chip, 154 + static const struct msi_parent_ops odmi_msi_parent_ops = { 155 + .supported_flags = ODMI_MSI_FLAGS_SUPPORTED, 156 + .required_flags = ODMI_MSI_FLAGS_REQUIRED, 157 + .bus_select_token = DOMAIN_BUS_GENERIC_MSI, 158 + .bus_select_mask = MATCH_PLATFORM_MSI, 159 + .prefix = "ODMI-", 160 + .init_dev_msi_info = msi_lib_init_dev_msi_info, 162 161 }; 163 162 164 163 static int __init mvebu_odmi_init(struct device_node *node, 165 164 struct device_node *parent) 166 165 { 167 - struct irq_domain *parent_domain, *inner_domain, *plat_domain; 166 + struct irq_domain *parent_domain, *inner_domain; 168 167 int ret, i; 169 168 170 169 if (of_property_read_u32(node, "marvell,odmi-frames", &odmis_count)) ··· 213 208 goto err_unmap; 214 209 } 215 210 216 - plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(node), 217 - &odmi_msi_domain_info, 218 - inner_domain); 219 - if (!plat_domain) { 220 - ret = -ENOMEM; 221 - goto err_remove_inner; 222 - } 211 + irq_domain_update_bus_token(inner_domain, DOMAIN_BUS_GENERIC_MSI); 212 + inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; 213 + inner_domain->msi_parent_ops = &odmi_msi_parent_ops; 223 214 224 215 return 0; 225 216 226 - err_remove_inner: 227 - irq_domain_remove(inner_domain); 228 217 err_unmap: 229 218 for (i = 0; i < odmis_count; i++) { 230 219 struct odmi_data *odmi = &odmis[i];
+20 -32
drivers/irqchip/irq-mvebu-sei.c
··· 14 14 #include <linux/of_irq.h> 15 15 #include <linux/of_platform.h> 16 16 17 + #include "irq-msi-lib.h" 18 + 17 19 /* Cause register */ 18 20 #define GICP_SECR(idx) (0x0 + ((idx) * 0x4)) 19 21 /* Mask register */ ··· 192 190 } 193 191 194 192 static const struct irq_domain_ops mvebu_sei_domain_ops = { 193 + .select = msi_lib_irq_domain_select, 195 194 .alloc = mvebu_sei_domain_alloc, 196 195 .free = mvebu_sei_domain_free, 197 196 }; ··· 310 307 .free = mvebu_sei_cp_domain_free, 311 308 }; 312 309 313 - static struct irq_chip mvebu_sei_msi_irq_chip = { 314 - .name = "SEI pMSI", 315 - .irq_ack = irq_chip_ack_parent, 316 - .irq_set_type = irq_chip_set_type_parent, 317 - }; 318 - 319 - static struct msi_domain_ops mvebu_sei_msi_ops = { 320 - }; 321 - 322 - static struct msi_domain_info mvebu_sei_msi_domain_info = { 323 - .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS, 324 - .ops = &mvebu_sei_msi_ops, 325 - .chip = &mvebu_sei_msi_irq_chip, 326 - }; 327 - 328 310 static void mvebu_sei_handle_cascade_irq(struct irq_desc *desc) 329 311 { 330 312 struct mvebu_sei *sei = irq_desc_get_handler_data(desc); ··· 348 360 } 349 361 } 350 362 363 + #define SEI_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ 364 + MSI_FLAG_USE_DEF_CHIP_OPS) 365 + 366 + #define SEI_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK) 367 + 368 + static const struct msi_parent_ops sei_msi_parent_ops = { 369 + .supported_flags = SEI_MSI_FLAGS_SUPPORTED, 370 + .required_flags = SEI_MSI_FLAGS_REQUIRED, 371 + .bus_select_mask = MATCH_PLATFORM_MSI, 372 + .bus_select_token = DOMAIN_BUS_GENERIC_MSI, 373 + .prefix = "SEI-", 374 + .init_dev_msi_info = msi_lib_init_dev_msi_info, 375 + }; 376 + 351 377 static int mvebu_sei_probe(struct platform_device *pdev) 352 378 { 353 379 struct device_node *node = pdev->dev.of_node; 354 - struct irq_domain *plat_domain; 355 380 struct mvebu_sei *sei; 356 381 u32 parent_irq; 357 382 int ret; ··· 441 440 } 442 441 443 442 irq_domain_update_bus_token(sei->cp_domain, DOMAIN_BUS_GENERIC_MSI); 444 - 445 - plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(node), 446 - &mvebu_sei_msi_domain_info, 447 - sei->cp_domain); 448 - if (!plat_domain) { 449 - pr_err("Failed to create CPs MSI domain\n"); 450 - ret = -ENOMEM; 451 - goto remove_cp_domain; 452 - } 443 + sei->cp_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; 444 + sei->cp_domain->msi_parent_ops = &sei_msi_parent_ops; 453 445 454 446 mvebu_sei_reset(sei); 455 447 456 - irq_set_chained_handler_and_data(parent_irq, 457 - mvebu_sei_handle_cascade_irq, 458 - sei); 459 - 448 + irq_set_chained_handler_and_data(parent_irq, mvebu_sei_handle_cascade_irq, sei); 460 449 return 0; 461 450 462 - remove_cp_domain: 463 - irq_domain_remove(sei->cp_domain); 464 451 remove_ap_domain: 465 452 irq_domain_remove(sei->ap_domain); 466 453 remove_sei_domain: 467 454 irq_domain_remove(sei->sei_domain); 468 455 dispose_irq: 469 456 irq_dispose_mapping(parent_irq); 470 - 471 457 return ret; 472 458 } 473 459
+20
drivers/pci/msi/irqdomain.c
··· 148 148 arg->hwirq = desc->msi_index; 149 149 } 150 150 151 + static __always_inline void cond_mask_parent(struct irq_data *data) 152 + { 153 + struct msi_domain_info *info = data->domain->host_data; 154 + 155 + if (unlikely(info->flags & MSI_FLAG_PCI_MSI_MASK_PARENT)) 156 + irq_chip_mask_parent(data); 157 + } 158 + 159 + static __always_inline void cond_unmask_parent(struct irq_data *data) 160 + { 161 + struct msi_domain_info *info = data->domain->host_data; 162 + 163 + if (unlikely(info->flags & MSI_FLAG_PCI_MSI_MASK_PARENT)) 164 + irq_chip_unmask_parent(data); 165 + } 166 + 151 167 static void pci_irq_mask_msi(struct irq_data *data) 152 168 { 153 169 struct msi_desc *desc = irq_data_get_msi_desc(data); 154 170 155 171 pci_msi_mask(desc, BIT(data->irq - desc->irq)); 172 + cond_mask_parent(data); 156 173 } 157 174 158 175 static void pci_irq_unmask_msi(struct irq_data *data) 159 176 { 160 177 struct msi_desc *desc = irq_data_get_msi_desc(data); 161 178 179 + cond_unmask_parent(data); 162 180 pci_msi_unmask(desc, BIT(data->irq - desc->irq)); 163 181 } 164 182 ··· 213 195 static void pci_irq_mask_msix(struct irq_data *data) 214 196 { 215 197 pci_msix_mask(irq_data_get_msi_desc(data)); 198 + cond_mask_parent(data); 216 199 } 217 200 218 201 static void pci_irq_unmask_msix(struct irq_data *data) 219 202 { 203 + cond_unmask_parent(data); 220 204 pci_msix_unmask(irq_data_get_msi_desc(data)); 221 205 } 222 206
+2 -50
include/linux/msi.h
··· 21 21 #include <linux/irqdomain_defs.h> 22 22 #include <linux/cpumask_types.h> 23 23 #include <linux/msi_api.h> 24 - #include <linux/xarray.h> 25 - #include <linux/mutex.h> 26 - #include <linux/list.h> 27 24 #include <linux/irq.h> 28 - #include <linux/bits.h> 29 25 30 26 #include <asm/msi.h> 31 27 ··· 77 81 /* Helper functions */ 78 82 struct msi_desc; 79 83 struct pci_dev; 80 - struct platform_msi_priv_data; 81 84 struct device_attribute; 82 85 struct irq_domain; 83 86 struct irq_affinity_desc; ··· 221 226 struct msi_dev_domain { 222 227 struct xarray store; 223 228 struct irq_domain *domain; 224 - }; 225 - 226 - /** 227 - * msi_device_data - MSI per device data 228 - * @properties: MSI properties which are interesting to drivers 229 - * @platform_data: Platform-MSI specific data 230 - * @mutex: Mutex protecting the MSI descriptor store 231 - * @__domains: Internal data for per device MSI domains 232 - * @__iter_idx: Index to search the next entry for iterators 233 - */ 234 - struct msi_device_data { 235 - unsigned long properties; 236 - struct platform_msi_priv_data *platform_data; 237 - struct mutex mutex; 238 - struct msi_dev_domain __domains[MSI_MAX_DEVICE_IRQDOMAINS]; 239 - unsigned long __iter_idx; 240 229 }; 241 230 242 231 int msi_setup_device_data(struct device *dev); ··· 535 556 MSI_FLAG_USE_DEV_FWNODE = (1 << 7), 536 557 /* Set parent->dev into domain->pm_dev on device domain creation */ 537 558 MSI_FLAG_PARENT_PM_DEV = (1 << 8), 559 + /* Support for parent mask/unmask */ 560 + MSI_FLAG_PCI_MSI_MASK_PARENT = (1 << 9), 538 561 539 562 /* Mask for the generic functionality */ 540 563 MSI_GENERIC_FLAGS_MASK = GENMASK(15, 0), ··· 620 639 621 640 struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain); 622 641 623 - struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode, 624 - struct msi_domain_info *info, 625 - struct irq_domain *parent); 626 - 627 - /* When an MSI domain is used as an intermediate domain */ 628 - int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev, 629 - int nvec, msi_alloc_info_t *args); 630 - int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev, 631 - int virq, int nvec, msi_alloc_info_t *args); 632 - void msi_domain_depopulate_descs(struct device *dev, int virq, int nvec); 633 - 634 - struct irq_domain * 635 - __platform_msi_create_device_domain(struct device *dev, 636 - unsigned int nvec, 637 - bool is_tree, 638 - irq_write_msi_msg_t write_msi_msg, 639 - const struct irq_domain_ops *ops, 640 - void *host_data); 641 - 642 - #define platform_msi_create_device_domain(dev, nvec, write, ops, data) \ 643 - __platform_msi_create_device_domain(dev, nvec, false, write, ops, data) 644 - #define platform_msi_create_device_tree_domain(dev, nvec, write, ops, data) \ 645 - __platform_msi_create_device_domain(dev, nvec, true, write, ops, data) 646 - 647 - int platform_msi_device_domain_alloc(struct irq_domain *domain, unsigned int virq, 648 - unsigned int nr_irqs); 649 - void platform_msi_device_domain_free(struct irq_domain *domain, unsigned int virq, 650 - unsigned int nvec); 651 - void *platform_msi_get_host_data(struct irq_domain *domain); 652 642 /* Per device platform MSI */ 653 643 int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nvec, 654 644 irq_write_msi_msg_t write_msi_msg);
+2 -1
kernel/irq/irqdomain.c
··· 503 503 struct fwnode_handle *fwnode = fwspec->fwnode; 504 504 int rc; 505 505 506 - /* We might want to match the legacy controller last since 506 + /* 507 + * We might want to match the legacy controller last since 507 508 * it might potentially be set to match all interrupts in 508 509 * the absence of a device node. This isn't a problem so far 509 510 * yet though...
+20 -75
kernel/irq/msi.c
··· 8 8 * This file contains common code to support Message Signaled Interrupts for 9 9 * PCI compatible and non PCI compatible devices. 10 10 */ 11 - #include <linux/types.h> 12 11 #include <linux/device.h> 13 12 #include <linux/irq.h> 14 13 #include <linux/irqdomain.h> 15 14 #include <linux/msi.h> 15 + #include <linux/mutex.h> 16 + #include <linux/pci.h> 16 17 #include <linux/slab.h> 17 18 #include <linux/sysfs.h> 18 - #include <linux/pci.h> 19 + #include <linux/types.h> 20 + #include <linux/xarray.h> 19 21 20 22 #include "internals.h" 23 + 24 + /** 25 + * struct msi_device_data - MSI per device data 26 + * @properties: MSI properties which are interesting to drivers 27 + * @mutex: Mutex protecting the MSI descriptor store 28 + * @__domains: Internal data for per device MSI domains 29 + * @__iter_idx: Index to search the next entry for iterators 30 + */ 31 + struct msi_device_data { 32 + unsigned long properties; 33 + struct mutex mutex; 34 + struct msi_dev_domain __domains[MSI_MAX_DEVICE_IRQDOMAINS]; 35 + unsigned long __iter_idx; 36 + }; 21 37 22 38 /** 23 39 * struct msi_ctrl - MSI internal management control structure ··· 1104 1088 return ret; 1105 1089 } 1106 1090 1107 - int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev, 1108 - int nvec, msi_alloc_info_t *arg) 1091 + static int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev, 1092 + int nvec, msi_alloc_info_t *arg) 1109 1093 { 1110 1094 struct msi_domain_info *info = domain->host_data; 1111 1095 struct msi_domain_ops *ops = info->ops; 1112 1096 1113 1097 return ops->msi_prepare(domain, dev, nvec, arg); 1114 - } 1115 - 1116 - int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev, 1117 - int virq_base, int nvec, msi_alloc_info_t *arg) 1118 - { 1119 - struct msi_domain_info *info = domain->host_data; 1120 - struct msi_domain_ops *ops = info->ops; 1121 - struct msi_ctrl ctrl = { 1122 - .domid = MSI_DEFAULT_DOMAIN, 1123 - .first = virq_base, 1124 - .last = virq_base + nvec - 1, 1125 - }; 1126 - struct msi_desc *desc; 1127 - struct xarray *xa; 1128 - int ret, virq; 1129 - 1130 - msi_lock_descs(dev); 1131 - 1132 - if (!msi_ctrl_valid(dev, &ctrl)) { 1133 - ret = -EINVAL; 1134 - goto unlock; 1135 - } 1136 - 1137 - ret = msi_domain_add_simple_msi_descs(dev, &ctrl); 1138 - if (ret) 1139 - goto unlock; 1140 - 1141 - xa = &dev->msi.data->__domains[ctrl.domid].store; 1142 - 1143 - for (virq = virq_base; virq < virq_base + nvec; virq++) { 1144 - desc = xa_load(xa, virq); 1145 - desc->irq = virq; 1146 - 1147 - ops->set_desc(arg, desc); 1148 - ret = irq_domain_alloc_irqs_hierarchy(domain, virq, 1, arg); 1149 - if (ret) 1150 - goto fail; 1151 - 1152 - irq_set_msi_desc(virq, desc); 1153 - } 1154 - msi_unlock_descs(dev); 1155 - return 0; 1156 - 1157 - fail: 1158 - for (--virq; virq >= virq_base; virq--) { 1159 - msi_domain_depopulate_descs(dev, virq, 1); 1160 - irq_domain_free_irqs_common(domain, virq, 1); 1161 - } 1162 - msi_domain_free_descs(dev, &ctrl); 1163 - unlock: 1164 - msi_unlock_descs(dev); 1165 - return ret; 1166 - } 1167 - 1168 - void msi_domain_depopulate_descs(struct device *dev, int virq_base, int nvec) 1169 - { 1170 - struct msi_ctrl ctrl = { 1171 - .domid = MSI_DEFAULT_DOMAIN, 1172 - .first = virq_base, 1173 - .last = virq_base + nvec - 1, 1174 - }; 1175 - struct msi_desc *desc; 1176 - struct xarray *xa; 1177 - unsigned long idx; 1178 - 1179 - if (!msi_ctrl_valid(dev, &ctrl)) 1180 - return; 1181 - 1182 - xa = &dev->msi.data->__domains[ctrl.domid].store; 1183 - xa_for_each_range(xa, idx, desc, ctrl.first, ctrl.last) 1184 - desc->irq = 0; 1185 1098 } 1186 1099 1187 1100 /*