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

Configure Feed

Select the types of activity you want to include in your feed.

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

Pull interrupt subsystem updates from Thomas Gleixner:
"Core:

- Provide a new mechanism to create interrupt domains. The existing
interfaces have already too many parameters and it's a pain to
expand any of this for new required functionality.

The new function takes a pointer to a data structure as argument.
The data structure combines all existing parameters and allows for
easy extension.

The first extension for this is to handle the instantiation of
generic interrupt chips at the core level and to allow drivers to
provide extra init/exit callbacks.

This is necessary to do the full interrupt chip initialization
before the new domain is published, so that concurrent usage sites
won't see a half initialized interrupt domain. Similar problems
exist on teardown.

This has turned out to be a real problem due to the deferred and
parallel probing which was added in recent years.

Handling this at the core level allows to remove quite some accrued
boilerplate code in existing drivers and avoids horrible
workarounds at the driver level.

- The usual small improvements all over the place

Drivers:

- Add support for LAN966x OIC and RZ/Five SoC

- Split the STM ExtI driver into a microcontroller and a SMP version
to allow building the latter as a module for multi-platform
kernels

- Enable MSI support for Armada 370XP on platforms which do not
support IPIs

- The usual small fixes and enhancements all over the place"

* tag 'irq-core-2024-07-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (59 commits)
irqdomain: Fix the kernel-doc and plug it into Documentation
genirq: Set IRQF_COND_ONESHOT in request_irq()
irqchip/imx-irqsteer: Handle runtime power management correctly
irqchip/gic-v3: Pass #redistributor-regions to gic_of_setup_kvm_info()
irqchip/bcm2835: Enable SKIP_SET_WAKE and MASK_ON_SUSPEND
irqchip/gic-v4: Make sure a VPE is locked when VMAPP is issued
irqchip/gic-v4: Substitute vmovp_lock for a per-VM lock
irqchip/gic-v4: Always configure affinity on VPE activation
Revert "irqchip/dw-apb-ictl: Support building as module"
Revert "Loongarch: Support loongarch avec"
arm64: Kconfig: Allow build irq-stm32mp-exti driver as module
ARM: stm32: Allow build irq-stm32mp-exti driver as module
irqchip/stm32mp-exti: Allow building as module
irqchip/stm32mp-exti: Rename internal symbols
irqchip/stm32-exti: Split MCU and MPU code
arm64: Kconfig: Select STM32MP_EXTI on STM32 platforms
ARM: stm32: Use different EXTI driver on ARMv7m and ARMv7a
irqchip/stm32-exti: Add CONFIG_STM32MP_EXTI
irqchip/dw-apb-ictl: Support building as module
irqchip/riscv-aplic: Simplify the initialization code
...

