From 855d4ca4bdb366aab3d43408b74e02ab629d1d55 Mon Sep 17 00:00:00 2001 From: Liu Peibao <liupeibao@loongson.cn> Date: Mon, 14 Nov 2022 19:38:23 +0800 Subject: [PATCH 01/28] irqchip: loongarch-cpu: add DT support LoongArch is coming to support booting with FDT, so DT support of this driver is desired. Signed-off-by: Liu Peibao <liupeibao@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221114113824.1880-2-liupeibao@loongson.cn --- drivers/irqchip/irq-loongarch-cpu.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c index 741612ba6a520..a28b7c5496546 100644 --- a/drivers/irqchip/irq-loongarch-cpu.c +++ b/drivers/irqchip/irq-loongarch-cpu.c @@ -92,6 +92,25 @@ static const struct irq_domain_ops loongarch_cpu_intc_irq_domain_ops = { .xlate = irq_domain_xlate_onecell, }; +#ifdef CONFIG_OF +int __init loongarch_cpu_irq_of_init(struct device_node *of_node, + struct device_node *parent) +{ + cpuintc_handle = of_node_to_fwnode(of_node); + + irq_domain = irq_domain_create_linear(cpuintc_handle, EXCCODE_INT_NUM, + &loongarch_cpu_intc_irq_domain_ops, NULL); + if (!irq_domain) + panic("Failed to add irqdomain for loongarch CPU"); + + set_handle_irq(&handle_cpu_irq); + + return 0; +} +IRQCHIP_DECLARE(cpu_intc, "loongson,cpu-interrupt-controller", + loongarch_cpu_irq_of_init); +#endif + static int __init liointc_parse_madt(union acpi_subtable_headers *header, const unsigned long end) From 6b2748ada244c7597e9b677a0bdda4e8781a8d8f Mon Sep 17 00:00:00 2001 From: Liu Peibao <liupeibao@loongson.cn> Date: Mon, 14 Nov 2022 19:38:24 +0800 Subject: [PATCH 02/28] dt-bindings: interrupt-controller: add yaml for LoongArch CPU interrupt controller Current LoongArch compatible CPUs support 14 CPU IRQs. We can describe how the 14 IRQs are wired to the platform's internal interrupt controller by devicetree. Signed-off-by: Liu Peibao <liupeibao@loongson.cn> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221114113824.1880-3-liupeibao@loongson.cn --- .../loongarch,cpu-interrupt-controller.yaml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/loongarch,cpu-interrupt-controller.yaml diff --git a/Documentation/devicetree/bindings/interrupt-controller/loongarch,cpu-interrupt-controller.yaml b/Documentation/devicetree/bindings/interrupt-controller/loongarch,cpu-interrupt-controller.yaml new file mode 100644 index 0000000000000..2a1cf885c99df --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/loongarch,cpu-interrupt-controller.yaml @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/loongarch,cpu-interrupt-controller.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LoongArch CPU Interrupt Controller + +maintainers: + - Liu Peibao <liupeibao@loongson.cn> + +properties: + compatible: + const: loongarch,cpu-interrupt-controller + + '#interrupt-cells': + const: 1 + + interrupt-controller: true + +additionalProperties: false + +required: + - compatible + - '#interrupt-cells' + - interrupt-controller + +examples: + - | + interrupt-controller { + compatible = "loongarch,cpu-interrupt-controller"; + #interrupt-cells = <1>; + interrupt-controller; + }; From d0c50cc4b957b2cf6e43cec4998d212b5abe9220 Mon Sep 17 00:00:00 2001 From: Jianmin Lv <lvjianmin@loongson.cn> Date: Sat, 22 Oct 2022 15:59:52 +0800 Subject: [PATCH 03/28] ACPI / PCI: fix LPIC IRQ model default PCI IRQ polarity On LoongArch based systems, the PCI devices (e.g. SATA controllers and PCI-to-PCI bridge controllers) in Loongson chipsets output high-level interrupt signal to the interrupt controller they are connected (see Loongson 7A1000 Bridge User Manual v2.00, sec 5.3, "For the bridge chip, AC97 DMA interrupts are edge triggered, gpio interrupts can be configured to be level triggered or edge triggered as needed, and the rest of the interrupts are level triggered and active high."), while the IRQs are active low from the perspective of PCI (see Conventional PCI spec r3.0, sec 2.2.6, "Interrupts on PCI are optional and defined as level sensitive, asserted low."), which means that the interrupt output of PCI devices plugged into PCI-to-PCI bridges of Loongson chipset will be also converted to high-level. So high level triggered type is required to be passed to acpi_register_gsi() when creating mappings for PCI devices. Signed-off-by: Jianmin Lv <lvjianmin@loongson.cn> Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221022075955.11726-2-lvjianmin@loongson.cn --- drivers/acpi/pci_irq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 08e15774fb9f9..ff30ceca2203e 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -387,13 +387,15 @@ int acpi_pci_irq_enable(struct pci_dev *dev) u8 pin; int triggering = ACPI_LEVEL_SENSITIVE; /* - * On ARM systems with the GIC interrupt model, level interrupts + * On ARM systems with the GIC interrupt model, or LoongArch + * systems with the LPIC interrupt model, level interrupts * are always polarity high by specification; PCI legacy * IRQs lines are inverted before reaching the interrupt * controller and must therefore be considered active high * as default. */ - int polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC ? + int polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC || + acpi_irq_model == ACPI_IRQ_MODEL_LPIC ? ACPI_ACTIVE_HIGH : ACPI_ACTIVE_LOW; char *link = NULL; char link_desc[16]; From c7c00138015975c8f0e268564249cc47d8de632c Mon Sep 17 00:00:00 2001 From: Jianmin Lv <lvjianmin@loongson.cn> Date: Sat, 22 Oct 2022 15:59:53 +0800 Subject: [PATCH 04/28] irqchip/loongson-pch-pic: Fix translate callback for DT path In DT path of translate callback, if fwspec->param_count==1 and of_node is non-null, fwspec->param[1] will be accessed, which is introduced from previous commit bcdd75c596c8 (irqchip/loongson-pch-pic: Add ACPI init support). Before the patch, for non-null of_node, translate callback (use irq_domain_translate_twocell()) will return -EINVAL if fwspec->param_count < 2, so the check in the patch is added. Fixes: bcdd75c596c8 ("irqchip/loongson-pch-pic: Add ACPI init support") Signed-off-by: Jianmin Lv <lvjianmin@loongson.cn> Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221022075955.11726-3-lvjianmin@loongson.cn --- drivers/irqchip/irq-loongson-pch-pic.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c index c01b9c2570053..03493cda65a37 100644 --- a/drivers/irqchip/irq-loongson-pch-pic.c +++ b/drivers/irqchip/irq-loongson-pch-pic.c @@ -159,6 +159,9 @@ static int pch_pic_domain_translate(struct irq_domain *d, return -EINVAL; if (of_node) { + if (fwspec->param_count < 2) + return -EINVAL; + *hwirq = fwspec->param[0] + priv->ht_vec_base; *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; } else { From 25f3514aab3748bfef4a279ed599f836ac83e62a Mon Sep 17 00:00:00 2001 From: Jianmin Lv <lvjianmin@loongson.cn> Date: Sat, 22 Oct 2022 15:59:54 +0800 Subject: [PATCH 05/28] irqchip/loongson-pch-pic: Support to set IRQ type for ACPI path For ACPI path, the translate callback used IRQ_TYPE_NONE and ignored the IRQ type in fwspec->param[1]. For supporting to set type for IRQs of the irqdomain, fwspec->param[1] should be used to get IRQ type. Signed-off-by: Jianmin Lv <lvjianmin@loongson.cn> Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221022075955.11726-4-lvjianmin@loongson.cn --- drivers/irqchip/irq-loongson-pch-pic.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c index 03493cda65a37..a26a3f59d4a5d 100644 --- a/drivers/irqchip/irq-loongson-pch-pic.c +++ b/drivers/irqchip/irq-loongson-pch-pic.c @@ -155,9 +155,6 @@ static int pch_pic_domain_translate(struct irq_domain *d, struct pch_pic *priv = d->host_data; struct device_node *of_node = to_of_node(fwspec->fwnode); - if (fwspec->param_count < 1) - return -EINVAL; - if (of_node) { if (fwspec->param_count < 2) return -EINVAL; @@ -165,8 +162,14 @@ static int pch_pic_domain_translate(struct irq_domain *d, *hwirq = fwspec->param[0] + priv->ht_vec_base; *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; } else { + if (fwspec->param_count < 1) + return -EINVAL; + *hwirq = fwspec->param[0] - priv->gsi_base; - *type = IRQ_TYPE_NONE; + if (fwspec->param_count > 1) + *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; + else + *type = IRQ_TYPE_NONE; } return 0; From 17343d0b4039196517ab5c40d8fce3e8d394c526 Mon Sep 17 00:00:00 2001 From: Jianmin Lv <lvjianmin@loongson.cn> Date: Sat, 22 Oct 2022 15:59:55 +0800 Subject: [PATCH 06/28] irqchip/loongson-liointc: Support to set IRQ type for ACPI path For ACPI path, the xlate callback used IRQ_TYPE_NONE and ignored the IRQ type in intspec[1]. For supporting to set type for IRQs of the irqdomain, intspec[1] should be used to get IRQ type. Signed-off-by: Jianmin Lv <lvjianmin@loongson.cn> Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221022075955.11726-5-lvjianmin@loongson.cn --- drivers/irqchip/irq-loongson-liointc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-loongson-liointc.c b/drivers/irqchip/irq-loongson-liointc.c index 0da8716f8f24b..838c8fa2d868a 100644 --- a/drivers/irqchip/irq-loongson-liointc.c +++ b/drivers/irqchip/irq-loongson-liointc.c @@ -167,7 +167,12 @@ static int liointc_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, if (WARN_ON(intsize < 1)) return -EINVAL; *out_hwirq = intspec[0] - GSI_MIN_CPU_IRQ; - *out_type = IRQ_TYPE_NONE; + + if (intsize > 1) + *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; + else + *out_type = IRQ_TYPE_NONE; + return 0; } From 70f7b6c008b37a0beb956e25a6c167edfd4b259e Mon Sep 17 00:00:00 2001 From: Huacai Chen <chenhuacai@loongson.cn> Date: Thu, 20 Oct 2022 22:25:35 +0800 Subject: [PATCH 07/28] irqchip/loongson-htvec: Add ACPI init support HTVECINTC stands for "HyperTransport Interrupts" that described in Section 14.3 of "Loongson 3A5000 Processor Reference Manual". For more information please refer Documentation/loongarch/irq-chip-model.rst. Though the extended model is the recommended one, there are still some legacy model machines. So we add ACPI init support for HTVECINTC. Co-developed-by: Jianmin Lv <lvjianmin@loongson.cn> Signed-off-by: Jianmin Lv <lvjianmin@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221020142535.1725573-1-chenhuacai@loongson.cn --- arch/loongarch/include/asm/irq.h | 2 +- drivers/irqchip/Kconfig | 1 + drivers/irqchip/irq-loongson-htvec.c | 149 +++++++++++++++++++------ drivers/irqchip/irq-loongson-liointc.c | 25 ++++- 4 files changed, 141 insertions(+), 36 deletions(-) diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h index d06d4542b634c..9d3d36e41afec 100644 --- a/arch/loongarch/include/asm/irq.h +++ b/arch/loongarch/include/asm/irq.h @@ -93,7 +93,7 @@ int liointc_acpi_init(struct irq_domain *parent, int eiointc_acpi_init(struct irq_domain *parent, struct acpi_madt_eio_pic *acpi_eiointc); -struct irq_domain *htvec_acpi_init(struct irq_domain *parent, +int htvec_acpi_init(struct irq_domain *parent, struct acpi_madt_ht_pic *acpi_htvec); int pch_lpc_acpi_init(struct irq_domain *parent, struct acpi_madt_lpc_pic *acpi_pchlpc); diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 7ef9f5e696d31..17396e6e42fc6 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -576,6 +576,7 @@ config IRQ_LOONGARCH_CPU select GENERIC_IRQ_CHIP select IRQ_DOMAIN select GENERIC_IRQ_EFFECTIVE_AFF_MASK + select LOONGSON_HTVEC select LOONGSON_LIOINTC select LOONGSON_EIOINTC select LOONGSON_PCH_PIC diff --git a/drivers/irqchip/irq-loongson-htvec.c b/drivers/irqchip/irq-loongson-htvec.c index 60a335d7e64ed..8b06082616cb5 100644 --- a/drivers/irqchip/irq-loongson-htvec.c +++ b/drivers/irqchip/irq-loongson-htvec.c @@ -20,7 +20,6 @@ /* Registers */ #define HTVEC_EN_OFF 0x20 #define HTVEC_MAX_PARENT_IRQ 8 - #define VEC_COUNT_PER_REG 32 #define VEC_REG_IDX(irq_id) ((irq_id) / VEC_COUNT_PER_REG) #define VEC_REG_BIT(irq_id) ((irq_id) % VEC_COUNT_PER_REG) @@ -32,6 +31,8 @@ struct htvec { raw_spinlock_t htvec_lock; }; +static struct htvec *htvec_priv; + static void htvec_irq_dispatch(struct irq_desc *desc) { int i; @@ -155,64 +156,144 @@ static void htvec_reset(struct htvec *priv) } } -static int htvec_of_init(struct device_node *node, - struct device_node *parent) +static int htvec_init(phys_addr_t addr, unsigned long size, + int num_parents, int parent_irq[], struct fwnode_handle *domain_handle) { + int i; struct htvec *priv; - int err, parent_irq[8], i; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + priv->num_parents = num_parents; + priv->base = ioremap(addr, size); raw_spin_lock_init(&priv->htvec_lock); - priv->base = of_iomap(node, 0); - if (!priv->base) { - err = -ENOMEM; - goto free_priv; - } - - /* Interrupt may come from any of the 8 interrupt lines */ - for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) { - parent_irq[i] = irq_of_parse_and_map(node, i); - if (parent_irq[i] <= 0) - break; - - priv->num_parents++; - } - if (!priv->num_parents) { - pr_err("Failed to get parent irqs\n"); - err = -ENODEV; - goto iounmap_base; - } - - priv->htvec_domain = irq_domain_create_linear(of_node_to_fwnode(node), + /* Setup IRQ domain */ + priv->htvec_domain = irq_domain_create_linear(domain_handle, (VEC_COUNT_PER_REG * priv->num_parents), &htvec_domain_ops, priv); if (!priv->htvec_domain) { - pr_err("Failed to create IRQ domain\n"); - err = -ENOMEM; - goto irq_dispose; + pr_err("loongson-htvec: cannot add IRQ domain\n"); + goto iounmap_base; } htvec_reset(priv); - for (i = 0; i < priv->num_parents; i++) + for (i = 0; i < priv->num_parents; i++) { irq_set_chained_handler_and_data(parent_irq[i], htvec_irq_dispatch, priv); + } + + htvec_priv = priv; return 0; -irq_dispose: - for (; i > 0; i--) - irq_dispose_mapping(parent_irq[i - 1]); iounmap_base: iounmap(priv->base); -free_priv: kfree(priv); - return err; + return -EINVAL; +} + +#ifdef CONFIG_OF + +static int htvec_of_init(struct device_node *node, + struct device_node *parent) +{ + int i, err; + int parent_irq[8]; + int num_parents = 0; + struct resource res; + + if (of_address_to_resource(node, 0, &res)) + return -EINVAL; + + /* Interrupt may come from any of the 8 interrupt lines */ + for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) { + parent_irq[i] = irq_of_parse_and_map(node, i); + if (parent_irq[i] <= 0) + break; + + num_parents++; + } + + err = htvec_init(res.start, resource_size(&res), + num_parents, parent_irq, of_node_to_fwnode(node)); + if (err < 0) + return err; + + return 0; } IRQCHIP_DECLARE(htvec, "loongson,htvec-1.0", htvec_of_init); + +#endif + +#ifdef CONFIG_ACPI +static int __init pch_pic_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header; + + return pch_pic_acpi_init(htvec_priv->htvec_domain, pchpic_entry); +} + +static int __init pch_msi_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header; + + return pch_msi_acpi_init(htvec_priv->htvec_domain, pchmsi_entry); +} + +static int __init acpi_cascade_irqdomain_init(void) +{ + int r; + + r = acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC, pch_pic_parse_madt, 0); + if (r < 0) + return r; + + r = acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 0); + if (r < 0) + return r; + + return 0; +} + +int __init htvec_acpi_init(struct irq_domain *parent, + struct acpi_madt_ht_pic *acpi_htvec) +{ + int i, ret; + int num_parents, parent_irq[8]; + struct fwnode_handle *domain_handle; + + if (!acpi_htvec) + return -EINVAL; + + num_parents = HTVEC_MAX_PARENT_IRQ; + + domain_handle = irq_domain_alloc_fwnode(&acpi_htvec->address); + if (!domain_handle) { + pr_err("Unable to allocate domain handle\n"); + return -ENOMEM; + } + + /* Interrupt may come from any of the 8 interrupt lines */ + for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) + parent_irq[i] = irq_create_mapping(parent, acpi_htvec->cascade[i]); + + ret = htvec_init(acpi_htvec->address, acpi_htvec->size, + num_parents, parent_irq, domain_handle); + + if (ret == 0) + ret = acpi_cascade_irqdomain_init(); + else + irq_domain_free_fwnode(domain_handle); + + return ret; +} + +#endif diff --git a/drivers/irqchip/irq-loongson-liointc.c b/drivers/irqchip/irq-loongson-liointc.c index 838c8fa2d868a..a4a7cccd11818 100644 --- a/drivers/irqchip/irq-loongson-liointc.c +++ b/drivers/irqchip/irq-loongson-liointc.c @@ -354,6 +354,26 @@ IRQCHIP_DECLARE(loongson_liointc_2_0, "loongson,liointc-2.0", liointc_of_init); #endif #ifdef CONFIG_ACPI +static int __init htintc_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_madt_ht_pic *htintc_entry = (struct acpi_madt_ht_pic *)header; + struct irq_domain *parent = irq_find_matching_fwnode(liointc_handle, DOMAIN_BUS_ANY); + + return htvec_acpi_init(parent, htintc_entry); +} + +static int __init acpi_cascade_irqdomain_init(void) +{ + int r; + + r = acpi_table_parse_madt(ACPI_MADT_TYPE_HT_PIC, htintc_parse_madt, 0); + if (r < 0) + return r; + + return 0; +} + int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic *acpi_liointc) { int ret; @@ -370,9 +390,12 @@ int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic pr_err("Unable to allocate domain handle\n"); return -ENOMEM; } + ret = liointc_init(acpi_liointc->address, acpi_liointc->size, 1, domain_handle, NULL); - if (ret) + if (ret == 0) + ret = acpi_cascade_irqdomain_init(); + else irq_domain_free_fwnode(domain_handle); return ret; From 1be356c9326d68c9b0161ca004a41f203864d7ee Mon Sep 17 00:00:00 2001 From: Huacai Chen <chenhuacai@loongson.cn> Date: Thu, 20 Oct 2022 15:35:24 +0800 Subject: [PATCH 08/28] irqchip/loongson-htvec: Add suspend/resume support Add suspend/resume support for HTVEC irqchip, which is needed for upcoming suspend/hibernation. Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221020073527.541845-2-chenhuacai@loongson.cn --- drivers/irqchip/irq-loongson-htvec.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/irqchip/irq-loongson-htvec.c b/drivers/irqchip/irq-loongson-htvec.c index 8b06082616cb5..fc8bf1f5d41b2 100644 --- a/drivers/irqchip/irq-loongson-htvec.c +++ b/drivers/irqchip/irq-loongson-htvec.c @@ -16,6 +16,7 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> +#include <linux/syscore_ops.h> /* Registers */ #define HTVEC_EN_OFF 0x20 @@ -29,6 +30,7 @@ struct htvec { void __iomem *base; struct irq_domain *htvec_domain; raw_spinlock_t htvec_lock; + u32 saved_vec_en[HTVEC_MAX_PARENT_IRQ]; }; static struct htvec *htvec_priv; @@ -156,6 +158,29 @@ static void htvec_reset(struct htvec *priv) } } +static int htvec_suspend(void) +{ + int i; + + for (i = 0; i < htvec_priv->num_parents; i++) + htvec_priv->saved_vec_en[i] = readl(htvec_priv->base + HTVEC_EN_OFF + 4 * i); + + return 0; +} + +static void htvec_resume(void) +{ + int i; + + for (i = 0; i < htvec_priv->num_parents; i++) + writel(htvec_priv->saved_vec_en[i], htvec_priv->base + HTVEC_EN_OFF + 4 * i); +} + +static struct syscore_ops htvec_syscore_ops = { + .suspend = htvec_suspend, + .resume = htvec_resume, +}; + static int htvec_init(phys_addr_t addr, unsigned long size, int num_parents, int parent_irq[], struct fwnode_handle *domain_handle) { @@ -188,6 +213,8 @@ static int htvec_init(phys_addr_t addr, unsigned long size, htvec_priv = priv; + register_syscore_ops(&htvec_syscore_ops); + return 0; iounmap_base: From a90335c2dfb4ffe572816f77a3c4f2d1d388d724 Mon Sep 17 00:00:00 2001 From: Huacai Chen <chenhuacai@loongson.cn> Date: Thu, 20 Oct 2022 15:35:25 +0800 Subject: [PATCH 09/28] irqchip/loongson-eiointc: Add suspend/resume support Add suspend/resume support for EIOINTC irqchip, which is needed for upcoming suspend/hibernation. Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221020073527.541845-3-chenhuacai@loongson.cn --- drivers/irqchip/irq-loongson-eiointc.c | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c index 16e9af8d8b1ea..5cf4b800e4998 100644 --- a/drivers/irqchip/irq-loongson-eiointc.c +++ b/drivers/irqchip/irq-loongson-eiointc.c @@ -17,6 +17,7 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> +#include <linux/syscore_ops.h> #define EIOINTC_REG_NODEMAP 0x14a0 #define EIOINTC_REG_IPMAP 0x14c0 @@ -301,6 +302,37 @@ static struct irq_domain *acpi_get_vec_parent(int node, struct acpi_vector_group return NULL; } +static int eiointc_suspend(void) +{ + return 0; +} + +static void eiointc_resume(void) +{ + int i, j; + struct irq_desc *desc; + struct irq_data *irq_data; + + eiointc_router_init(0); + + for (i = 0; i < nr_pics; i++) { + for (j = 0; j < VEC_COUNT; j++) { + desc = irq_resolve_mapping(eiointc_priv[i]->eiointc_domain, j); + if (desc && desc->handle_irq && desc->handle_irq != handle_bad_irq) { + raw_spin_lock(&desc->lock); + irq_data = &desc->irq_data; + eiointc_set_irq_affinity(irq_data, irq_data->common->affinity, 0); + raw_spin_unlock(&desc->lock); + } + } + } +} + +static struct syscore_ops eiointc_syscore_ops = { + .suspend = eiointc_suspend, + .resume = eiointc_resume, +}; + static int __init pch_pic_parse_madt(union acpi_subtable_headers *header, const unsigned long end) @@ -380,6 +412,7 @@ int __init eiointc_acpi_init(struct irq_domain *parent, parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade); irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv); + register_syscore_ops(&eiointc_syscore_ops); cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING, "irqchip/loongarch/intc:starting", eiointc_router_init, NULL); From 1ed008a2c3310ada91e86bd96b354212a9025a61 Mon Sep 17 00:00:00 2001 From: Huacai Chen <chenhuacai@loongson.cn> Date: Thu, 20 Oct 2022 15:35:26 +0800 Subject: [PATCH 10/28] irqchip/loongson-pch-pic: Add suspend/resume support Add suspend/resume support for PCH-PIC irqchip, which is needed for upcoming suspend/hibernation. Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221020073527.541845-4-chenhuacai@loongson.cn --- drivers/irqchip/irq-loongson-pch-pic.c | 47 ++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c index a26a3f59d4a5d..1fd015e77ecfd 100644 --- a/drivers/irqchip/irq-loongson-pch-pic.c +++ b/drivers/irqchip/irq-loongson-pch-pic.c @@ -15,6 +15,7 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> +#include <linux/syscore_ops.h> /* Registers */ #define PCH_PIC_MASK 0x20 @@ -42,6 +43,9 @@ struct pch_pic { raw_spinlock_t pic_lock; u32 vec_count; u32 gsi_base; + u32 saved_vec_en[PIC_REG_COUNT]; + u32 saved_vec_pol[PIC_REG_COUNT]; + u32 saved_vec_edge[PIC_REG_COUNT]; }; static struct pch_pic *pch_pic_priv[MAX_IO_PICS]; @@ -145,6 +149,7 @@ static struct irq_chip pch_pic_irq_chip = { .irq_ack = pch_pic_ack_irq, .irq_set_affinity = irq_chip_set_affinity_parent, .irq_set_type = pch_pic_set_type, + .flags = IRQCHIP_SKIP_SET_WAKE, }; static int pch_pic_domain_translate(struct irq_domain *d, @@ -234,6 +239,46 @@ static void pch_pic_reset(struct pch_pic *priv) } } +static int pch_pic_suspend(void) +{ + int i, j; + + for (i = 0; i < nr_pics; i++) { + for (j = 0; j < PIC_REG_COUNT; j++) { + pch_pic_priv[i]->saved_vec_pol[j] = + readl(pch_pic_priv[i]->base + PCH_PIC_POL + 4 * j); + pch_pic_priv[i]->saved_vec_edge[j] = + readl(pch_pic_priv[i]->base + PCH_PIC_EDGE + 4 * j); + pch_pic_priv[i]->saved_vec_en[j] = + readl(pch_pic_priv[i]->base + PCH_PIC_MASK + 4 * j); + } + } + + return 0; +} + +static void pch_pic_resume(void) +{ + int i, j; + + for (i = 0; i < nr_pics; i++) { + pch_pic_reset(pch_pic_priv[i]); + for (j = 0; j < PIC_REG_COUNT; j++) { + writel(pch_pic_priv[i]->saved_vec_pol[j], + pch_pic_priv[i]->base + PCH_PIC_POL + 4 * j); + writel(pch_pic_priv[i]->saved_vec_edge[j], + pch_pic_priv[i]->base + PCH_PIC_EDGE + 4 * j); + writel(pch_pic_priv[i]->saved_vec_en[j], + pch_pic_priv[i]->base + PCH_PIC_MASK + 4 * j); + } + } +} + +static struct syscore_ops pch_pic_syscore_ops = { + .suspend = pch_pic_suspend, + .resume = pch_pic_resume, +}; + static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base, struct irq_domain *parent_domain, struct fwnode_handle *domain_handle, u32 gsi_base) @@ -266,6 +311,8 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base, pch_pic_handle[nr_pics] = domain_handle; pch_pic_priv[nr_pics++] = priv; + register_syscore_ops(&pch_pic_syscore_ops); + return 0; iounmap_base: From c7c75e32f8a61854c38326aef276e3a58dc7fd08 Mon Sep 17 00:00:00 2001 From: Huacai Chen <chenhuacai@loongson.cn> Date: Thu, 20 Oct 2022 15:35:27 +0800 Subject: [PATCH 11/28] irqchip/loongson-pch-lpc: Add suspend/resume support Add suspend/resume support for PCH-LPC irqchip, which is needed for upcoming suspend/hibernation. Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221020073527.541845-5-chenhuacai@loongson.cn --- drivers/irqchip/irq-loongson-pch-lpc.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/irqchip/irq-loongson-pch-lpc.c b/drivers/irqchip/irq-loongson-pch-lpc.c index bf2324910a75c..9b35492fb6be9 100644 --- a/drivers/irqchip/irq-loongson-pch-lpc.c +++ b/drivers/irqchip/irq-loongson-pch-lpc.c @@ -13,6 +13,7 @@ #include <linux/irqchip/chained_irq.h> #include <linux/irqdomain.h> #include <linux/kernel.h> +#include <linux/syscore_ops.h> /* Registers */ #define LPC_INT_CTL 0x00 @@ -34,6 +35,7 @@ struct pch_lpc { u32 saved_reg_pol; }; +static struct pch_lpc *pch_lpc_priv; struct fwnode_handle *pch_lpc_handle; static void lpc_irq_ack(struct irq_data *d) @@ -147,6 +149,26 @@ static int pch_lpc_disabled(struct pch_lpc *priv) (readl(priv->base + LPC_INT_STS) == 0xffffffff); } +static int pch_lpc_suspend(void) +{ + pch_lpc_priv->saved_reg_ctl = readl(pch_lpc_priv->base + LPC_INT_CTL); + pch_lpc_priv->saved_reg_ena = readl(pch_lpc_priv->base + LPC_INT_ENA); + pch_lpc_priv->saved_reg_pol = readl(pch_lpc_priv->base + LPC_INT_POL); + return 0; +} + +static void pch_lpc_resume(void) +{ + writel(pch_lpc_priv->saved_reg_ctl, pch_lpc_priv->base + LPC_INT_CTL); + writel(pch_lpc_priv->saved_reg_ena, pch_lpc_priv->base + LPC_INT_ENA); + writel(pch_lpc_priv->saved_reg_pol, pch_lpc_priv->base + LPC_INT_POL); +} + +static struct syscore_ops pch_lpc_syscore_ops = { + .suspend = pch_lpc_suspend, + .resume = pch_lpc_resume, +}; + int __init pch_lpc_acpi_init(struct irq_domain *parent, struct acpi_madt_lpc_pic *acpi_pchlpc) { @@ -191,7 +213,10 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent, parent_irq = irq_create_fwspec_mapping(&fwspec); irq_set_chained_handler_and_data(parent_irq, lpc_irq_dispatch, priv); + pch_lpc_priv = priv; pch_lpc_handle = irq_handle; + register_syscore_ops(&pch_lpc_syscore_ops); + return 0; free_irq_handle: From d46b99656a16c450681985661a249dbb18e55cc4 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio <konrad.dybcio@somainline.org> Date: Sat, 22 Oct 2022 01:55:23 +0200 Subject: [PATCH 12/28] irqchip/apple-aic: Mark aic_info structs __initconst These structs hold information used only at init time that never gets modified, hence mark them __initconst. Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org> Suggested-by: Marc Zyngier <maz@kernel.org> Reviewed-by: Eric Curtin <ecurtin@redhat.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221021235523.76585-1-konrad.dybcio@somainline.org --- drivers/irqchip/irq-apple-aic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c index 1c2813ad8bbe2..ae3437f03e6c2 100644 --- a/drivers/irqchip/irq-apple-aic.c +++ b/drivers/irqchip/irq-apple-aic.c @@ -248,14 +248,14 @@ struct aic_info { bool fast_ipi; }; -static const struct aic_info aic1_info = { +static const struct aic_info aic1_info __initconst = { .version = 1, .event = AIC_EVENT, .target_cpu = AIC_TARGET_CPU, }; -static const struct aic_info aic1_fipi_info = { +static const struct aic_info aic1_fipi_info __initconst = { .version = 1, .event = AIC_EVENT, @@ -264,7 +264,7 @@ static const struct aic_info aic1_fipi_info = { .fast_ipi = true, }; -static const struct aic_info aic2_info = { +static const struct aic_info aic2_info __initconst = { .version = 2, .irq_cfg = AIC2_IRQ_CFG, From 915649da01de13961f9d6a891b6db5a6255ac0b2 Mon Sep 17 00:00:00 2001 From: wangjianli <wangjianli@cdjrlc.com> Date: Sat, 22 Oct 2022 13:46:55 +0800 Subject: [PATCH 13/28] irqchip/mips-gic: Drop repeated word in comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delete the redundant word 'the'. Signed-off-by: wangjianli <wangjianli@cdjrlc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221022054655.36496-1-wangjianli@cdjrlc.com --- drivers/irqchip/irq-mips-gic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 1ba0f1555c805..1a6a7a672ad77 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -494,7 +494,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin; /* - * If adding support for more per-cpu interrupts, keep the the + * If adding support for more per-cpu interrupts, keep the * array in gic_all_vpes_irq_cpu_online() in sync. */ switch (intr) { From f9ee20c85b3a3ba0afd3672630ec4f93d339f015 Mon Sep 17 00:00:00 2001 From: Shang XiaoJing <shangxiaojing@huawei.com> Date: Thu, 24 Nov 2022 14:51:50 +0800 Subject: [PATCH 14/28] irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe() gic_probe() calls pm_runtime_get_sync() and added fail path as rpm_put to put usage_counter. However, pm_runtime_get_sync() will increment usage_counter even it failed. Fix it by replacing it with pm_runtime_resume_and_get() to keep usage counter balanced. Fixes: 9c8edddfc992 ("irqchip/gic: Add platform driver for non-root GICs that require RPM") Signed-off-by: Shang XiaoJing <shangxiaojing@huawei.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221124065150.22809-1-shangxiaojing@huawei.com --- drivers/irqchip/irq-gic-pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-pm.c b/drivers/irqchip/irq-gic-pm.c index b60e1853593f4..3989d16f997b3 100644 --- a/drivers/irqchip/irq-gic-pm.c +++ b/drivers/irqchip/irq-gic-pm.c @@ -102,7 +102,7 @@ static int gic_probe(struct platform_device *pdev) pm_runtime_enable(dev); - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) goto rpm_disable; From 9869f37aa4ee2a2e08536529dab4ccda9e23ce0c Mon Sep 17 00:00:00 2001 From: Jean Delvare <jdelvare@suse.de> Date: Mon, 21 Nov 2022 16:16:22 +0100 Subject: [PATCH 15/28] irqchip/al-fic: Drop obsolete dependency on COMPILE_TEST Since commit 0166dc11be91 ("of: make CONFIG_OF user selectable"), it is possible to test-build any driver which depends on OF on any architecture by explicitly selecting OF. Therefore depending on COMPILE_TEST as an alternative is no longer needed. It is actually better to always build such drivers with OF enabled, so that the test builds are closer to how each driver will actually be built on its intended target. Building them without OF may not test much as the compiler will optimize out potentially large parts of the code. In the worst case, this could even pop false positive warnings. Dropping COMPILE_TEST here improves the quality of our testing and avoids wasting time on non-existent issues. Signed-off-by: Jean Delvare <jdelvare@suse.de> Cc: Talel Shenhar <talel@amazon.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Marc Zyngier <maz@kernel.org> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221121161622.6294a899@endymion.delvare --- drivers/irqchip/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 7ef9f5e696d31..de43144da4a31 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -86,7 +86,7 @@ config ALPINE_MSI config AL_FIC bool "Amazon's Annapurna Labs Fabric Interrupt Controller" - depends on OF || COMPILE_TEST + depends on OF select GENERIC_IRQ_CHIP select IRQ_DOMAIN help From 4e08a286b1f7a0a32828d6411255296e4ef51fa6 Mon Sep 17 00:00:00 2001 From: ye xingchen <ye.xingchen@zte.com.cn> Date: Thu, 17 Nov 2022 19:16:50 +0800 Subject: [PATCH 16/28] irqchip/st: Use device_get_match_data() to simplify the code Directly get the match data with device_get_match_data(). Signed-off-by: ye xingchen <ye.xingchen@zte.com.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/202211171916504943604@zte.com.cn --- drivers/irqchip/irq-st.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/irqchip/irq-st.c b/drivers/irqchip/irq-st.c index 801551e46a7b0..1b83512b29c62 100644 --- a/drivers/irqchip/irq-st.c +++ b/drivers/irqchip/irq-st.c @@ -153,18 +153,13 @@ static int st_irq_syscfg_enable(struct platform_device *pdev) static int st_irq_syscfg_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - const struct of_device_id *match; struct st_irq_syscfg *ddata; ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); if (!ddata) return -ENOMEM; - match = of_match_device(st_irq_syscfg_match, &pdev->dev); - if (!match) - return -ENODEV; - - ddata->syscfg = (unsigned int)match->data; + ddata->syscfg = (unsigned int) device_get_match_data(&pdev->dev); ddata->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); if (IS_ERR(ddata->regmap)) { From 4208d4faf36573a507b5e5de17abe342e9276759 Mon Sep 17 00:00:00 2001 From: Wei Yongjun <weiyongjun1@huawei.com> Date: Tue, 15 Nov 2022 09:25:32 +0000 Subject: [PATCH 17/28] irqchip/wpcm450: Fix memory leak in wpcm450_aic_of_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If of_iomap() failed, 'aic' should be freed before return. Otherwise there is a memory leak. Fixes: fead4dd49663 ("irqchip: Add driver for WPCM450 interrupt controller") Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com> Reviewed-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221115092532.1704032-1-weiyongjun@huaweicloud.com --- drivers/irqchip/irq-wpcm450-aic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/irqchip/irq-wpcm450-aic.c b/drivers/irqchip/irq-wpcm450-aic.c index 0dcbeb1a05a1f..91df62a64cd91 100644 --- a/drivers/irqchip/irq-wpcm450-aic.c +++ b/drivers/irqchip/irq-wpcm450-aic.c @@ -146,6 +146,7 @@ static int __init wpcm450_aic_of_init(struct device_node *node, aic->regs = of_iomap(node, 0); if (!aic->regs) { pr_err("Failed to map WPCM450 AIC registers\n"); + kfree(aic); return -ENOMEM; } From d502c558fd2b190c9125e8da54bef3f302fa9b15 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald <aidanmacdonald.0x0@gmail.com> Date: Sat, 12 Nov 2022 15:27:01 +0000 Subject: [PATCH 18/28] irqchip/sl28cpld: Replace irqchip mask_invert with unmask_base Remove use of the deprecated mask_invert flag. Inverted mask registers (where a '1' bit enables an IRQ) can be described more directly as an unmask register. Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com> Reviewed-by: Michael Walle <michael@walle.cc> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221112152701.41990-1-aidanmacdonald.0x0@gmail.com --- drivers/irqchip/irq-sl28cpld.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-sl28cpld.c b/drivers/irqchip/irq-sl28cpld.c index fbb354413ffa1..f2172240172c4 100644 --- a/drivers/irqchip/irq-sl28cpld.c +++ b/drivers/irqchip/irq-sl28cpld.c @@ -65,8 +65,7 @@ static int sl28cpld_intc_probe(struct platform_device *pdev) irqchip->chip.num_irqs = ARRAY_SIZE(sl28cpld_irqs); irqchip->chip.num_regs = 1; irqchip->chip.status_base = base + INTC_IP; - irqchip->chip.mask_base = base + INTC_IE; - irqchip->chip.mask_invert = true; + irqchip->chip.unmask_base = base + INTC_IE; irqchip->chip.ack_base = base + INTC_IP; return devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev), From 4a60a3cdcf1875c965095eb9e22c3d12bbc5a53d Mon Sep 17 00:00:00 2001 From: Liu Peibao <liupeibao@loongson.cn> Date: Fri, 4 Nov 2022 19:07:12 +0800 Subject: [PATCH 19/28] irqchip/loongson-liointc: Fix improper error handling in liointc_init() For cores less than 4, eg, loongson2k1000 with 2 cores, the of_property_match_string() may return with an error value, which causes that liointc could not work. At least isr0 is what should be checked like previous commit b2c4c3969fd7 ("irqchip/loongson-liointc: irqchip add 2.0 version") did. Fixes: 0858ed035a85 ("irqchip/loongson-liointc: Add ACPI init support") Signed-off-by: Liu Peibao <liupeibao@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221104110712.23300-1-liupeibao@loongson.cn --- drivers/irqchip/irq-loongson-liointc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-loongson-liointc.c b/drivers/irqchip/irq-loongson-liointc.c index 0da8716f8f24b..c4584e2f0ad3d 100644 --- a/drivers/irqchip/irq-loongson-liointc.c +++ b/drivers/irqchip/irq-loongson-liointc.c @@ -207,10 +207,13 @@ static int liointc_init(phys_addr_t addr, unsigned long size, int revision, "reg-names", core_reg_names[i]); if (index < 0) - goto out_iounmap; + continue; priv->core_isr[i] = of_iomap(node, index); } + + if (!priv->core_isr[0]) + goto out_iounmap; } /* Setup IRQ domain */ From f5259b045c19f6e997bd12d53a5f76663537c1fd Mon Sep 17 00:00:00 2001 From: Samuel Holland <samuel@sholland.org> Date: Sat, 26 Nov 2022 13:48:05 -0600 Subject: [PATCH 20/28] irqchip/sifive-plic: Support wake IRQs The PLIC does not define any special method for marking interrupts as wakeup-capable, so it should have the IRQCHIP_SKIP_SET_WAKE flag set. Signed-off-by: Samuel Holland <samuel@sholland.org> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221126194805.19431-1-samuel@sholland.org --- drivers/irqchip/irq-sifive-plic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index 2f4784860df5d..ff47bd0dec455 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -187,7 +187,8 @@ static struct irq_chip plic_edge_chip = { .irq_set_affinity = plic_set_affinity, #endif .irq_set_type = plic_irq_set_type, - .flags = IRQCHIP_AFFINITY_PRE_STARTUP, + .flags = IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_AFFINITY_PRE_STARTUP, }; static struct irq_chip plic_chip = { @@ -201,7 +202,8 @@ static struct irq_chip plic_chip = { .irq_set_affinity = plic_set_affinity, #endif .irq_set_type = plic_irq_set_type, - .flags = IRQCHIP_AFFINITY_PRE_STARTUP, + .flags = IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_AFFINITY_PRE_STARTUP, }; static int plic_irq_set_type(struct irq_data *d, unsigned int type) From 7f3974ef4e31d730e7aa902b30800ba0962277da Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Date: Mon, 28 Nov 2022 10:22:14 +0100 Subject: [PATCH 21/28] dt-bindings: interrupt-controller: mediatek,cirq: Migrate to dt schema Migrate mediatek,cirq.txt to dt schema as mediatek,mtk-cirq.yaml. While at it, I've also fixed some typos that were present in the original txt binding, as it was suggesting that the compatible string would have "mediatek,cirq" as compatible but, in reality, that's supposed to be "mediatek,mtk-cirq" instead. Little rewording on property descriptions also happened for them to be more concise. Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221128092217.36552-2-angelogioacchino.delregno@collabora.com --- .../interrupt-controller/mediatek,cirq.txt | 33 --------- .../mediatek,mtk-cirq.yaml | 67 +++++++++++++++++++ 2 files changed, 67 insertions(+), 33 deletions(-) delete mode 100644 Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt create mode 100644 Documentation/devicetree/bindings/interrupt-controller/mediatek,mtk-cirq.yaml diff --git a/Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt b/Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt deleted file mode 100644 index 5865f4f2c69dc..0000000000000 --- a/Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt +++ /dev/null @@ -1,33 +0,0 @@ -* Mediatek 27xx cirq - -In Mediatek SOCs, the CIRQ is a low power interrupt controller designed to -work outside MCUSYS which comprises with Cortex-Ax cores,CCI and GIC. -The external interrupts (outside MCUSYS) will feed through CIRQ and connect -to GIC in MCUSYS. When CIRQ is enabled, it will record the edge-sensitive -interrupts and generate a pulse signal to parent interrupt controller when -flush command is executed. With CIRQ, MCUSYS can be completely turned off -to improve the system power consumption without losing interrupts. - -Required properties: -- compatible: should be one of - - "mediatek,mt2701-cirq" for mt2701 CIRQ - - "mediatek,mt8135-cirq" for mt8135 CIRQ - - "mediatek,mt8173-cirq" for mt8173 CIRQ - and "mediatek,cirq" as a fallback. -- interrupt-controller : Identifies the node as an interrupt controller. -- #interrupt-cells : Use the same format as specified by GIC in arm,gic.txt. -- reg: Physical base address of the cirq registers and length of memory - mapped region. -- mediatek,ext-irq-range: Identifies external irq number range in different - SOCs. - -Example: - cirq: interrupt-controller@10204000 { - compatible = "mediatek,mt2701-cirq", - "mediatek,mtk-cirq"; - interrupt-controller; - #interrupt-cells = <3>; - interrupt-parent = <&sysirq>; - reg = <0 0x10204000 0 0x400>; - mediatek,ext-irq-start = <32 200>; - }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/mediatek,mtk-cirq.yaml b/Documentation/devicetree/bindings/interrupt-controller/mediatek,mtk-cirq.yaml new file mode 100644 index 0000000000000..4f1132c077ff1 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/mediatek,mtk-cirq.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/mediatek,mtk-cirq.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek System Interrupt Controller + +maintainers: + - Youlin Pei <youlin.pei@mediatek.com> + +description: + In MediaTek SoCs, the CIRQ is a low power interrupt controller designed to + work outside of MCUSYS which comprises with Cortex-Ax cores, CCI and GIC. + The external interrupts (outside MCUSYS) will feed through CIRQ and connect + to GIC in MCUSYS. When CIRQ is enabled, it will record the edge-sensitive + interrupts and generate a pulse signal to parent interrupt controller when + flush command is executed. With CIRQ, MCUSYS can be completely turned off + to improve the system power consumption without losing interrupts. + + +properties: + compatible: + items: + - enum: + - mediatek,mt2701-cirq + - mediatek,mt8135-cirq + - mediatek,mt8173-cirq + - const: mediatek,mtk-cirq + + reg: + maxItems: 1 + + '#interrupt-cells': + const: 3 + + interrupt-controller: true + + mediatek,ext-irq-range: + $ref: /schemas/types.yaml#/definitions/uint32-array + items: + - description: First CIRQ interrupt + - description: Last CIRQ interrupt + description: + Identifies the range of external interrupts in different SoCs + +required: + - compatible + - reg + - '#interrupt-cells' + - interrupt-controller + - mediatek,ext-irq-range + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + + cirq: interrupt-controller@10204000 { + compatible = "mediatek,mt2701-cirq", "mediatek,mtk-cirq"; + reg = <0x10204000 0x400>; + #interrupt-cells = <3>; + interrupt-controller; + interrupt-parent = <&sysirq>; + mediatek,ext-irq-range = <32 200>; + }; From 85de640c6b89eb76fc314a3b451d054bedd5e9dc Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Date: Mon, 28 Nov 2022 10:22:15 +0100 Subject: [PATCH 22/28] dt-bindings: interrupt-controller: mediatek,cirq: Document MT8192 Add compatible to support the SYS_CIRQ controller found on MT8192. Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221128092217.36552-3-angelogioacchino.delregno@collabora.com --- .../bindings/interrupt-controller/mediatek,mtk-cirq.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/mediatek,mtk-cirq.yaml b/Documentation/devicetree/bindings/interrupt-controller/mediatek,mtk-cirq.yaml index 4f1132c077ff1..fdcb4d8db8185 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/mediatek,mtk-cirq.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/mediatek,mtk-cirq.yaml @@ -26,6 +26,7 @@ properties: - mediatek,mt2701-cirq - mediatek,mt8135-cirq - mediatek,mt8173-cirq + - mediatek,mt8192-cirq - const: mediatek,mtk-cirq reg: From 45ac01959edcecfa5d6652c2397d3866e55b0da8 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Date: Mon, 28 Nov 2022 10:22:16 +0100 Subject: [PATCH 23/28] irqchip/irq-mtk-cirq: Move register offsets to const array In preparation to add support for new SoCs having a different register layout, add an enumeration that documents register offsets and move the definitions for the same to a u32 array; Selecting the right register offsets array is done by adding an of_device_id array containing all of the currently supported compatible strings pointing to the "v1" offsets array (as data): since no devicetree declares the `mediatek,mtk-cirq` compatible without a SoC-specific one, it wasn't necessary to provide any legacy fallback. Every usage of the aforemementioned definitions was changed to get a register address through a newly introduced `mtk_cirq_reg()` accessor. This change brings no functional changes. Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221128092217.36552-4-angelogioacchino.delregno@collabora.com --- drivers/irqchip/irq-mtk-cirq.c | 82 +++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 17 deletions(-) diff --git a/drivers/irqchip/irq-mtk-cirq.c b/drivers/irqchip/irq-mtk-cirq.c index 9bca0918078e8..4776ed6492fbb 100644 --- a/drivers/irqchip/irq-mtk-cirq.c +++ b/drivers/irqchip/irq-mtk-cirq.c @@ -15,14 +15,29 @@ #include <linux/slab.h> #include <linux/syscore_ops.h> -#define CIRQ_ACK 0x40 -#define CIRQ_MASK_SET 0xc0 -#define CIRQ_MASK_CLR 0x100 -#define CIRQ_SENS_SET 0x180 -#define CIRQ_SENS_CLR 0x1c0 -#define CIRQ_POL_SET 0x240 -#define CIRQ_POL_CLR 0x280 -#define CIRQ_CONTROL 0x300 +enum mtk_cirq_regoffs_index { + CIRQ_STA, + CIRQ_ACK, + CIRQ_MASK_SET, + CIRQ_MASK_CLR, + CIRQ_SENS_SET, + CIRQ_SENS_CLR, + CIRQ_POL_SET, + CIRQ_POL_CLR, + CIRQ_CONTROL +}; + +static const u32 mtk_cirq_regoffs_v1[] = { + [CIRQ_STA] = 0x0, + [CIRQ_ACK] = 0x40, + [CIRQ_MASK_SET] = 0xc0, + [CIRQ_MASK_CLR] = 0x100, + [CIRQ_SENS_SET] = 0x180, + [CIRQ_SENS_CLR] = 0x1c0, + [CIRQ_POL_SET] = 0x240, + [CIRQ_POL_CLR] = 0x280, + [CIRQ_CONTROL] = 0x300, +}; #define CIRQ_EN 0x1 #define CIRQ_EDGE 0x2 @@ -32,18 +47,32 @@ struct mtk_cirq_chip_data { void __iomem *base; unsigned int ext_irq_start; unsigned int ext_irq_end; + const u32 *offsets; struct irq_domain *domain; }; static struct mtk_cirq_chip_data *cirq_data; -static void mtk_cirq_write_mask(struct irq_data *data, unsigned int offset) +static void __iomem *mtk_cirq_reg(struct mtk_cirq_chip_data *chip_data, + enum mtk_cirq_regoffs_index idx) +{ + return chip_data->base + chip_data->offsets[idx]; +} + +static void __iomem *mtk_cirq_irq_reg(struct mtk_cirq_chip_data *chip_data, + enum mtk_cirq_regoffs_index idx, + unsigned int cirq_num) +{ + return mtk_cirq_reg(chip_data, idx) + (cirq_num / 32) * 4; +} + +static void mtk_cirq_write_mask(struct irq_data *data, enum mtk_cirq_regoffs_index idx) { struct mtk_cirq_chip_data *chip_data = data->chip_data; unsigned int cirq_num = data->hwirq; u32 mask = 1 << (cirq_num % 32); - writel_relaxed(mask, chip_data->base + offset + (cirq_num / 32) * 4); + writel_relaxed(mask, mtk_cirq_irq_reg(chip_data, idx, cirq_num)); } static void mtk_cirq_mask(struct irq_data *data) @@ -160,6 +189,7 @@ static const struct irq_domain_ops cirq_domain_ops = { #ifdef CONFIG_PM_SLEEP static int mtk_cirq_suspend(void) { + void __iomem *reg; u32 value, mask; unsigned int irq, hwirq_num; bool pending, masked; @@ -200,31 +230,34 @@ static int mtk_cirq_suspend(void) continue; } + reg = mtk_cirq_irq_reg(cirq_data, CIRQ_ACK, i); mask = 1 << (i % 32); - writel_relaxed(mask, cirq_data->base + CIRQ_ACK + (i / 32) * 4); + writel_relaxed(mask, reg); } /* set edge_only mode, record edge-triggerd interrupts */ /* enable cirq */ - value = readl_relaxed(cirq_data->base + CIRQ_CONTROL); + reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL); + value = readl_relaxed(reg); value |= (CIRQ_EDGE | CIRQ_EN); - writel_relaxed(value, cirq_data->base + CIRQ_CONTROL); + writel_relaxed(value, reg); return 0; } static void mtk_cirq_resume(void) { + void __iomem *reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL); u32 value; /* flush recorded interrupts, will send signals to parent controller */ - value = readl_relaxed(cirq_data->base + CIRQ_CONTROL); - writel_relaxed(value | CIRQ_FLUSH, cirq_data->base + CIRQ_CONTROL); + value = readl_relaxed(reg); + writel_relaxed(value | CIRQ_FLUSH, reg); /* disable cirq */ - value = readl_relaxed(cirq_data->base + CIRQ_CONTROL); + value = readl_relaxed(reg); value &= ~(CIRQ_EDGE | CIRQ_EN); - writel_relaxed(value, cirq_data->base + CIRQ_CONTROL); + writel_relaxed(value, reg); } static struct syscore_ops mtk_cirq_syscore_ops = { @@ -240,10 +273,18 @@ static void mtk_cirq_syscore_init(void) static inline void mtk_cirq_syscore_init(void) {} #endif +static const struct of_device_id mtk_cirq_of_match[] = { + { .compatible = "mediatek,mt2701-cirq", .data = &mtk_cirq_regoffs_v1 }, + { .compatible = "mediatek,mt8135-cirq", .data = &mtk_cirq_regoffs_v1 }, + { .compatible = "mediatek,mt8173-cirq", .data = &mtk_cirq_regoffs_v1 }, + { /* sentinel */ } +}; + static int __init mtk_cirq_of_init(struct device_node *node, struct device_node *parent) { struct irq_domain *domain, *domain_parent; + const struct of_device_id *match; unsigned int irq_num; int ret; @@ -274,6 +315,13 @@ static int __init mtk_cirq_of_init(struct device_node *node, if (ret) goto out_unmap; + match = of_match_node(mtk_cirq_of_match, node); + if (!match) { + ret = -ENODEV; + goto out_unmap; + } + cirq_data->offsets = match->data; + irq_num = cirq_data->ext_irq_end - cirq_data->ext_irq_start + 1; domain = irq_domain_add_hierarchy(domain_parent, 0, irq_num, node, From 5c4e0aac0b2a27168844da49cee2c5dff2925d22 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Date: Mon, 28 Nov 2022 10:22:17 +0100 Subject: [PATCH 24/28] irqchip/irq-mtk-cirq: Add support for System CIRQ on MT8192 On some SoCs the System CIRQ register layout is slightly different, as there are more registers per function and in some cases other differences later in the layout: this is seen on at least MT8192, but it's also valid for some other "contemporary" SoCs both for Chromebooks and for smartphones. Add the new "v2" register layout and use it if the compatible "mediatek,mt8192-cirq" is found. Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221128092217.36552-5-angelogioacchino.delregno@collabora.com --- drivers/irqchip/irq-mtk-cirq.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/irqchip/irq-mtk-cirq.c b/drivers/irqchip/irq-mtk-cirq.c index 4776ed6492fbb..76bc0283e3b96 100644 --- a/drivers/irqchip/irq-mtk-cirq.c +++ b/drivers/irqchip/irq-mtk-cirq.c @@ -39,6 +39,18 @@ static const u32 mtk_cirq_regoffs_v1[] = { [CIRQ_CONTROL] = 0x300, }; +static const u32 mtk_cirq_regoffs_v2[] = { + [CIRQ_STA] = 0x0, + [CIRQ_ACK] = 0x80, + [CIRQ_MASK_SET] = 0x180, + [CIRQ_MASK_CLR] = 0x200, + [CIRQ_SENS_SET] = 0x300, + [CIRQ_SENS_CLR] = 0x380, + [CIRQ_POL_SET] = 0x480, + [CIRQ_POL_CLR] = 0x500, + [CIRQ_CONTROL] = 0x600, +}; + #define CIRQ_EN 0x1 #define CIRQ_EDGE 0x2 #define CIRQ_FLUSH 0x4 @@ -277,6 +289,7 @@ static const struct of_device_id mtk_cirq_of_match[] = { { .compatible = "mediatek,mt2701-cirq", .data = &mtk_cirq_regoffs_v1 }, { .compatible = "mediatek,mt8135-cirq", .data = &mtk_cirq_regoffs_v1 }, { .compatible = "mediatek,mt8173-cirq", .data = &mtk_cirq_regoffs_v1 }, + { .compatible = "mediatek,mt8192-cirq", .data = &mtk_cirq_regoffs_v2 }, { /* sentinel */ } }; From 3d12938dbc048ecb193fec69898d95f6b4813a4b Mon Sep 17 00:00:00 2001 From: Huacai Chen <chenhuacai@loongson.cn> Date: Thu, 20 Oct 2022 22:25:14 +0800 Subject: [PATCH 25/28] irqchip/loongarch: Adjust acpi_cascade_irqdomain_init() and sub-routines 1, Adjust the return of acpi_cascade_irqdomain_init() and check its return value. 2, Combine unnecessary short lines to one long line. Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221020142514.1725514-1-chenhuacai@loongson.cn --- drivers/irqchip/irq-loongarch-cpu.c | 30 +++++++++++++++----------- drivers/irqchip/irq-loongson-eiointc.c | 30 +++++++++++++++----------- drivers/irqchip/irq-loongson-pch-pic.c | 15 +++++++------ 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c index 741612ba6a520..fdec3e9cfacfb 100644 --- a/drivers/irqchip/irq-loongarch-cpu.c +++ b/drivers/irqchip/irq-loongarch-cpu.c @@ -92,18 +92,16 @@ static const struct irq_domain_ops loongarch_cpu_intc_irq_domain_ops = { .xlate = irq_domain_xlate_onecell, }; -static int __init -liointc_parse_madt(union acpi_subtable_headers *header, - const unsigned long end) +static int __init liointc_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) { struct acpi_madt_lio_pic *liointc_entry = (struct acpi_madt_lio_pic *)header; return liointc_acpi_init(irq_domain, liointc_entry); } -static int __init -eiointc_parse_madt(union acpi_subtable_headers *header, - const unsigned long end) +static int __init eiointc_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) { struct acpi_madt_eio_pic *eiointc_entry = (struct acpi_madt_eio_pic *)header; @@ -112,16 +110,24 @@ eiointc_parse_madt(union acpi_subtable_headers *header, static int __init acpi_cascade_irqdomain_init(void) { - acpi_table_parse_madt(ACPI_MADT_TYPE_LIO_PIC, - liointc_parse_madt, 0); - acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC, - eiointc_parse_madt, 0); + int r; + + r = acpi_table_parse_madt(ACPI_MADT_TYPE_LIO_PIC, liointc_parse_madt, 0); + if (r < 0) + return r; + + r = acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC, eiointc_parse_madt, 0); + if (r < 0) + return r; + return 0; } static int __init cpuintc_acpi_init(union acpi_subtable_headers *header, const unsigned long end) { + int ret; + if (irq_domain) return 0; @@ -139,9 +145,9 @@ static int __init cpuintc_acpi_init(union acpi_subtable_headers *header, set_handle_irq(&handle_cpu_irq); acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id); acpi_set_gsi_to_irq_fallback(lpic_gsi_to_irq); - acpi_cascade_irqdomain_init(); + ret = acpi_cascade_irqdomain_init(); - return 0; + return ret; } IRQCHIP_ACPI_DECLARE(cpuintc_v1, ACPI_MADT_TYPE_CORE_PIC, diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c index 5cf4b800e4998..d15fd38c17568 100644 --- a/drivers/irqchip/irq-loongson-eiointc.c +++ b/drivers/irqchip/irq-loongson-eiointc.c @@ -333,9 +333,8 @@ static struct syscore_ops eiointc_syscore_ops = { .resume = eiointc_resume, }; -static int __init -pch_pic_parse_madt(union acpi_subtable_headers *header, - const unsigned long end) +static int __init pch_pic_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) { struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header; unsigned int node = (pchpic_entry->address >> 44) & 0xf; @@ -347,9 +346,8 @@ pch_pic_parse_madt(union acpi_subtable_headers *header, return -EINVAL; } -static int __init -pch_msi_parse_madt(union acpi_subtable_headers *header, - const unsigned long end) +static int __init pch_msi_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) { struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header; struct irq_domain *parent = acpi_get_vec_parent(eiointc_priv[nr_pics - 1]->node, msi_group); @@ -362,17 +360,23 @@ pch_msi_parse_madt(union acpi_subtable_headers *header, static int __init acpi_cascade_irqdomain_init(void) { - acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC, - pch_pic_parse_madt, 0); - acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, - pch_msi_parse_madt, 1); + int r; + + r = acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC, pch_pic_parse_madt, 0); + if (r < 0) + return r; + + r = acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 1); + if (r < 0) + return r; + return 0; } int __init eiointc_acpi_init(struct irq_domain *parent, struct acpi_madt_eio_pic *acpi_eiointc) { - int i, parent_irq; + int i, ret, parent_irq; unsigned long node_map; struct eiointc_priv *priv; @@ -419,9 +423,9 @@ int __init eiointc_acpi_init(struct irq_domain *parent, acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, pch_group); acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, msi_group); - acpi_cascade_irqdomain_init(); + ret = acpi_cascade_irqdomain_init(); - return 0; + return ret; out_free_handle: irq_domain_free_fwnode(priv->domain_handle); diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c index 1fd015e77ecfd..437f1af693d01 100644 --- a/drivers/irqchip/irq-loongson-pch-pic.c +++ b/drivers/irqchip/irq-loongson-pch-pic.c @@ -378,9 +378,8 @@ int find_pch_pic(u32 gsi) return -1; } -static int __init -pch_lpc_parse_madt(union acpi_subtable_headers *header, - const unsigned long end) +static int __init pch_lpc_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) { struct acpi_madt_lpc_pic *pchlpc_entry = (struct acpi_madt_lpc_pic *)header; @@ -389,8 +388,12 @@ pch_lpc_parse_madt(union acpi_subtable_headers *header, static int __init acpi_cascade_irqdomain_init(void) { - acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC, - pch_lpc_parse_madt, 0); + int r; + + r = acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC, pch_lpc_parse_madt, 0); + if (r < 0) + return r; + return 0; } @@ -417,7 +420,7 @@ int __init pch_pic_acpi_init(struct irq_domain *parent, } if (acpi_pchpic->id == 0) - acpi_cascade_irqdomain_init(); + ret = acpi_cascade_irqdomain_init(); return ret; } From 5e279739d7312b8958ec816fa38dba2725638503 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET <christophe.jaillet@wanadoo.fr> Date: Tue, 1 Nov 2022 22:13:51 +0100 Subject: [PATCH 26/28] irqchip/gic: Use kstrtobool() instead of strtobool() strtobool() is the same as kstrtobool(). However, the latter is more used within the kernel. In order to remove strtobool() and slightly simplify kstrtox.h, switch to the other function name. While at it, include the corresponding header file (<linux/kstrtox.h>) Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/755c4083122071bb27aa8ed5d98156a07bb63a39.1667336095.git.christophe.jaillet@wanadoo.fr --- drivers/irqchip/irq-gic-v3.c | 3 ++- drivers/irqchip/irq-gic.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 34d58567b78d1..997104d4338e7 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -12,6 +12,7 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/irqdomain.h> +#include <linux/kstrtox.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> @@ -1171,7 +1172,7 @@ static bool gicv3_nolpi; static int __init gicv3_nolpi_cfg(char *buf) { - return strtobool(buf, &gicv3_nolpi); + return kstrtobool(buf, &gicv3_nolpi); } early_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4c7bae0ec8f96..799f86d84b43c 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -19,6 +19,7 @@ */ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/kstrtox.h> #include <linux/err.h> #include <linux/module.h> #include <linux/list.h> @@ -1332,7 +1333,7 @@ static bool gicv2_force_probe; static int __init gicv2_force_probe_cfg(char *buf) { - return strtobool(buf, &gicv2_force_probe); + return kstrtobool(buf, &gicv2_force_probe); } early_param("irqchip.gicv2_force_probe", gicv2_force_probe_cfg); From 3ae977d0e4e3a2a2ccc912ca2d20c9430508ecdd Mon Sep 17 00:00:00 2001 From: Sean Anderson <sean.anderson@seco.com> Date: Thu, 1 Dec 2022 16:28:07 -0500 Subject: [PATCH 27/28] irqchip/ls-extirq: Fix endianness detection parent is the interrupt parent, not the parent of node. Use node->parent. This fixes endianness detection on big-endian platforms. Fixes: 1b00adce8afd ("irqchip/ls-extirq: Fix invalid wait context by avoiding to use regmap") Signed-off-by: Sean Anderson <sean.anderson@seco.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221201212807.616191-1-sean.anderson@seco.com --- drivers/irqchip/irq-ls-extirq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-ls-extirq.c b/drivers/irqchip/irq-ls-extirq.c index d8d48b1f7c29d..139f26b0a6ef8 100644 --- a/drivers/irqchip/irq-ls-extirq.c +++ b/drivers/irqchip/irq-ls-extirq.c @@ -203,7 +203,7 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent) if (ret) goto err_parse_map; - priv->big_endian = of_device_is_big_endian(parent); + priv->big_endian = of_device_is_big_endian(node->parent); priv->is_ls1021a_or_ls1043a = of_device_is_compatible(node, "fsl,ls1021a-extirq") || of_device_is_compatible(node, "fsl,ls1043a-extirq"); raw_spin_lock_init(&priv->lock); From 065abd13a63f40318162eeca6c0215fc5cbb9b0a Mon Sep 17 00:00:00 2001 From: Huacai Chen <chenhuacai@loongson.cn> Date: Mon, 5 Dec 2022 12:47:08 +0800 Subject: [PATCH 28/28] irqchip/loongarch-cpu: Fix a missing prototype warning 1, Rename loongarch_cpu_irq_of_init() to cpuintc_of_init() in order to keep the same style as the ACPI version. 2, Fix a missing prototype warning by adding a "static" modifier. Fixes: 855d4ca4bdb366aab3d4 ("irqchip: loongarch-cpu: add DT support") Reported-by: kernel test robot <lkp@intel.com> Cc: Peibao Liu <liupeibao@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20221205044708.2054022-1-chenhuacai@loongson.cn --- drivers/irqchip/irq-loongarch-cpu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c index a28b7c5496546..738d69c4d4a33 100644 --- a/drivers/irqchip/irq-loongarch-cpu.c +++ b/drivers/irqchip/irq-loongarch-cpu.c @@ -93,7 +93,7 @@ static const struct irq_domain_ops loongarch_cpu_intc_irq_domain_ops = { }; #ifdef CONFIG_OF -int __init loongarch_cpu_irq_of_init(struct device_node *of_node, +static int __init cpuintc_of_init(struct device_node *of_node, struct device_node *parent) { cpuintc_handle = of_node_to_fwnode(of_node); @@ -107,8 +107,7 @@ int __init loongarch_cpu_irq_of_init(struct device_node *of_node, return 0; } -IRQCHIP_DECLARE(cpu_intc, "loongson,cpu-interrupt-controller", - loongarch_cpu_irq_of_init); +IRQCHIP_DECLARE(cpu_intc, "loongson,cpu-interrupt-controller", cpuintc_of_init); #endif static int __init