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

irqchip: Provide irq-msi-lib

All irqdomains which provide MSI parent domain functionality for per device
MSI domains need to provide a select() callback for the irqdomain and a
function to initialize the child domain.

Most of these functions would just be copy&paste with minimal
modifications, so provide a library function which implements the required
functionality and is customizable via parent_domain::msi_parent_ops. The
check for the supported bus tokens in msi_lib_init_dev_msi_info() is
expanded step by step within the next patches.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
Signed-off-by: Shivamurthy Shastri <shivamurthy.shastri@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20240623142234.840975799@linutronix.de



+135
+3
drivers/irqchip/Kconfig
··· 74 74 The maximum number of VICs available in the system, for 75 75 power management. 76 76 77 + config IRQ_MSI_LIB 78 + bool 79 + 77 80 config ARMADA_370_XP_IRQ 78 81 bool 79 82 select GENERIC_IRQ_CHIP
+1
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 35 obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-platform-msi.o irq-gic-v4.o
+112
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 + 32 + /* Parent ops available? */ 33 + if (WARN_ON_ONCE(!pops)) 34 + return false; 35 + 36 + /* 37 + * MSI parent domain specific settings. For now there is only the 38 + * root parent domain, e.g. NEXUS, acting as a MSI parent, but it is 39 + * possible to stack MSI parents. See x86 vector -> irq remapping 40 + */ 41 + if (domain->bus_token == pops->bus_select_token) { 42 + if (WARN_ON_ONCE(domain != real_parent)) 43 + return false; 44 + } else { 45 + WARN_ON_ONCE(1); 46 + return false; 47 + } 48 + 49 + /* Is the target domain bus token supported? */ 50 + switch(info->bus_token) { 51 + default: 52 + /* 53 + * This should never be reached. See 54 + * msi_lib_irq_domain_select() 55 + */ 56 + WARN_ON_ONCE(1); 57 + return false; 58 + } 59 + 60 + /* 61 + * Mask out the domain specific MSI feature flags which are not 62 + * supported by the real parent. 63 + */ 64 + info->flags &= pops->supported_flags; 65 + /* Enforce the required flags */ 66 + info->flags |= pops->required_flags; 67 + 68 + /* Chip updates for all child bus types */ 69 + if (!info->chip->irq_eoi) 70 + info->chip->irq_eoi = irq_chip_eoi_parent; 71 + 72 + /* 73 + * The device MSI domain can never have a set affinity callback. It 74 + * always has to rely on the parent domain to handle affinity 75 + * settings. The device MSI domain just has to write the resulting 76 + * MSI message into the hardware which is the whole purpose of the 77 + * device MSI domain aside of mask/unmask which is provided e.g. by 78 + * PCI/MSI device domains. 79 + */ 80 + info->chip->irq_set_affinity = msi_domain_set_affinity; 81 + return true; 82 + } 83 + EXPORT_SYMBOL_GPL(msi_lib_init_dev_msi_info); 84 + 85 + /** 86 + * msi_lib_irq_domain_select - Shared select function for NEXUS domains 87 + * @d: Pointer to the irq domain on which select is invoked 88 + * @fwspec: Firmware spec describing what is searched 89 + * @bus_token: The bus token for which a matching irq domain is looked up 90 + * 91 + * Returns: %0 if @d is not what is being looked for 92 + * 93 + * %1 if @d is either the domain which is directly searched for or 94 + * if @d is providing the parent MSI domain for the functionality 95 + * requested with @bus_token. 96 + */ 97 + int msi_lib_irq_domain_select(struct irq_domain *d, struct irq_fwspec *fwspec, 98 + enum irq_domain_bus_token bus_token) 99 + { 100 + const struct msi_parent_ops *ops = d->msi_parent_ops; 101 + u32 busmask = BIT(bus_token); 102 + 103 + if (fwspec->fwnode != d->fwnode || fwspec->param_count != 0) 104 + return 0; 105 + 106 + /* Handle pure domain searches */ 107 + if (bus_token == ops->bus_select_token) 108 + return 1; 109 + 110 + return ops && !!(ops->bus_select_mask & busmask); 111 + } 112 + EXPORT_SYMBOL_GPL(msi_lib_irq_domain_select);
+19
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 + int msi_lib_irq_domain_select(struct irq_domain *d, struct irq_fwspec *fwspec, 13 + enum irq_domain_bus_token bus_token); 14 + 15 + bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain, 16 + struct irq_domain *real_parent, 17 + struct msi_domain_info *info); 18 + 19 + #endif /* _DRIVERS_IRQCHIP_IRQ_MSI_LIB_H */