+1993 -928
+2
Documentation/core-api/genericirq.rst
··· 410 410 .. kernel-doc:: include/linux/interrupt.h 411 411 :internal: 412 412 413 + .. kernel-doc:: include/linux/irqdomain.h 414 + 413 415 Public Functions Provided 414 416 ========================= 415 417
+55
Documentation/devicetree/bindings/interrupt-controller/microchip,lan966x-oic.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/interrupt-controller/microchip,lan966x-oic.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Microchip LAN966x outband interrupt controller 8 + 9 + maintainers: 10 + - Herve Codina <herve.codina@bootlin.com> 11 + 12 + allOf: 13 + - $ref: /schemas/interrupt-controller.yaml# 14 + 15 + description: | 16 + The Microchip LAN966x outband interrupt controller (OIC) maps the internal 17 + interrupt sources of the LAN966x device to an external interrupt. 18 + When the LAN966x device is used as a PCI device, the external interrupt is 19 + routed to the PCI interrupt. 20 + 21 + properties: 22 + compatible: 23 + const: microchip,lan966x-oic 24 + 25 + '#interrupt-cells': 26 + const: 2 27 + 28 + interrupt-controller: true 29 + 30 + reg: 31 + maxItems: 1 32 + 33 + interrupts: 34 + maxItems: 1 35 + 36 + required: 37 + - compatible 38 + - '#interrupt-cells' 39 + - interrupt-controller 40 + - interrupts 41 + - reg 42 + 43 + additionalProperties: false 44 + 45 + examples: 46 + - | 47 + interrupt-controller@e00c0120 { 48 + compatible = "microchip,lan966x-oic"; 49 + reg = <0xe00c0120 0x190>; 50 + #interrupt-cells = <2>; 51 + interrupt-controller; 52 + interrupts = <0>; 53 + interrupt-parent = <&intc>; 54 + }; 55 + ...
+10 -7
Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml
··· 21 21 22 22 properties: 23 23 compatible: 24 - items: 25 - - enum: 26 - - renesas,r9a07g043u-irqc # RZ/G2UL 27 - - renesas,r9a07g044-irqc # RZ/G2{L,LC} 28 - - renesas,r9a07g054-irqc # RZ/V2L 29 - - renesas,r9a08g045-irqc # RZ/G3S 30 - - const: renesas,rzg2l-irqc 24 + oneOf: 25 + - items: 26 + - enum: 27 + - renesas,r9a07g043u-irqc # RZ/G2UL 28 + - renesas,r9a07g044-irqc # RZ/G2{L,LC} 29 + - renesas,r9a07g054-irqc # RZ/V2L 30 + - renesas,r9a08g045-irqc # RZ/G3S 31 + - const: renesas,rzg2l-irqc 32 + 33 + - const: renesas,r9a07g043f-irqc # RZ/Five 31 34 32 35 '#interrupt-cells': 33 36 description: The first cell should contain a macro RZG2L_{NMI,IRQX} included in the
+6
MAINTAINERS
··· 14942 14942 S: Maintained 14943 14943 F: drivers/net/ethernet/microchip/lan966x/* 14944 14944 14945 + MICROCHIP LAN966X OIC DRIVER 14946 + M: Herve Codina <herve.codina@bootlin.com> 14947 + S: Maintained 14948 + F: Documentation/devicetree/bindings/interrupt-controller/microchip,lan966x-oic.yaml 14949 + F: drivers/irqchip/irq-lan966x-oic.c 14950 + 14945 14951 MICROCHIP LCDFB DRIVER 14946 14952 M: Nicolas Ferre <nicolas.ferre@microchip.com> 14947 14953 L: linux-fbdev@vger.kernel.org
+1 -1
arch/arm/mach-stm32/Kconfig
··· 11 11 select CLKSRC_STM32 12 12 select PINCTRL 13 13 select RESET_CONTROLLER 14 - select STM32_EXTI 14 + select STM32_EXTI if ARM_SINGLE_ARMV7M 15 15 select STM32_FIREWALL 16 16 help 17 17 Support for STMicroelectronics STM32 processors.
-1
arch/arm64/Kconfig.platforms
··· 309 309 select GPIOLIB 310 310 select PINCTRL 311 311 select PINCTRL_STM32MP257 312 - select STM32_EXTI 313 312 select ARM_SMC_MBOX 314 313 select ARM_SCMI_PROTOCOL 315 314 select REGULATOR
+10 -6
arch/um/drivers/virt-pci.c
··· 988 988 989 989 static int __init um_pci_init(void) 990 990 { 991 + struct irq_domain_info inner_domain_info = { 992 + .size = MAX_MSI_VECTORS, 993 + .hwirq_max = MAX_MSI_VECTORS, 994 + .ops = &um_pci_inner_domain_ops, 995 + }; 991 996 int err, i; 992 997 993 998 WARN_ON(logic_iomem_add_region(&virt_cfgspace_resource, ··· 1022 1017 goto free; 1023 1018 } 1024 1019 1025 - um_pci_inner_domain = __irq_domain_add(um_pci_fwnode, MAX_MSI_VECTORS, 1026 - MAX_MSI_VECTORS, 0, 1027 - &um_pci_inner_domain_ops, NULL); 1028 - if (!um_pci_inner_domain) { 1029 - err = -ENOMEM; 1020 + inner_domain_info.fwnode = um_pci_fwnode; 1021 + um_pci_inner_domain = irq_domain_instantiate(&inner_domain_info); 1022 + if (IS_ERR(um_pci_inner_domain)) { 1023 + err = PTR_ERR(um_pci_inner_domain); 1030 1024 goto free; 1031 1025 } 1032 1026 ··· 1062 1058 goto free; 1063 1059 return 0; 1064 1060 free: 1065 - if (um_pci_inner_domain) 1061 + if (!IS_ERR_OR_NULL(um_pci_inner_domain)) 1066 1062 irq_domain_remove(um_pci_inner_domain); 1067 1063 if (um_pci_fwnode) 1068 1064 irq_domain_free_fwnode(um_pci_fwnode);
+15
drivers/acpi/processor_core.c
··· 216 216 return rv; 217 217 } 218 218 219 + int __init acpi_get_madt_revision(void) 220 + { 221 + struct acpi_table_header *madt = NULL; 222 + int revision; 223 + 224 + if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, &madt))) 225 + return -EINVAL; 226 + 227 + revision = madt->revision; 228 + 229 + acpi_put_table(madt); 230 + 231 + return revision; 232 + } 233 + 219 234 static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id) 220 235 { 221 236 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+21
drivers/irqchip/Kconfig
··· 169 169 select IRQ_DOMAIN 170 170 select SPARSE_IRQ 171 171 172 + config LAN966X_OIC 173 + tristate "Microchip LAN966x OIC Support" 174 + select GENERIC_IRQ_CHIP 175 + select IRQ_DOMAIN 176 + help 177 + Enable support for the LAN966x Outbound Interrupt Controller. 178 + This controller is present on the Microchip LAN966x PCI device and 179 + maps the internal interrupts sources to PCIe interrupt. 180 + 181 + To compile this driver as a module, choose M here: the module 182 + will be called irq-lan966x-oic. 183 + 172 184 config MADERA_IRQ 173 185 tristate 174 186 ··· 403 391 404 392 config PARTITION_PERCPU 405 393 bool 394 + 395 + config STM32MP_EXTI 396 + tristate "STM32MP extended interrupts and event controller" 397 + depends on (ARCH_STM32 && !ARM_SINGLE_ARMV7M) || COMPILE_TEST 398 + default y 399 + select IRQ_DOMAIN_HIERARCHY 400 + select GENERIC_IRQ_CHIP 401 + help 402 + Support STM32MP EXTI (extended interrupts and event) controller. 406 403 407 404 config STM32_EXTI 408 405 bool
+2
drivers/irqchip/Makefile
··· 84 84 obj-$(CONFIG_LS_EXTIRQ) += irq-ls-extirq.o 85 85 obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o 86 86 obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o 87 + obj-$(CONFIG_STM32MP_EXTI) += irq-stm32mp-exti.o 87 88 obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o 88 89 obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o 89 90 obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o ··· 105 104 obj-$(CONFIG_IMX_INTMUX) += irq-imx-intmux.o 106 105 obj-$(CONFIG_IMX_MU_MSI) += irq-imx-mu-msi.o 107 106 obj-$(CONFIG_MADERA_IRQ) += irq-madera.o 107 + obj-$(CONFIG_LAN966X_OIC) += irq-lan966x-oic.o 108 108 obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o 109 109 obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o 110 110 obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
+95 -26
drivers/irqchip/irq-armada-370-xp.c
··· 13 13 * warranty of any kind, whether express or implied. 14 14 */ 15 15 16 + #include <linux/bits.h> 16 17 #include <linux/kernel.h> 17 18 #include <linux/module.h> 18 19 #include <linux/init.h> ··· 30 29 #include <linux/slab.h> 31 30 #include <linux/syscore_ops.h> 32 31 #include <linux/msi.h> 32 + #include <linux/types.h> 33 33 #include <asm/mach/arch.h> 34 34 #include <asm/exception.h> 35 35 #include <asm/smp_plat.h> ··· 137 135 138 136 #define ARMADA_370_XP_MAX_PER_CPU_IRQS (28) 139 137 138 + /* IPI and MSI interrupt definitions for IPI platforms */ 140 139 #define IPI_DOORBELL_START (0) 141 140 #define IPI_DOORBELL_END (8) 142 141 #define IPI_DOORBELL_MASK 0xFF ··· 145 142 #define PCI_MSI_DOORBELL_NR (16) 146 143 #define PCI_MSI_DOORBELL_END (32) 147 144 #define PCI_MSI_DOORBELL_MASK 0xFFFF0000 145 + 146 + /* MSI interrupt definitions for non-IPI platforms */ 147 + #define PCI_MSI_FULL_DOORBELL_START 0 148 + #define PCI_MSI_FULL_DOORBELL_NR 32 149 + #define PCI_MSI_FULL_DOORBELL_END 32 150 + #define PCI_MSI_FULL_DOORBELL_MASK GENMASK(31, 0) 151 + #define PCI_MSI_FULL_DOORBELL_SRC0_MASK GENMASK(15, 0) 152 + #define PCI_MSI_FULL_DOORBELL_SRC1_MASK GENMASK(31, 16) 148 153 149 154 static void __iomem *per_cpu_int_base; 150 155 static void __iomem *main_int_base; ··· 162 151 #ifdef CONFIG_PCI_MSI 163 152 static struct irq_domain *armada_370_xp_msi_domain; 164 153 static struct irq_domain *armada_370_xp_msi_inner_domain; 165 - static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR); 154 + static DECLARE_BITMAP(msi_used, PCI_MSI_FULL_DOORBELL_NR); 166 155 static DEFINE_MUTEX(msi_used_lock); 167 156 static phys_addr_t msi_doorbell_addr; 168 157 #endif 158 + 159 + static inline bool is_ipi_available(void) 160 + { 161 + /* 162 + * We distinguish IPI availability in the IC by the IC not having a 163 + * parent irq defined. If a parent irq is defined, there is a parent 164 + * interrupt controller (e.g. GIC) that takes care of inter-processor 165 + * interrupts. 166 + */ 167 + return parent_irq <= 0; 168 + } 169 + 170 + static inline u32 msi_doorbell_mask(void) 171 + { 172 + return is_ipi_available() ? PCI_MSI_DOORBELL_MASK : 173 + PCI_MSI_FULL_DOORBELL_MASK; 174 + } 175 + 176 + static inline unsigned int msi_doorbell_start(void) 177 + { 178 + return is_ipi_available() ? PCI_MSI_DOORBELL_START : 179 + PCI_MSI_FULL_DOORBELL_START; 180 + } 181 + 182 + static inline unsigned int msi_doorbell_size(void) 183 + { 184 + return is_ipi_available() ? PCI_MSI_DOORBELL_NR : 185 + PCI_MSI_FULL_DOORBELL_NR; 186 + } 187 + 188 + static inline unsigned int msi_doorbell_end(void) 189 + { 190 + return is_ipi_available() ? PCI_MSI_DOORBELL_END : 191 + PCI_MSI_FULL_DOORBELL_END; 192 + } 169 193 170 194 static inline bool is_percpu_irq(irq_hw_number_t irq) 171 195 { ··· 259 213 260 214 msg->address_lo = lower_32_bits(msi_doorbell_addr); 261 215 msg->address_hi = upper_32_bits(msi_doorbell_addr); 262 - msg->data = BIT(cpu + 8) | (data->hwirq + PCI_MSI_DOORBELL_START); 216 + msg->data = BIT(cpu + 8) | (data->hwirq + msi_doorbell_start()); 263 217 } 264 218 265 219 static int armada_370_xp_msi_set_affinity(struct irq_data *irq_data, ··· 292 246 int hwirq, i; 293 247 294 248 mutex_lock(&msi_used_lock); 295 - hwirq = bitmap_find_free_region(msi_used, PCI_MSI_DOORBELL_NR, 249 + hwirq = bitmap_find_free_region(msi_used, msi_doorbell_size(), 296 250 order_base_2(nr_irqs)); 297 251 mutex_unlock(&msi_used_lock); 298 252 ··· 329 283 u32 reg; 330 284 331 285 /* Enable MSI doorbell mask and combined cpu local interrupt */ 332 - reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS) 333 - | PCI_MSI_DOORBELL_MASK; 286 + reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); 287 + reg |= msi_doorbell_mask(); 334 288 writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); 289 + 335 290 /* Unmask local doorbell interrupt */ 336 291 writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 337 292 } ··· 344 297 ARMADA_370_XP_SW_TRIG_INT_OFFS; 345 298 346 299 armada_370_xp_msi_inner_domain = 347 - irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR, 300 + irq_domain_add_linear(NULL, msi_doorbell_size(), 348 301 &armada_370_xp_msi_domain_ops, NULL); 349 302 if (!armada_370_xp_msi_inner_domain) 350 303 return -ENOMEM; ··· 359 312 } 360 313 361 314 armada_370_xp_msi_reenable_percpu(); 315 + 316 + /* Unmask low 16 MSI irqs on non-IPI platforms */ 317 + if (!is_ipi_available()) 318 + writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 362 319 363 320 return 0; 364 321 } ··· 512 461 set_smp_ipi_range(base_ipi, IPI_DOORBELL_END); 513 462 } 514 463 515 - static DEFINE_RAW_SPINLOCK(irq_controller_lock); 516 - 517 464 static int armada_xp_set_affinity(struct irq_data *d, 518 465 const struct cpumask *mask_val, bool force) 519 466 { 520 467 irq_hw_number_t hwirq = irqd_to_hwirq(d); 521 - unsigned long reg, mask; 522 468 int cpu; 523 469 524 470 /* Select a single core from the affinity mask which is online */ 525 471 cpu = cpumask_any_and(mask_val, cpu_online_mask); 526 - mask = 1UL << cpu_logical_map(cpu); 527 472 528 - raw_spin_lock(&irq_controller_lock); 529 - reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq)); 530 - reg = (reg & (~ARMADA_370_XP_INT_SOURCE_CPU_MASK)) | mask; 531 - writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq)); 532 - raw_spin_unlock(&irq_controller_lock); 473 + atomic_io_modify(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq), 474 + ARMADA_370_XP_INT_SOURCE_CPU_MASK, 475 + BIT(cpu_logical_map(cpu))); 533 476 534 477 irq_data_update_effective_affinity(d, cpumask_of(cpu)); 535 478 ··· 540 495 541 496 for (i = 0; i < nr_irqs; i++) 542 497 writel(i, per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS); 498 + 499 + if (!is_ipi_available()) 500 + return; 543 501 544 502 /* Disable all IPIs */ 545 503 writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); ··· 575 527 armada_370_xp_irq_unmask(data); 576 528 } 577 529 578 - ipi_resume(); 530 + if (is_ipi_available()) 531 + ipi_resume(); 579 532 580 533 armada_370_xp_msi_reenable_percpu(); 581 534 } ··· 615 566 static int armada_370_xp_mpic_irq_map(struct irq_domain *h, 616 567 unsigned int virq, irq_hw_number_t hw) 617 568 { 569 + /* IRQs 0 and 1 cannot be mapped, they are handled internally */ 570 + if (hw <= 1) 571 + return -EINVAL; 572 + 618 573 armada_370_xp_irq_mask(irq_get_irq_data(virq)); 619 574 if (!is_percpu_irq(hw)) 620 575 writel(hw, per_cpu_int_base + ··· 652 599 u32 msimask, msinr; 653 600 654 601 msimask = readl_relaxed(per_cpu_int_base + 655 - ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS) 656 - & PCI_MSI_DOORBELL_MASK; 602 + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); 603 + msimask &= msi_doorbell_mask(); 657 604 658 605 writel(~msimask, per_cpu_int_base + 659 606 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); 660 607 661 - for (msinr = PCI_MSI_DOORBELL_START; 662 - msinr < PCI_MSI_DOORBELL_END; msinr++) { 608 + for (msinr = msi_doorbell_start(); 609 + msinr < msi_doorbell_end(); msinr++) { 663 610 unsigned int irq; 664 611 665 612 if (!(msimask & BIT(msinr))) 666 613 continue; 667 614 668 - irq = msinr - PCI_MSI_DOORBELL_START; 615 + irq = msinr - msi_doorbell_start(); 669 616 670 617 generic_handle_domain_irq(armada_370_xp_msi_inner_domain, irq); 671 618 } ··· 694 641 if (!(irqsrc & ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid))) 695 642 continue; 696 643 697 - if (irqn == 1) { 644 + if (irqn == 0 || irqn == 1) { 698 645 armada_370_xp_handle_msi_irq(NULL, true); 699 646 continue; 700 647 } ··· 755 702 756 703 static void armada_370_xp_mpic_resume(void) 757 704 { 705 + bool src0, src1; 758 706 int nirqs; 759 707 irq_hw_number_t irq; 760 708 ··· 795 741 /* Reconfigure doorbells for IPIs and MSIs */ 796 742 writel(doorbell_mask_reg, 797 743 per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); 798 - if (doorbell_mask_reg & IPI_DOORBELL_MASK) 744 + 745 + if (is_ipi_available()) { 746 + src0 = doorbell_mask_reg & IPI_DOORBELL_MASK; 747 + src1 = doorbell_mask_reg & PCI_MSI_DOORBELL_MASK; 748 + } else { 749 + src0 = doorbell_mask_reg & PCI_MSI_FULL_DOORBELL_SRC0_MASK; 750 + src1 = doorbell_mask_reg & PCI_MSI_FULL_DOORBELL_SRC1_MASK; 751 + } 752 + 753 + if (src0) 799 754 writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 800 - if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK) 755 + if (src1) 801 756 writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 802 757 803 - ipi_resume(); 758 + if (is_ipi_available()) 759 + ipi_resume(); 804 760 } 805 761 806 762 static struct syscore_ops armada_370_xp_mpic_syscore_ops = { ··· 855 791 BUG_ON(!armada_370_xp_mpic_domain); 856 792 irq_domain_update_bus_token(armada_370_xp_mpic_domain, DOMAIN_BUS_WIRED); 857 793 794 + /* 795 + * Initialize parent_irq before calling any other functions, since it is 796 + * used to distinguish between IPI and non-IPI platforms. 797 + */ 798 + parent_irq = irq_of_parse_and_map(node, 0); 799 + 858 800 /* Setup for the boot CPU */ 859 801 armada_xp_mpic_perf_init(); 860 802 armada_xp_mpic_smp_cpu_init(); 861 803 862 804 armada_370_xp_msi_init(node, main_int_res.start); 863 805 864 - parent_irq = irq_of_parse_and_map(node, 0); 865 806 if (parent_irq <= 0) { 866 807 irq_set_default_host(armada_370_xp_mpic_domain); 867 808 set_handle_irq(armada_370_xp_handle_irq);
+3 -1
drivers/irqchip/irq-bcm2835.c
··· 102 102 static struct irq_chip armctrl_chip = { 103 103 .name = "ARMCTRL-level", 104 104 .irq_mask = armctrl_mask_irq, 105 - .irq_unmask = armctrl_unmask_irq 105 + .irq_unmask = armctrl_unmask_irq, 106 + .flags = IRQCHIP_MASK_ON_SUSPEND | 107 + IRQCHIP_SKIP_SET_WAKE, 106 108 }; 107 109 108 110 static int armctrl_xlate(struct irq_domain *d, struct device_node *ctrlr,
+26 -26
drivers/irqchip/irq-gic-v3-its.c
··· 1317 1317 { 1318 1318 struct its_cmd_desc desc = {}; 1319 1319 struct its_node *its; 1320 - unsigned long flags; 1321 1320 int col_id = vpe->col_idx; 1322 1321 1323 1322 desc.its_vmovp_cmd.vpe = vpe; ··· 1329 1330 } 1330 1331 1331 1332 /* 1333 + * Protect against concurrent updates of the mapping state on 1334 + * individual VMs. 1335 + */ 1336 + guard(raw_spinlock_irqsave)(&vpe->its_vm->vmapp_lock); 1337 + 1338 + /* 1332 1339 * Yet another marvel of the architecture. If using the 1333 1340 * its_list "feature", we need to make sure that all ITSs 1334 1341 * receive all VMOVP commands in the same order. The only way ··· 1342 1337 * 1343 1338 * Wall <-- Head. 1344 1339 */ 1345 - raw_spin_lock_irqsave(&vmovp_lock, flags); 1346 - 1340 + guard(raw_spinlock)(&vmovp_lock); 1347 1341 desc.its_vmovp_cmd.seq_num = vmovp_seq_num++; 1348 1342 desc.its_vmovp_cmd.its_list = get_its_list(vpe->its_vm); 1349 1343 ··· 1357 1353 desc.its_vmovp_cmd.col = &its->collections[col_id]; 1358 1354 its_send_single_vcommand(its, its_build_vmovp_cmd, &desc); 1359 1355 } 1360 - 1361 - raw_spin_unlock_irqrestore(&vmovp_lock, flags); 1362 1356 } 1363 1357 1364 1358 static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe) ··· 1793 1791 1794 1792 static void its_map_vm(struct its_node *its, struct its_vm *vm) 1795 1793 { 1796 - unsigned long flags; 1797 - 1798 1794 if (gic_requires_eager_mapping()) 1799 1795 return; 1800 1796 1801 - raw_spin_lock_irqsave(&vmovp_lock, flags); 1797 + guard(raw_spinlock_irqsave)(&vm->vmapp_lock); 1802 1798 1803 1799 /* 1804 1800 * If the VM wasn't mapped yet, iterate over the vpes and get ··· 1809 1809 1810 1810 for (i = 0; i < vm->nr_vpes; i++) { 1811 1811 struct its_vpe *vpe = vm->vpes[i]; 1812 - struct irq_data *d = irq_get_irq_data(vpe->irq); 1813 1812 1814 - /* Map the VPE to the first possible CPU */ 1815 - vpe->col_idx = cpumask_first(cpu_online_mask); 1816 - its_send_vmapp(its, vpe, true); 1813 + scoped_guard(raw_spinlock, &vpe->vpe_lock) 1814 + its_send_vmapp(its, vpe, true); 1815 + 1817 1816 its_send_vinvall(its, vpe); 1818 - irq_data_update_effective_affinity(d, cpumask_of(vpe->col_idx)); 1819 1817 } 1820 1818 } 1821 - 1822 - raw_spin_unlock_irqrestore(&vmovp_lock, flags); 1823 1819 } 1824 1820 1825 1821 static void its_unmap_vm(struct its_node *its, struct its_vm *vm) 1826 1822 { 1827 - unsigned long flags; 1828 - 1829 1823 /* Not using the ITS list? Everything is always mapped. */ 1830 1824 if (gic_requires_eager_mapping()) 1831 1825 return; 1832 1826 1833 - raw_spin_lock_irqsave(&vmovp_lock, flags); 1827 + guard(raw_spinlock_irqsave)(&vm->vmapp_lock); 1834 1828 1835 1829 if (!--vm->vlpi_count[its->list_nr]) { 1836 1830 int i; 1837 1831 1838 - for (i = 0; i < vm->nr_vpes; i++) 1832 + for (i = 0; i < vm->nr_vpes; i++) { 1833 + guard(raw_spinlock)(&vm->vpes[i]->vpe_lock); 1839 1834 its_send_vmapp(its, vm->vpes[i], false); 1835 + } 1840 1836 } 1841 - 1842 - raw_spin_unlock_irqrestore(&vmovp_lock, flags); 1843 1837 } 1844 1838 1845 1839 static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info) ··· 3920 3926 { 3921 3927 struct its_node *its; 3922 3928 3929 + guard(raw_spinlock_irqsave)(&vpe->its_vm->vmapp_lock); 3930 + 3923 3931 list_for_each_entry(its, &its_nodes, entry) { 3924 3932 if (!is_v4(its)) 3925 3933 continue; ··· 4527 4531 vm->db_lpi_base = base; 4528 4532 vm->nr_db_lpis = nr_ids; 4529 4533 vm->vprop_page = vprop_page; 4534 + raw_spin_lock_init(&vm->vmapp_lock); 4530 4535 4531 4536 if (gic_rdists->has_rvpeid) 4532 4537 irqchip = &its_vpe_4_1_irq_chip; ··· 4559 4562 struct its_vpe *vpe = irq_data_get_irq_chip_data(d); 4560 4563 struct its_node *its; 4561 4564 4565 + /* Map the VPE to the first possible CPU */ 4566 + vpe->col_idx = cpumask_first(cpu_online_mask); 4567 + irq_data_update_effective_affinity(d, cpumask_of(vpe->col_idx)); 4568 + 4562 4569 /* 4563 4570 * If we use the list map, we issue VMAPP on demand... Unless 4564 4571 * we're on a GICv4.1 and we eagerly map the VPE on all ITSs ··· 4571 4570 if (!gic_requires_eager_mapping()) 4572 4571 return 0; 4573 4572 4574 - /* Map the VPE to the first possible CPU */ 4575 - vpe->col_idx = cpumask_first(cpu_online_mask); 4576 - 4577 4573 list_for_each_entry(its, &its_nodes, entry) { 4578 4574 if (!is_v4(its)) 4579 4575 continue; ··· 4578 4580 its_send_vmapp(its, vpe, true); 4579 4581 its_send_vinvall(its, vpe); 4580 4582 } 4581 - 4582 - irq_data_update_effective_affinity(d, cpumask_of(vpe->col_idx)); 4583 4583 4584 4584 return 0; 4585 4585 } ··· 5575 5579 err = -ENOMEM; 5576 5580 goto node_err; 5577 5581 } 5582 + 5583 + if (acpi_get_madt_revision() >= 7 && 5584 + (its_entry->flags & ACPI_MADT_ITS_NON_COHERENT)) 5585 + its->flags |= ITS_FLAGS_FORCE_NON_SHAREABLE; 5578 5586 5579 5587 err = its_probe_one(its); 5580 5588 if (!err)
+13 -9
drivers/irqchip/irq-gic-v3.c
··· 2203 2203 of_node_put(parts_node); 2204 2204 } 2205 2205 2206 - static void __init gic_of_setup_kvm_info(struct device_node *node) 2206 + static void __init gic_of_setup_kvm_info(struct device_node *node, u32 nr_redist_regions) 2207 2207 { 2208 2208 int ret; 2209 2209 struct resource r; 2210 - u32 gicv_idx; 2211 2210 2212 2211 gic_v3_kvm_info.type = GIC_V3; 2213 2212 ··· 2214 2215 if (!gic_v3_kvm_info.maint_irq) 2215 2216 return; 2216 2217 2217 - if (of_property_read_u32(node, "#redistributor-regions", 2218 - &gicv_idx)) 2219 - gicv_idx = 1; 2220 - 2221 - gicv_idx += 3; /* Also skip GICD, GICC, GICH */ 2222 - ret = of_address_to_resource(node, gicv_idx, &r); 2218 + /* Also skip GICD, GICC, GICH */ 2219 + ret = of_address_to_resource(node, nr_redist_regions + 3, &r); 2223 2220 if (!ret) 2224 2221 gic_v3_kvm_info.vcpu = r; 2225 2222 ··· 2305 2310 gic_populate_ppi_partitions(node); 2306 2311 2307 2312 if (static_branch_likely(&supports_deactivate_key)) 2308 - gic_of_setup_kvm_info(node); 2313 + gic_of_setup_kvm_info(node, nr_redist_regions); 2309 2314 return 0; 2310 2315 2311 2316 out_unmap_rdist: ··· 2357 2362 pr_err("Couldn't map GICR region @%llx\n", redist->base_address); 2358 2363 return -ENOMEM; 2359 2364 } 2365 + 2366 + if (acpi_get_madt_revision() >= 7 && 2367 + (redist->flags & ACPI_MADT_GICR_NON_COHERENT)) 2368 + gic_data.rdists.flags |= RDIST_FLAGS_FORCE_NON_SHAREABLE; 2369 + 2360 2370 gic_request_region(redist->base_address, redist->length, "GICR"); 2361 2371 2362 2372 gic_acpi_register_redist(redist->base_address, redist_base); ··· 2401 2401 if (!redist_base) 2402 2402 return -ENOMEM; 2403 2403 gic_request_region(gicc->gicr_base_address, size, "GICR"); 2404 + 2405 + if (acpi_get_madt_revision() >= 7 && 2406 + (gicc->flags & ACPI_MADT_GICC_NON_COHERENT)) 2407 + gic_data.rdists.flags |= RDIST_FLAGS_FORCE_NON_SHAREABLE; 2404 2408 2405 2409 gic_acpi_register_redist(gicc->gicr_base_address, redist_base); 2406 2410 return 0;
+21 -3
drivers/irqchip/irq-imx-irqsteer.c
··· 36 36 int channel; 37 37 struct irq_domain *domain; 38 38 u32 *saved_reg; 39 + struct device *dev; 39 40 }; 40 41 41 42 static int imx_irqsteer_get_reg_index(struct irqsteer_data *data, ··· 73 72 raw_spin_unlock_irqrestore(&data->lock, flags); 74 73 } 75 74 75 + static void imx_irqsteer_irq_bus_lock(struct irq_data *d) 76 + { 77 + struct irqsteer_data *data = d->chip_data; 78 + 79 + pm_runtime_get_sync(data->dev); 80 + } 81 + 82 + static void imx_irqsteer_irq_bus_sync_unlock(struct irq_data *d) 83 + { 84 + struct irqsteer_data *data = d->chip_data; 85 + 86 + pm_runtime_put_autosuspend(data->dev); 87 + } 88 + 76 89 static const struct irq_chip imx_irqsteer_irq_chip = { 77 - .name = "irqsteer", 78 - .irq_mask = imx_irqsteer_irq_mask, 79 - .irq_unmask = imx_irqsteer_irq_unmask, 90 + .name = "irqsteer", 91 + .irq_mask = imx_irqsteer_irq_mask, 92 + .irq_unmask = imx_irqsteer_irq_unmask, 93 + .irq_bus_lock = imx_irqsteer_irq_bus_lock, 94 + .irq_bus_sync_unlock = imx_irqsteer_irq_bus_sync_unlock, 80 95 }; 81 96 82 97 static int imx_irqsteer_irq_map(struct irq_domain *h, unsigned int irq, ··· 167 150 if (!data) 168 151 return -ENOMEM; 169 152 153 + data->dev = &pdev->dev; 170 154 data->regs = devm_platform_ioremap_resource(pdev, 0); 171 155 if (IS_ERR(data->regs)) { 172 156 dev_err(&pdev->dev, "failed to initialize reg\n");
+278
drivers/irqchip/irq-lan966x-oic.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Driver for the Microchip LAN966x outbound interrupt controller 4 + * 5 + * Copyright (c) 2024 Technology Inc. and its subsidiaries. 6 + * 7 + * Authors: 8 + * Horatiu Vultur <horatiu.vultur@microchip.com> 9 + * Clément Léger <clement.leger@bootlin.com> 10 + * Herve Codina <herve.codina@bootlin.com> 11 + */ 12 + 13 + #include <linux/interrupt.h> 14 + #include <linux/irqchip/chained_irq.h> 15 + #include <linux/irqchip.h> 16 + #include <linux/irq.h> 17 + #include <linux/mod_devicetable.h> 18 + #include <linux/module.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/slab.h> 21 + 22 + struct lan966x_oic_chip_regs { 23 + int reg_off_ena_set; 24 + int reg_off_ena_clr; 25 + int reg_off_sticky; 26 + int reg_off_ident; 27 + int reg_off_map; 28 + }; 29 + 30 + struct lan966x_oic_data { 31 + void __iomem *regs; 32 + int irq; 33 + }; 34 + 35 + #define LAN966X_OIC_NR_IRQ 86 36 + 37 + /* Interrupt sticky status */ 38 + #define LAN966X_OIC_INTR_STICKY 0x30 39 + #define LAN966X_OIC_INTR_STICKY1 0x34 40 + #define LAN966X_OIC_INTR_STICKY2 0x38 41 + 42 + /* Interrupt enable */ 43 + #define LAN966X_OIC_INTR_ENA 0x48 44 + #define LAN966X_OIC_INTR_ENA1 0x4c 45 + #define LAN966X_OIC_INTR_ENA2 0x50 46 + 47 + /* Atomic clear of interrupt enable */ 48 + #define LAN966X_OIC_INTR_ENA_CLR 0x54 49 + #define LAN966X_OIC_INTR_ENA_CLR1 0x58 50 + #define LAN966X_OIC_INTR_ENA_CLR2 0x5c 51 + 52 + /* Atomic set of interrupt */ 53 + #define LAN966X_OIC_INTR_ENA_SET 0x60 54 + #define LAN966X_OIC_INTR_ENA_SET1 0x64 55 + #define LAN966X_OIC_INTR_ENA_SET2 0x68 56 + 57 + /* Mapping of source to destination interrupts (_n = 0..8) */ 58 + #define LAN966X_OIC_DST_INTR_MAP(_n) (0x78 + (_n) * 4) 59 + #define LAN966X_OIC_DST_INTR_MAP1(_n) (0x9c + (_n) * 4) 60 + #define LAN966X_OIC_DST_INTR_MAP2(_n) (0xc0 + (_n) * 4) 61 + 62 + /* Currently active interrupt sources per destination (_n = 0..8) */ 63 + #define LAN966X_OIC_DST_INTR_IDENT(_n) (0xe4 + (_n) * 4) 64 + #define LAN966X_OIC_DST_INTR_IDENT1(_n) (0x108 + (_n) * 4) 65 + #define LAN966X_OIC_DST_INTR_IDENT2(_n) (0x12c + (_n) * 4) 66 + 67 + static unsigned int lan966x_oic_irq_startup(struct irq_data *data) 68 + { 69 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); 70 + struct irq_chip_type *ct = irq_data_get_chip_type(data); 71 + struct lan966x_oic_chip_regs *chip_regs = gc->private; 72 + u32 map; 73 + 74 + irq_gc_lock(gc); 75 + 76 + /* Map the source interrupt to the destination */ 77 + map = irq_reg_readl(gc, chip_regs->reg_off_map); 78 + map |= data->mask; 79 + irq_reg_writel(gc, map, chip_regs->reg_off_map); 80 + 81 + irq_gc_unlock(gc); 82 + 83 + ct->chip.irq_ack(data); 84 + ct->chip.irq_unmask(data); 85 + 86 + return 0; 87 + } 88 + 89 + static void lan966x_oic_irq_shutdown(struct irq_data *data) 90 + { 91 + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); 92 + struct irq_chip_type *ct = irq_data_get_chip_type(data); 93 + struct lan966x_oic_chip_regs *chip_regs = gc->private; 94 + u32 map; 95 + 96 + ct->chip.irq_mask(data); 97 + 98 + irq_gc_lock(gc); 99 + 100 + /* Unmap the interrupt */ 101 + map = irq_reg_readl(gc, chip_regs->reg_off_map); 102 + map &= ~data->mask; 103 + irq_reg_writel(gc, map, chip_regs->reg_off_map); 104 + 105 + irq_gc_unlock(gc); 106 + } 107 + 108 + static int lan966x_oic_irq_set_type(struct irq_data *data, 109 + unsigned int flow_type) 110 + { 111 + if (flow_type != IRQ_TYPE_LEVEL_HIGH) { 112 + pr_err("lan966x oic doesn't support flow type %d\n", flow_type); 113 + return -EINVAL; 114 + } 115 + 116 + return 0; 117 + } 118 + 119 + static void lan966x_oic_irq_handler_domain(struct irq_domain *d, u32 first_irq) 120 + { 121 + struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, first_irq); 122 + struct lan966x_oic_chip_regs *chip_regs = gc->private; 123 + unsigned long ident; 124 + unsigned int hwirq; 125 + 126 + ident = irq_reg_readl(gc, chip_regs->reg_off_ident); 127 + if (!ident) 128 + return; 129 + 130 + for_each_set_bit(hwirq, &ident, 32) 131 + generic_handle_domain_irq(d, hwirq + first_irq); 132 + } 133 + 134 + static void lan966x_oic_irq_handler(struct irq_desc *desc) 135 + { 136 + struct irq_domain *d = irq_desc_get_handler_data(desc); 137 + struct irq_chip *chip = irq_desc_get_chip(desc); 138 + 139 + chained_irq_enter(chip, desc); 140 + lan966x_oic_irq_handler_domain(d, 0); 141 + lan966x_oic_irq_handler_domain(d, 32); 142 + lan966x_oic_irq_handler_domain(d, 64); 143 + chained_irq_exit(chip, desc); 144 + } 145 + 146 + static struct lan966x_oic_chip_regs lan966x_oic_chip_regs[3] = { 147 + { 148 + .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET, 149 + .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR, 150 + .reg_off_sticky = LAN966X_OIC_INTR_STICKY, 151 + .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT(0), 152 + .reg_off_map = LAN966X_OIC_DST_INTR_MAP(0), 153 + }, { 154 + .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET1, 155 + .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR1, 156 + .reg_off_sticky = LAN966X_OIC_INTR_STICKY1, 157 + .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT1(0), 158 + .reg_off_map = LAN966X_OIC_DST_INTR_MAP1(0), 159 + }, { 160 + .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET2, 161 + .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR2, 162 + .reg_off_sticky = LAN966X_OIC_INTR_STICKY2, 163 + .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT2(0), 164 + .reg_off_map = LAN966X_OIC_DST_INTR_MAP2(0), 165 + } 166 + }; 167 + 168 + static int lan966x_oic_chip_init(struct irq_chip_generic *gc) 169 + { 170 + struct lan966x_oic_data *lan966x_oic = gc->domain->host_data; 171 + struct lan966x_oic_chip_regs *chip_regs; 172 + 173 + chip_regs = &lan966x_oic_chip_regs[gc->irq_base / 32]; 174 + 175 + gc->reg_base = lan966x_oic->regs; 176 + gc->chip_types[0].regs.enable = chip_regs->reg_off_ena_set; 177 + gc->chip_types[0].regs.disable = chip_regs->reg_off_ena_clr; 178 + gc->chip_types[0].regs.ack = chip_regs->reg_off_sticky; 179 + gc->chip_types[0].chip.irq_startup = lan966x_oic_irq_startup; 180 + gc->chip_types[0].chip.irq_shutdown = lan966x_oic_irq_shutdown; 181 + gc->chip_types[0].chip.irq_set_type = lan966x_oic_irq_set_type; 182 + gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; 183 + gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; 184 + gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; 185 + gc->private = chip_regs; 186 + 187 + /* Disable all interrupts handled by this chip */ 188 + irq_reg_writel(gc, ~0U, chip_regs->reg_off_ena_clr); 189 + 190 + return 0; 191 + } 192 + 193 + static void lan966x_oic_chip_exit(struct irq_chip_generic *gc) 194 + { 195 + /* Disable and ack all interrupts handled by this chip */ 196 + irq_reg_writel(gc, ~0U, gc->chip_types[0].regs.disable); 197 + irq_reg_writel(gc, ~0U, gc->chip_types[0].regs.ack); 198 + } 199 + 200 + static int lan966x_oic_domain_init(struct irq_domain *d) 201 + { 202 + struct lan966x_oic_data *lan966x_oic = d->host_data; 203 + 204 + irq_set_chained_handler_and_data(lan966x_oic->irq, lan966x_oic_irq_handler, d); 205 + 206 + return 0; 207 + } 208 + 209 + static void lan966x_oic_domain_exit(struct irq_domain *d) 210 + { 211 + struct lan966x_oic_data *lan966x_oic = d->host_data; 212 + 213 + irq_set_chained_handler_and_data(lan966x_oic->irq, NULL, NULL); 214 + } 215 + 216 + static int lan966x_oic_probe(struct platform_device *pdev) 217 + { 218 + struct irq_domain_chip_generic_info dgc_info = { 219 + .name = "lan966x-oic", 220 + .handler = handle_level_irq, 221 + .irqs_per_chip = 32, 222 + .num_ct = 1, 223 + .init = lan966x_oic_chip_init, 224 + .exit = lan966x_oic_chip_exit, 225 + }; 226 + struct irq_domain_info d_info = { 227 + .fwnode = of_node_to_fwnode(pdev->dev.of_node), 228 + .domain_flags = IRQ_DOMAIN_FLAG_DESTROY_GC, 229 + .size = LAN966X_OIC_NR_IRQ, 230 + .hwirq_max = LAN966X_OIC_NR_IRQ, 231 + .ops = &irq_generic_chip_ops, 232 + .dgc_info = &dgc_info, 233 + .init = lan966x_oic_domain_init, 234 + .exit = lan966x_oic_domain_exit, 235 + }; 236 + struct lan966x_oic_data *lan966x_oic; 237 + struct device *dev = &pdev->dev; 238 + struct irq_domain *domain; 239 + 240 + lan966x_oic = devm_kmalloc(dev, sizeof(*lan966x_oic), GFP_KERNEL); 241 + if (!lan966x_oic) 242 + return -ENOMEM; 243 + 244 + lan966x_oic->regs = devm_platform_ioremap_resource(pdev, 0); 245 + if (IS_ERR(lan966x_oic->regs)) 246 + return dev_err_probe(dev, PTR_ERR(lan966x_oic->regs), 247 + "failed to map resource\n"); 248 + 249 + lan966x_oic->irq = platform_get_irq(pdev, 0); 250 + if (lan966x_oic->irq < 0) 251 + return dev_err_probe(dev, lan966x_oic->irq, "failed to get the IRQ\n"); 252 + 253 + d_info.host_data = lan966x_oic; 254 + domain = devm_irq_domain_instantiate(dev, &d_info); 255 + if (IS_ERR(domain)) 256 + return dev_err_probe(dev, PTR_ERR(domain), 257 + "failed to instantiate the IRQ domain\n"); 258 + return 0; 259 + } 260 + 261 + static const struct of_device_id lan966x_oic_of_match[] = { 262 + { .compatible = "microchip,lan966x-oic" }, 263 + {} /* sentinel */ 264 + }; 265 + MODULE_DEVICE_TABLE(of, lan966x_oic_of_match); 266 + 267 + static struct platform_driver lan966x_oic_driver = { 268 + .probe = lan966x_oic_probe, 269 + .driver = { 270 + .name = "lan966x-oic", 271 + .of_match_table = lan966x_oic_of_match, 272 + }, 273 + }; 274 + module_platform_driver(lan966x_oic_driver); 275 + 276 + MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); 277 + MODULE_DESCRIPTION("Microchip LAN966x OIC driver"); 278 + MODULE_LICENSE("GPL");
+1
drivers/irqchip/irq-meson-gpio.c
··· 608 608 IRQCHIP_PLATFORM_DRIVER_END(meson_gpio_intc) 609 609 610 610 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 611 + MODULE_DESCRIPTION("Meson GPIO Interrupt Multiplexer driver"); 611 612 MODULE_LICENSE("GPL v2"); 612 613 MODULE_ALIAS("platform:meson-gpio-intc");
+1
drivers/irqchip/irq-mvebu-pic.c
··· 193 193 194 194 MODULE_AUTHOR("Yehuda Yitschak <yehuday@marvell.com>"); 195 195 MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>"); 196 + MODULE_DESCRIPTION("Marvell Armada 7K/8K PIC driver"); 196 197 MODULE_LICENSE("GPL v2"); 197 198 MODULE_ALIAS("platform:mvebu_pic"); 198 199
+146 -4
drivers/irqchip/irq-renesas-rzg2l.c
··· 37 37 #define TSSEL_SHIFT(n) (8 * (n)) 38 38 #define TSSEL_MASK GENMASK(7, 0) 39 39 #define IRQ_MASK 0x3 40 + #define IMSK 0x10010 41 + #define TMSK 0x10020 40 42 41 43 #define TSSR_OFFSET(n) ((n) % 4) 42 44 #define TSSR_INDEX(n) ((n) / 4) ··· 71 69 /** 72 70 * struct rzg2l_irqc_priv - IRQ controller private data structure 73 71 * @base: Controller's base address 72 + * @irqchip: Pointer to struct irq_chip 74 73 * @fwspec: IRQ firmware specific data 75 74 * @lock: Lock to serialize access to hardware registers 76 75 * @cache: Registers cache for suspend/resume 77 76 */ 78 77 static struct rzg2l_irqc_priv { 79 78 void __iomem *base; 79 + const struct irq_chip *irqchip; 80 80 struct irq_fwspec fwspec[IRQC_NUM_IRQ]; 81 81 raw_spinlock_t lock; 82 82 struct rzg2l_irqc_reg_cache cache; ··· 142 138 irq_chip_eoi_parent(d); 143 139 } 144 140 141 + static void rzfive_irqc_mask_irq_interrupt(struct rzg2l_irqc_priv *priv, 142 + unsigned int hwirq) 143 + { 144 + u32 bit = BIT(hwirq - IRQC_IRQ_START); 145 + 146 + writel_relaxed(readl_relaxed(priv->base + IMSK) | bit, priv->base + IMSK); 147 + } 148 + 149 + static void rzfive_irqc_unmask_irq_interrupt(struct rzg2l_irqc_priv *priv, 150 + unsigned int hwirq) 151 + { 152 + u32 bit = BIT(hwirq - IRQC_IRQ_START); 153 + 154 + writel_relaxed(readl_relaxed(priv->base + IMSK) & ~bit, priv->base + IMSK); 155 + } 156 + 157 + static void rzfive_irqc_mask_tint_interrupt(struct rzg2l_irqc_priv *priv, 158 + unsigned int hwirq) 159 + { 160 + u32 bit = BIT(hwirq - IRQC_TINT_START); 161 + 162 + writel_relaxed(readl_relaxed(priv->base + TMSK) | bit, priv->base + TMSK); 163 + } 164 + 165 + static void rzfive_irqc_unmask_tint_interrupt(struct rzg2l_irqc_priv *priv, 166 + unsigned int hwirq) 167 + { 168 + u32 bit = BIT(hwirq - IRQC_TINT_START); 169 + 170 + writel_relaxed(readl_relaxed(priv->base + TMSK) & ~bit, priv->base + TMSK); 171 + } 172 + 173 + static void rzfive_irqc_mask(struct irq_data *d) 174 + { 175 + struct rzg2l_irqc_priv *priv = irq_data_to_priv(d); 176 + unsigned int hwirq = irqd_to_hwirq(d); 177 + 178 + raw_spin_lock(&priv->lock); 179 + if (hwirq >= IRQC_IRQ_START && hwirq <= IRQC_IRQ_COUNT) 180 + rzfive_irqc_mask_irq_interrupt(priv, hwirq); 181 + else if (hwirq >= IRQC_TINT_START && hwirq < IRQC_NUM_IRQ) 182 + rzfive_irqc_mask_tint_interrupt(priv, hwirq); 183 + raw_spin_unlock(&priv->lock); 184 + irq_chip_mask_parent(d); 185 + } 186 + 187 + static void rzfive_irqc_unmask(struct irq_data *d) 188 + { 189 + struct rzg2l_irqc_priv *priv = irq_data_to_priv(d); 190 + unsigned int hwirq = irqd_to_hwirq(d); 191 + 192 + raw_spin_lock(&priv->lock); 193 + if (hwirq >= IRQC_IRQ_START && hwirq <= IRQC_IRQ_COUNT) 194 + rzfive_irqc_unmask_irq_interrupt(priv, hwirq); 195 + else if (hwirq >= IRQC_TINT_START && hwirq < IRQC_NUM_IRQ) 196 + rzfive_irqc_unmask_tint_interrupt(priv, hwirq); 197 + raw_spin_unlock(&priv->lock); 198 + irq_chip_unmask_parent(d); 199 + } 200 + 201 + static void rzfive_tint_irq_endisable(struct irq_data *d, bool enable) 202 + { 203 + struct rzg2l_irqc_priv *priv = irq_data_to_priv(d); 204 + unsigned int hwirq = irqd_to_hwirq(d); 205 + 206 + if (hwirq >= IRQC_TINT_START && hwirq < IRQC_NUM_IRQ) { 207 + u32 offset = hwirq - IRQC_TINT_START; 208 + u32 tssr_offset = TSSR_OFFSET(offset); 209 + u8 tssr_index = TSSR_INDEX(offset); 210 + u32 reg; 211 + 212 + raw_spin_lock(&priv->lock); 213 + if (enable) 214 + rzfive_irqc_unmask_tint_interrupt(priv, hwirq); 215 + else 216 + rzfive_irqc_mask_tint_interrupt(priv, hwirq); 217 + reg = readl_relaxed(priv->base + TSSR(tssr_index)); 218 + if (enable) 219 + reg |= TIEN << TSSEL_SHIFT(tssr_offset); 220 + else 221 + reg &= ~(TIEN << TSSEL_SHIFT(tssr_offset)); 222 + writel_relaxed(reg, priv->base + TSSR(tssr_index)); 223 + raw_spin_unlock(&priv->lock); 224 + } else { 225 + raw_spin_lock(&priv->lock); 226 + if (enable) 227 + rzfive_irqc_unmask_irq_interrupt(priv, hwirq); 228 + else 229 + rzfive_irqc_mask_irq_interrupt(priv, hwirq); 230 + raw_spin_unlock(&priv->lock); 231 + } 232 + } 233 + 234 + static void rzfive_irqc_irq_disable(struct irq_data *d) 235 + { 236 + irq_chip_disable_parent(d); 237 + rzfive_tint_irq_endisable(d, false); 238 + } 239 + 240 + static void rzfive_irqc_irq_enable(struct irq_data *d) 241 + { 242 + rzfive_tint_irq_endisable(d, true); 243 + irq_chip_enable_parent(d); 244 + } 245 + 145 246 static void rzg2l_tint_irq_endisable(struct irq_data *d, bool enable) 146 247 { 147 248 unsigned int hw_irq = irqd_to_hwirq(d); ··· 271 162 272 163 static void rzg2l_irqc_irq_disable(struct irq_data *d) 273 164 { 274 - rzg2l_tint_irq_endisable(d, false); 275 165 irq_chip_disable_parent(d); 166 + rzg2l_tint_irq_endisable(d, false); 276 167 } 277 168 278 169 static void rzg2l_irqc_irq_enable(struct irq_data *d) ··· 430 321 .resume = rzg2l_irqc_irq_resume, 431 322 }; 432 323 433 - static const struct irq_chip irqc_chip = { 324 + static const struct irq_chip rzg2l_irqc_chip = { 434 325 .name = "rzg2l-irqc", 435 326 .irq_eoi = rzg2l_irqc_eoi, 436 327 .irq_mask = irq_chip_mask_parent, 437 328 .irq_unmask = irq_chip_unmask_parent, 438 329 .irq_disable = rzg2l_irqc_irq_disable, 439 330 .irq_enable = rzg2l_irqc_irq_enable, 331 + .irq_get_irqchip_state = irq_chip_get_parent_state, 332 + .irq_set_irqchip_state = irq_chip_set_parent_state, 333 + .irq_retrigger = irq_chip_retrigger_hierarchy, 334 + .irq_set_type = rzg2l_irqc_set_type, 335 + .irq_set_affinity = irq_chip_set_affinity_parent, 336 + .flags = IRQCHIP_MASK_ON_SUSPEND | 337 + IRQCHIP_SET_TYPE_MASKED | 338 + IRQCHIP_SKIP_SET_WAKE, 339 + }; 340 + 341 + static const struct irq_chip rzfive_irqc_chip = { 342 + .name = "rzfive-irqc", 343 + .irq_eoi = rzg2l_irqc_eoi, 344 + .irq_mask = rzfive_irqc_mask, 345 + .irq_unmask = rzfive_irqc_unmask, 346 + .irq_disable = rzfive_irqc_irq_disable, 347 + .irq_enable = rzfive_irqc_irq_enable, 440 348 .irq_get_irqchip_state = irq_chip_get_parent_state, 441 349 .irq_set_irqchip_state = irq_chip_set_parent_state, 442 350 .irq_retrigger = irq_chip_retrigger_hierarchy, ··· 495 369 if (hwirq > (IRQC_NUM_IRQ - 1)) 496 370 return -EINVAL; 497 371 498 - ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &irqc_chip, 372 + ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, priv->irqchip, 499 373 (void *)(uintptr_t)tint); 500 374 if (ret) 501 375 return ret; ··· 527 401 return 0; 528 402 } 529 403 530 - static int rzg2l_irqc_init(struct device_node *node, struct device_node *parent) 404 + static int rzg2l_irqc_common_init(struct device_node *node, struct device_node *parent, 405 + const struct irq_chip *irq_chip) 531 406 { 532 407 struct irq_domain *irq_domain, *parent_domain; 533 408 struct platform_device *pdev; ··· 548 421 rzg2l_irqc_data = devm_kzalloc(&pdev->dev, sizeof(*rzg2l_irqc_data), GFP_KERNEL); 549 422 if (!rzg2l_irqc_data) 550 423 return -ENOMEM; 424 + 425 + rzg2l_irqc_data->irqchip = irq_chip; 551 426 552 427 rzg2l_irqc_data->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL); 553 428 if (IS_ERR(rzg2l_irqc_data->base)) ··· 601 472 return ret; 602 473 } 603 474 475 + static int __init rzg2l_irqc_init(struct device_node *node, 476 + struct device_node *parent) 477 + { 478 + return rzg2l_irqc_common_init(node, parent, &rzg2l_irqc_chip); 479 + } 480 + 481 + static int __init rzfive_irqc_init(struct device_node *node, 482 + struct device_node *parent) 483 + { 484 + return rzg2l_irqc_common_init(node, parent, &rzfive_irqc_chip); 485 + } 486 + 604 487 IRQCHIP_PLATFORM_DRIVER_BEGIN(rzg2l_irqc) 605 488 IRQCHIP_MATCH("renesas,rzg2l-irqc", rzg2l_irqc_init) 489 + IRQCHIP_MATCH("renesas,r9a07g043f-irqc", rzfive_irqc_init) 606 490 IRQCHIP_PLATFORM_DRIVER_END(rzg2l_irqc) 607 491 MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>"); 608 492 MODULE_DESCRIPTION("Renesas RZ/G2L IRQC Driver");
+6 -7
drivers/irqchip/irq-riscv-aplic-main.c
··· 127 127 128 128 int aplic_setup_priv(struct aplic_priv *priv, struct device *dev, void __iomem *regs) 129 129 { 130 + struct device_node *np = to_of_node(dev->fwnode); 130 131 struct of_phandle_args parent; 131 132 int rc; 132 133 ··· 135 134 * Currently, only OF fwnode is supported so extend this 136 135 * function for ACPI support. 137 136 */ 138 - if (!is_of_node(dev->fwnode)) 137 + if (!np) 139 138 return -EINVAL; 140 139 141 140 /* Save device pointer and register base */ ··· 143 142 priv->regs = regs; 144 143 145 144 /* Find out number of interrupt sources */ 146 - rc = of_property_read_u32(to_of_node(dev->fwnode), "riscv,num-sources", 147 - &priv->nr_irqs); 145 + rc = of_property_read_u32(np, "riscv,num-sources", &priv->nr_irqs); 148 146 if (rc) { 149 147 dev_err(dev, "failed to get number of interrupt sources\n"); 150 148 return rc; ··· 155 155 * If "msi-parent" property is present then we ignore the 156 156 * APLIC IDCs which forces the APLIC driver to use MSI mode. 157 157 */ 158 - if (!of_property_present(to_of_node(dev->fwnode), "msi-parent")) { 159 - while (!of_irq_parse_one(to_of_node(dev->fwnode), priv->nr_idcs, &parent)) 158 + if (!of_property_present(np, "msi-parent")) { 159 + while (!of_irq_parse_one(np, priv->nr_idcs, &parent)) 160 160 priv->nr_idcs++; 161 161 } 162 162 ··· 184 184 * If msi-parent property is present then setup APLIC MSI 185 185 * mode otherwise setup APLIC direct mode. 186 186 */ 187 - if (is_of_node(dev->fwnode)) 188 - msi_mode = of_property_present(to_of_node(dev->fwnode), "msi-parent"); 187 + msi_mode = of_property_present(to_of_node(dev->fwnode), "msi-parent"); 189 188 if (msi_mode) 190 189 rc = aplic_msi_setup(dev, regs); 191 190 else
+2 -2
drivers/irqchip/irq-riscv-intc.c
··· 26 26 static unsigned int riscv_intc_custom_base __ro_after_init = BITS_PER_LONG; 27 27 static unsigned int riscv_intc_custom_nr_irqs __ro_after_init; 28 28 29 - static asmlinkage void riscv_intc_irq(struct pt_regs *regs) 29 + static void riscv_intc_irq(struct pt_regs *regs) 30 30 { 31 31 unsigned long cause = regs->cause & ~CAUSE_IRQ_FLAG; 32 32 ··· 34 34 pr_warn_ratelimited("Failed to handle interrupt (cause: %ld)\n", cause); 35 35 } 36 36 37 - static asmlinkage void riscv_intc_aia_irq(struct pt_regs *regs) 37 + static void riscv_intc_aia_irq(struct pt_regs *regs) 38 38 { 39 39 unsigned long topi; 40 40
+4 -666
drivers/irqchip/irq-stm32-exti.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 3 * Copyright (C) Maxime Coquelin 2015 4 - * Copyright (C) STMicroelectronics 2017 4 + * Copyright (C) STMicroelectronics 2017-2024 5 5 * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com> 6 6 */ 7 7 8 8 #include <linux/bitops.h> 9 - #include <linux/delay.h> 10 - #include <linux/hwspinlock.h> 11 9 #include <linux/interrupt.h> 12 10 #include <linux/io.h> 13 11 #include <linux/irq.h> 14 12 #include <linux/irqchip.h> 15 13 #include <linux/irqchip/chained_irq.h> 16 14 #include <linux/irqdomain.h> 17 - #include <linux/mod_devicetable.h> 18 - #include <linux/module.h> 19 15 #include <linux/of_address.h> 20 16 #include <linux/of_irq.h> 21 - #include <linux/platform_device.h> 22 - #include <linux/pm.h> 23 - 24 - #include <dt-bindings/interrupt-controller/arm-gic.h> 25 17 26 18 #define IRQS_PER_BANK 32 27 - 28 - #define HWSPNLCK_TIMEOUT 1000 /* usec */ 29 - 30 - #define EXTI_EnCIDCFGR(n) (0x180 + (n) * 4) 31 - #define EXTI_HWCFGR1 0x3f0 32 - 33 - /* Register: EXTI_EnCIDCFGR(n) */ 34 - #define EXTI_CIDCFGR_CFEN_MASK BIT(0) 35 - #define EXTI_CIDCFGR_CID_MASK GENMASK(6, 4) 36 - #define EXTI_CIDCFGR_CID_SHIFT 4 37 - 38 - /* Register: EXTI_HWCFGR1 */ 39 - #define EXTI_HWCFGR1_CIDWIDTH_MASK GENMASK(27, 24) 40 - 41 - #define EXTI_CID1 1 42 19 43 20 struct stm32_exti_bank { 44 21 u32 imr_ofst; ··· 24 47 u32 ftsr_ofst; 25 48 u32 swier_ofst; 26 49 u32 rpr_ofst; 27 - u32 fpr_ofst; 28 - u32 trg_ofst; 29 - u32 seccfgr_ofst; 30 50 }; 31 - 32 - #define UNDEF_REG ~0 33 51 34 52 struct stm32_exti_drv_data { 35 53 const struct stm32_exti_bank **exti_banks; ··· 35 63 struct stm32_exti_chip_data { 36 64 struct stm32_exti_host_data *host_data; 37 65 const struct stm32_exti_bank *reg_bank; 38 - struct raw_spinlock rlock; 39 66 u32 wake_active; 40 67 u32 mask_cache; 41 68 u32 rtsr_cache; ··· 47 76 struct device *dev; 48 77 struct stm32_exti_chip_data *chips_data; 49 78 const struct stm32_exti_drv_data *drv_data; 50 - struct hwspinlock *hwlock; 51 - bool dt_has_irqs_desc; /* skip internal desc_irqs array and get it from DT */ 52 79 }; 53 80 54 81 static const struct stm32_exti_bank stm32f4xx_exti_b1 = { ··· 56 87 .ftsr_ofst = 0x0C, 57 88 .swier_ofst = 0x10, 58 89 .rpr_ofst = 0x14, 59 - .fpr_ofst = UNDEF_REG, 60 - .trg_ofst = UNDEF_REG, 61 - .seccfgr_ofst = UNDEF_REG, 62 90 }; 63 91 64 92 static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = { ··· 74 108 .ftsr_ofst = 0x04, 75 109 .swier_ofst = 0x08, 76 110 .rpr_ofst = 0x88, 77 - .fpr_ofst = UNDEF_REG, 78 - .trg_ofst = UNDEF_REG, 79 - .seccfgr_ofst = UNDEF_REG, 80 111 }; 81 112 82 113 static const struct stm32_exti_bank stm32h7xx_exti_b2 = { ··· 83 120 .ftsr_ofst = 0x24, 84 121 .swier_ofst = 0x28, 85 122 .rpr_ofst = 0x98, 86 - .fpr_ofst = UNDEF_REG, 87 - .trg_ofst = UNDEF_REG, 88 - .seccfgr_ofst = UNDEF_REG, 89 123 }; 90 124 91 125 static const struct stm32_exti_bank stm32h7xx_exti_b3 = { ··· 92 132 .ftsr_ofst = 0x44, 93 133 .swier_ofst = 0x48, 94 134 .rpr_ofst = 0xA8, 95 - .fpr_ofst = UNDEF_REG, 96 - .trg_ofst = UNDEF_REG, 97 - .seccfgr_ofst = UNDEF_REG, 98 135 }; 99 136 100 137 static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = { ··· 105 148 .bank_nr = ARRAY_SIZE(stm32h7xx_exti_banks), 106 149 }; 107 150 108 - static const struct stm32_exti_bank stm32mp1_exti_b1 = { 109 - .imr_ofst = 0x80, 110 - .emr_ofst = UNDEF_REG, 111 - .rtsr_ofst = 0x00, 112 - .ftsr_ofst = 0x04, 113 - .swier_ofst = 0x08, 114 - .rpr_ofst = 0x0C, 115 - .fpr_ofst = 0x10, 116 - .trg_ofst = 0x3EC, 117 - .seccfgr_ofst = 0x14, 118 - }; 119 - 120 - static const struct stm32_exti_bank stm32mp1_exti_b2 = { 121 - .imr_ofst = 0x90, 122 - .emr_ofst = UNDEF_REG, 123 - .rtsr_ofst = 0x20, 124 - .ftsr_ofst = 0x24, 125 - .swier_ofst = 0x28, 126 - .rpr_ofst = 0x2C, 127 - .fpr_ofst = 0x30, 128 - .trg_ofst = 0x3E8, 129 - .seccfgr_ofst = 0x34, 130 - }; 131 - 132 - static const struct stm32_exti_bank stm32mp1_exti_b3 = { 133 - .imr_ofst = 0xA0, 134 - .emr_ofst = UNDEF_REG, 135 - .rtsr_ofst = 0x40, 136 - .ftsr_ofst = 0x44, 137 - .swier_ofst = 0x48, 138 - .rpr_ofst = 0x4C, 139 - .fpr_ofst = 0x50, 140 - .trg_ofst = 0x3E4, 141 - .seccfgr_ofst = 0x54, 142 - }; 143 - 144 - static const struct stm32_exti_bank *stm32mp1_exti_banks[] = { 145 - &stm32mp1_exti_b1, 146 - &stm32mp1_exti_b2, 147 - &stm32mp1_exti_b3, 148 - }; 149 - 150 - static struct irq_chip stm32_exti_h_chip; 151 - static struct irq_chip stm32_exti_h_chip_direct; 152 - 153 - #define EXTI_INVALID_IRQ U8_MAX 154 - #define STM32MP1_DESC_IRQ_SIZE (ARRAY_SIZE(stm32mp1_exti_banks) * IRQS_PER_BANK) 155 - 156 - /* 157 - * Use some intentionally tricky logic here to initialize the whole array to 158 - * EXTI_INVALID_IRQ, but then override certain fields, requiring us to indicate 159 - * that we "know" that there are overrides in this structure, and we'll need to 160 - * disable that warning from W=1 builds. 161 - */ 162 - __diag_push(); 163 - __diag_ignore_all("-Woverride-init", 164 - "logic to initialize all and then override some is OK"); 165 - 166 - static const u8 stm32mp1_desc_irq[] = { 167 - /* default value */ 168 - [0 ... (STM32MP1_DESC_IRQ_SIZE - 1)] = EXTI_INVALID_IRQ, 169 - 170 - [0] = 6, 171 - [1] = 7, 172 - [2] = 8, 173 - [3] = 9, 174 - [4] = 10, 175 - [5] = 23, 176 - [6] = 64, 177 - [7] = 65, 178 - [8] = 66, 179 - [9] = 67, 180 - [10] = 40, 181 - [11] = 42, 182 - [12] = 76, 183 - [13] = 77, 184 - [14] = 121, 185 - [15] = 127, 186 - [16] = 1, 187 - [19] = 3, 188 - [21] = 31, 189 - [22] = 33, 190 - [23] = 72, 191 - [24] = 95, 192 - [25] = 107, 193 - [26] = 37, 194 - [27] = 38, 195 - [28] = 39, 196 - [29] = 71, 197 - [30] = 52, 198 - [31] = 53, 199 - [32] = 82, 200 - [33] = 83, 201 - [46] = 151, 202 - [47] = 93, 203 - [48] = 138, 204 - [50] = 139, 205 - [52] = 140, 206 - [53] = 141, 207 - [54] = 135, 208 - [61] = 100, 209 - [65] = 144, 210 - [68] = 143, 211 - [70] = 62, 212 - [73] = 129, 213 - }; 214 - 215 - static const u8 stm32mp13_desc_irq[] = { 216 - /* default value */ 217 - [0 ... (STM32MP1_DESC_IRQ_SIZE - 1)] = EXTI_INVALID_IRQ, 218 - 219 - [0] = 6, 220 - [1] = 7, 221 - [2] = 8, 222 - [3] = 9, 223 - [4] = 10, 224 - [5] = 24, 225 - [6] = 65, 226 - [7] = 66, 227 - [8] = 67, 228 - [9] = 68, 229 - [10] = 41, 230 - [11] = 43, 231 - [12] = 77, 232 - [13] = 78, 233 - [14] = 106, 234 - [15] = 109, 235 - [16] = 1, 236 - [19] = 3, 237 - [21] = 32, 238 - [22] = 34, 239 - [23] = 73, 240 - [24] = 93, 241 - [25] = 114, 242 - [26] = 38, 243 - [27] = 39, 244 - [28] = 40, 245 - [29] = 72, 246 - [30] = 53, 247 - [31] = 54, 248 - [32] = 83, 249 - [33] = 84, 250 - [44] = 96, 251 - [47] = 92, 252 - [48] = 116, 253 - [50] = 117, 254 - [52] = 118, 255 - [53] = 119, 256 - [68] = 63, 257 - [70] = 98, 258 - }; 259 - 260 - __diag_pop(); 261 - 262 - static const struct stm32_exti_drv_data stm32mp1_drv_data = { 263 - .exti_banks = stm32mp1_exti_banks, 264 - .bank_nr = ARRAY_SIZE(stm32mp1_exti_banks), 265 - .desc_irqs = stm32mp1_desc_irq, 266 - }; 267 - 268 - static const struct stm32_exti_drv_data stm32mp13_drv_data = { 269 - .exti_banks = stm32mp1_exti_banks, 270 - .bank_nr = ARRAY_SIZE(stm32mp1_exti_banks), 271 - .desc_irqs = stm32mp13_desc_irq, 272 - }; 273 - 274 151 static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) 275 152 { 276 153 struct stm32_exti_chip_data *chip_data = gc->private; 277 154 const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; 278 - unsigned long pending; 279 155 280 - pending = irq_reg_readl(gc, stm32_bank->rpr_ofst); 281 - if (stm32_bank->fpr_ofst != UNDEF_REG) 282 - pending |= irq_reg_readl(gc, stm32_bank->fpr_ofst); 283 - 284 - return pending; 156 + return irq_reg_readl(gc, stm32_bank->rpr_ofst); 285 157 } 286 158 287 159 static void stm32_irq_handler(struct irq_desc *desc) ··· 166 380 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 167 381 struct stm32_exti_chip_data *chip_data = gc->private; 168 382 const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; 169 - struct hwspinlock *hwlock = chip_data->host_data->hwlock; 170 383 u32 rtsr, ftsr; 171 384 int err; 172 385 173 386 irq_gc_lock(gc); 174 - 175 - if (hwlock) { 176 - err = hwspin_lock_timeout_in_atomic(hwlock, HWSPNLCK_TIMEOUT); 177 - if (err) { 178 - pr_err("%s can't get hwspinlock (%d)\n", __func__, err); 179 - goto unlock; 180 - } 181 - } 182 387 183 388 rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); 184 389 ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); 185 390 186 391 err = stm32_exti_set_type(d, type, &rtsr, &ftsr); 187 392 if (err) 188 - goto unspinlock; 393 + goto unlock; 189 394 190 395 irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst); 191 396 irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); 192 397 193 - unspinlock: 194 - if (hwlock) 195 - hwspin_unlock_in_atomic(hwlock); 196 398 unlock: 197 399 irq_gc_unlock(gc); 198 400 ··· 268 494 irq_gc_lock(gc); 269 495 270 496 irq_reg_writel(gc, d->mask, stm32_bank->rpr_ofst); 271 - if (stm32_bank->fpr_ofst != UNDEF_REG) 272 - irq_reg_writel(gc, d->mask, stm32_bank->fpr_ofst); 273 497 274 498 irq_gc_unlock(gc); 275 - } 276 - 277 - /* directly set the target bit without reading first. */ 278 - static inline void stm32_exti_write_bit(struct irq_data *d, u32 reg) 279 - { 280 - struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 281 - void __iomem *base = chip_data->host_data->base; 282 - u32 val = BIT(d->hwirq % IRQS_PER_BANK); 283 - 284 - writel_relaxed(val, base + reg); 285 - } 286 - 287 - static inline u32 stm32_exti_set_bit(struct irq_data *d, u32 reg) 288 - { 289 - struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 290 - void __iomem *base = chip_data->host_data->base; 291 - u32 val; 292 - 293 - val = readl_relaxed(base + reg); 294 - val |= BIT(d->hwirq % IRQS_PER_BANK); 295 - writel_relaxed(val, base + reg); 296 - 297 - return val; 298 - } 299 - 300 - static inline u32 stm32_exti_clr_bit(struct irq_data *d, u32 reg) 301 - { 302 - struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 303 - void __iomem *base = chip_data->host_data->base; 304 - u32 val; 305 - 306 - val = readl_relaxed(base + reg); 307 - val &= ~BIT(d->hwirq % IRQS_PER_BANK); 308 - writel_relaxed(val, base + reg); 309 - 310 - return val; 311 - } 312 - 313 - static void stm32_exti_h_eoi(struct irq_data *d) 314 - { 315 - struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 316 - const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; 317 - 318 - raw_spin_lock(&chip_data->rlock); 319 - 320 - stm32_exti_write_bit(d, stm32_bank->rpr_ofst); 321 - if (stm32_bank->fpr_ofst != UNDEF_REG) 322 - stm32_exti_write_bit(d, stm32_bank->fpr_ofst); 323 - 324 - raw_spin_unlock(&chip_data->rlock); 325 - 326 - if (d->parent_data->chip) 327 - irq_chip_eoi_parent(d); 328 - } 329 - 330 - static void stm32_exti_h_mask(struct irq_data *d) 331 - { 332 - struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 333 - const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; 334 - 335 - raw_spin_lock(&chip_data->rlock); 336 - chip_data->mask_cache = stm32_exti_clr_bit(d, stm32_bank->imr_ofst); 337 - raw_spin_unlock(&chip_data->rlock); 338 - 339 - if (d->parent_data->chip) 340 - irq_chip_mask_parent(d); 341 - } 342 - 343 - static void stm32_exti_h_unmask(struct irq_data *d) 344 - { 345 - struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 346 - const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; 347 - 348 - raw_spin_lock(&chip_data->rlock); 349 - chip_data->mask_cache = stm32_exti_set_bit(d, stm32_bank->imr_ofst); 350 - raw_spin_unlock(&chip_data->rlock); 351 - 352 - if (d->parent_data->chip) 353 - irq_chip_unmask_parent(d); 354 - } 355 - 356 - static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) 357 - { 358 - struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 359 - const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; 360 - struct hwspinlock *hwlock = chip_data->host_data->hwlock; 361 - void __iomem *base = chip_data->host_data->base; 362 - u32 rtsr, ftsr; 363 - int err; 364 - 365 - raw_spin_lock(&chip_data->rlock); 366 - 367 - if (hwlock) { 368 - err = hwspin_lock_timeout_in_atomic(hwlock, HWSPNLCK_TIMEOUT); 369 - if (err) { 370 - pr_err("%s can't get hwspinlock (%d)\n", __func__, err); 371 - goto unlock; 372 - } 373 - } 374 - 375 - rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst); 376 - ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst); 377 - 378 - err = stm32_exti_set_type(d, type, &rtsr, &ftsr); 379 - if (err) 380 - goto unspinlock; 381 - 382 - writel_relaxed(rtsr, base + stm32_bank->rtsr_ofst); 383 - writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst); 384 - 385 - unspinlock: 386 - if (hwlock) 387 - hwspin_unlock_in_atomic(hwlock); 388 - unlock: 389 - raw_spin_unlock(&chip_data->rlock); 390 - 391 - return err; 392 - } 393 - 394 - static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) 395 - { 396 - struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 397 - u32 mask = BIT(d->hwirq % IRQS_PER_BANK); 398 - 399 - raw_spin_lock(&chip_data->rlock); 400 - 401 - if (on) 402 - chip_data->wake_active |= mask; 403 - else 404 - chip_data->wake_active &= ~mask; 405 - 406 - raw_spin_unlock(&chip_data->rlock); 407 - 408 - return 0; 409 - } 410 - 411 - static int stm32_exti_h_set_affinity(struct irq_data *d, 412 - const struct cpumask *dest, bool force) 413 - { 414 - if (d->parent_data->chip) 415 - return irq_chip_set_affinity_parent(d, dest, force); 416 - 417 - return IRQ_SET_MASK_OK_DONE; 418 - } 419 - 420 - static int stm32_exti_h_suspend(struct device *dev) 421 - { 422 - struct stm32_exti_host_data *host_data = dev_get_drvdata(dev); 423 - struct stm32_exti_chip_data *chip_data; 424 - int i; 425 - 426 - for (i = 0; i < host_data->drv_data->bank_nr; i++) { 427 - chip_data = &host_data->chips_data[i]; 428 - stm32_chip_suspend(chip_data, chip_data->wake_active); 429 - } 430 - 431 - return 0; 432 - } 433 - 434 - static int stm32_exti_h_resume(struct device *dev) 435 - { 436 - struct stm32_exti_host_data *host_data = dev_get_drvdata(dev); 437 - struct stm32_exti_chip_data *chip_data; 438 - int i; 439 - 440 - for (i = 0; i < host_data->drv_data->bank_nr; i++) { 441 - chip_data = &host_data->chips_data[i]; 442 - stm32_chip_resume(chip_data, chip_data->mask_cache); 443 - } 444 - 445 - return 0; 446 - } 447 - 448 - static int stm32_exti_h_retrigger(struct irq_data *d) 449 - { 450 - struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 451 - const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; 452 - void __iomem *base = chip_data->host_data->base; 453 - u32 mask = BIT(d->hwirq % IRQS_PER_BANK); 454 - 455 - writel_relaxed(mask, base + stm32_bank->swier_ofst); 456 - 457 - return 0; 458 - } 459 - 460 - static struct irq_chip stm32_exti_h_chip = { 461 - .name = "stm32-exti-h", 462 - .irq_eoi = stm32_exti_h_eoi, 463 - .irq_mask = stm32_exti_h_mask, 464 - .irq_unmask = stm32_exti_h_unmask, 465 - .irq_retrigger = stm32_exti_h_retrigger, 466 - .irq_set_type = stm32_exti_h_set_type, 467 - .irq_set_wake = stm32_exti_h_set_wake, 468 - .flags = IRQCHIP_MASK_ON_SUSPEND, 469 - .irq_set_affinity = IS_ENABLED(CONFIG_SMP) ? stm32_exti_h_set_affinity : NULL, 470 - }; 471 - 472 - static struct irq_chip stm32_exti_h_chip_direct = { 473 - .name = "stm32-exti-h-direct", 474 - .irq_eoi = irq_chip_eoi_parent, 475 - .irq_ack = irq_chip_ack_parent, 476 - .irq_mask = stm32_exti_h_mask, 477 - .irq_unmask = stm32_exti_h_unmask, 478 - .irq_retrigger = irq_chip_retrigger_hierarchy, 479 - .irq_set_type = irq_chip_set_type_parent, 480 - .irq_set_wake = stm32_exti_h_set_wake, 481 - .flags = IRQCHIP_MASK_ON_SUSPEND, 482 - .irq_set_affinity = IS_ENABLED(CONFIG_SMP) ? irq_chip_set_affinity_parent : NULL, 483 - }; 484 - 485 - static int stm32_exti_h_domain_alloc(struct irq_domain *dm, 486 - unsigned int virq, 487 - unsigned int nr_irqs, void *data) 488 - { 489 - struct stm32_exti_host_data *host_data = dm->host_data; 490 - struct stm32_exti_chip_data *chip_data; 491 - u8 desc_irq; 492 - struct irq_fwspec *fwspec = data; 493 - struct irq_fwspec p_fwspec; 494 - irq_hw_number_t hwirq; 495 - int bank; 496 - u32 event_trg; 497 - struct irq_chip *chip; 498 - 499 - hwirq = fwspec->param[0]; 500 - if (hwirq >= host_data->drv_data->bank_nr * IRQS_PER_BANK) 501 - return -EINVAL; 502 - 503 - bank = hwirq / IRQS_PER_BANK; 504 - chip_data = &host_data->chips_data[bank]; 505 - 506 - /* Check if event is reserved (Secure) */ 507 - if (chip_data->event_reserved & BIT(hwirq % IRQS_PER_BANK)) { 508 - dev_err(host_data->dev, "event %lu is reserved, secure\n", hwirq); 509 - return -EPERM; 510 - } 511 - 512 - event_trg = readl_relaxed(host_data->base + chip_data->reg_bank->trg_ofst); 513 - chip = (event_trg & BIT(hwirq % IRQS_PER_BANK)) ? 514 - &stm32_exti_h_chip : &stm32_exti_h_chip_direct; 515 - 516 - irq_domain_set_hwirq_and_chip(dm, virq, hwirq, chip, chip_data); 517 - 518 - if (host_data->dt_has_irqs_desc) { 519 - struct of_phandle_args out_irq; 520 - int ret; 521 - 522 - ret = of_irq_parse_one(host_data->dev->of_node, hwirq, &out_irq); 523 - if (ret) 524 - return ret; 525 - /* we only support one parent, so far */ 526 - if (of_node_to_fwnode(out_irq.np) != dm->parent->fwnode) 527 - return -EINVAL; 528 - 529 - of_phandle_args_to_fwspec(out_irq.np, out_irq.args, 530 - out_irq.args_count, &p_fwspec); 531 - 532 - return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec); 533 - } 534 - 535 - if (!host_data->drv_data->desc_irqs) 536 - return -EINVAL; 537 - 538 - desc_irq = host_data->drv_data->desc_irqs[hwirq]; 539 - if (desc_irq != EXTI_INVALID_IRQ) { 540 - p_fwspec.fwnode = dm->parent->fwnode; 541 - p_fwspec.param_count = 3; 542 - p_fwspec.param[0] = GIC_SPI; 543 - p_fwspec.param[1] = desc_irq; 544 - p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; 545 - 546 - return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec); 547 - } 548 - 549 - return 0; 550 499 } 551 500 552 501 static struct ··· 319 822 chip_data->host_data = h_data; 320 823 chip_data->reg_bank = stm32_bank; 321 824 322 - raw_spin_lock_init(&chip_data->rlock); 323 - 324 825 /* 325 826 * This IP has no reset, so after hot reboot we should 326 827 * clear registers to avoid residue 327 828 */ 328 829 writel_relaxed(0, base + stm32_bank->imr_ofst); 329 - if (stm32_bank->emr_ofst != UNDEF_REG) 330 - writel_relaxed(0, base + stm32_bank->emr_ofst); 331 - 332 - /* reserve Secure events */ 333 - if (stm32_bank->seccfgr_ofst != UNDEF_REG) 334 - chip_data->event_reserved = readl_relaxed(base + stm32_bank->seccfgr_ofst); 830 + writel_relaxed(0, base + stm32_bank->emr_ofst); 335 831 336 832 pr_info("%pOF: bank%d\n", node, bank_idx); 337 833 ··· 404 914 return ret; 405 915 } 406 916 407 - static const struct irq_domain_ops stm32_exti_h_domain_ops = { 408 - .alloc = stm32_exti_h_domain_alloc, 409 - .free = irq_domain_free_irqs_common, 410 - .xlate = irq_domain_xlate_twocell, 411 - }; 412 - 413 - static void stm32_exti_check_rif(struct stm32_exti_host_data *host_data) 414 - { 415 - unsigned int bank, i, event; 416 - u32 cid, cidcfgr, hwcfgr1; 417 - 418 - /* quit on CID not supported */ 419 - hwcfgr1 = readl_relaxed(host_data->base + EXTI_HWCFGR1); 420 - if ((hwcfgr1 & EXTI_HWCFGR1_CIDWIDTH_MASK) == 0) 421 - return; 422 - 423 - for (bank = 0; bank < host_data->drv_data->bank_nr; bank++) { 424 - for (i = 0; i < IRQS_PER_BANK; i++) { 425 - event = bank * IRQS_PER_BANK + i; 426 - cidcfgr = readl_relaxed(host_data->base + EXTI_EnCIDCFGR(event)); 427 - cid = (cidcfgr & EXTI_CIDCFGR_CID_MASK) >> EXTI_CIDCFGR_CID_SHIFT; 428 - if ((cidcfgr & EXTI_CIDCFGR_CFEN_MASK) && cid != EXTI_CID1) 429 - host_data->chips_data[bank].event_reserved |= BIT(i); 430 - } 431 - } 432 - } 433 - 434 - static void stm32_exti_remove_irq(void *data) 435 - { 436 - struct irq_domain *domain = data; 437 - 438 - irq_domain_remove(domain); 439 - } 440 - 441 - static int stm32_exti_probe(struct platform_device *pdev) 442 - { 443 - int ret, i; 444 - struct device *dev = &pdev->dev; 445 - struct device_node *np = dev->of_node; 446 - struct irq_domain *parent_domain, *domain; 447 - struct stm32_exti_host_data *host_data; 448 - const struct stm32_exti_drv_data *drv_data; 449 - 450 - host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL); 451 - if (!host_data) 452 - return -ENOMEM; 453 - 454 - dev_set_drvdata(dev, host_data); 455 - host_data->dev = dev; 456 - 457 - /* check for optional hwspinlock which may be not available yet */ 458 - ret = of_hwspin_lock_get_id(np, 0); 459 - if (ret == -EPROBE_DEFER) 460 - /* hwspinlock framework not yet ready */ 461 - return ret; 462 - 463 - if (ret >= 0) { 464 - host_data->hwlock = devm_hwspin_lock_request_specific(dev, ret); 465 - if (!host_data->hwlock) { 466 - dev_err(dev, "Failed to request hwspinlock\n"); 467 - return -EINVAL; 468 - } 469 - } else if (ret != -ENOENT) { 470 - /* note: ENOENT is a valid case (means 'no hwspinlock') */ 471 - dev_err(dev, "Failed to get hwspinlock\n"); 472 - return ret; 473 - } 474 - 475 - /* initialize host_data */ 476 - drv_data = of_device_get_match_data(dev); 477 - if (!drv_data) { 478 - dev_err(dev, "no of match data\n"); 479 - return -ENODEV; 480 - } 481 - host_data->drv_data = drv_data; 482 - 483 - host_data->chips_data = devm_kcalloc(dev, drv_data->bank_nr, 484 - sizeof(*host_data->chips_data), 485 - GFP_KERNEL); 486 - if (!host_data->chips_data) 487 - return -ENOMEM; 488 - 489 - host_data->base = devm_platform_ioremap_resource(pdev, 0); 490 - if (IS_ERR(host_data->base)) 491 - return PTR_ERR(host_data->base); 492 - 493 - for (i = 0; i < drv_data->bank_nr; i++) 494 - stm32_exti_chip_init(host_data, i, np); 495 - 496 - stm32_exti_check_rif(host_data); 497 - 498 - parent_domain = irq_find_host(of_irq_find_parent(np)); 499 - if (!parent_domain) { 500 - dev_err(dev, "GIC interrupt-parent not found\n"); 501 - return -EINVAL; 502 - } 503 - 504 - domain = irq_domain_add_hierarchy(parent_domain, 0, 505 - drv_data->bank_nr * IRQS_PER_BANK, 506 - np, &stm32_exti_h_domain_ops, 507 - host_data); 508 - 509 - if (!domain) { 510 - dev_err(dev, "Could not register exti domain\n"); 511 - return -ENOMEM; 512 - } 513 - 514 - ret = devm_add_action_or_reset(dev, stm32_exti_remove_irq, domain); 515 - if (ret) 516 - return ret; 517 - 518 - if (of_property_read_bool(np, "interrupts-extended")) 519 - host_data->dt_has_irqs_desc = true; 520 - 521 - return 0; 522 - } 523 - 524 - /* platform driver only for MP1 */ 525 - static const struct of_device_id stm32_exti_ids[] = { 526 - { .compatible = "st,stm32mp1-exti", .data = &stm32mp1_drv_data}, 527 - { .compatible = "st,stm32mp13-exti", .data = &stm32mp13_drv_data}, 528 - {}, 529 - }; 530 - MODULE_DEVICE_TABLE(of, stm32_exti_ids); 531 - 532 - static const struct dev_pm_ops stm32_exti_dev_pm_ops = { 533 - NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_exti_h_suspend, stm32_exti_h_resume) 534 - }; 535 - 536 - static struct platform_driver stm32_exti_driver = { 537 - .probe = stm32_exti_probe, 538 - .driver = { 539 - .name = "stm32_exti", 540 - .of_match_table = stm32_exti_ids, 541 - .pm = &stm32_exti_dev_pm_ops, 542 - }, 543 - }; 544 - 545 - static int __init stm32_exti_arch_init(void) 546 - { 547 - return platform_driver_register(&stm32_exti_driver); 548 - } 549 - 550 - static void __exit stm32_exti_arch_exit(void) 551 - { 552 - return platform_driver_unregister(&stm32_exti_driver); 553 - } 554 - 555 - arch_initcall(stm32_exti_arch_init); 556 - module_exit(stm32_exti_arch_exit); 557 - 558 - /* no platform driver for F4 and H7 */ 559 917 static int __init stm32f4_exti_of_init(struct device_node *np, 560 918 struct device_node *parent) 561 919 {
+729
drivers/irqchip/irq-stm32mp-exti.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) Maxime Coquelin 2015 4 + * Copyright (C) STMicroelectronics 2017-2024 5 + * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com> 6 + */ 7 + 8 + #include <linux/bitops.h> 9 + #include <linux/hwspinlock.h> 10 + #include <linux/interrupt.h> 11 + #include <linux/io.h> 12 + #include <linux/irq.h> 13 + #include <linux/irqchip.h> 14 + #include <linux/irqdomain.h> 15 + #include <linux/mod_devicetable.h> 16 + #include <linux/module.h> 17 + #include <linux/of_address.h> 18 + #include <linux/of_irq.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/pm.h> 21 + 22 + #include <dt-bindings/interrupt-controller/arm-gic.h> 23 + 24 + #define IRQS_PER_BANK 32 25 + 26 + #define HWSPNLCK_TIMEOUT 1000 /* usec */ 27 + 28 + #define EXTI_EnCIDCFGR(n) (0x180 + (n) * 4) 29 + #define EXTI_HWCFGR1 0x3f0 30 + 31 + /* Register: EXTI_EnCIDCFGR(n) */ 32 + #define EXTI_CIDCFGR_CFEN_MASK BIT(0) 33 + #define EXTI_CIDCFGR_CID_MASK GENMASK(6, 4) 34 + #define EXTI_CIDCFGR_CID_SHIFT 4 35 + 36 + /* Register: EXTI_HWCFGR1 */ 37 + #define EXTI_HWCFGR1_CIDWIDTH_MASK GENMASK(27, 24) 38 + 39 + #define EXTI_CID1 1 40 + 41 + struct stm32mp_exti_bank { 42 + u32 imr_ofst; 43 + u32 rtsr_ofst; 44 + u32 ftsr_ofst; 45 + u32 swier_ofst; 46 + u32 rpr_ofst; 47 + u32 fpr_ofst; 48 + u32 trg_ofst; 49 + u32 seccfgr_ofst; 50 + }; 51 + 52 + struct stm32mp_exti_drv_data { 53 + const struct stm32mp_exti_bank **exti_banks; 54 + const u8 *desc_irqs; 55 + u32 bank_nr; 56 + }; 57 + 58 + struct stm32mp_exti_chip_data { 59 + struct stm32mp_exti_host_data *host_data; 60 + const struct stm32mp_exti_bank *reg_bank; 61 + struct raw_spinlock rlock; 62 + u32 wake_active; 63 + u32 mask_cache; 64 + u32 rtsr_cache; 65 + u32 ftsr_cache; 66 + u32 event_reserved; 67 + }; 68 + 69 + struct stm32mp_exti_host_data { 70 + void __iomem *base; 71 + struct device *dev; 72 + struct stm32mp_exti_chip_data *chips_data; 73 + const struct stm32mp_exti_drv_data *drv_data; 74 + struct hwspinlock *hwlock; 75 + /* skip internal desc_irqs array and get it from DT */ 76 + bool dt_has_irqs_desc; 77 + }; 78 + 79 + static const struct stm32mp_exti_bank stm32mp_exti_b1 = { 80 + .imr_ofst = 0x80, 81 + .rtsr_ofst = 0x00, 82 + .ftsr_ofst = 0x04, 83 + .swier_ofst = 0x08, 84 + .rpr_ofst = 0x0C, 85 + .fpr_ofst = 0x10, 86 + .trg_ofst = 0x3EC, 87 + .seccfgr_ofst = 0x14, 88 + }; 89 + 90 + static const struct stm32mp_exti_bank stm32mp_exti_b2 = { 91 + .imr_ofst = 0x90, 92 + .rtsr_ofst = 0x20, 93 + .ftsr_ofst = 0x24, 94 + .swier_ofst = 0x28, 95 + .rpr_ofst = 0x2C, 96 + .fpr_ofst = 0x30, 97 + .trg_ofst = 0x3E8, 98 + .seccfgr_ofst = 0x34, 99 + }; 100 + 101 + static const struct stm32mp_exti_bank stm32mp_exti_b3 = { 102 + .imr_ofst = 0xA0, 103 + .rtsr_ofst = 0x40, 104 + .ftsr_ofst = 0x44, 105 + .swier_ofst = 0x48, 106 + .rpr_ofst = 0x4C, 107 + .fpr_ofst = 0x50, 108 + .trg_ofst = 0x3E4, 109 + .seccfgr_ofst = 0x54, 110 + }; 111 + 112 + static const struct stm32mp_exti_bank *stm32mp_exti_banks[] = { 113 + &stm32mp_exti_b1, 114 + &stm32mp_exti_b2, 115 + &stm32mp_exti_b3, 116 + }; 117 + 118 + static struct irq_chip stm32mp_exti_chip; 119 + static struct irq_chip stm32mp_exti_chip_direct; 120 + 121 + #define EXTI_INVALID_IRQ U8_MAX 122 + #define STM32MP_DESC_IRQ_SIZE (ARRAY_SIZE(stm32mp_exti_banks) * IRQS_PER_BANK) 123 + 124 + /* 125 + * Use some intentionally tricky logic here to initialize the whole array to 126 + * EXTI_INVALID_IRQ, but then override certain fields, requiring us to indicate 127 + * that we "know" that there are overrides in this structure, and we'll need to 128 + * disable that warning from W=1 builds. 129 + */ 130 + __diag_push(); 131 + __diag_ignore_all("-Woverride-init", 132 + "logic to initialize all and then override some is OK"); 133 + 134 + static const u8 stm32mp1_desc_irq[] = { 135 + /* default value */ 136 + [0 ... (STM32MP_DESC_IRQ_SIZE - 1)] = EXTI_INVALID_IRQ, 137 + 138 + [0] = 6, 139 + [1] = 7, 140 + [2] = 8, 141 + [3] = 9, 142 + [4] = 10, 143 + [5] = 23, 144 + [6] = 64, 145 + [7] = 65, 146 + [8] = 66, 147 + [9] = 67, 148 + [10] = 40, 149 + [11] = 42, 150 + [12] = 76, 151 + [13] = 77, 152 + [14] = 121, 153 + [15] = 127, 154 + [16] = 1, 155 + [19] = 3, 156 + [21] = 31, 157 + [22] = 33, 158 + [23] = 72, 159 + [24] = 95, 160 + [25] = 107, 161 + [26] = 37, 162 + [27] = 38, 163 + [28] = 39, 164 + [29] = 71, 165 + [30] = 52, 166 + [31] = 53, 167 + [32] = 82, 168 + [33] = 83, 169 + [46] = 151, 170 + [47] = 93, 171 + [48] = 138, 172 + [50] = 139, 173 + [52] = 140, 174 + [53] = 141, 175 + [54] = 135, 176 + [61] = 100, 177 + [65] = 144, 178 + [68] = 143, 179 + [70] = 62, 180 + [73] = 129, 181 + }; 182 + 183 + static const u8 stm32mp13_desc_irq[] = { 184 + /* default value */ 185 + [0 ... (STM32MP_DESC_IRQ_SIZE - 1)] = EXTI_INVALID_IRQ, 186 + 187 + [0] = 6, 188 + [1] = 7, 189 + [2] = 8, 190 + [3] = 9, 191 + [4] = 10, 192 + [5] = 24, 193 + [6] = 65, 194 + [7] = 66, 195 + [8] = 67, 196 + [9] = 68, 197 + [10] = 41, 198 + [11] = 43, 199 + [12] = 77, 200 + [13] = 78, 201 + [14] = 106, 202 + [15] = 109, 203 + [16] = 1, 204 + [19] = 3, 205 + [21] = 32, 206 + [22] = 34, 207 + [23] = 73, 208 + [24] = 93, 209 + [25] = 114, 210 + [26] = 38, 211 + [27] = 39, 212 + [28] = 40, 213 + [29] = 72, 214 + [30] = 53, 215 + [31] = 54, 216 + [32] = 83, 217 + [33] = 84, 218 + [44] = 96, 219 + [47] = 92, 220 + [48] = 116, 221 + [50] = 117, 222 + [52] = 118, 223 + [53] = 119, 224 + [68] = 63, 225 + [70] = 98, 226 + }; 227 + 228 + __diag_pop(); 229 + 230 + static const struct stm32mp_exti_drv_data stm32mp1_drv_data = { 231 + .exti_banks = stm32mp_exti_banks, 232 + .bank_nr = ARRAY_SIZE(stm32mp_exti_banks), 233 + .desc_irqs = stm32mp1_desc_irq, 234 + }; 235 + 236 + static const struct stm32mp_exti_drv_data stm32mp13_drv_data = { 237 + .exti_banks = stm32mp_exti_banks, 238 + .bank_nr = ARRAY_SIZE(stm32mp_exti_banks), 239 + .desc_irqs = stm32mp13_desc_irq, 240 + }; 241 + 242 + static int stm32mp_exti_convert_type(struct irq_data *d, unsigned int type, u32 *rtsr, u32 *ftsr) 243 + { 244 + u32 mask = BIT(d->hwirq % IRQS_PER_BANK); 245 + 246 + switch (type) { 247 + case IRQ_TYPE_EDGE_RISING: 248 + *rtsr |= mask; 249 + *ftsr &= ~mask; 250 + break; 251 + case IRQ_TYPE_EDGE_FALLING: 252 + *rtsr &= ~mask; 253 + *ftsr |= mask; 254 + break; 255 + case IRQ_TYPE_EDGE_BOTH: 256 + *rtsr |= mask; 257 + *ftsr |= mask; 258 + break; 259 + default: 260 + return -EINVAL; 261 + } 262 + 263 + return 0; 264 + } 265 + 266 + static void stm32mp_chip_suspend(struct stm32mp_exti_chip_data *chip_data, u32 wake_active) 267 + { 268 + const struct stm32mp_exti_bank *bank = chip_data->reg_bank; 269 + void __iomem *base = chip_data->host_data->base; 270 + 271 + /* save rtsr, ftsr registers */ 272 + chip_data->rtsr_cache = readl_relaxed(base + bank->rtsr_ofst); 273 + chip_data->ftsr_cache = readl_relaxed(base + bank->ftsr_ofst); 274 + 275 + writel_relaxed(wake_active, base + bank->imr_ofst); 276 + } 277 + 278 + static void stm32mp_chip_resume(struct stm32mp_exti_chip_data *chip_data, u32 mask_cache) 279 + { 280 + const struct stm32mp_exti_bank *bank = chip_data->reg_bank; 281 + void __iomem *base = chip_data->host_data->base; 282 + 283 + /* restore rtsr, ftsr, registers */ 284 + writel_relaxed(chip_data->rtsr_cache, base + bank->rtsr_ofst); 285 + writel_relaxed(chip_data->ftsr_cache, base + bank->ftsr_ofst); 286 + 287 + writel_relaxed(mask_cache, base + bank->imr_ofst); 288 + } 289 + 290 + /* directly set the target bit without reading first. */ 291 + static inline void stm32mp_exti_write_bit(struct irq_data *d, u32 reg) 292 + { 293 + struct stm32mp_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 294 + void __iomem *base = chip_data->host_data->base; 295 + u32 val = BIT(d->hwirq % IRQS_PER_BANK); 296 + 297 + writel_relaxed(val, base + reg); 298 + } 299 + 300 + static inline u32 stm32mp_exti_set_bit(struct irq_data *d, u32 reg) 301 + { 302 + struct stm32mp_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 303 + void __iomem *base = chip_data->host_data->base; 304 + u32 val; 305 + 306 + val = readl_relaxed(base + reg); 307 + val |= BIT(d->hwirq % IRQS_PER_BANK); 308 + writel_relaxed(val, base + reg); 309 + 310 + return val; 311 + } 312 + 313 + static inline u32 stm32mp_exti_clr_bit(struct irq_data *d, u32 reg) 314 + { 315 + struct stm32mp_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 316 + void __iomem *base = chip_data->host_data->base; 317 + u32 val; 318 + 319 + val = readl_relaxed(base + reg); 320 + val &= ~BIT(d->hwirq % IRQS_PER_BANK); 321 + writel_relaxed(val, base + reg); 322 + 323 + return val; 324 + } 325 + 326 + static void stm32mp_exti_eoi(struct irq_data *d) 327 + { 328 + struct stm32mp_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 329 + const struct stm32mp_exti_bank *bank = chip_data->reg_bank; 330 + 331 + raw_spin_lock(&chip_data->rlock); 332 + 333 + stm32mp_exti_write_bit(d, bank->rpr_ofst); 334 + stm32mp_exti_write_bit(d, bank->fpr_ofst); 335 + 336 + raw_spin_unlock(&chip_data->rlock); 337 + 338 + if (d->parent_data->chip) 339 + irq_chip_eoi_parent(d); 340 + } 341 + 342 + static void stm32mp_exti_mask(struct irq_data *d) 343 + { 344 + struct stm32mp_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 345 + const struct stm32mp_exti_bank *bank = chip_data->reg_bank; 346 + 347 + raw_spin_lock(&chip_data->rlock); 348 + chip_data->mask_cache = stm32mp_exti_clr_bit(d, bank->imr_ofst); 349 + raw_spin_unlock(&chip_data->rlock); 350 + 351 + if (d->parent_data->chip) 352 + irq_chip_mask_parent(d); 353 + } 354 + 355 + static void stm32mp_exti_unmask(struct irq_data *d) 356 + { 357 + struct stm32mp_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 358 + const struct stm32mp_exti_bank *bank = chip_data->reg_bank; 359 + 360 + raw_spin_lock(&chip_data->rlock); 361 + chip_data->mask_cache = stm32mp_exti_set_bit(d, bank->imr_ofst); 362 + raw_spin_unlock(&chip_data->rlock); 363 + 364 + if (d->parent_data->chip) 365 + irq_chip_unmask_parent(d); 366 + } 367 + 368 + static int stm32mp_exti_set_type(struct irq_data *d, unsigned int type) 369 + { 370 + struct stm32mp_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 371 + const struct stm32mp_exti_bank *bank = chip_data->reg_bank; 372 + struct hwspinlock *hwlock = chip_data->host_data->hwlock; 373 + void __iomem *base = chip_data->host_data->base; 374 + u32 rtsr, ftsr; 375 + int err; 376 + 377 + raw_spin_lock(&chip_data->rlock); 378 + 379 + if (hwlock) { 380 + err = hwspin_lock_timeout_in_atomic(hwlock, HWSPNLCK_TIMEOUT); 381 + if (err) { 382 + pr_err("%s can't get hwspinlock (%d)\n", __func__, err); 383 + goto unlock; 384 + } 385 + } 386 + 387 + rtsr = readl_relaxed(base + bank->rtsr_ofst); 388 + ftsr = readl_relaxed(base + bank->ftsr_ofst); 389 + 390 + err = stm32mp_exti_convert_type(d, type, &rtsr, &ftsr); 391 + if (!err) { 392 + writel_relaxed(rtsr, base + bank->rtsr_ofst); 393 + writel_relaxed(ftsr, base + bank->ftsr_ofst); 394 + } 395 + 396 + if (hwlock) 397 + hwspin_unlock_in_atomic(hwlock); 398 + unlock: 399 + raw_spin_unlock(&chip_data->rlock); 400 + return err; 401 + } 402 + 403 + static int stm32mp_exti_set_wake(struct irq_data *d, unsigned int on) 404 + { 405 + struct stm32mp_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 406 + u32 mask = BIT(d->hwirq % IRQS_PER_BANK); 407 + 408 + raw_spin_lock(&chip_data->rlock); 409 + 410 + if (on) 411 + chip_data->wake_active |= mask; 412 + else 413 + chip_data->wake_active &= ~mask; 414 + 415 + raw_spin_unlock(&chip_data->rlock); 416 + 417 + return 0; 418 + } 419 + 420 + static int stm32mp_exti_set_affinity(struct irq_data *d, const struct cpumask *dest, bool force) 421 + { 422 + if (d->parent_data->chip) 423 + return irq_chip_set_affinity_parent(d, dest, force); 424 + 425 + return IRQ_SET_MASK_OK_DONE; 426 + } 427 + 428 + static int stm32mp_exti_suspend(struct device *dev) 429 + { 430 + struct stm32mp_exti_host_data *host_data = dev_get_drvdata(dev); 431 + struct stm32mp_exti_chip_data *chip_data; 432 + int i; 433 + 434 + for (i = 0; i < host_data->drv_data->bank_nr; i++) { 435 + chip_data = &host_data->chips_data[i]; 436 + stm32mp_chip_suspend(chip_data, chip_data->wake_active); 437 + } 438 + 439 + return 0; 440 + } 441 + 442 + static int stm32mp_exti_resume(struct device *dev) 443 + { 444 + struct stm32mp_exti_host_data *host_data = dev_get_drvdata(dev); 445 + struct stm32mp_exti_chip_data *chip_data; 446 + int i; 447 + 448 + for (i = 0; i < host_data->drv_data->bank_nr; i++) { 449 + chip_data = &host_data->chips_data[i]; 450 + stm32mp_chip_resume(chip_data, chip_data->mask_cache); 451 + } 452 + 453 + return 0; 454 + } 455 + 456 + static int stm32mp_exti_retrigger(struct irq_data *d) 457 + { 458 + struct stm32mp_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); 459 + const struct stm32mp_exti_bank *bank = chip_data->reg_bank; 460 + void __iomem *base = chip_data->host_data->base; 461 + u32 mask = BIT(d->hwirq % IRQS_PER_BANK); 462 + 463 + writel_relaxed(mask, base + bank->swier_ofst); 464 + 465 + return 0; 466 + } 467 + 468 + static struct irq_chip stm32mp_exti_chip = { 469 + .name = "stm32mp-exti", 470 + .irq_eoi = stm32mp_exti_eoi, 471 + .irq_mask = stm32mp_exti_mask, 472 + .irq_unmask = stm32mp_exti_unmask, 473 + .irq_retrigger = stm32mp_exti_retrigger, 474 + .irq_set_type = stm32mp_exti_set_type, 475 + .irq_set_wake = stm32mp_exti_set_wake, 476 + .flags = IRQCHIP_MASK_ON_SUSPEND, 477 + .irq_set_affinity = IS_ENABLED(CONFIG_SMP) ? stm32mp_exti_set_affinity : NULL, 478 + }; 479 + 480 + static struct irq_chip stm32mp_exti_chip_direct = { 481 + .name = "stm32mp-exti-direct", 482 + .irq_eoi = irq_chip_eoi_parent, 483 + .irq_ack = irq_chip_ack_parent, 484 + .irq_mask = stm32mp_exti_mask, 485 + .irq_unmask = stm32mp_exti_unmask, 486 + .irq_retrigger = irq_chip_retrigger_hierarchy, 487 + .irq_set_type = irq_chip_set_type_parent, 488 + .irq_set_wake = stm32mp_exti_set_wake, 489 + .flags = IRQCHIP_MASK_ON_SUSPEND, 490 + .irq_set_affinity = IS_ENABLED(CONFIG_SMP) ? irq_chip_set_affinity_parent : NULL, 491 + }; 492 + 493 + static int stm32mp_exti_domain_alloc(struct irq_domain *dm, 494 + unsigned int virq, 495 + unsigned int nr_irqs, void *data) 496 + { 497 + struct stm32mp_exti_host_data *host_data = dm->host_data; 498 + struct stm32mp_exti_chip_data *chip_data; 499 + struct irq_fwspec *fwspec = data; 500 + struct irq_fwspec p_fwspec; 501 + irq_hw_number_t hwirq; 502 + struct irq_chip *chip; 503 + u32 event_trg; 504 + u8 desc_irq; 505 + int bank; 506 + 507 + hwirq = fwspec->param[0]; 508 + if (hwirq >= host_data->drv_data->bank_nr * IRQS_PER_BANK) 509 + return -EINVAL; 510 + 511 + bank = hwirq / IRQS_PER_BANK; 512 + chip_data = &host_data->chips_data[bank]; 513 + 514 + /* Check if event is reserved (Secure) */ 515 + if (chip_data->event_reserved & BIT(hwirq % IRQS_PER_BANK)) { 516 + dev_err(host_data->dev, "event %lu is reserved, secure\n", hwirq); 517 + return -EPERM; 518 + } 519 + 520 + event_trg = readl_relaxed(host_data->base + chip_data->reg_bank->trg_ofst); 521 + chip = (event_trg & BIT(hwirq % IRQS_PER_BANK)) ? 522 + &stm32mp_exti_chip : &stm32mp_exti_chip_direct; 523 + 524 + irq_domain_set_hwirq_and_chip(dm, virq, hwirq, chip, chip_data); 525 + 526 + if (host_data->dt_has_irqs_desc) { 527 + struct of_phandle_args out_irq; 528 + int ret; 529 + 530 + ret = of_irq_parse_one(host_data->dev->of_node, hwirq, &out_irq); 531 + if (ret) 532 + return ret; 533 + /* we only support one parent, so far */ 534 + if (of_node_to_fwnode(out_irq.np) != dm->parent->fwnode) 535 + return -EINVAL; 536 + 537 + of_phandle_args_to_fwspec(out_irq.np, out_irq.args, 538 + out_irq.args_count, &p_fwspec); 539 + 540 + return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec); 541 + } 542 + 543 + if (!host_data->drv_data->desc_irqs) 544 + return -EINVAL; 545 + 546 + desc_irq = host_data->drv_data->desc_irqs[hwirq]; 547 + if (desc_irq != EXTI_INVALID_IRQ) { 548 + p_fwspec.fwnode = dm->parent->fwnode; 549 + p_fwspec.param_count = 3; 550 + p_fwspec.param[0] = GIC_SPI; 551 + p_fwspec.param[1] = desc_irq; 552 + p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; 553 + 554 + return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec); 555 + } 556 + 557 + return 0; 558 + } 559 + 560 + static struct stm32mp_exti_chip_data *stm32mp_exti_chip_init(struct stm32mp_exti_host_data *h_data, 561 + u32 bank_idx, struct device_node *node) 562 + { 563 + struct stm32mp_exti_chip_data *chip_data; 564 + const struct stm32mp_exti_bank *bank; 565 + void __iomem *base = h_data->base; 566 + 567 + bank = h_data->drv_data->exti_banks[bank_idx]; 568 + chip_data = &h_data->chips_data[bank_idx]; 569 + chip_data->host_data = h_data; 570 + chip_data->reg_bank = bank; 571 + 572 + raw_spin_lock_init(&chip_data->rlock); 573 + 574 + /* 575 + * This IP has no reset, so after hot reboot we should 576 + * clear registers to avoid residue 577 + */ 578 + writel_relaxed(0, base + bank->imr_ofst); 579 + 580 + /* reserve Secure events */ 581 + chip_data->event_reserved = readl_relaxed(base + bank->seccfgr_ofst); 582 + 583 + pr_info("%pOF: bank%d\n", node, bank_idx); 584 + 585 + return chip_data; 586 + } 587 + 588 + static const struct irq_domain_ops stm32mp_exti_domain_ops = { 589 + .alloc = stm32mp_exti_domain_alloc, 590 + .free = irq_domain_free_irqs_common, 591 + .xlate = irq_domain_xlate_twocell, 592 + }; 593 + 594 + static void stm32mp_exti_check_rif(struct stm32mp_exti_host_data *host_data) 595 + { 596 + unsigned int bank, i, event; 597 + u32 cid, cidcfgr, hwcfgr1; 598 + 599 + /* quit on CID not supported */ 600 + hwcfgr1 = readl_relaxed(host_data->base + EXTI_HWCFGR1); 601 + if ((hwcfgr1 & EXTI_HWCFGR1_CIDWIDTH_MASK) == 0) 602 + return; 603 + 604 + for (bank = 0; bank < host_data->drv_data->bank_nr; bank++) { 605 + for (i = 0; i < IRQS_PER_BANK; i++) { 606 + event = bank * IRQS_PER_BANK + i; 607 + cidcfgr = readl_relaxed(host_data->base + EXTI_EnCIDCFGR(event)); 608 + cid = (cidcfgr & EXTI_CIDCFGR_CID_MASK) >> EXTI_CIDCFGR_CID_SHIFT; 609 + if ((cidcfgr & EXTI_CIDCFGR_CFEN_MASK) && cid != EXTI_CID1) 610 + host_data->chips_data[bank].event_reserved |= BIT(i); 611 + } 612 + } 613 + } 614 + 615 + static void stm32mp_exti_remove_irq(void *data) 616 + { 617 + struct irq_domain *domain = data; 618 + 619 + irq_domain_remove(domain); 620 + } 621 + 622 + static int stm32mp_exti_probe(struct platform_device *pdev) 623 + { 624 + const struct stm32mp_exti_drv_data *drv_data; 625 + struct irq_domain *parent_domain, *domain; 626 + struct stm32mp_exti_host_data *host_data; 627 + struct device *dev = &pdev->dev; 628 + struct device_node *np = dev->of_node; 629 + int ret, i; 630 + 631 + host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL); 632 + if (!host_data) 633 + return -ENOMEM; 634 + 635 + dev_set_drvdata(dev, host_data); 636 + host_data->dev = dev; 637 + 638 + /* check for optional hwspinlock which may be not available yet */ 639 + ret = of_hwspin_lock_get_id(np, 0); 640 + if (ret == -EPROBE_DEFER) 641 + /* hwspinlock framework not yet ready */ 642 + return ret; 643 + 644 + if (ret >= 0) { 645 + host_data->hwlock = devm_hwspin_lock_request_specific(dev, ret); 646 + if (!host_data->hwlock) { 647 + dev_err(dev, "Failed to request hwspinlock\n"); 648 + return -EINVAL; 649 + } 650 + } else if (ret != -ENOENT) { 651 + /* note: ENOENT is a valid case (means 'no hwspinlock') */ 652 + dev_err(dev, "Failed to get hwspinlock\n"); 653 + return ret; 654 + } 655 + 656 + /* initialize host_data */ 657 + drv_data = of_device_get_match_data(dev); 658 + if (!drv_data) { 659 + dev_err(dev, "no of match data\n"); 660 + return -ENODEV; 661 + } 662 + host_data->drv_data = drv_data; 663 + 664 + host_data->chips_data = devm_kcalloc(dev, drv_data->bank_nr, 665 + sizeof(*host_data->chips_data), 666 + GFP_KERNEL); 667 + if (!host_data->chips_data) 668 + return -ENOMEM; 669 + 670 + host_data->base = devm_platform_ioremap_resource(pdev, 0); 671 + if (IS_ERR(host_data->base)) 672 + return PTR_ERR(host_data->base); 673 + 674 + for (i = 0; i < drv_data->bank_nr; i++) 675 + stm32mp_exti_chip_init(host_data, i, np); 676 + 677 + stm32mp_exti_check_rif(host_data); 678 + 679 + parent_domain = irq_find_host(of_irq_find_parent(np)); 680 + if (!parent_domain) { 681 + dev_err(dev, "GIC interrupt-parent not found\n"); 682 + return -EINVAL; 683 + } 684 + 685 + domain = irq_domain_add_hierarchy(parent_domain, 0, 686 + drv_data->bank_nr * IRQS_PER_BANK, 687 + np, &stm32mp_exti_domain_ops, 688 + host_data); 689 + 690 + if (!domain) { 691 + dev_err(dev, "Could not register exti domain\n"); 692 + return -ENOMEM; 693 + } 694 + 695 + ret = devm_add_action_or_reset(dev, stm32mp_exti_remove_irq, domain); 696 + if (ret) 697 + return ret; 698 + 699 + if (of_property_read_bool(np, "interrupts-extended")) 700 + host_data->dt_has_irqs_desc = true; 701 + 702 + return 0; 703 + } 704 + 705 + static const struct of_device_id stm32mp_exti_ids[] = { 706 + { .compatible = "st,stm32mp1-exti", .data = &stm32mp1_drv_data}, 707 + { .compatible = "st,stm32mp13-exti", .data = &stm32mp13_drv_data}, 708 + {}, 709 + }; 710 + MODULE_DEVICE_TABLE(of, stm32mp_exti_ids); 711 + 712 + static const struct dev_pm_ops stm32mp_exti_dev_pm_ops = { 713 + NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32mp_exti_suspend, stm32mp_exti_resume) 714 + }; 715 + 716 + static struct platform_driver stm32mp_exti_driver = { 717 + .probe = stm32mp_exti_probe, 718 + .driver = { 719 + .name = "stm32mp_exti", 720 + .of_match_table = stm32mp_exti_ids, 721 + .pm = &stm32mp_exti_dev_pm_ops, 722 + }, 723 + }; 724 + 725 + module_platform_driver(stm32mp_exti_driver); 726 + 727 + MODULE_AUTHOR("Maxime Coquelin <mcoquelin.stm32@gmail.com>"); 728 + MODULE_DESCRIPTION("STM32MP EXTI driver"); 729 + MODULE_LICENSE("GPL");
+1
drivers/irqchip/irq-ts4800.c
··· 163 163 module_platform_driver(ts4800_ic_driver); 164 164 165 165 MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>"); 166 + MODULE_DESCRIPTION("Multiplexed-IRQs driver for TS-4800's FPGA"); 166 167 MODULE_LICENSE("GPL v2"); 167 168 MODULE_ALIAS("platform:ts4800_irqc");
+3
include/linux/acpi.h
··· 274 274 return phys_id == PHYS_CPUID_INVALID; 275 275 } 276 276 277 + 278 + int __init acpi_get_madt_revision(void); 279 + 277 280 /* Validate the processor object's proc_id */ 278 281 bool acpi_duplicate_processor_id(int proc_id); 279 282 /* Processor _CTS control */
+1 -1
include/linux/interrupt.h
··· 169 169 request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, 170 170 const char *name, void *dev) 171 171 { 172 - return request_threaded_irq(irq, handler, NULL, flags, name, dev); 172 + return request_threaded_irq(irq, handler, NULL, flags | IRQF_COND_ONESHOT, name, dev); 173 173 } 174 174 175 175 extern int __must_check
+43
include/linux/irq.h
··· 1106 1106 * @irq_flags_to_set: IRQ* flags to set on irq setup 1107 1107 * @irq_flags_to_clear: IRQ* flags to clear on irq setup 1108 1108 * @gc_flags: Generic chip specific setup flags 1109 + * @exit: Function called on each chip when they are destroyed. 1109 1110 * @gc: Array of pointers to generic interrupt chips 1110 1111 */ 1111 1112 struct irq_domain_chip_generic { ··· 1115 1114 unsigned int irq_flags_to_clear; 1116 1115 unsigned int irq_flags_to_set; 1117 1116 enum irq_gc_flags gc_flags; 1117 + void (*exit)(struct irq_chip_generic *gc); 1118 1118 struct irq_chip_generic *gc[]; 1119 + }; 1120 + 1121 + /** 1122 + * struct irq_domain_chip_generic_info - Generic chip information structure 1123 + * @name: Name of the generic interrupt chip 1124 + * @handler: Interrupt handler used by the generic interrupt chip 1125 + * @irqs_per_chip: Number of interrupts each chip handles (max 32) 1126 + * @num_ct: Number of irq_chip_type instances associated with each 1127 + * chip 1128 + * @irq_flags_to_clear: IRQ_* bits to clear in the mapping function 1129 + * @irq_flags_to_set: IRQ_* bits to set in the mapping function 1130 + * @gc_flags: Generic chip specific setup flags 1131 + * @init: Function called on each chip when they are created. 1132 + * Allow to do some additional chip initialisation. 1133 + * @exit: Function called on each chip when they are destroyed. 1134 + * Allow to do some chip cleanup operation. 1135 + */ 1136 + struct irq_domain_chip_generic_info { 1137 + const char *name; 1138 + irq_flow_handler_t handler; 1139 + unsigned int irqs_per_chip; 1140 + unsigned int num_ct; 1141 + unsigned int irq_flags_to_clear; 1142 + unsigned int irq_flags_to_set; 1143 + enum irq_gc_flags gc_flags; 1144 + int (*init)(struct irq_chip_generic *gc); 1145 + void (*exit)(struct irq_chip_generic *gc); 1119 1146 }; 1120 1147 1121 1148 /* Generic chip callback functions */ ··· 1181 1152 unsigned int clr, unsigned int set); 1182 1153 1183 1154 struct irq_chip_generic *irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq); 1155 + 1156 + #ifdef CONFIG_GENERIC_IRQ_CHIP 1157 + int irq_domain_alloc_generic_chips(struct irq_domain *d, 1158 + const struct irq_domain_chip_generic_info *info); 1159 + void irq_domain_remove_generic_chips(struct irq_domain *d); 1160 + #else 1161 + static inline int 1162 + irq_domain_alloc_generic_chips(struct irq_domain *d, 1163 + const struct irq_domain_chip_generic_info *info) 1164 + { 1165 + return -EINVAL; 1166 + } 1167 + static inline void irq_domain_remove_generic_chips(struct irq_domain *d) { } 1168 + #endif /* CONFIG_GENERIC_IRQ_CHIP */ 1184 1169 1185 1170 int __irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip, 1186 1171 int num_ct, const char *name,
+8
include/linux/irqchip/arm-gic-v4.h
··· 25 25 irq_hw_number_t db_lpi_base; 26 26 unsigned long *db_bitmap; 27 27 int nr_db_lpis; 28 + /* 29 + * Ensures mutual exclusion between updates to vlpi_count[] 30 + * and map/unmap when using the ITSList mechanism. 31 + * 32 + * The lock order for any sequence involving the ITSList is 33 + * vmapp_lock -> vpe_lock ->vmovp_lock. 34 + */ 35 + raw_spinlock_t vmapp_lock; 28 36 u32 vlpi_count[GICv4_ITS_LIST_MAX]; 29 37 }; 30 38
+124 -12
include/linux/irqdomain.h
··· 74 74 * struct irq_domain_ops - Methods for irq_domain objects 75 75 * @match: Match an interrupt controller device node to a host, returns 76 76 * 1 on a match 77 + * @select: Match an interrupt controller fw specification. It is more generic 78 + * than @match as it receives a complete struct irq_fwspec. Therefore, 79 + * @select is preferred if provided. Returns 1 on a match. 77 80 * @map: Create or update a mapping between a virtual irq number and a hw 78 81 * irq number. This is called only once for a given mapping. 79 82 * @unmap: Dispose of such a mapping 80 83 * @xlate: Given a device tree node and interrupt specifier, decode 81 84 * the hardware irq number and linux irq type value. 85 + * @alloc: Allocate @nr_irqs interrupts starting from @virq. 86 + * @free: Free @nr_irqs interrupts starting from @virq. 87 + * @activate: Activate one interrupt in HW (@irqd). If @reserve is set, only 88 + * reserve the vector. If unset, assign the vector (called from 89 + * request_irq()). 90 + * @deactivate: Disarm one interrupt (@irqd). 91 + * @translate: Given @fwspec, decode the hardware irq number (@out_hwirq) and 92 + * linux irq type value (@out_type). This is a generalised @xlate 93 + * (over struct irq_fwspec) and is preferred if provided. 94 + * @debug_show: For domains to show specific data for an interrupt in debugfs. 82 95 * 83 96 * Functions below are provided by the driver and called whenever a new mapping 84 97 * is created or an old mapping is disposed. The driver can then proceed to ··· 144 131 * Optional elements: 145 132 * @fwnode: Pointer to firmware node associated with the irq_domain. Pretty easy 146 133 * to swap it for the of_node via the irq_domain_get_of_node accessor 134 + * @bus_token: @fwnode's device_node might be used for several irq domains. But 135 + * in connection with @bus_token, the pair shall be unique in a 136 + * system. 147 137 * @gc: Pointer to a list of generic chips. There is a helper function for 148 138 * setting up one or more generic chips for interrupt controllers 149 139 * drivers using the generic chip library which uses this pointer. ··· 157 141 * purposes related to the irq domain. 158 142 * @parent: Pointer to parent irq_domain to support hierarchy irq_domains 159 143 * @msi_parent_ops: Pointer to MSI parent domain methods for per device domain init 144 + * @exit: Function called when the domain is destroyed 160 145 * 161 146 * Revmap data, used internally by the irq domain code: 162 - * @revmap_size: Size of the linear map table @revmap[] 147 + * @hwirq_max: Top limit for the HW irq number. Especially to avoid 148 + * conflicts/failures with reserved HW irqs. Can be ~0. 149 + * @revmap_size: Size of the linear map table @revmap 163 150 * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map 164 151 * @revmap: Linear table of irq_data pointers 165 152 */ ··· 188 169 #ifdef CONFIG_GENERIC_MSI_IRQ 189 170 const struct msi_parent_ops *msi_parent_ops; 190 171 #endif 172 + void (*exit)(struct irq_domain *d); 191 173 192 174 /* reverse map data. The linear map gets appended to the irq_domain */ 193 175 irq_hw_number_t hwirq_max; ··· 202 182 /* Irq domain is hierarchical */ 203 183 IRQ_DOMAIN_FLAG_HIERARCHY = (1 << 0), 204 184 205 - /* Irq domain name was allocated in __irq_domain_add() */ 185 + /* Irq domain name was allocated internally */ 206 186 IRQ_DOMAIN_NAME_ALLOCATED = (1 << 1), 207 187 208 188 /* Irq domain is an IPI domain with virq per cpu */ ··· 227 207 228 208 /* Irq domain is a MSI device domain */ 229 209 IRQ_DOMAIN_FLAG_MSI_DEVICE = (1 << 9), 210 + 211 + /* Irq domain must destroy generic chips when removed */ 212 + IRQ_DOMAIN_FLAG_DESTROY_GC = (1 << 10), 230 213 231 214 /* 232 215 * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved ··· 280 257 } 281 258 282 259 void irq_domain_free_fwnode(struct fwnode_handle *fwnode); 283 - struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size, 284 - irq_hw_number_t hwirq_max, int direct_max, 285 - const struct irq_domain_ops *ops, 286 - void *host_data); 260 + 261 + struct irq_domain_chip_generic_info; 262 + 263 + /** 264 + * struct irq_domain_info - Domain information structure 265 + * @fwnode: firmware node for the interrupt controller 266 + * @domain_flags: Additional flags to add to the domain flags 267 + * @size: Size of linear map; 0 for radix mapping only 268 + * @hwirq_max: Maximum number of interrupts supported by controller 269 + * @direct_max: Maximum value of direct maps; 270 + * Use ~0 for no limit; 0 for no direct mapping 271 + * @bus_token: Domain bus token 272 + * @ops: Domain operation callbacks 273 + * @host_data: Controller private data pointer 274 + * @dgc_info: Geneneric chip information structure pointer used to 275 + * create generic chips for the domain if not NULL. 276 + * @init: Function called when the domain is created. 277 + * Allow to do some additional domain initialisation. 278 + * @exit: Function called when the domain is destroyed. 279 + * Allow to do some additional cleanup operation. 280 + */ 281 + struct irq_domain_info { 282 + struct fwnode_handle *fwnode; 283 + unsigned int domain_flags; 284 + unsigned int size; 285 + irq_hw_number_t hwirq_max; 286 + int direct_max; 287 + enum irq_domain_bus_token bus_token; 288 + const struct irq_domain_ops *ops; 289 + void *host_data; 290 + #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY 291 + /** 292 + * @parent: Pointer to the parent irq domain used in a hierarchy domain 293 + */ 294 + struct irq_domain *parent; 295 + #endif 296 + struct irq_domain_chip_generic_info *dgc_info; 297 + int (*init)(struct irq_domain *d); 298 + void (*exit)(struct irq_domain *d); 299 + }; 300 + 301 + struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info); 302 + struct irq_domain *devm_irq_domain_instantiate(struct device *dev, 303 + const struct irq_domain_info *info); 304 + 287 305 struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode, 288 306 unsigned int size, 289 307 unsigned int first_irq, ··· 357 293 358 294 extern const struct fwnode_operations irqchip_fwnode_ops; 359 295 360 - static inline bool is_fwnode_irqchip(struct fwnode_handle *fwnode) 296 + static inline bool is_fwnode_irqchip(const struct fwnode_handle *fwnode) 361 297 { 362 298 return fwnode && fwnode->ops == &irqchip_fwnode_ops; 363 299 } ··· 414 350 const struct irq_domain_ops *ops, 415 351 void *host_data) 416 352 { 417 - return __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops, host_data); 353 + struct irq_domain_info info = { 354 + .fwnode = of_node_to_fwnode(of_node), 355 + .size = size, 356 + .hwirq_max = size, 357 + .ops = ops, 358 + .host_data = host_data, 359 + }; 360 + struct irq_domain *d; 361 + 362 + d = irq_domain_instantiate(&info); 363 + return IS_ERR(d) ? NULL : d; 418 364 } 419 365 420 366 #ifdef CONFIG_IRQ_DOMAIN_NOMAP ··· 433 359 const struct irq_domain_ops *ops, 434 360 void *host_data) 435 361 { 436 - return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq, ops, host_data); 362 + struct irq_domain_info info = { 363 + .fwnode = of_node_to_fwnode(of_node), 364 + .hwirq_max = max_irq, 365 + .direct_max = max_irq, 366 + .ops = ops, 367 + .host_data = host_data, 368 + }; 369 + struct irq_domain *d; 370 + 371 + d = irq_domain_instantiate(&info); 372 + return IS_ERR(d) ? NULL : d; 437 373 } 438 374 439 375 extern unsigned int irq_create_direct_mapping(struct irq_domain *host); ··· 453 369 const struct irq_domain_ops *ops, 454 370 void *host_data) 455 371 { 456 - return __irq_domain_add(of_node_to_fwnode(of_node), 0, ~0, 0, ops, host_data); 372 + struct irq_domain_info info = { 373 + .fwnode = of_node_to_fwnode(of_node), 374 + .hwirq_max = ~0U, 375 + .ops = ops, 376 + .host_data = host_data, 377 + }; 378 + struct irq_domain *d; 379 + 380 + d = irq_domain_instantiate(&info); 381 + return IS_ERR(d) ? NULL : d; 457 382 } 458 383 459 384 static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *fwnode, ··· 470 377 const struct irq_domain_ops *ops, 471 378 void *host_data) 472 379 { 473 - return __irq_domain_add(fwnode, size, size, 0, ops, host_data); 380 + struct irq_domain_info info = { 381 + .fwnode = fwnode, 382 + .size = size, 383 + .hwirq_max = size, 384 + .ops = ops, 385 + .host_data = host_data, 386 + }; 387 + struct irq_domain *d; 388 + 389 + d = irq_domain_instantiate(&info); 390 + return IS_ERR(d) ? NULL : d; 474 391 } 475 392 476 393 static inline struct irq_domain *irq_domain_create_tree(struct fwnode_handle *fwnode, 477 394 const struct irq_domain_ops *ops, 478 395 void *host_data) 479 396 { 480 - return __irq_domain_add(fwnode, 0, ~0, 0, ops, host_data); 397 + struct irq_domain_info info = { 398 + .fwnode = fwnode, 399 + .hwirq_max = ~0, 400 + .ops = ops, 401 + .host_data = host_data, 402 + }; 403 + struct irq_domain *d; 404 + 405 + d = irq_domain_instantiate(&info); 406 + return IS_ERR(d) ? NULL : d; 481 407 } 482 408 483 409 extern void irq_domain_remove(struct irq_domain *host);
+2 -8
kernel/irq/debugfs.c
··· 9 9 10 10 static struct dentry *irq_dir; 11 11 12 - struct irq_bit_descr { 13 - unsigned int mask; 14 - char *name; 15 - }; 16 - #define BIT_MASK_DESCR(m) { .mask = m, .name = #m } 17 - 18 - static void irq_debug_show_bits(struct seq_file *m, int ind, unsigned int state, 19 - const struct irq_bit_descr *sd, int size) 12 + void irq_debug_show_bits(struct seq_file *m, int ind, unsigned int state, 13 + const struct irq_bit_descr *sd, int size) 20 14 { 21 15 int i; 22 16
+41
kernel/irq/devres.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 #include <linux/module.h> 3 3 #include <linux/interrupt.h> 4 + #include <linux/irqdomain.h> 4 5 #include <linux/device.h> 5 6 #include <linux/gfp.h> 6 7 #include <linux/irq.h> ··· 283 282 } 284 283 EXPORT_SYMBOL_GPL(devm_irq_setup_generic_chip); 285 284 #endif /* CONFIG_GENERIC_IRQ_CHIP */ 285 + 286 + #ifdef CONFIG_IRQ_DOMAIN 287 + static void devm_irq_domain_remove(struct device *dev, void *res) 288 + { 289 + struct irq_domain **domain = res; 290 + 291 + irq_domain_remove(*domain); 292 + } 293 + 294 + /** 295 + * devm_irq_domain_instantiate() - Instantiate a new irq domain data for a 296 + * managed device. 297 + * @dev: Device to instantiate the domain for 298 + * @info: Domain information pointer pointing to the information for this 299 + * domain 300 + * 301 + * Return: A pointer to the instantiated irq domain or an ERR_PTR value. 302 + */ 303 + struct irq_domain *devm_irq_domain_instantiate(struct device *dev, 304 + const struct irq_domain_info *info) 305 + { 306 + struct irq_domain *domain; 307 + struct irq_domain **dr; 308 + 309 + dr = devres_alloc(devm_irq_domain_remove, sizeof(*dr), GFP_KERNEL); 310 + if (!dr) 311 + return ERR_PTR(-ENOMEM); 312 + 313 + domain = irq_domain_instantiate(info); 314 + if (!IS_ERR(domain)) { 315 + *dr = domain; 316 + devres_add(dev, dr); 317 + } else { 318 + devres_free(dr); 319 + } 320 + 321 + return domain; 322 + } 323 + EXPORT_SYMBOL_GPL(devm_irq_domain_instantiate); 324 + #endif /* CONFIG_IRQ_DOMAIN */
+116 -51
kernel/irq/generic-chip.c
··· 276 276 } 277 277 278 278 /** 279 + * irq_domain_alloc_generic_chips - Allocate generic chips for an irq domain 280 + * @d: irq domain for which to allocate chips 281 + * @info: Generic chip information 282 + * 283 + * Return: 0 on success, negative error code on failure 284 + */ 285 + int irq_domain_alloc_generic_chips(struct irq_domain *d, 286 + const struct irq_domain_chip_generic_info *info) 287 + { 288 + struct irq_domain_chip_generic *dgc; 289 + struct irq_chip_generic *gc; 290 + unsigned long flags; 291 + int numchips, i; 292 + size_t dgc_sz; 293 + size_t gc_sz; 294 + size_t sz; 295 + void *tmp; 296 + int ret; 297 + 298 + if (d->gc) 299 + return -EBUSY; 300 + 301 + numchips = DIV_ROUND_UP(d->revmap_size, info->irqs_per_chip); 302 + if (!numchips) 303 + return -EINVAL; 304 + 305 + /* Allocate a pointer, generic chip and chiptypes for each chip */ 306 + gc_sz = struct_size(gc, chip_types, info->num_ct); 307 + dgc_sz = struct_size(dgc, gc, numchips); 308 + sz = dgc_sz + numchips * gc_sz; 309 + 310 + tmp = dgc = kzalloc(sz, GFP_KERNEL); 311 + if (!dgc) 312 + return -ENOMEM; 313 + dgc->irqs_per_chip = info->irqs_per_chip; 314 + dgc->num_chips = numchips; 315 + dgc->irq_flags_to_set = info->irq_flags_to_set; 316 + dgc->irq_flags_to_clear = info->irq_flags_to_clear; 317 + dgc->gc_flags = info->gc_flags; 318 + dgc->exit = info->exit; 319 + d->gc = dgc; 320 + 321 + /* Calc pointer to the first generic chip */ 322 + tmp += dgc_sz; 323 + for (i = 0; i < numchips; i++) { 324 + /* Store the pointer to the generic chip */ 325 + dgc->gc[i] = gc = tmp; 326 + irq_init_generic_chip(gc, info->name, info->num_ct, 327 + i * dgc->irqs_per_chip, NULL, 328 + info->handler); 329 + 330 + gc->domain = d; 331 + if (dgc->gc_flags & IRQ_GC_BE_IO) { 332 + gc->reg_readl = &irq_readl_be; 333 + gc->reg_writel = &irq_writel_be; 334 + } 335 + 336 + if (info->init) { 337 + ret = info->init(gc); 338 + if (ret) 339 + goto err; 340 + } 341 + 342 + raw_spin_lock_irqsave(&gc_lock, flags); 343 + list_add_tail(&gc->list, &gc_list); 344 + raw_spin_unlock_irqrestore(&gc_lock, flags); 345 + /* Calc pointer to the next generic chip */ 346 + tmp += gc_sz; 347 + } 348 + return 0; 349 + 350 + err: 351 + while (i--) { 352 + if (dgc->exit) 353 + dgc->exit(dgc->gc[i]); 354 + irq_remove_generic_chip(dgc->gc[i], ~0U, 0, 0); 355 + } 356 + d->gc = NULL; 357 + kfree(dgc); 358 + return ret; 359 + } 360 + EXPORT_SYMBOL_GPL(irq_domain_alloc_generic_chips); 361 + 362 + /** 363 + * irq_domain_remove_generic_chips - Remove generic chips from an irq domain 364 + * @d: irq domain for which generic chips are to be removed 365 + */ 366 + void irq_domain_remove_generic_chips(struct irq_domain *d) 367 + { 368 + struct irq_domain_chip_generic *dgc = d->gc; 369 + unsigned int i; 370 + 371 + if (!dgc) 372 + return; 373 + 374 + for (i = 0; i < dgc->num_chips; i++) { 375 + if (dgc->exit) 376 + dgc->exit(dgc->gc[i]); 377 + irq_remove_generic_chip(dgc->gc[i], ~0U, 0, 0); 378 + } 379 + d->gc = NULL; 380 + kfree(dgc); 381 + } 382 + EXPORT_SYMBOL_GPL(irq_domain_remove_generic_chips); 383 + 384 + /** 279 385 * __irq_alloc_domain_generic_chips - Allocate generic chips for an irq domain 280 386 * @d: irq domain for which to allocate chips 281 387 * @irqs_per_chip: Number of interrupts each chip handles (max 32) ··· 398 292 unsigned int clr, unsigned int set, 399 293 enum irq_gc_flags gcflags) 400 294 { 401 - struct irq_domain_chip_generic *dgc; 402 - struct irq_chip_generic *gc; 403 - unsigned long flags; 404 - int numchips, i; 405 - size_t dgc_sz; 406 - size_t gc_sz; 407 - size_t sz; 408 - void *tmp; 295 + struct irq_domain_chip_generic_info info = { 296 + .irqs_per_chip = irqs_per_chip, 297 + .num_ct = num_ct, 298 + .name = name, 299 + .handler = handler, 300 + .irq_flags_to_clear = clr, 301 + .irq_flags_to_set = set, 302 + .gc_flags = gcflags, 303 + }; 409 304 410 - if (d->gc) 411 - return -EBUSY; 412 - 413 - numchips = DIV_ROUND_UP(d->revmap_size, irqs_per_chip); 414 - if (!numchips) 415 - return -EINVAL; 416 - 417 - /* Allocate a pointer, generic chip and chiptypes for each chip */ 418 - gc_sz = struct_size(gc, chip_types, num_ct); 419 - dgc_sz = struct_size(dgc, gc, numchips); 420 - sz = dgc_sz + numchips * gc_sz; 421 - 422 - tmp = dgc = kzalloc(sz, GFP_KERNEL); 423 - if (!dgc) 424 - return -ENOMEM; 425 - dgc->irqs_per_chip = irqs_per_chip; 426 - dgc->num_chips = numchips; 427 - dgc->irq_flags_to_set = set; 428 - dgc->irq_flags_to_clear = clr; 429 - dgc->gc_flags = gcflags; 430 - d->gc = dgc; 431 - 432 - /* Calc pointer to the first generic chip */ 433 - tmp += dgc_sz; 434 - for (i = 0; i < numchips; i++) { 435 - /* Store the pointer to the generic chip */ 436 - dgc->gc[i] = gc = tmp; 437 - irq_init_generic_chip(gc, name, num_ct, i * irqs_per_chip, 438 - NULL, handler); 439 - 440 - gc->domain = d; 441 - if (gcflags & IRQ_GC_BE_IO) { 442 - gc->reg_readl = &irq_readl_be; 443 - gc->reg_writel = &irq_writel_be; 444 - } 445 - 446 - raw_spin_lock_irqsave(&gc_lock, flags); 447 - list_add_tail(&gc->list, &gc_list); 448 - raw_spin_unlock_irqrestore(&gc_lock, flags); 449 - /* Calc pointer to the next generic chip */ 450 - tmp += gc_sz; 451 - } 452 - return 0; 305 + return irq_domain_alloc_generic_chips(d, &info); 453 306 } 454 307 EXPORT_SYMBOL_GPL(__irq_alloc_domain_generic_chips); 455 308
+10
kernel/irq/internals.h
··· 501 501 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS 502 502 #include <linux/debugfs.h> 503 503 504 + struct irq_bit_descr { 505 + unsigned int mask; 506 + char *name; 507 + }; 508 + 509 + #define BIT_MASK_DESCR(m) { .mask = m, .name = #m } 510 + 511 + void irq_debug_show_bits(struct seq_file *m, int ind, unsigned int state, 512 + const struct irq_bit_descr *sd, int size); 513 + 504 514 void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *desc); 505 515 static inline void irq_remove_debugfs_entry(struct irq_desc *desc) 506 516 {
+195 -92
kernel/irq/irqdomain.c
··· 111 111 112 112 /** 113 113 * irq_domain_free_fwnode - Free a non-OF-backed fwnode_handle 114 + * @fwnode: fwnode_handle to free 114 115 * 115 116 * Free a fwnode_handle allocated with irq_domain_alloc_fwnode. 116 117 */ ··· 128 127 } 129 128 EXPORT_SYMBOL_GPL(irq_domain_free_fwnode); 130 129 131 - static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode, 132 - unsigned int size, 133 - irq_hw_number_t hwirq_max, 134 - int direct_max, 135 - const struct irq_domain_ops *ops, 136 - void *host_data) 130 + static int irq_domain_set_name(struct irq_domain *domain, 131 + const struct fwnode_handle *fwnode, 132 + enum irq_domain_bus_token bus_token) 137 133 { 138 - struct irqchip_fwid *fwid; 139 - struct irq_domain *domain; 140 - 141 134 static atomic_t unknown_domains; 142 - 143 - if (WARN_ON((size && direct_max) || 144 - (!IS_ENABLED(CONFIG_IRQ_DOMAIN_NOMAP) && direct_max) || 145 - (direct_max && (direct_max != hwirq_max)))) 146 - return NULL; 147 - 148 - domain = kzalloc_node(struct_size(domain, revmap, size), 149 - GFP_KERNEL, of_node_to_nid(to_of_node(fwnode))); 150 - if (!domain) 151 - return NULL; 135 + struct irqchip_fwid *fwid; 152 136 153 137 if (is_fwnode_irqchip(fwnode)) { 154 138 fwid = container_of(fwnode, struct irqchip_fwid, fwnode); ··· 141 155 switch (fwid->type) { 142 156 case IRQCHIP_FWNODE_NAMED: 143 157 case IRQCHIP_FWNODE_NAMED_ID: 144 - domain->fwnode = fwnode; 145 - domain->name = kstrdup(fwid->name, GFP_KERNEL); 146 - if (!domain->name) { 147 - kfree(domain); 148 - return NULL; 149 - } 158 + domain->name = bus_token ? 159 + kasprintf(GFP_KERNEL, "%s-%d", 160 + fwid->name, bus_token) : 161 + kstrdup(fwid->name, GFP_KERNEL); 162 + if (!domain->name) 163 + return -ENOMEM; 150 164 domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; 151 165 break; 152 166 default: 153 - domain->fwnode = fwnode; 154 167 domain->name = fwid->name; 168 + if (bus_token) { 169 + domain->name = kasprintf(GFP_KERNEL, "%s-%d", 170 + fwid->name, bus_token); 171 + if (!domain->name) 172 + return -ENOMEM; 173 + domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; 174 + } 155 175 break; 156 176 } 157 177 } else if (is_of_node(fwnode) || is_acpi_device_node(fwnode) || ··· 169 177 * unhappy about. Replace them with ':', which does 170 178 * the trick and is not as offensive as '\'... 171 179 */ 172 - name = kasprintf(GFP_KERNEL, "%pfw", fwnode); 173 - if (!name) { 174 - kfree(domain); 175 - return NULL; 176 - } 180 + name = bus_token ? 181 + kasprintf(GFP_KERNEL, "%pfw-%d", fwnode, bus_token) : 182 + kasprintf(GFP_KERNEL, "%pfw", fwnode); 183 + if (!name) 184 + return -ENOMEM; 177 185 178 186 domain->name = strreplace(name, '/', ':'); 179 - domain->fwnode = fwnode; 180 187 domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; 181 188 } 182 189 183 190 if (!domain->name) { 184 191 if (fwnode) 185 192 pr_err("Invalid fwnode type for irqdomain\n"); 186 - domain->name = kasprintf(GFP_KERNEL, "unknown-%d", 187 - atomic_inc_return(&unknown_domains)); 188 - if (!domain->name) { 189 - kfree(domain); 190 - return NULL; 191 - } 193 + domain->name = bus_token ? 194 + kasprintf(GFP_KERNEL, "unknown-%d-%d", 195 + atomic_inc_return(&unknown_domains), 196 + bus_token) : 197 + kasprintf(GFP_KERNEL, "unknown-%d", 198 + atomic_inc_return(&unknown_domains)); 199 + if (!domain->name) 200 + return -ENOMEM; 192 201 domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED; 193 202 } 194 203 195 - fwnode_handle_get(fwnode); 196 - fwnode_dev_initialized(fwnode, true); 204 + return 0; 205 + } 206 + 207 + static struct irq_domain *__irq_domain_create(const struct irq_domain_info *info) 208 + { 209 + struct irq_domain *domain; 210 + int err; 211 + 212 + if (WARN_ON((info->size && info->direct_max) || 213 + (!IS_ENABLED(CONFIG_IRQ_DOMAIN_NOMAP) && info->direct_max) || 214 + (info->direct_max && info->direct_max != info->hwirq_max))) 215 + return ERR_PTR(-EINVAL); 216 + 217 + domain = kzalloc_node(struct_size(domain, revmap, info->size), 218 + GFP_KERNEL, of_node_to_nid(to_of_node(info->fwnode))); 219 + if (!domain) 220 + return ERR_PTR(-ENOMEM); 221 + 222 + err = irq_domain_set_name(domain, info->fwnode, info->bus_token); 223 + if (err) { 224 + kfree(domain); 225 + return ERR_PTR(err); 226 + } 227 + 228 + domain->fwnode = fwnode_handle_get(info->fwnode); 229 + fwnode_dev_initialized(domain->fwnode, true); 197 230 198 231 /* Fill structure */ 199 232 INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL); 200 - domain->ops = ops; 201 - domain->host_data = host_data; 202 - domain->hwirq_max = hwirq_max; 233 + domain->ops = info->ops; 234 + domain->host_data = info->host_data; 235 + domain->bus_token = info->bus_token; 236 + domain->hwirq_max = info->hwirq_max; 203 237 204 - if (direct_max) 238 + if (info->direct_max) 205 239 domain->flags |= IRQ_DOMAIN_FLAG_NO_MAP; 206 240 207 - domain->revmap_size = size; 241 + domain->revmap_size = info->size; 208 242 209 243 /* 210 244 * Hierarchical domains use the domain lock of the root domain ··· 258 240 pr_debug("Added domain %s\n", domain->name); 259 241 } 260 242 243 + static void irq_domain_free(struct irq_domain *domain) 244 + { 245 + fwnode_dev_initialized(domain->fwnode, false); 246 + fwnode_handle_put(domain->fwnode); 247 + if (domain->flags & IRQ_DOMAIN_NAME_ALLOCATED) 248 + kfree(domain->name); 249 + kfree(domain); 250 + } 251 + 261 252 /** 262 - * __irq_domain_add() - Allocate a new irq_domain data structure 263 - * @fwnode: firmware node for the interrupt controller 264 - * @size: Size of linear map; 0 for radix mapping only 265 - * @hwirq_max: Maximum number of interrupts supported by controller 266 - * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no 267 - * direct mapping 268 - * @ops: domain callbacks 269 - * @host_data: Controller private data pointer 253 + * irq_domain_instantiate() - Instantiate a new irq domain data structure 254 + * @info: Domain information pointer pointing to the information for this domain 270 255 * 271 - * Allocates and initializes an irq_domain structure. 272 - * Returns pointer to IRQ domain, or NULL on failure. 256 + * Return: A pointer to the instantiated irq domain or an ERR_PTR value. 273 257 */ 274 - struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size, 275 - irq_hw_number_t hwirq_max, int direct_max, 276 - const struct irq_domain_ops *ops, 277 - void *host_data) 258 + struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info) 278 259 { 279 260 struct irq_domain *domain; 261 + int err; 280 262 281 - domain = __irq_domain_create(fwnode, size, hwirq_max, direct_max, 282 - ops, host_data); 283 - if (domain) 284 - __irq_domain_publish(domain); 263 + domain = __irq_domain_create(info); 264 + if (IS_ERR(domain)) 265 + return domain; 266 + 267 + domain->flags |= info->domain_flags; 268 + domain->exit = info->exit; 269 + 270 + #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY 271 + if (info->parent) { 272 + domain->root = info->parent->root; 273 + domain->parent = info->parent; 274 + } 275 + #endif 276 + 277 + if (info->dgc_info) { 278 + err = irq_domain_alloc_generic_chips(domain, info->dgc_info); 279 + if (err) 280 + goto err_domain_free; 281 + } 282 + 283 + if (info->init) { 284 + err = info->init(domain); 285 + if (err) 286 + goto err_domain_gc_remove; 287 + } 288 + 289 + __irq_domain_publish(domain); 285 290 286 291 return domain; 292 + 293 + err_domain_gc_remove: 294 + if (info->dgc_info) 295 + irq_domain_remove_generic_chips(domain); 296 + err_domain_free: 297 + irq_domain_free(domain); 298 + return ERR_PTR(err); 287 299 } 288 - EXPORT_SYMBOL_GPL(__irq_domain_add); 300 + EXPORT_SYMBOL_GPL(irq_domain_instantiate); 289 301 290 302 /** 291 303 * irq_domain_remove() - Remove an irq domain. ··· 327 279 */ 328 280 void irq_domain_remove(struct irq_domain *domain) 329 281 { 282 + if (domain->exit) 283 + domain->exit(domain); 284 + 330 285 mutex_lock(&irq_domain_mutex); 331 286 debugfs_remove_domain_dir(domain); 332 287 ··· 345 294 346 295 mutex_unlock(&irq_domain_mutex); 347 296 348 - pr_debug("Removed domain %s\n", domain->name); 297 + if (domain->flags & IRQ_DOMAIN_FLAG_DESTROY_GC) 298 + irq_domain_remove_generic_chips(domain); 349 299 350 - fwnode_dev_initialized(domain->fwnode, false); 351 - fwnode_handle_put(domain->fwnode); 352 - if (domain->flags & IRQ_DOMAIN_NAME_ALLOCATED) 353 - kfree(domain->name); 354 - kfree(domain); 300 + pr_debug("Removed domain %s\n", domain->name); 301 + irq_domain_free(domain); 355 302 } 356 303 EXPORT_SYMBOL_GPL(irq_domain_remove); 357 304 ··· 409 360 const struct irq_domain_ops *ops, 410 361 void *host_data) 411 362 { 363 + struct irq_domain_info info = { 364 + .fwnode = fwnode, 365 + .size = size, 366 + .hwirq_max = size, 367 + .ops = ops, 368 + .host_data = host_data, 369 + }; 412 370 struct irq_domain *domain; 413 371 414 - domain = __irq_domain_add(fwnode, size, size, 0, ops, host_data); 415 - if (!domain) 372 + domain = irq_domain_instantiate(&info); 373 + if (IS_ERR(domain)) 416 374 return NULL; 417 375 418 376 if (first_irq > 0) { ··· 472 416 const struct irq_domain_ops *ops, 473 417 void *host_data) 474 418 { 419 + struct irq_domain_info info = { 420 + .fwnode = fwnode, 421 + .size = first_hwirq + size, 422 + .hwirq_max = first_hwirq + size, 423 + .ops = ops, 424 + .host_data = host_data, 425 + }; 475 426 struct irq_domain *domain; 476 427 477 - domain = __irq_domain_add(fwnode, first_hwirq + size, first_hwirq + size, 0, ops, host_data); 478 - if (domain) 479 - irq_domain_associate_many(domain, first_irq, first_hwirq, size); 428 + domain = irq_domain_instantiate(&info); 429 + if (IS_ERR(domain)) 430 + return NULL; 431 + 432 + irq_domain_associate_many(domain, first_irq, first_hwirq, size); 480 433 481 434 return domain; 482 435 } ··· 1047 982 1048 983 /** 1049 984 * irq_domain_xlate_onecell() - Generic xlate for direct one cell bindings 985 + * @d: Interrupt domain involved in the translation 986 + * @ctrlr: The device tree node for the device whose interrupt is translated 987 + * @intspec: The interrupt specifier data from the device tree 988 + * @intsize: The number of entries in @intspec 989 + * @out_hwirq: Pointer to storage for the hardware interrupt number 990 + * @out_type: Pointer to storage for the interrupt type 1050 991 * 1051 992 * Device Tree IRQ specifier translation function which works with one cell 1052 993 * bindings where the cell value maps directly to the hwirq number. ··· 1071 1000 1072 1001 /** 1073 1002 * irq_domain_xlate_twocell() - Generic xlate for direct two cell bindings 1003 + * @d: Interrupt domain involved in the translation 1004 + * @ctrlr: The device tree node for the device whose interrupt is translated 1005 + * @intspec: The interrupt specifier data from the device tree 1006 + * @intsize: The number of entries in @intspec 1007 + * @out_hwirq: Pointer to storage for the hardware interrupt number 1008 + * @out_type: Pointer to storage for the interrupt type 1074 1009 * 1075 1010 * Device Tree IRQ specifier translation function which works with two cell 1076 1011 * bindings where the cell values map directly to the hwirq number ··· 1095 1018 1096 1019 /** 1097 1020 * irq_domain_xlate_onetwocell() - Generic xlate for one or two cell bindings 1021 + * @d: Interrupt domain involved in the translation 1022 + * @ctrlr: The device tree node for the device whose interrupt is translated 1023 + * @intspec: The interrupt specifier data from the device tree 1024 + * @intsize: The number of entries in @intspec 1025 + * @out_hwirq: Pointer to storage for the hardware interrupt number 1026 + * @out_type: Pointer to storage for the interrupt type 1098 1027 * 1099 1028 * Device Tree IRQ specifier translation function which works with either one 1100 1029 * or two cell bindings where the cell values map directly to the hwirq number ··· 1134 1051 /** 1135 1052 * irq_domain_translate_onecell() - Generic translate for direct one cell 1136 1053 * bindings 1054 + * @d: Interrupt domain involved in the translation 1055 + * @fwspec: The firmware interrupt specifier to translate 1056 + * @out_hwirq: Pointer to storage for the hardware interrupt number 1057 + * @out_type: Pointer to storage for the interrupt type 1137 1058 */ 1138 1059 int irq_domain_translate_onecell(struct irq_domain *d, 1139 1060 struct irq_fwspec *fwspec, ··· 1155 1068 /** 1156 1069 * irq_domain_translate_twocell() - Generic translate for direct two cell 1157 1070 * bindings 1071 + * @d: Interrupt domain involved in the translation 1072 + * @fwspec: The firmware interrupt specifier to translate 1073 + * @out_hwirq: Pointer to storage for the hardware interrupt number 1074 + * @out_type: Pointer to storage for the interrupt type 1158 1075 * 1159 1076 * Device Tree IRQ specifier translation function which works with two cell 1160 1077 * bindings where the cell values map directly to the hwirq number ··· 1235 1144 const struct irq_domain_ops *ops, 1236 1145 void *host_data) 1237 1146 { 1238 - struct irq_domain *domain; 1147 + struct irq_domain_info info = { 1148 + .fwnode = fwnode, 1149 + .size = size, 1150 + .hwirq_max = size, 1151 + .ops = ops, 1152 + .host_data = host_data, 1153 + .domain_flags = flags, 1154 + .parent = parent, 1155 + }; 1156 + struct irq_domain *d; 1239 1157 1240 - if (size) 1241 - domain = __irq_domain_create(fwnode, size, size, 0, ops, host_data); 1242 - else 1243 - domain = __irq_domain_create(fwnode, 0, ~0, 0, ops, host_data); 1158 + if (!info.size) 1159 + info.hwirq_max = ~0U; 1244 1160 1245 - if (domain) { 1246 - if (parent) 1247 - domain->root = parent->root; 1248 - domain->parent = parent; 1249 - domain->flags |= flags; 1250 - 1251 - __irq_domain_publish(domain); 1252 - } 1253 - 1254 - return domain; 1161 + d = irq_domain_instantiate(&info); 1162 + return IS_ERR(d) ? NULL : d; 1255 1163 } 1256 1164 EXPORT_SYMBOL_GPL(irq_domain_create_hierarchy); 1257 1165 ··· 2022 1932 2023 1933 static struct dentry *domain_dir; 2024 1934 2025 - static void 2026 - irq_domain_debug_show_one(struct seq_file *m, struct irq_domain *d, int ind) 1935 + static const struct irq_bit_descr irqdomain_flags[] = { 1936 + BIT_MASK_DESCR(IRQ_DOMAIN_FLAG_HIERARCHY), 1937 + BIT_MASK_DESCR(IRQ_DOMAIN_NAME_ALLOCATED), 1938 + BIT_MASK_DESCR(IRQ_DOMAIN_FLAG_IPI_PER_CPU), 1939 + BIT_MASK_DESCR(IRQ_DOMAIN_FLAG_IPI_SINGLE), 1940 + BIT_MASK_DESCR(IRQ_DOMAIN_FLAG_MSI), 1941 + BIT_MASK_DESCR(IRQ_DOMAIN_FLAG_ISOLATED_MSI), 1942 + BIT_MASK_DESCR(IRQ_DOMAIN_FLAG_NO_MAP), 1943 + BIT_MASK_DESCR(IRQ_DOMAIN_FLAG_MSI_PARENT), 1944 + BIT_MASK_DESCR(IRQ_DOMAIN_FLAG_MSI_DEVICE), 1945 + BIT_MASK_DESCR(IRQ_DOMAIN_FLAG_NONCORE), 1946 + }; 1947 + 1948 + static void irq_domain_debug_show_one(struct seq_file *m, struct irq_domain *d, int ind) 2027 1949 { 2028 1950 seq_printf(m, "%*sname: %s\n", ind, "", d->name); 2029 1951 seq_printf(m, "%*ssize: %u\n", ind + 1, "", d->revmap_size); 2030 1952 seq_printf(m, "%*smapped: %u\n", ind + 1, "", d->mapcount); 2031 1953 seq_printf(m, "%*sflags: 0x%08x\n", ind +1 , "", d->flags); 1954 + irq_debug_show_bits(m, ind, d->flags, irqdomain_flags, ARRAY_SIZE(irqdomain_flags)); 2032 1955 if (d->ops && d->ops->debug_show) 2033 1956 d->ops->debug_show(m, d, NULL, ind + 1); 2034 1957 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+2 -5
kernel/irq/proc.c
··· 461 461 { 462 462 static int prec; 463 463 464 - unsigned long flags, any_count = 0; 465 464 int i = *(loff_t *) v, j; 466 465 struct irqaction *action; 467 466 struct irq_desc *desc; 467 + unsigned long flags; 468 468 469 469 if (i > ACTUAL_NR_IRQS) 470 470 return 0; ··· 488 488 if (!desc || irq_settings_is_hidden(desc)) 489 489 goto outsparse; 490 490 491 - if (desc->kstat_irqs) 492 - any_count = kstat_irqs_desc(desc, cpu_online_mask); 493 - 494 - if ((!desc->action || irq_desc_is_chained(desc)) && !any_count) 491 + if (!desc->action || irq_desc_is_chained(desc) || !desc->kstat_irqs) 495 492 goto outsparse; 496 493 497 494 seq_printf(p, "%*d: ", prec, i);