diff options
Diffstat (limited to 'drivers/irqchip')
32 files changed, 299 insertions, 325 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 0d196e447142..94a41c7d430e 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -74,17 +74,20 @@ config ARM_VIC_NR config IRQ_MSI_LIB bool + select GENERIC_MSI_IRQ config ARMADA_370_XP_IRQ bool select GENERIC_IRQ_CHIP select PCI_MSI if PCI + select IRQ_MSI_LIB if PCI select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP config ALPINE_MSI bool depends on PCI select PCI_MSI + select IRQ_MSI_LIB select GENERIC_IRQ_CHIP config AL_FIC @@ -434,6 +437,7 @@ config LS_SCFG_MSI def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE select IRQ_MSI_IOMMU depends on PCI_MSI + select IRQ_MSI_LIB config PARTITION_PERCPU bool @@ -634,18 +638,25 @@ config STARFIVE_JH8100_INTC If you don't know what to do here, say Y. -config THEAD_C900_ACLINT_SSWI - bool "THEAD C9XX ACLINT S-mode IPI Interrupt Controller" +config ACLINT_SSWI + bool "RISC-V ACLINT S-mode IPI Interrupt Controller" depends on RISCV depends on SMP select IRQ_DOMAIN_HIERARCHY select GENERIC_IRQ_IPI_MUX help - This enables support for T-HEAD specific ACLINT SSWI device - support. + This enables support for variants of the RISC-V ACLINT-SSWI device. + Supported variants are: + - T-HEAD, with compatible "thead,c900-aclint-sswi" + - MIPS P8700, with compatible "mips,p8700-aclint-sswi" If you don't know what to do here, say Y. +# Backwards compatibility so oldconfig does not drop it. +config THEAD_C900_ACLINT_SSWI + bool + select ACLINT_SSWI + config EXYNOS_IRQ_COMBINER bool "Samsung Exynos IRQ combiner support" if COMPILE_TEST depends on (ARCH_EXYNOS && ARM) || COMPILE_TEST diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 23ca4959e6ce..0458d6c5d161 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -105,7 +105,7 @@ obj-$(CONFIG_RISCV_APLIC_MSI) += irq-riscv-aplic-msi.o obj-$(CONFIG_RISCV_IMSIC) += irq-riscv-imsic-state.o irq-riscv-imsic-early.o irq-riscv-imsic-platform.o obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o obj-$(CONFIG_STARFIVE_JH8100_INTC) += irq-starfive-jh8100-intc.o -obj-$(CONFIG_THEAD_C900_ACLINT_SSWI) += irq-thead-c900-aclint-sswi.o +obj-$(CONFIG_ACLINT_SSWI) += irq-aclint-sswi.o obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o obj-$(CONFIG_IMX_INTMUX) += irq-imx-intmux.o obj-$(CONFIG_IMX_MU_MSI) += irq-imx-mu-msi.o diff --git a/drivers/irqchip/irq-thead-c900-aclint-sswi.c b/drivers/irqchip/irq-aclint-sswi.c index 8ff6e7a1363b..93e28e9f281f 100644 --- a/drivers/irqchip/irq-thead-c900-aclint-sswi.c +++ b/drivers/irqchip/irq-aclint-sswi.c @@ -3,87 +3,77 @@ * Copyright (C) 2024 Inochi Amaoto <inochiama@gmail.com> */ -#define pr_fmt(fmt) "thead-c900-aclint-sswi: " fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/cpu.h> #include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h> #include <linux/irqchip.h> #include <linux/irqchip/chained_irq.h> -#include <linux/module.h> -#include <linux/of.h> #include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/pci.h> #include <linux/spinlock.h> #include <linux/smp.h> #include <linux/string_choices.h> #include <asm/sbi.h> #include <asm/vendorid_list.h> -#define THEAD_ACLINT_xSWI_REGISTER_SIZE 4 - -#define THEAD_C9XX_CSR_SXSTATUS 0x5c0 -#define THEAD_C9XX_SXSTATUS_CLINTEE BIT(17) - static int sswi_ipi_virq __ro_after_init; static DEFINE_PER_CPU(void __iomem *, sswi_cpu_regs); -static void thead_aclint_sswi_ipi_send(unsigned int cpu) +static void aclint_sswi_ipi_send(unsigned int cpu) { writel(0x1, per_cpu(sswi_cpu_regs, cpu)); } -static void thead_aclint_sswi_ipi_clear(void) +static void aclint_sswi_ipi_clear(void) { writel_relaxed(0x0, this_cpu_read(sswi_cpu_regs)); } -static void thead_aclint_sswi_ipi_handle(struct irq_desc *desc) +static void aclint_sswi_ipi_handle(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); csr_clear(CSR_IP, IE_SIE); - thead_aclint_sswi_ipi_clear(); + aclint_sswi_ipi_clear(); ipi_mux_process(); chained_irq_exit(chip, desc); } -static int thead_aclint_sswi_starting_cpu(unsigned int cpu) +static int aclint_sswi_starting_cpu(unsigned int cpu) { enable_percpu_irq(sswi_ipi_virq, irq_get_trigger_type(sswi_ipi_virq)); return 0; } -static int thead_aclint_sswi_dying_cpu(unsigned int cpu) +static int aclint_sswi_dying_cpu(unsigned int cpu) { - thead_aclint_sswi_ipi_clear(); + aclint_sswi_ipi_clear(); disable_percpu_irq(sswi_ipi_virq); return 0; } -static int __init thead_aclint_sswi_parse_irq(struct fwnode_handle *fwnode, - void __iomem *reg) +static int __init aclint_sswi_parse_irq(struct fwnode_handle *fwnode, void __iomem *reg) { - struct of_phandle_args parent; - unsigned long hartid; - u32 contexts, i; - int rc, cpu; + u32 contexts = of_irq_count(to_of_node(fwnode)); - contexts = of_irq_count(to_of_node(fwnode)); if (!(contexts)) { pr_err("%pfwP: no ACLINT SSWI context available\n", fwnode); return -EINVAL; } - for (i = 0; i < contexts; i++) { + for (u32 i = 0; i < contexts; i++) { + struct of_phandle_args parent; + unsigned long hartid; + u32 hart_index; + int rc, cpu; + rc = of_irq_parse_one(to_of_node(fwnode), i, &parent); if (rc) return rc; @@ -97,7 +87,12 @@ static int __init thead_aclint_sswi_parse_irq(struct fwnode_handle *fwnode, cpu = riscv_hartid_to_cpuid(hartid); - per_cpu(sswi_cpu_regs, cpu) = reg + i * THEAD_ACLINT_xSWI_REGISTER_SIZE; + rc = riscv_get_hart_index(fwnode, i, &hart_index); + if (rc) { + pr_warn("%pfwP: hart index [%d] not found\n", fwnode, i); + return -EINVAL; + } + per_cpu(sswi_cpu_regs, cpu) = reg + hart_index * 4; } pr_info("%pfwP: register %u CPU%s\n", fwnode, contexts, str_plural(contexts)); @@ -105,17 +100,12 @@ static int __init thead_aclint_sswi_parse_irq(struct fwnode_handle *fwnode, return 0; } -static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) +static int __init aclint_sswi_probe(struct fwnode_handle *fwnode) { struct irq_domain *domain; void __iomem *reg; int virq, rc; - /* If it is T-HEAD CPU, check whether SSWI is enabled */ - if (riscv_cached_mvendorid(0) == THEAD_VENDOR_ID && - !(csr_read(THEAD_C9XX_CSR_SXSTATUS) & THEAD_C9XX_SXSTATUS_CLINTEE)) - return -ENOTSUPP; - if (!is_of_node(fwnode)) return -EINVAL; @@ -124,7 +114,7 @@ static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) return -ENOMEM; /* Parse SSWI setting */ - rc = thead_aclint_sswi_parse_irq(fwnode, reg); + rc = aclint_sswi_parse_irq(fwnode, reg); if (rc < 0) return rc; @@ -146,22 +136,64 @@ static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) } /* Register SSWI irq and handler */ - virq = ipi_mux_create(BITS_PER_BYTE, thead_aclint_sswi_ipi_send); + virq = ipi_mux_create(BITS_PER_BYTE, aclint_sswi_ipi_send); if (virq <= 0) { pr_err("unable to create muxed IPIs\n"); irq_dispose_mapping(sswi_ipi_virq); return virq < 0 ? virq : -ENOMEM; } - irq_set_chained_handler(sswi_ipi_virq, thead_aclint_sswi_ipi_handle); + irq_set_chained_handler(sswi_ipi_virq, aclint_sswi_ipi_handle); - cpuhp_setup_state(CPUHP_AP_IRQ_THEAD_ACLINT_SSWI_STARTING, - "irqchip/thead-aclint-sswi:starting", - thead_aclint_sswi_starting_cpu, - thead_aclint_sswi_dying_cpu); + cpuhp_setup_state(CPUHP_AP_IRQ_ACLINT_SSWI_STARTING, + "irqchip/aclint-sswi:starting", + aclint_sswi_starting_cpu, + aclint_sswi_dying_cpu); riscv_ipi_set_virq_range(virq, BITS_PER_BYTE); + return 0; +} + +/* generic/MIPS variant */ +static int __init generic_aclint_sswi_probe(struct fwnode_handle *fwnode) +{ + int rc; + + rc = aclint_sswi_probe(fwnode); + if (rc) + return rc; + + /* Announce that SSWI is providing IPIs */ + pr_info("providing IPIs using ACLINT SSWI\n"); + + return 0; +} + +static int __init generic_aclint_sswi_early_probe(struct device_node *node, + struct device_node *parent) +{ + return generic_aclint_sswi_probe(&node->fwnode); +} +IRQCHIP_DECLARE(generic_aclint_sswi, "mips,p8700-aclint-sswi", generic_aclint_sswi_early_probe); + +/* THEAD variant */ +#define THEAD_C9XX_CSR_SXSTATUS 0x5c0 +#define THEAD_C9XX_SXSTATUS_CLINTEE BIT(17) + +static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) +{ + int rc; + + /* If it is T-HEAD CPU, check whether SSWI is enabled */ + if (riscv_cached_mvendorid(0) == THEAD_VENDOR_ID && + !(csr_read(THEAD_C9XX_CSR_SXSTATUS) & THEAD_C9XX_SXSTATUS_CLINTEE)) + return -ENOTSUPP; + + rc = aclint_sswi_probe(fwnode); + if (rc) + return rc; + /* Announce that SSWI is providing IPIs */ pr_info("providing IPIs using THEAD ACLINT SSWI\n"); diff --git a/drivers/irqchip/irq-alpine-msi.c b/drivers/irqchip/irq-alpine-msi.c index a5289dc26dca..159d9ec7c0dd 100644 --- a/drivers/irqchip/irq-alpine-msi.c +++ b/drivers/irqchip/irq-alpine-msi.c @@ -14,6 +14,7 @@ #include <linux/irqchip.h> #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/irq-msi-lib.h> #include <linux/msi.h> #include <linux/of.h> #include <linux/of_address.h> @@ -29,84 +30,45 @@ #define ALPINE_MSIX_SPI_TARGET_CLUSTER0 BIT(16) struct alpine_msix_data { - spinlock_t msi_map_lock; - phys_addr_t addr; - u32 spi_first; /* The SGI number that MSIs start */ - u32 num_spis; /* The number of SGIs for MSIs */ - unsigned long *msi_map; -}; - -static void alpine_msix_mask_msi_irq(struct irq_data *d) -{ - pci_msi_mask_irq(d); - irq_chip_mask_parent(d); -} - -static void alpine_msix_unmask_msi_irq(struct irq_data *d) -{ - pci_msi_unmask_irq(d); - irq_chip_unmask_parent(d); -} - -static struct irq_chip alpine_msix_irq_chip = { - .name = "MSIx", - .irq_mask = alpine_msix_mask_msi_irq, - .irq_unmask = alpine_msix_unmask_msi_irq, - .irq_eoi = irq_chip_eoi_parent, - .irq_set_affinity = irq_chip_set_affinity_parent, + spinlock_t msi_map_lock; + phys_addr_t addr; + u32 spi_first; /* The SGI number that MSIs start */ + u32 num_spis; /* The number of SGIs for MSIs */ + unsigned long *msi_map; }; static int alpine_msix_allocate_sgi(struct alpine_msix_data *priv, int num_req) { int first; - spin_lock(&priv->msi_map_lock); - - first = bitmap_find_next_zero_area(priv->msi_map, priv->num_spis, 0, - num_req, 0); - if (first >= priv->num_spis) { - spin_unlock(&priv->msi_map_lock); + guard(spinlock)(&priv->msi_map_lock); + first = bitmap_find_next_zero_area(priv->msi_map, priv->num_spis, 0, num_req, 0); + if (first >= priv->num_spis) return -ENOSPC; - } bitmap_set(priv->msi_map, first, num_req); - - spin_unlock(&priv->msi_map_lock); - return priv->spi_first + first; } -static void alpine_msix_free_sgi(struct alpine_msix_data *priv, unsigned sgi, - int num_req) +static void alpine_msix_free_sgi(struct alpine_msix_data *priv, unsigned int sgi, int num_req) { int first = sgi - priv->spi_first; - spin_lock(&priv->msi_map_lock); - + guard(spinlock)(&priv->msi_map_lock); bitmap_clear(priv->msi_map, first, num_req); - - spin_unlock(&priv->msi_map_lock); } -static void alpine_msix_compose_msi_msg(struct irq_data *data, - struct msi_msg *msg) +static void alpine_msix_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) { struct alpine_msix_data *priv = irq_data_get_irq_chip_data(data); phys_addr_t msg_addr = priv->addr; msg_addr |= (data->hwirq << 3); - msg->address_hi = upper_32_bits(msg_addr); msg->address_lo = lower_32_bits(msg_addr); msg->data = 0; } -static struct msi_domain_info alpine_msix_domain_info = { - .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_PCI_MSIX, - .chip = &alpine_msix_irq_chip, -}; - static struct irq_chip middle_irq_chip = { .name = "alpine_msix_middle", .irq_mask = irq_chip_mask_parent, @@ -116,8 +78,7 @@ static struct irq_chip middle_irq_chip = { .irq_compose_msi_msg = alpine_msix_compose_msi_msg, }; -static int alpine_msix_gic_domain_alloc(struct irq_domain *domain, - unsigned int virq, int sgi) +static int alpine_msix_gic_domain_alloc(struct irq_domain *domain, unsigned int virq, int sgi) { struct irq_fwspec fwspec; struct irq_data *d; @@ -138,12 +99,10 @@ static int alpine_msix_gic_domain_alloc(struct irq_domain *domain, d = irq_domain_get_irq_data(domain->parent, virq); d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING); - return 0; } -static int alpine_msix_middle_domain_alloc(struct irq_domain *domain, - unsigned int virq, +static int alpine_msix_middle_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *args) { struct alpine_msix_data *priv = domain->host_data; @@ -161,7 +120,6 @@ static int alpine_msix_middle_domain_alloc(struct irq_domain *domain, irq_domain_set_hwirq_and_chip(domain, virq + i, sgi + i, &middle_irq_chip, priv); } - return 0; err_sgi: @@ -170,8 +128,7 @@ err_sgi: return err; } -static void alpine_msix_middle_domain_free(struct irq_domain *domain, - unsigned int virq, +static void alpine_msix_middle_domain_free(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs) { struct irq_data *d = irq_domain_get_irq_data(domain, virq); @@ -182,14 +139,35 @@ static void alpine_msix_middle_domain_free(struct irq_domain *domain, } static const struct irq_domain_ops alpine_msix_middle_domain_ops = { + .select = msi_lib_irq_domain_select, .alloc = alpine_msix_middle_domain_alloc, .free = alpine_msix_middle_domain_free, }; -static int alpine_msix_init_domains(struct alpine_msix_data *priv, - struct device_node *node) +#define ALPINE_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ + MSI_FLAG_USE_DEF_CHIP_OPS | \ + MSI_FLAG_PCI_MSI_MASK_PARENT) + +#define ALPINE_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ + MSI_FLAG_PCI_MSIX) + +static struct msi_parent_ops alpine_msi_parent_ops = { + .supported_flags = ALPINE_MSI_FLAGS_SUPPORTED, + .required_flags = ALPINE_MSI_FLAGS_REQUIRED, + .chip_flags = MSI_CHIP_FLAG_SET_EOI, + .bus_select_token = DOMAIN_BUS_NEXUS, + .bus_select_mask = MATCH_PCI_MSI, + .prefix = "ALPINE-", + .init_dev_msi_info = msi_lib_init_dev_msi_info, +}; + +static int alpine_msix_init_domains(struct alpine_msix_data *priv, struct device_node *node) { - struct irq_domain *middle_domain, *msi_domain, *gic_domain; + struct irq_domain_info info = { + .fwnode = of_fwnode_handle(node), + .ops = &alpine_msix_middle_domain_ops, + .host_data = priv, + }; struct device_node *gic_node; gic_node = of_irq_find_parent(node); @@ -198,40 +176,26 @@ static int alpine_msix_init_domains(struct alpine_msix_data *priv, return -ENODEV; } - gic_domain = irq_find_host(gic_node); + info.parent = irq_find_host(gic_node); of_node_put(gic_node); - if (!gic_domain) { + if (!info.parent) { pr_err("Failed to find the GIC domain\n"); return -ENXIO; } - middle_domain = irq_domain_create_hierarchy(gic_domain, 0, 0, NULL, - &alpine_msix_middle_domain_ops, priv); - if (!middle_domain) { - pr_err("Failed to create the MSIX middle domain\n"); - return -ENOMEM; - } - - msi_domain = pci_msi_create_irq_domain(of_fwnode_handle(node), - &alpine_msix_domain_info, - middle_domain); - if (!msi_domain) { + if (!msi_create_parent_irq_domain(&info, &alpine_msi_parent_ops)) { pr_err("Failed to create MSI domain\n"); - irq_domain_remove(middle_domain); return -ENOMEM; } - return 0; } -static int alpine_msix_init(struct device_node *node, - struct device_node *parent) +static int alpine_msix_init(struct device_node *node, struct device_node *parent) { - struct alpine_msix_data *priv; + struct alpine_msix_data *priv __free(kfree) = kzalloc(sizeof(*priv), GFP_KERNEL); struct resource res; int ret; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -240,7 +204,7 @@ static int alpine_msix_init(struct device_node *node, ret = of_address_to_resource(node, 0, &res); if (ret) { pr_err("Failed to allocate resource\n"); - goto err_priv; + return ret; } /* @@ -255,35 +219,28 @@ static int alpine_msix_init(struct device_node *node, if (of_property_read_u32(node, "al,msi-base-spi", &priv->spi_first)) { pr_err("Unable to parse MSI base\n"); - ret = -EINVAL; - goto err_priv; + return -EINVAL; } if (of_property_read_u32(node, "al,msi-num-spis", &priv->num_spis)) { pr_err("Unable to parse MSI numbers\n"); - ret = -EINVAL; - goto err_priv; + return -EINVAL; } - priv->msi_map = bitmap_zalloc(priv->num_spis, GFP_KERNEL); - if (!priv->msi_map) { - ret = -ENOMEM; - goto err_priv; - } + unsigned long *msi_map __free(kfree) = bitmap_zalloc(priv->num_spis, GFP_KERNEL); - pr_debug("Registering %d msixs, starting at %d\n", - priv->num_spis, priv->spi_first); + if (!msi_map) + return -ENOMEM; + priv->msi_map = msi_map; + + pr_debug("Registering %d msixs, starting at %d\n", priv->num_spis, priv->spi_first); ret = alpine_msix_init_domains(priv, node); if (ret) - goto err_map; + return ret; + retain_and_null_ptr(priv); + retain_and_null_ptr(msi_map); return 0; - -err_map: - bitmap_free(priv->msi_map); -err_priv: - kfree(priv); - return ret; } IRQCHIP_DECLARE(alpine_msix, "al,alpine-msix", alpine_msix_init); diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 67b672a78862..a44c49e985b7 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -20,6 +20,7 @@ #include <linux/interrupt.h> #include <linux/irqchip.h> #include <linux/irqchip/chained_irq.h> +#include <linux/irqchip/irq-msi-lib.h> #include <linux/cpu.h> #include <linux/io.h> #include <linux/of_address.h> @@ -156,7 +157,6 @@ * @parent_irq: parent IRQ if MPIC is not top-level interrupt controller * @domain: MPIC main interrupt domain * @ipi_domain: IPI domain - * @msi_domain: MSI domain * @msi_inner_domain: MSI inner domain * @msi_used: bitmap of used MSI numbers * @msi_lock: mutex serializing access to @msi_used @@ -176,7 +176,6 @@ struct mpic { struct irq_domain *ipi_domain; #endif #ifdef CONFIG_PCI_MSI - struct irq_domain *msi_domain; struct irq_domain *msi_inner_domain; DECLARE_BITMAP(msi_used, PCI_MSI_FULL_DOORBELL_NR); struct mutex msi_lock; @@ -234,18 +233,6 @@ static void mpic_irq_unmask(struct irq_data *d) #ifdef CONFIG_PCI_MSI -static struct irq_chip mpic_msi_irq_chip = { - .name = "MPIC MSI", - .irq_mask = pci_msi_mask_irq, - .irq_unmask = pci_msi_unmask_irq, -}; - -static struct msi_domain_info mpic_msi_domain_info = { - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), - .chip = &mpic_msi_irq_chip, -}; - static void mpic_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) { unsigned int cpu = cpumask_first(irq_data_get_effective_affinity_mask(d)); @@ -314,6 +301,7 @@ static void mpic_msi_free(struct irq_domain *domain, unsigned int virq, unsigned } static const struct irq_domain_ops mpic_msi_domain_ops = { + .select = msi_lib_irq_domain_select, .alloc = mpic_msi_alloc, .free = mpic_msi_free, }; @@ -331,6 +319,21 @@ static void mpic_msi_reenable_percpu(struct mpic *mpic) writel(1, mpic->per_cpu + MPIC_INT_CLEAR_MASK); } +#define MPIC_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ + MSI_FLAG_USE_DEF_CHIP_OPS) +#define MPIC_MSI_FLAGS_SUPPORTED (MSI_FLAG_MULTI_PCI_MSI | \ + MSI_FLAG_PCI_MSIX | \ + MSI_GENERIC_FLAGS_MASK) + +static const struct msi_parent_ops mpic_msi_parent_ops = { + .required_flags = MPIC_MSI_FLAGS_REQUIRED, + .supported_flags = MPIC_MSI_FLAGS_SUPPORTED, + .bus_select_token = DOMAIN_BUS_NEXUS, + .bus_select_mask = MATCH_PCI_MSI, + .prefix = "MPIC-", + .init_dev_msi_info = msi_lib_init_dev_msi_info, +}; + static int __init mpic_msi_init(struct mpic *mpic, struct device_node *node, phys_addr_t main_int_phys_base) { @@ -348,17 +351,16 @@ static int __init mpic_msi_init(struct mpic *mpic, struct device_node *node, mpic->msi_doorbell_mask = PCI_MSI_FULL_DOORBELL_MASK; } - mpic->msi_inner_domain = irq_domain_create_linear(NULL, mpic->msi_doorbell_size, - &mpic_msi_domain_ops, mpic); - if (!mpic->msi_inner_domain) - return -ENOMEM; + struct irq_domain_info info = { + .fwnode = of_fwnode_handle(node), + .ops = &mpic_msi_domain_ops, + .host_data = mpic, + .size = mpic->msi_doorbell_size, + }; - mpic->msi_domain = pci_msi_create_irq_domain(of_fwnode_handle(node), &mpic_msi_domain_info, - mpic->msi_inner_domain); - if (!mpic->msi_domain) { - irq_domain_remove(mpic->msi_inner_domain); + mpic->msi_inner_domain = msi_create_parent_irq_domain(&info, &mpic_msi_parent_ops); + if (!mpic->msi_inner_domain) return -ENOMEM; - } mpic_msi_reenable_percpu(mpic); diff --git a/drivers/irqchip/irq-ath79-misc.c b/drivers/irqchip/irq-ath79-misc.c index 268cc18b781f..258b8e9a2d57 100644 --- a/drivers/irqchip/irq-ath79-misc.c +++ b/drivers/irqchip/irq-ath79-misc.c @@ -15,6 +15,8 @@ #include <linux/of_address.h> #include <linux/of_irq.h> +#include <asm/time.h> + #define AR71XX_RESET_REG_MISC_INT_STATUS 0 #define AR71XX_RESET_REG_MISC_INT_ENABLE 4 @@ -177,21 +179,3 @@ static int __init ar7240_misc_intc_of_init( IRQCHIP_DECLARE(ar7240_misc_intc, "qca,ar7240-misc-intc", ar7240_misc_intc_of_init); - -void __init ath79_misc_irq_init(void __iomem *regs, int irq, - int irq_base, bool is_ar71xx) -{ - struct irq_domain *domain; - - if (is_ar71xx) - ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; - else - ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; - - domain = irq_domain_create_legacy(NULL, ATH79_MISC_IRQ_COUNT, - irq_base, 0, &misc_irq_domain_ops, regs); - if (!domain) - panic("Failed to create MISC irqdomain"); - - ath79_misc_intc_domain_init(domain, irq); -} diff --git a/drivers/irqchip/irq-bcm2712-mip.c b/drivers/irqchip/irq-bcm2712-mip.c index 63de5ef6cf2d..9bd7bc0bf6d5 100644 --- a/drivers/irqchip/irq-bcm2712-mip.c +++ b/drivers/irqchip/irq-bcm2712-mip.c @@ -172,18 +172,18 @@ static const struct msi_parent_ops mip_msi_parent_ops = { static int mip_init_domains(struct mip_priv *mip, struct device_node *np) { - struct irq_domain *middle; - - middle = irq_domain_create_hierarchy(mip->parent, 0, mip->num_msis, of_fwnode_handle(np), - &mip_middle_domain_ops, mip); - if (!middle) + struct irq_domain_info info = { + .fwnode = of_fwnode_handle(np), + .ops = &mip_middle_domain_ops, + .host_data = mip, + .size = mip->num_msis, + .parent = mip->parent, + .dev = mip->dev, + }; + + if (!msi_create_parent_irq_domain(&info, &mip_msi_parent_ops)) return -ENOMEM; - irq_domain_update_bus_token(middle, DOMAIN_BUS_GENERIC_MSI); - middle->dev = mip->dev; - middle->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; - middle->msi_parent_ops = &mip_msi_parent_ops; - /* * All MSI-X unmasked for the host, masked for the VPU, and edge-triggered. */ diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index efc791c43d44..dbeb85677b08 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -190,12 +190,12 @@ static void __init gic_prio_init(void) /* * How priority values are used by the GIC depends on two things: - * the security state of the GIC (controlled by the GICD_CTRL.DS bit) + * the security state of the GIC (controlled by the GICD_CTLR.DS bit) * and if Group 0 interrupts can be delivered to Linux in the non-secure * world as FIQs (controlled by the SCR_EL3.FIQ bit). These affect the * way priorities are presented in ICC_PMR_EL1 and in the distributor: * - * GICD_CTRL.DS | SCR_EL3.FIQ | ICC_PMR_EL1 | Distributor + * GICD_CTLR.DS | SCR_EL3.FIQ | ICC_PMR_EL1 | Distributor * ------------------------------------------------------- * 1 | - | unchanged | unchanged * ------------------------------------------------------- @@ -223,7 +223,7 @@ static void __init gic_prio_init(void) dist_prio_nmi = __gicv3_prio_to_ns(dist_prio_nmi); } - pr_info("GICD_CTRL.DS=%d, SCR_EL3.FIQ=%d\n", + pr_info("GICD_CTLR.DS=%d, SCR_EL3.FIQ=%d\n", cpus_have_security_disabled, !cpus_have_group0); } diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c index f0410d5d7315..e9ef2f5a7207 100644 --- a/drivers/irqchip/irq-imgpdc.c +++ b/drivers/irqchip/irq-imgpdc.c @@ -372,8 +372,8 @@ static int pdc_intc_probe(struct platform_device *pdev) priv->syswake_irq = irq; /* Set up an IRQ domain */ - priv->domain = irq_domain_create_linear(of_fwnode_handle(node), 16, &irq_generic_chip_ops, - priv); + priv->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), 16, &irq_generic_chip_ops, + priv); if (unlikely(!priv->domain)) { dev_err(&pdev->dev, "cannot add IRQ domain\n"); return -ENOMEM; diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c index 6dc9ac48fee5..4682ce5bf8d3 100644 --- a/drivers/irqchip/irq-imx-irqsteer.c +++ b/drivers/irqchip/irq-imx-irqsteer.c @@ -212,8 +212,8 @@ static int imx_irqsteer_probe(struct platform_device *pdev) /* steer all IRQs into configured channel */ writel_relaxed(BIT(data->channel), data->regs + CHANCTRL); - data->domain = irq_domain_create_linear(of_fwnode_handle(np), data->reg_num * 32, - &imx_irqsteer_domain_ops, data); + data->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), data->reg_num * 32, + &imx_irqsteer_domain_ops, data); if (!data->domain) { dev_err(&pdev->dev, "failed to create IRQ domain\n"); ret = -ENOMEM; diff --git a/drivers/irqchip/irq-imx-mu-msi.c b/drivers/irqchip/irq-imx-mu-msi.c index 137da1927d14..d2a4e8a61a42 100644 --- a/drivers/irqchip/irq-imx-mu-msi.c +++ b/drivers/irqchip/irq-imx-mu-msi.c @@ -223,21 +223,21 @@ static const struct msi_parent_ops imx_mu_msi_parent_ops = { static int imx_mu_msi_domains_init(struct imx_mu_msi *msi_data, struct device *dev) { - struct fwnode_handle *fwnodes = dev_fwnode(dev); + struct irq_domain_info info = { + .ops = &imx_mu_msi_domain_ops, + .fwnode = dev_fwnode(dev), + .size = IMX_MU_CHANS, + .host_data = msi_data, + }; struct irq_domain *parent; /* Initialize MSI domain parent */ - parent = irq_domain_create_linear(fwnodes, IMX_MU_CHANS, - &imx_mu_msi_domain_ops, msi_data); + parent = msi_create_parent_irq_domain(&info, &imx_mu_msi_parent_ops); if (!parent) { dev_err(dev, "failed to create IRQ domain\n"); return -ENOMEM; } - - irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS); parent->dev = parent->pm_dev = dev; - parent->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; - parent->msi_parent_ops = &imx_mu_msi_parent_ops; return 0; } diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index c9e902b7bf48..922fff09354f 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -157,8 +157,8 @@ static int keystone_irq_probe(struct platform_device *pdev) kirq->chip.irq_mask = keystone_irq_setmask; kirq->chip.irq_unmask = keystone_irq_unmask; - kirq->irqd = irq_domain_create_linear(of_fwnode_handle(np), KEYSTONE_N_IRQ, - &keystone_irq_ops, kirq); + kirq->irqd = irq_domain_create_linear(dev_fwnode(dev), KEYSTONE_N_IRQ, &keystone_irq_ops, + kirq); if (!kirq->irqd) { dev_err(dev, "IRQ domain registration failed\n"); return -ENODEV; diff --git a/drivers/irqchip/irq-loongson-pch-msi.c b/drivers/irqchip/irq-loongson-pch-msi.c index a0257c7bef10..4aedc9b90ff7 100644 --- a/drivers/irqchip/irq-loongson-pch-msi.c +++ b/drivers/irqchip/irq-loongson-pch-msi.c @@ -153,26 +153,21 @@ static struct msi_parent_ops pch_msi_parent_ops = { .init_dev_msi_info = msi_lib_init_dev_msi_info, }; -static int pch_msi_init_domains(struct pch_msi_data *priv, - struct irq_domain *parent, +static int pch_msi_init_domains(struct pch_msi_data *priv, struct irq_domain *parent, struct fwnode_handle *domain_handle) { - struct irq_domain *middle_domain; - - middle_domain = irq_domain_create_hierarchy(parent, 0, priv->num_irqs, - domain_handle, - &pch_msi_middle_domain_ops, - priv); - if (!middle_domain) { + struct irq_domain_info info = { + .ops = &pch_msi_middle_domain_ops, + .size = priv->num_irqs, + .parent = parent, + .host_data = priv, + .fwnode = domain_handle, + }; + + if (!msi_create_parent_irq_domain(&info, &pch_msi_parent_ops)) { pr_err("Failed to create the MSI middle domain\n"); return -ENOMEM; } - - irq_domain_update_bus_token(middle_domain, DOMAIN_BUS_NEXUS); - - middle_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; - middle_domain->msi_parent_ops = &pch_msi_parent_ops; - return 0; } diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 84bc5e4b47cf..4910f364e568 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -14,6 +14,7 @@ #include <linux/iommu.h> #include <linux/irq.h> #include <linux/irqchip/chained_irq.h> +#include <linux/irqchip/irq-msi-lib.h> #include <linux/irqdomain.h> #include <linux/of_irq.h> #include <linux/of_pci.h> @@ -47,7 +48,6 @@ struct ls_scfg_msi { spinlock_t lock; struct platform_device *pdev; struct irq_domain *parent; - struct irq_domain *msi_domain; void __iomem *regs; phys_addr_t msiir_addr; struct ls_scfg_msi_cfg *cfg; @@ -57,17 +57,18 @@ struct ls_scfg_msi { unsigned long *used; }; -static struct irq_chip ls_scfg_msi_irq_chip = { - .name = "MSI", - .irq_mask = pci_msi_mask_irq, - .irq_unmask = pci_msi_unmask_irq, -}; - -static struct msi_domain_info ls_scfg_msi_domain_info = { - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | - MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_PCI_MSIX), - .chip = &ls_scfg_msi_irq_chip, +#define MPIC_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ + MSI_FLAG_USE_DEF_CHIP_OPS) +#define MPIC_MSI_FLAGS_SUPPORTED (MSI_FLAG_PCI_MSIX | \ + MSI_GENERIC_FLAGS_MASK) + +static const struct msi_parent_ops ls_scfg_msi_parent_ops = { + .required_flags = MPIC_MSI_FLAGS_REQUIRED, + .supported_flags = MPIC_MSI_FLAGS_SUPPORTED, + .bus_select_token = DOMAIN_BUS_NEXUS, + .bus_select_mask = MATCH_PCI_MSI, + .prefix = "MSI-", + .init_dev_msi_info = msi_lib_init_dev_msi_info, }; static int msi_affinity_flag = 1; @@ -185,6 +186,7 @@ static void ls_scfg_msi_domain_irq_free(struct irq_domain *domain, } static const struct irq_domain_ops ls_scfg_msi_domain_ops = { + .select = msi_lib_irq_domain_select, .alloc = ls_scfg_msi_domain_irq_alloc, .free = ls_scfg_msi_domain_irq_free, }; @@ -214,23 +216,16 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc) static int ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data) { - /* Initialize MSI domain parent */ - msi_data->parent = irq_domain_create_linear(NULL, - msi_data->irqs_num, - &ls_scfg_msi_domain_ops, - msi_data); + struct irq_domain_info info = { + .fwnode = of_fwnode_handle(msi_data->pdev->dev.of_node), + .ops = &ls_scfg_msi_domain_ops, + .host_data = msi_data, + .size = msi_data->irqs_num, + }; + + msi_data->parent = msi_create_parent_irq_domain(&info, &ls_scfg_msi_parent_ops); if (!msi_data->parent) { - dev_err(&msi_data->pdev->dev, "failed to create IRQ domain\n"); - return -ENOMEM; - } - - msi_data->msi_domain = pci_msi_create_irq_domain( - of_fwnode_handle(msi_data->pdev->dev.of_node), - &ls_scfg_msi_domain_info, - msi_data->parent); - if (!msi_data->msi_domain) { dev_err(&msi_data->pdev->dev, "failed to create MSI domain\n"); - irq_domain_remove(msi_data->parent); return -ENOMEM; } @@ -405,7 +400,6 @@ static void ls_scfg_msi_remove(struct platform_device *pdev) for (i = 0; i < msi_data->msir_num; i++) ls_scfg_msi_teardown_hwirq(&msi_data->msir[i]); - irq_domain_remove(msi_data->msi_domain); irq_domain_remove(msi_data->parent); platform_set_drvdata(pdev, NULL); diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 34e8d09c12a0..19a57c5e2b2e 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -375,9 +375,13 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, /* * The GIC specifies that we can only route an interrupt to one VP(E), * ie. CPU in Linux parlance, at a time. Therefore we always route to - * the first online CPU in the mask. + * the first forced or online CPU in the mask. */ - cpu = cpumask_first_and(cpumask, cpu_online_mask); + if (force) + cpu = cpumask_first(cpumask); + else + cpu = cpumask_first_and(cpumask, cpu_online_mask); + if (cpu >= NR_CPUS) return -EINVAL; diff --git a/drivers/irqchip/irq-mvebu-pic.c b/drivers/irqchip/irq-mvebu-pic.c index 8db638aa21d2..cd8b73482b9f 100644 --- a/drivers/irqchip/irq-mvebu-pic.c +++ b/drivers/irqchip/irq-mvebu-pic.c @@ -150,7 +150,7 @@ static int mvebu_pic_probe(struct platform_device *pdev) return -EINVAL; } - pic->domain = irq_domain_create_linear(of_fwnode_handle(node), PIC_MAX_IRQS, + pic->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), PIC_MAX_IRQS, &mvebu_pic_domain_ops, pic); if (!pic->domain) { dev_err(&pdev->dev, "Failed to allocate irq domain\n"); diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c index 87a5813fd835..81078d56f38d 100644 --- a/drivers/irqchip/irq-pruss-intc.c +++ b/drivers/irqchip/irq-pruss-intc.c @@ -555,7 +555,7 @@ static int pruss_intc_probe(struct platform_device *pdev) mutex_init(&intc->lock); - intc->domain = irq_domain_create_linear(of_fwnode_handle(dev->of_node), max_system_events, + intc->domain = irq_domain_create_linear(dev_fwnode(dev), max_system_events, &pruss_intc_irq_domain_ops, intc); if (!intc->domain) return -ENOMEM; diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index 0959ed43b1a9..7951292d2d9b 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -513,10 +513,8 @@ static int intc_irqpin_probe(struct platform_device *pdev) irq_chip->irq_set_wake = intc_irqpin_irq_set_wake; irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND; - p->irq_domain = irq_domain_create_simple(of_fwnode_handle(dev->of_node), - nirqs, 0, - &intc_irqpin_irq_domain_ops, - p); + p->irq_domain = irq_domain_create_simple(dev_fwnode(dev), nirqs, 0, + &intc_irqpin_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; dev_err(dev, "cannot initialize irq domain\n"); @@ -572,7 +570,7 @@ static void intc_irqpin_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused intc_irqpin_suspend(struct device *dev) +static int intc_irqpin_suspend(struct device *dev) { struct intc_irqpin_priv *p = dev_get_drvdata(dev); @@ -582,7 +580,7 @@ static int __maybe_unused intc_irqpin_suspend(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(intc_irqpin_pm_ops, intc_irqpin_suspend, NULL); +static DEFINE_SIMPLE_DEV_PM_OPS(intc_irqpin_pm_ops, intc_irqpin_suspend, NULL); static struct platform_driver intc_irqpin_device_driver = { .probe = intc_irqpin_probe, @@ -590,7 +588,7 @@ static struct platform_driver intc_irqpin_device_driver = { .driver = { .name = "renesas_intc_irqpin", .of_match_table = intc_irqpin_dt_ids, - .pm = &intc_irqpin_pm_ops, + .pm = pm_sleep_ptr(&intc_irqpin_pm_ops), } }; diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 5c3196e5a437..a20a6471b0e4 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -168,7 +168,7 @@ static int irqc_probe(struct platform_device *pdev) p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */ - p->irq_domain = irq_domain_create_linear(of_fwnode_handle(dev->of_node), p->number_of_irqs, + p->irq_domain = irq_domain_create_linear(dev_fwnode(dev), p->number_of_irqs, &irq_generic_chip_ops, p); if (!p->irq_domain) { ret = -ENXIO; @@ -227,7 +227,7 @@ static void irqc_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused irqc_suspend(struct device *dev) +static int irqc_suspend(struct device *dev) { struct irqc_priv *p = dev_get_drvdata(dev); @@ -237,7 +237,7 @@ static int __maybe_unused irqc_suspend(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(irqc_pm_ops, irqc_suspend, NULL); +static DEFINE_SIMPLE_DEV_PM_OPS(irqc_pm_ops, irqc_suspend, NULL); static const struct of_device_id irqc_dt_ids[] = { { .compatible = "renesas,irqc", }, @@ -251,7 +251,7 @@ static struct platform_driver irqc_device_driver = { .driver = { .name = "renesas_irqc", .of_match_table = irqc_dt_ids, - .pm = &irqc_pm_ops, + .pm = pm_sleep_ptr(&irqc_pm_ops), } }; diff --git a/drivers/irqchip/irq-renesas-rza1.c b/drivers/irqchip/irq-renesas-rza1.c index 0a9640ba0adb..a697eb55ac90 100644 --- a/drivers/irqchip/irq-renesas-rza1.c +++ b/drivers/irqchip/irq-renesas-rza1.c @@ -231,9 +231,8 @@ static int rza1_irqc_probe(struct platform_device *pdev) priv->chip.irq_set_type = rza1_irqc_set_type; priv->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE; - priv->irq_domain = irq_domain_create_hierarchy(parent, 0, IRQC_NUM_IRQ, - of_fwnode_handle(np), &rza1_irqc_domain_ops, - priv); + priv->irq_domain = irq_domain_create_hierarchy(parent, 0, IRQC_NUM_IRQ, dev_fwnode(dev), + &rza1_irqc_domain_ops, priv); if (!priv->irq_domain) { dev_err(dev, "cannot initialize irq domain\n"); ret = -ENOMEM; diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c index 1e861bd64f97..360d88687e4f 100644 --- a/drivers/irqchip/irq-renesas-rzg2l.c +++ b/drivers/irqchip/irq-renesas-rzg2l.c @@ -574,9 +574,8 @@ static int rzg2l_irqc_common_init(struct device_node *node, struct device_node * raw_spin_lock_init(&rzg2l_irqc_data->lock); - irq_domain = irq_domain_create_hierarchy(parent_domain, 0, IRQC_NUM_IRQ, - of_fwnode_handle(node), &rzg2l_irqc_domain_ops, - rzg2l_irqc_data); + irq_domain = irq_domain_create_hierarchy(parent_domain, 0, IRQC_NUM_IRQ, dev_fwnode(dev), + &rzg2l_irqc_domain_ops, rzg2l_irqc_data); if (!irq_domain) { pm_runtime_put(dev); return dev_err_probe(dev, -ENOMEM, "failed to add irq domain\n"); diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c index 69b32c19e8ff..9018d9c3911e 100644 --- a/drivers/irqchip/irq-renesas-rzv2h.c +++ b/drivers/irqchip/irq-renesas-rzv2h.c @@ -11,18 +11,15 @@ #include <linux/bitfield.h> #include <linux/cleanup.h> -#include <linux/clk.h> #include <linux/err.h> #include <linux/io.h> #include <linux/irqchip.h> #include <linux/irqchip/irq-renesas-rzv2h.h> #include <linux/irqdomain.h> -#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/pm_runtime.h> #include <linux/reset.h> #include <linux/spinlock.h> -#include <linux/syscore_ops.h> /* DT "interrupts" indexes */ #define ICU_IRQ_START 1 @@ -427,7 +424,9 @@ static const struct irq_chip rzv2h_icu_chip = { .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_set_type = rzv2h_icu_set_type, .irq_set_affinity = irq_chip_set_affinity_parent, - .flags = IRQCHIP_SET_TYPE_MASKED, + .flags = IRQCHIP_MASK_ON_SUSPEND | + IRQCHIP_SET_TYPE_MASKED | + IRQCHIP_SKIP_SET_WAKE, }; static int rzv2h_icu_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, @@ -558,7 +557,7 @@ static int rzv2h_icu_init_common(struct device_node *node, struct device_node *p raw_spin_lock_init(&rzv2h_icu_data->lock); irq_domain = irq_domain_create_hierarchy(parent_domain, 0, ICU_NUM_IRQ, - of_fwnode_handle(node), &rzv2h_icu_domain_ops, + dev_fwnode(&pdev->dev), &rzv2h_icu_domain_ops, rzv2h_icu_data); if (!irq_domain) { dev_err(&pdev->dev, "failed to add irq domain\n"); diff --git a/drivers/irqchip/irq-riscv-aplic-direct.c b/drivers/irqchip/irq-riscv-aplic-direct.c index 205ad61d15e4..c2a75bf3d20c 100644 --- a/drivers/irqchip/irq-riscv-aplic-direct.c +++ b/drivers/irqchip/irq-riscv-aplic-direct.c @@ -219,20 +219,6 @@ static int aplic_direct_parse_parent_hwirq(struct device *dev, u32 index, return 0; } -static int aplic_direct_get_hart_index(struct device *dev, u32 logical_index, - u32 *hart_index) -{ - const char *prop_hart_index = "riscv,hart-indexes"; - struct device_node *np = to_of_node(dev->fwnode); - - if (!np || !of_property_present(np, prop_hart_index)) { - *hart_index = logical_index; - return 0; - } - - return of_property_read_u32_index(np, prop_hart_index, logical_index, hart_index); -} - int aplic_direct_setup(struct device *dev, void __iomem *regs) { int i, j, rc, cpu, current_cpu, setup_count = 0; @@ -279,7 +265,7 @@ int aplic_direct_setup(struct device *dev, void __iomem *regs) cpumask_set_cpu(cpu, &direct->lmask); idc = per_cpu_ptr(&aplic_idcs, cpu); - rc = aplic_direct_get_hart_index(dev, i, &idc->hart_index); + rc = riscv_get_hart_index(dev->fwnode, i, &idc->hart_index); if (rc) { dev_warn(dev, "hart index not found for IDC%d\n", i); continue; diff --git a/drivers/irqchip/irq-riscv-imsic-early.c b/drivers/irqchip/irq-riscv-imsic-early.c index d9ae87808651..2709cacf4855 100644 --- a/drivers/irqchip/irq-riscv-imsic-early.c +++ b/drivers/irqchip/irq-riscv-imsic-early.c @@ -8,6 +8,7 @@ #include <linux/acpi.h> #include <linux/cpu.h> #include <linux/interrupt.h> +#include <linux/init.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/irqchip.h> @@ -21,6 +22,14 @@ #include "irq-riscv-imsic-state.h" static int imsic_parent_irq; +bool imsic_noipi __ro_after_init; + +static int __init imsic_noipi_cfg(char *buf) +{ + imsic_noipi = true; + return 0; +} +early_param("irqchip.riscv_imsic_noipi", imsic_noipi_cfg); #ifdef CONFIG_SMP static void imsic_ipi_send(unsigned int cpu) @@ -32,12 +41,18 @@ static void imsic_ipi_send(unsigned int cpu) static void imsic_ipi_starting_cpu(void) { + if (imsic_noipi) + return; + /* Enable IPIs for current CPU. */ __imsic_id_set_enable(IMSIC_IPI_ID); } static void imsic_ipi_dying_cpu(void) { + if (imsic_noipi) + return; + /* Disable IPIs for current CPU. */ __imsic_id_clear_enable(IMSIC_IPI_ID); } @@ -46,6 +61,9 @@ static int __init imsic_ipi_domain_init(void) { int virq; + if (imsic_noipi) + return 0; + /* Create IMSIC IPI multiplexing */ virq = ipi_mux_create(IMSIC_NR_IPI, imsic_ipi_send); if (virq <= 0) @@ -88,7 +106,7 @@ static void imsic_handle_irq(struct irq_desc *desc) while ((local_id = csr_swap(CSR_TOPEI, 0))) { local_id >>= TOPEI_ID_SHIFT; - if (local_id == IMSIC_IPI_ID) { + if (!imsic_noipi && local_id == IMSIC_IPI_ID) { if (IS_ENABLED(CONFIG_SMP)) ipi_mux_process(); continue; diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c index 1b9fbfce9581..74a2a28f9403 100644 --- a/drivers/irqchip/irq-riscv-imsic-platform.c +++ b/drivers/irqchip/irq-riscv-imsic-platform.c @@ -307,6 +307,11 @@ static const struct msi_parent_ops imsic_msi_parent_ops = { int imsic_irqdomain_init(void) { + struct irq_domain_info info = { + .fwnode = imsic->fwnode, + .ops = &imsic_base_domain_ops, + .host_data = imsic, + }; struct imsic_global_config *global; if (!imsic || !imsic->fwnode) { @@ -320,16 +325,11 @@ int imsic_irqdomain_init(void) } /* Create Base IRQ domain */ - imsic->base_domain = irq_domain_create_tree(imsic->fwnode, - &imsic_base_domain_ops, imsic); + imsic->base_domain = msi_create_parent_irq_domain(&info, &imsic_msi_parent_ops); if (!imsic->base_domain) { pr_err("%pfwP: failed to create IMSIC base domain\n", imsic->fwnode); return -ENOMEM; } - imsic->base_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; - imsic->base_domain->msi_parent_ops = &imsic_msi_parent_ops; - - irq_domain_update_bus_token(imsic->base_domain, DOMAIN_BUS_NEXUS); global = &imsic->global; pr_info("%pfwP: hart-index-bits: %d, guest-index-bits: %d\n", diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c index 77670dd645ac..dc95ad856d80 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.c +++ b/drivers/irqchip/irq-riscv-imsic-state.c @@ -134,7 +134,7 @@ static bool __imsic_local_sync(struct imsic_local_priv *lpriv) lockdep_assert_held(&lpriv->lock); for_each_set_bit(i, lpriv->dirty_bitmap, imsic->global.nr_ids + 1) { - if (!i || i == IMSIC_IPI_ID) + if (!i || (!imsic_noipi && i == IMSIC_IPI_ID)) goto skip; vec = &lpriv->vectors[i]; @@ -419,7 +419,7 @@ void imsic_vector_debug_show(struct seq_file *m, struct imsic_vector *vec, int i seq_printf(m, "%*starget_cpu : %5u\n", ind, "", vec->cpu); seq_printf(m, "%*starget_local_id : %5u\n", ind, "", vec->local_id); seq_printf(m, "%*sis_reserved : %5u\n", ind, "", - (vec->local_id <= IMSIC_IPI_ID) ? 1 : 0); + (!imsic_noipi && vec->local_id <= IMSIC_IPI_ID) ? 1 : 0); seq_printf(m, "%*sis_enabled : %5u\n", ind, "", is_enabled ? 1 : 0); seq_printf(m, "%*sis_move_pending : %5u\n", ind, "", mvec ? 1 : 0); if (mvec) { @@ -583,7 +583,8 @@ static int __init imsic_matrix_init(void) irq_matrix_assign_system(imsic->matrix, 0, false); /* Reserve IPI ID because it is special and used internally */ - irq_matrix_assign_system(imsic->matrix, IMSIC_IPI_ID, false); + if (!imsic_noipi) + irq_matrix_assign_system(imsic->matrix, IMSIC_IPI_ID, false); return 0; } diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h index 3202ffa4e849..57f951952b0c 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.h +++ b/drivers/irqchip/irq-riscv-imsic-state.h @@ -61,6 +61,7 @@ struct imsic_priv { struct irq_domain *base_domain; }; +extern bool imsic_noipi; extern struct imsic_priv *imsic; void __imsic_eix_update(unsigned long base_id, unsigned long num_id, bool pend, bool val); diff --git a/drivers/irqchip/irq-sg2042-msi.c b/drivers/irqchip/irq-sg2042-msi.c index af16bc5a3c8b..bcfddc51bc6a 100644 --- a/drivers/irqchip/irq-sg2042-msi.c +++ b/drivers/irqchip/irq-sg2042-msi.c @@ -219,20 +219,18 @@ static const struct msi_parent_ops sg2044_msi_parent_ops = { static int sg204x_msi_init_domains(struct sg204x_msi_chipdata *data, struct irq_domain *plic_domain, struct device *dev) { - struct fwnode_handle *fwnode = dev_fwnode(dev); - struct irq_domain *middle_domain; - - middle_domain = irq_domain_create_hierarchy(plic_domain, 0, data->num_irqs, fwnode, - &sg204x_msi_middle_domain_ops, data); - if (!middle_domain) { + struct irq_domain_info info = { + .ops = &sg204x_msi_middle_domain_ops, + .parent = plic_domain, + .size = data->num_irqs, + .fwnode = dev_fwnode(dev), + .host_data = data, + }; + + if (!msi_create_parent_irq_domain(&info, data->chip_info->parent_ops)) { pr_err("Failed to create the MSI middle domain\n"); return -ENOMEM; } - - irq_domain_update_bus_token(middle_domain, DOMAIN_BUS_NEXUS); - - middle_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; - middle_domain->msi_parent_ops = data->chip_info->parent_ops; return 0; } diff --git a/drivers/irqchip/irq-stm32mp-exti.c b/drivers/irqchip/irq-stm32mp-exti.c index c6b4407d05f9..a24f4f1a4f8f 100644 --- a/drivers/irqchip/irq-stm32mp-exti.c +++ b/drivers/irqchip/irq-stm32mp-exti.c @@ -683,9 +683,7 @@ static int stm32mp_exti_probe(struct platform_device *pdev) } domain = irq_domain_create_hierarchy(parent_domain, 0, drv_data->bank_nr * IRQS_PER_BANK, - of_fwnode_handle(np), &stm32mp_exti_domain_ops, - host_data); - + dev_fwnode(dev), &stm32mp_exti_domain_ops, host_data); if (!domain) { dev_err(dev, "Could not register exti domain\n"); return -ENOMEM; diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c index 7de59238e6b0..01963d36cfaf 100644 --- a/drivers/irqchip/irq-ti-sci-inta.c +++ b/drivers/irqchip/irq-ti-sci-inta.c @@ -701,8 +701,7 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev) if (ret) return ret; - domain = irq_domain_create_linear(of_fwnode_handle(dev_of_node(dev)), - ti_sci_get_num_resources(inta->vint), + domain = irq_domain_create_linear(dev_fwnode(dev), ti_sci_get_num_resources(inta->vint), &ti_sci_inta_irq_domain_ops, inta); if (!domain) { dev_err(dev, "Failed to allocate IRQ domain\n"); diff --git a/drivers/irqchip/irq-ti-sci-intr.c b/drivers/irqchip/irq-ti-sci-intr.c index 07fff5ae5ce0..354613e74ad0 100644 --- a/drivers/irqchip/irq-ti-sci-intr.c +++ b/drivers/irqchip/irq-ti-sci-intr.c @@ -274,8 +274,7 @@ static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev) return PTR_ERR(intr->out_irqs); } - domain = irq_domain_create_hierarchy(parent_domain, 0, 0, - of_fwnode_handle(dev_of_node(dev)), + domain = irq_domain_create_hierarchy(parent_domain, 0, 0, dev_fwnode(dev), &ti_sci_intr_irq_domain_ops, intr); if (!domain) { dev_err(dev, "Failed to allocate IRQ domain\n"); diff --git a/drivers/irqchip/irq-ts4800.c b/drivers/irqchip/irq-ts4800.c index e625f4fb2bb8..1e236d5b7516 100644 --- a/drivers/irqchip/irq-ts4800.c +++ b/drivers/irqchip/irq-ts4800.c @@ -125,7 +125,7 @@ static int ts4800_ic_probe(struct platform_device *pdev) return -EINVAL; } - data->domain = irq_domain_create_linear(of_fwnode_handle(node), 8, &ts4800_ic_ops, data); + data->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), 8, &ts4800_ic_ops, data); if (!data->domain) { dev_err(&pdev->dev, "cannot add IRQ domain\n"); return -ENOMEM; |