mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-04 04:02:26 +00:00
Updates for the interrupt subsystem:
Core changes: - Prevent a potential deadlock when initial priority is assigned to a newly created interrupt thread. A recent change to plug a race between cpuset and __sched_setscheduler() introduced a new lock dependency which is now triggered. Break the lock dependency chain by moving the priority assignment to the thread function. - A couple of small updates to make the irq core RT safe. - Confine the irq_cpu_online/offline() API to the only left unfixable user Cavium Octeon so that it does not grow new usage. - A small documentation update Driver changes: - A large cross architecture rework to move irq_enter/exit() into the architecture code to make addressing the NOHZ_FULL/RCU issues simpler. - The obligatory new irq chip driver for Microchip EIC - Modularize a few irq chip drivers - Expand usage of devm_*() helpers throughout the driver code - The usual small fixes and improvements all over the place -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAmF+8BUTHHRnbHhAbGlu dXRyb25peC5kZQAKCRCmGPVMDXSYoWs2EACeNbL93aIFokd2/RllRSr4VvMjKNyW PpA0RYDOz1Jh4ldK+7b/EYapKgAkR3yyOtz+jyjRE7jsQK0pQeLtYNLd3cTzsD7K LCvl8rq6cbRqyFoSC15UKKNbQ/f+o/3LeGPoipr5NQZRMepxk2J/yBCNRXHvIbe6 oLMQJUgw7KKtvCrCUX9OSei4F09T1qsNrIYb7QafP5+v0zndAT7uKNivWrKGFrsh Uk9epoH3hIkvQERkpmzwJEJaq6oyqhoYQy7ZRGayEPwIdCyivJGZrVX0mZk1LX58 uc8u5grIslX9MqZEQWBweR5y7nISB494NGKmoCInu66U/+3DSOg3AGH2Rfw8PNFZ lMKdXzYoDgv2y6LeiLtTUKV4K1NBRXo0BhwSGbPw0o6C03/x003kG824Y+/naU75 6q05BZSia1PagPV3e0UAm0A2Rnjj/5uso2fEk0eGBSGM27jf9SQcSE8DVrEiLRd1 2N5uAXbMdfu4xACsEI1Uxu1KNOSQnUhBCy0X6Ppj1a083kLG7jg/126ebb05R8G4 MF79PFt+xUPSzmuKc/xwCdANtW+zzoyjYl5w6mwELBJ9veNbPShokGBTN/qzjXKZ vdr3/pXx95lRAzFnGOnETesm3IyObruU4K8NbMKd2b+eYa0w1WuZCKnutGLfsqxg byhCEw459e3P2g== =r6ln -----END PGP SIGNATURE----- Merge tag 'irq-core-2021-10-31' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull irq updates from Thomas Gleixner: "Updates for the interrupt subsystem: Core changes: - Prevent a potential deadlock when initial priority is assigned to a newly created interrupt thread. A recent change to plug a race between cpuset and __sched_setscheduler() introduced a new lock dependency which is now triggered. Break the lock dependency chain by moving the priority assignment to the thread function. - A couple of small updates to make the irq core RT safe. - Confine the irq_cpu_online/offline() API to the only left unfixable user Cavium Octeon so that it does not grow new usage. - A small documentation update Driver changes: - A large cross architecture rework to move irq_enter/exit() into the architecture code to make addressing the NOHZ_FULL/RCU issues simpler. - The obligatory new irq chip driver for Microchip EIC - Modularize a few irq chip drivers - Expand usage of devm_*() helpers throughout the driver code - The usual small fixes and improvements all over the place" * tag 'irq-core-2021-10-31' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (53 commits) h8300: Fix linux/irqchip.h include mess dt-bindings: irqchip: renesas-irqc: Document r8a774e1 bindings MIPS: irq: Avoid an unused-variable error genirq: Hide irq_cpu_{on,off}line() behind a deprecated option irqchip/mips-gic: Get rid of the reliance on irq_cpu_online() MIPS: loongson64: Drop call to irq_cpu_offline() irq: remove handle_domain_{irq,nmi}() irq: remove CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY irq: riscv: perform irqentry in entry code irq: openrisc: perform irqentry in entry code irq: csky: perform irqentry in entry code irq: arm64: perform irqentry in entry code irq: arm: perform irqentry in entry code irq: add a (temporary) CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY irq: nds32: avoid CONFIG_HANDLE_DOMAIN_IRQ irq: arc: avoid CONFIG_HANDLE_DOMAIN_IRQ irq: add generic_handle_arch_irq() irq: unexport handle_irq_desc() irq: simplify handle_domain_{irq,nmi}() irq: mips: simplify do_domain_IRQ() ...
This commit is contained in:
commit
5a47ebe98e
@ -67,9 +67,6 @@ variety of methods:
|
|||||||
deprecated
|
deprecated
|
||||||
- generic_handle_domain_irq() handles an interrupt described by a
|
- generic_handle_domain_irq() handles an interrupt described by a
|
||||||
domain and a hwirq number
|
domain and a hwirq number
|
||||||
- handle_domain_irq() does the same thing for root interrupt
|
|
||||||
controllers and deals with the set_irq_reg()/irq_enter() sequences
|
|
||||||
that most architecture requires
|
|
||||||
|
|
||||||
Note that irq domain lookups must happen in contexts that are
|
Note that irq domain lookups must happen in contexts that are
|
||||||
compatible with a RCU read-side critical section.
|
compatible with a RCU read-side critical section.
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/interrupt-controller/microchip,eic.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Microchip External Interrupt Controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Claudiu Beznea <claudiu.beznea@microchip.com>
|
||||||
|
|
||||||
|
description:
|
||||||
|
This interrupt controller is found in Microchip SoCs (SAMA7G5) and provides
|
||||||
|
support for handling up to 2 external interrupt lines.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- microchip,sama7g5-eic
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupt-controller: true
|
||||||
|
|
||||||
|
'#interrupt-cells':
|
||||||
|
const: 2
|
||||||
|
description:
|
||||||
|
The first cell is the input IRQ number (between 0 and 1), the second cell
|
||||||
|
is the trigger type as defined in interrupt.txt present in this directory.
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
description: |
|
||||||
|
Contains the GIC SPI IRQs mapped to the external interrupt lines. They
|
||||||
|
should be specified sequentially from output 0 to output 1.
|
||||||
|
minItems: 2
|
||||||
|
maxItems: 2
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
const: pclk
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupt-controller
|
||||||
|
- '#interrupt-cells'
|
||||||
|
- interrupts
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/clock/at91.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
|
||||||
|
eic: interrupt-controller@e1628000 {
|
||||||
|
compatible = "microchip,sama7g5-eic";
|
||||||
|
reg = <0xe1628000 0x100>;
|
||||||
|
interrupt-parent = <&gic>;
|
||||||
|
interrupt-controller;
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
clocks = <&pmc PMC_TYPE_PERIPHERAL 37>;
|
||||||
|
clock-names = "pclk";
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
@ -27,6 +27,7 @@ properties:
|
|||||||
- renesas,intc-ex-r8a774a1 # RZ/G2M
|
- renesas,intc-ex-r8a774a1 # RZ/G2M
|
||||||
- renesas,intc-ex-r8a774b1 # RZ/G2N
|
- renesas,intc-ex-r8a774b1 # RZ/G2N
|
||||||
- renesas,intc-ex-r8a774c0 # RZ/G2E
|
- renesas,intc-ex-r8a774c0 # RZ/G2E
|
||||||
|
- renesas,intc-ex-r8a774e1 # RZ/G2H
|
||||||
- renesas,intc-ex-r8a7795 # R-Car H3
|
- renesas,intc-ex-r8a7795 # R-Car H3
|
||||||
- renesas,intc-ex-r8a7796 # R-Car M3-W
|
- renesas,intc-ex-r8a7796 # R-Car M3-W
|
||||||
- renesas,intc-ex-r8a77961 # R-Car M3-W+
|
- renesas,intc-ex-r8a77961 # R-Car M3-W+
|
||||||
|
@ -1552,7 +1552,7 @@ ARM PRIMECELL VIC PL190/PL192 DRIVER
|
|||||||
M: Linus Walleij <linus.walleij@linaro.org>
|
M: Linus Walleij <linus.walleij@linaro.org>
|
||||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/devicetree/bindings/interrupt-controller/arm,vic.txt
|
F: Documentation/devicetree/bindings/interrupt-controller/arm,vic.yaml
|
||||||
F: drivers/irqchip/irq-vic.c
|
F: drivers/irqchip/irq-vic.c
|
||||||
|
|
||||||
ARM SMC WATCHDOG DRIVER
|
ARM SMC WATCHDOG DRIVER
|
||||||
@ -12270,6 +12270,12 @@ L: linux-crypto@vger.kernel.org
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/crypto/atmel-ecc.*
|
F: drivers/crypto/atmel-ecc.*
|
||||||
|
|
||||||
|
MICROCHIP EIC DRIVER
|
||||||
|
M: Claudiu Beznea <claudiu.beznea@microchip.com>
|
||||||
|
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||||
|
S: Supported
|
||||||
|
F: drivers/irqchip/irq-mchp-eic.c
|
||||||
|
|
||||||
MICROCHIP I2C DRIVER
|
MICROCHIP I2C DRIVER
|
||||||
M: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
|
M: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
|
||||||
L: linux-i2c@vger.kernel.org
|
L: linux-i2c@vger.kernel.org
|
||||||
|
@ -40,7 +40,6 @@ config ARC
|
|||||||
select HAVE_KRETPROBES
|
select HAVE_KRETPROBES
|
||||||
select HAVE_MOD_ARCH_SPECIFIC
|
select HAVE_MOD_ARCH_SPECIFIC
|
||||||
select HAVE_PERF_EVENTS
|
select HAVE_PERF_EVENTS
|
||||||
select HANDLE_DOMAIN_IRQ
|
|
||||||
select IRQ_DOMAIN
|
select IRQ_DOMAIN
|
||||||
select MODULES_USE_ELF_RELA
|
select MODULES_USE_ELF_RELA
|
||||||
select OF
|
select OF
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irqchip.h>
|
#include <linux/irqchip.h>
|
||||||
#include <asm/mach_desc.h>
|
#include <asm/mach_desc.h>
|
||||||
|
|
||||||
|
#include <asm/irq_regs.h>
|
||||||
#include <asm/smp.h>
|
#include <asm/smp.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -39,5 +41,11 @@ void __init init_IRQ(void)
|
|||||||
*/
|
*/
|
||||||
void arch_do_IRQ(unsigned int hwirq, struct pt_regs *regs)
|
void arch_do_IRQ(unsigned int hwirq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
handle_domain_irq(NULL, hwirq, regs);
|
struct pt_regs *old_regs;
|
||||||
|
|
||||||
|
irq_enter();
|
||||||
|
old_regs = set_irq_regs(regs);
|
||||||
|
generic_handle_domain_irq(NULL, hwirq);
|
||||||
|
set_irq_regs(old_regs);
|
||||||
|
irq_exit();
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,6 @@ config ARM
|
|||||||
select GENERIC_PCI_IOMAP
|
select GENERIC_PCI_IOMAP
|
||||||
select GENERIC_SCHED_CLOCK
|
select GENERIC_SCHED_CLOCK
|
||||||
select GENERIC_SMP_IDLE_THREAD
|
select GENERIC_SMP_IDLE_THREAD
|
||||||
select HANDLE_DOMAIN_IRQ
|
|
||||||
select HARDIRQS_SW_RESEND
|
select HARDIRQS_SW_RESEND
|
||||||
select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT
|
select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT
|
||||||
select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
|
select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
|
||||||
|
@ -38,14 +38,11 @@
|
|||||||
*/
|
*/
|
||||||
.macro irq_handler
|
.macro irq_handler
|
||||||
#ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER
|
#ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER
|
||||||
ldr r1, =handle_arch_irq
|
|
||||||
mov r0, sp
|
mov r0, sp
|
||||||
badr lr, 9997f
|
bl generic_handle_arch_irq
|
||||||
ldr pc, [r1]
|
|
||||||
#else
|
#else
|
||||||
arch_irq_handler_default
|
arch_irq_handler_default
|
||||||
#endif
|
#endif
|
||||||
9997:
|
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro pabt_helper
|
.macro pabt_helper
|
||||||
|
@ -63,11 +63,8 @@ int arch_show_interrupts(struct seq_file *p, int prec)
|
|||||||
*/
|
*/
|
||||||
void handle_IRQ(unsigned int irq, struct pt_regs *regs)
|
void handle_IRQ(unsigned int irq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
|
||||||
struct irq_desc *desc;
|
struct irq_desc *desc;
|
||||||
|
|
||||||
irq_enter();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some hardware gives randomly wrong interrupts. Rather
|
* Some hardware gives randomly wrong interrupts. Rather
|
||||||
* than crashing, do something sensible.
|
* than crashing, do something sensible.
|
||||||
@ -81,9 +78,6 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs)
|
|||||||
handle_irq_desc(desc);
|
handle_irq_desc(desc);
|
||||||
else
|
else
|
||||||
ack_bad_irq(irq);
|
ack_bad_irq(irq);
|
||||||
|
|
||||||
irq_exit();
|
|
||||||
set_irq_regs(old_regs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -92,7 +86,15 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs)
|
|||||||
asmlinkage void __exception_irq_entry
|
asmlinkage void __exception_irq_entry
|
||||||
asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
|
asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
struct pt_regs *old_regs;
|
||||||
|
|
||||||
|
irq_enter();
|
||||||
|
old_regs = set_irq_regs(regs);
|
||||||
|
|
||||||
handle_IRQ(irq, regs);
|
handle_IRQ(irq, regs);
|
||||||
|
|
||||||
|
set_irq_regs(old_regs);
|
||||||
|
irq_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init init_IRQ(void)
|
void __init init_IRQ(void)
|
||||||
|
@ -161,7 +161,6 @@ config ARCH_BCM2835
|
|||||||
select ARM_TIMER_SP804
|
select ARM_TIMER_SP804
|
||||||
select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
|
select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
|
||||||
select BCM2835_TIMER
|
select BCM2835_TIMER
|
||||||
select BRCMSTB_L2_IRQ
|
|
||||||
select PINCTRL
|
select PINCTRL
|
||||||
select PINCTRL_BCM2835
|
select PINCTRL_BCM2835
|
||||||
select MFD_CORE
|
select MFD_CORE
|
||||||
@ -209,9 +208,6 @@ config ARCH_BRCMSTB
|
|||||||
select ARM_GIC
|
select ARM_GIC
|
||||||
select ARM_ERRATA_798181 if SMP
|
select ARM_ERRATA_798181 if SMP
|
||||||
select HAVE_ARM_ARCH_TIMER
|
select HAVE_ARM_ARCH_TIMER
|
||||||
select BCM7038_L1_IRQ
|
|
||||||
select BRCMSTB_L2_IRQ
|
|
||||||
select BCM7120_L2_IRQ
|
|
||||||
select ZONE_DMA if ARM_LPAE
|
select ZONE_DMA if ARM_LPAE
|
||||||
select SOC_BRCMSTB
|
select SOC_BRCMSTB
|
||||||
select SOC_BUS
|
select SOC_BUS
|
||||||
|
@ -154,7 +154,7 @@ static void __exception_irq_entry avic_handle_irq(struct pt_regs *regs)
|
|||||||
if (nivector == 0xffff)
|
if (nivector == 0xffff)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
handle_domain_irq(domain, nivector, regs);
|
generic_handle_domain_irq(domain, nivector);
|
||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ static void __exception_irq_entry tzic_handle_irq(struct pt_regs *regs)
|
|||||||
while (stat) {
|
while (stat) {
|
||||||
handled = 1;
|
handled = 1;
|
||||||
irqofs = fls(stat) - 1;
|
irqofs = fls(stat) - 1;
|
||||||
handle_domain_irq(domain, irqofs + i * 32, regs);
|
generic_handle_domain_irq(domain, irqofs + i * 32);
|
||||||
stat &= ~(1 << irqofs);
|
stat &= ~(1 << irqofs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ asmlinkage void __exception_irq_entry omap1_handle_irq(struct pt_regs *regs)
|
|||||||
}
|
}
|
||||||
irq:
|
irq:
|
||||||
if (irqnr)
|
if (irqnr)
|
||||||
handle_domain_irq(domain, irqnr, regs);
|
generic_handle_domain_irq(domain, irqnr);
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
} while (irqnr);
|
} while (irqnr);
|
||||||
|
@ -354,7 +354,7 @@ static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
|
|||||||
if (!(pnd & (1 << offset)))
|
if (!(pnd & (1 << offset)))
|
||||||
offset = __ffs(pnd);
|
offset = __ffs(pnd);
|
||||||
|
|
||||||
handle_domain_irq(intc->domain, intc_offset + offset, regs);
|
generic_handle_domain_irq(intc->domain, intc_offset + offset);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +133,6 @@ config ARM64
|
|||||||
select GENERIC_TIME_VSYSCALL
|
select GENERIC_TIME_VSYSCALL
|
||||||
select GENERIC_GETTIMEOFDAY
|
select GENERIC_GETTIMEOFDAY
|
||||||
select GENERIC_VDSO_TIME_NS
|
select GENERIC_VDSO_TIME_NS
|
||||||
select HANDLE_DOMAIN_IRQ
|
|
||||||
select HARDIRQS_SW_RESEND
|
select HARDIRQS_SW_RESEND
|
||||||
select HAVE_MOVE_PMD
|
select HAVE_MOVE_PMD
|
||||||
select HAVE_MOVE_PUD
|
select HAVE_MOVE_PUD
|
||||||
|
@ -44,7 +44,6 @@ config ARCH_BCM2835
|
|||||||
select ARM_AMBA
|
select ARM_AMBA
|
||||||
select ARM_GIC
|
select ARM_GIC
|
||||||
select ARM_TIMER_SP804
|
select ARM_TIMER_SP804
|
||||||
select BRCMSTB_L2_IRQ
|
|
||||||
help
|
help
|
||||||
This enables support for the Broadcom BCM2837 and BCM2711 SoC.
|
This enables support for the Broadcom BCM2837 and BCM2711 SoC.
|
||||||
These SoCs are used in the Raspberry Pi 3 and 4 devices.
|
These SoCs are used in the Raspberry Pi 3 and 4 devices.
|
||||||
@ -82,8 +81,6 @@ config ARCH_BITMAIN
|
|||||||
config ARCH_BRCMSTB
|
config ARCH_BRCMSTB
|
||||||
bool "Broadcom Set-Top-Box SoCs"
|
bool "Broadcom Set-Top-Box SoCs"
|
||||||
select ARCH_HAS_RESET_CONTROLLER
|
select ARCH_HAS_RESET_CONTROLLER
|
||||||
select BCM7038_L1_IRQ
|
|
||||||
select BRCMSTB_L2_IRQ
|
|
||||||
select GENERIC_IRQ_CHIP
|
select GENERIC_IRQ_CHIP
|
||||||
select PINCTRL
|
select PINCTRL
|
||||||
help
|
help
|
||||||
@ -167,7 +164,6 @@ config ARCH_MEDIATEK
|
|||||||
config ARCH_MESON
|
config ARCH_MESON
|
||||||
bool "Amlogic Platforms"
|
bool "Amlogic Platforms"
|
||||||
select COMMON_CLK
|
select COMMON_CLK
|
||||||
select MESON_IRQ_GPIO
|
|
||||||
help
|
help
|
||||||
This enables support for the arm64 based Amlogic SoCs
|
This enables support for the arm64 based Amlogic SoCs
|
||||||
such as the s905, S905X/D, S912, A113X/D or S905X/D2
|
such as the s905, S905X/D, S912, A113X/D or S905X/D2
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <asm/daifflags.h>
|
#include <asm/daifflags.h>
|
||||||
#include <asm/esr.h>
|
#include <asm/esr.h>
|
||||||
#include <asm/exception.h>
|
#include <asm/exception.h>
|
||||||
|
#include <asm/irq_regs.h>
|
||||||
#include <asm/kprobes.h>
|
#include <asm/kprobes.h>
|
||||||
#include <asm/mmu.h>
|
#include <asm/mmu.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
@ -219,22 +220,6 @@ static void noinstr arm64_exit_el1_dbg(struct pt_regs *regs)
|
|||||||
lockdep_hardirqs_on(CALLER_ADDR0);
|
lockdep_hardirqs_on(CALLER_ADDR0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void noinstr enter_el1_irq_or_nmi(struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
if (IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && !interrupts_enabled(regs))
|
|
||||||
arm64_enter_nmi(regs);
|
|
||||||
else
|
|
||||||
enter_from_kernel_mode(regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void noinstr exit_el1_irq_or_nmi(struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
if (IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && !interrupts_enabled(regs))
|
|
||||||
arm64_exit_nmi(regs);
|
|
||||||
else
|
|
||||||
exit_to_kernel_mode(regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __sched arm64_preempt_schedule_irq(void)
|
static void __sched arm64_preempt_schedule_irq(void)
|
||||||
{
|
{
|
||||||
lockdep_assert_irqs_disabled();
|
lockdep_assert_irqs_disabled();
|
||||||
@ -263,10 +248,14 @@ static void __sched arm64_preempt_schedule_irq(void)
|
|||||||
static void do_interrupt_handler(struct pt_regs *regs,
|
static void do_interrupt_handler(struct pt_regs *regs,
|
||||||
void (*handler)(struct pt_regs *))
|
void (*handler)(struct pt_regs *))
|
||||||
{
|
{
|
||||||
|
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||||
|
|
||||||
if (on_thread_stack())
|
if (on_thread_stack())
|
||||||
call_on_irq_stack(regs, handler);
|
call_on_irq_stack(regs, handler);
|
||||||
else
|
else
|
||||||
handler(regs);
|
handler(regs);
|
||||||
|
|
||||||
|
set_irq_regs(old_regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void (*handle_arch_irq)(struct pt_regs *);
|
extern void (*handle_arch_irq)(struct pt_regs *);
|
||||||
@ -432,13 +421,22 @@ asmlinkage void noinstr el1h_64_sync_handler(struct pt_regs *regs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void noinstr el1_interrupt(struct pt_regs *regs,
|
static __always_inline void __el1_pnmi(struct pt_regs *regs,
|
||||||
void (*handler)(struct pt_regs *))
|
void (*handler)(struct pt_regs *))
|
||||||
{
|
{
|
||||||
write_sysreg(DAIF_PROCCTX_NOIRQ, daif);
|
arm64_enter_nmi(regs);
|
||||||
|
|
||||||
enter_el1_irq_or_nmi(regs);
|
|
||||||
do_interrupt_handler(regs, handler);
|
do_interrupt_handler(regs, handler);
|
||||||
|
arm64_exit_nmi(regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __always_inline void __el1_irq(struct pt_regs *regs,
|
||||||
|
void (*handler)(struct pt_regs *))
|
||||||
|
{
|
||||||
|
enter_from_kernel_mode(regs);
|
||||||
|
|
||||||
|
irq_enter_rcu();
|
||||||
|
do_interrupt_handler(regs, handler);
|
||||||
|
irq_exit_rcu();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: thread_info::preempt_count includes both thread_info::count
|
* Note: thread_info::preempt_count includes both thread_info::count
|
||||||
@ -449,7 +447,17 @@ static void noinstr el1_interrupt(struct pt_regs *regs,
|
|||||||
READ_ONCE(current_thread_info()->preempt_count) == 0)
|
READ_ONCE(current_thread_info()->preempt_count) == 0)
|
||||||
arm64_preempt_schedule_irq();
|
arm64_preempt_schedule_irq();
|
||||||
|
|
||||||
exit_el1_irq_or_nmi(regs);
|
exit_to_kernel_mode(regs);
|
||||||
|
}
|
||||||
|
static void noinstr el1_interrupt(struct pt_regs *regs,
|
||||||
|
void (*handler)(struct pt_regs *))
|
||||||
|
{
|
||||||
|
write_sysreg(DAIF_PROCCTX_NOIRQ, daif);
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && !interrupts_enabled(regs))
|
||||||
|
__el1_pnmi(regs, handler);
|
||||||
|
else
|
||||||
|
__el1_irq(regs, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage void noinstr el1h_64_irq_handler(struct pt_regs *regs)
|
asmlinkage void noinstr el1h_64_irq_handler(struct pt_regs *regs)
|
||||||
@ -667,7 +675,9 @@ static void noinstr el0_interrupt(struct pt_regs *regs,
|
|||||||
if (regs->pc & BIT(55))
|
if (regs->pc & BIT(55))
|
||||||
arm64_apply_bp_hardening();
|
arm64_apply_bp_hardening();
|
||||||
|
|
||||||
|
irq_enter_rcu();
|
||||||
do_interrupt_handler(regs, handler);
|
do_interrupt_handler(regs, handler);
|
||||||
|
irq_exit_rcu();
|
||||||
|
|
||||||
exit_to_user_mode(regs);
|
exit_to_user_mode(regs);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ config CSKY
|
|||||||
select CSKY_APB_INTC
|
select CSKY_APB_INTC
|
||||||
select DMA_DIRECT_REMAP
|
select DMA_DIRECT_REMAP
|
||||||
select IRQ_DOMAIN
|
select IRQ_DOMAIN
|
||||||
select HANDLE_DOMAIN_IRQ
|
|
||||||
select DW_APB_TIMER_OF
|
select DW_APB_TIMER_OF
|
||||||
select GENERIC_IOREMAP
|
select GENERIC_IOREMAP
|
||||||
select GENERIC_LIB_ASHLDI3
|
select GENERIC_LIB_ASHLDI3
|
||||||
|
@ -249,7 +249,7 @@ ENTRY(csky_irq)
|
|||||||
|
|
||||||
|
|
||||||
mov a0, sp
|
mov a0, sp
|
||||||
jbsr csky_do_IRQ
|
jbsr generic_handle_arch_irq
|
||||||
|
|
||||||
jmpi ret_from_exception
|
jmpi ret_from_exception
|
||||||
|
|
||||||
|
@ -15,8 +15,3 @@ void __init init_IRQ(void)
|
|||||||
setup_smp_ipi();
|
setup_smp_ipi();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage void __irq_entry csky_do_IRQ(struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
handle_arch_irq(regs);
|
|
||||||
}
|
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
#ifndef _H8300_IRQ_H_
|
#ifndef _H8300_IRQ_H_
|
||||||
#define _H8300_IRQ_H_
|
#define _H8300_IRQ_H_
|
||||||
|
|
||||||
#include <linux/irqchip.h>
|
|
||||||
|
|
||||||
#if defined(CONFIG_CPU_H8300H)
|
#if defined(CONFIG_CPU_H8300H)
|
||||||
#define NR_IRQS 64
|
#define NR_IRQS 64
|
||||||
#define IRQ_CHIP h8300h_irq_chip
|
#define IRQ_CHIP h8300h_irq_chip
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
|
#include <linux/irqchip.h>
|
||||||
#include <linux/irqdomain.h>
|
#include <linux/irqdomain.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <asm/traps.h>
|
#include <asm/traps.h>
|
||||||
|
@ -47,7 +47,6 @@ config MIPS
|
|||||||
select GENERIC_SMP_IDLE_THREAD
|
select GENERIC_SMP_IDLE_THREAD
|
||||||
select GENERIC_TIME_VSYSCALL
|
select GENERIC_TIME_VSYSCALL
|
||||||
select GUP_GET_PTE_LOW_HIGH if CPU_MIPS32 && PHYS_ADDR_T_64BIT
|
select GUP_GET_PTE_LOW_HIGH if CPU_MIPS32 && PHYS_ADDR_T_64BIT
|
||||||
select HANDLE_DOMAIN_IRQ
|
|
||||||
select HAVE_ARCH_COMPILER_H
|
select HAVE_ARCH_COMPILER_H
|
||||||
select HAVE_ARCH_JUMP_LABEL
|
select HAVE_ARCH_JUMP_LABEL
|
||||||
select HAVE_ARCH_KGDB if MIPS_FP_SUPPORT
|
select HAVE_ARCH_KGDB if MIPS_FP_SUPPORT
|
||||||
@ -1782,6 +1781,7 @@ config CPU_BMIPS
|
|||||||
select CPU_HAS_PREFETCH
|
select CPU_HAS_PREFETCH
|
||||||
select CPU_SUPPORTS_CPUFREQ
|
select CPU_SUPPORTS_CPUFREQ
|
||||||
select MIPS_EXTERNAL_TIMER
|
select MIPS_EXTERNAL_TIMER
|
||||||
|
select GENERIC_IRQ_MIGRATION if HOTPLUG_CPU
|
||||||
help
|
help
|
||||||
Support for BMIPS32/3300/4350/4380 and BMIPS5000 processors.
|
Support for BMIPS32/3300/4350/4380 and BMIPS5000 processors.
|
||||||
|
|
||||||
|
@ -2609,7 +2609,10 @@ static void octeon_irq_ciu3_ip2(void)
|
|||||||
else
|
else
|
||||||
hw = intsn;
|
hw = intsn;
|
||||||
|
|
||||||
ret = handle_domain_irq(domain, hw, NULL);
|
irq_enter();
|
||||||
|
ret = generic_handle_domain_irq(domain, hw);
|
||||||
|
irq_exit();
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
union cvmx_ciu3_iscx_w1c isc_w1c;
|
union cvmx_ciu3_iscx_w1c isc_w1c;
|
||||||
u64 isc_w1c_addr = ciu3_addr + CIU3_ISC_W1C(intsn);
|
u64 isc_w1c_addr = ciu3_addr + CIU3_ISC_W1C(intsn);
|
||||||
|
@ -111,15 +111,9 @@ void __irq_entry do_IRQ(unsigned int irq)
|
|||||||
#ifdef CONFIG_IRQ_DOMAIN
|
#ifdef CONFIG_IRQ_DOMAIN
|
||||||
void __irq_entry do_domain_IRQ(struct irq_domain *domain, unsigned int hwirq)
|
void __irq_entry do_domain_IRQ(struct irq_domain *domain, unsigned int hwirq)
|
||||||
{
|
{
|
||||||
struct irq_desc *desc;
|
|
||||||
|
|
||||||
irq_enter();
|
irq_enter();
|
||||||
check_stack_overflow();
|
check_stack_overflow();
|
||||||
|
generic_handle_domain_irq(domain, hwirq);
|
||||||
desc = irq_resolve_mapping(domain, hwirq);
|
|
||||||
if (likely(desc))
|
|
||||||
handle_irq_desc(desc);
|
|
||||||
|
|
||||||
irq_exit();
|
irq_exit();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <linux/bug.h>
|
#include <linux/bug.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/kexec.h>
|
#include <linux/kexec.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
|
||||||
#include <asm/time.h>
|
#include <asm/time.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
@ -373,7 +374,7 @@ static int bmips_cpu_disable(void)
|
|||||||
|
|
||||||
set_cpu_online(cpu, false);
|
set_cpu_online(cpu, false);
|
||||||
calculate_cpu_foreign_map();
|
calculate_cpu_foreign_map();
|
||||||
irq_cpu_offline();
|
irq_migrate_all_off_this_cpu();
|
||||||
clear_c0_status(IE_IRQ5);
|
clear_c0_status(IE_IRQ5);
|
||||||
|
|
||||||
local_flush_tlb_all();
|
local_flush_tlb_all();
|
||||||
|
@ -550,7 +550,6 @@ static int loongson3_cpu_disable(void)
|
|||||||
set_cpu_online(cpu, false);
|
set_cpu_online(cpu, false);
|
||||||
calculate_cpu_foreign_map();
|
calculate_cpu_foreign_map();
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
irq_cpu_offline();
|
|
||||||
clear_c0_status(ST0_IM);
|
clear_c0_status(ST0_IM);
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
local_flush_tlb_all();
|
local_flush_tlb_all();
|
||||||
|
@ -27,7 +27,6 @@ config NDS32
|
|||||||
select GENERIC_LIB_MULDI3
|
select GENERIC_LIB_MULDI3
|
||||||
select GENERIC_LIB_UCMPDI2
|
select GENERIC_LIB_UCMPDI2
|
||||||
select GENERIC_TIME_VSYSCALL
|
select GENERIC_TIME_VSYSCALL
|
||||||
select HANDLE_DOMAIN_IRQ
|
|
||||||
select HAVE_ARCH_TRACEHOOK
|
select HAVE_ARCH_TRACEHOOK
|
||||||
select HAVE_DEBUG_KMEMLEAK
|
select HAVE_DEBUG_KMEMLEAK
|
||||||
select HAVE_EXIT_THREAD
|
select HAVE_EXIT_THREAD
|
||||||
|
@ -13,7 +13,6 @@ config OPENRISC
|
|||||||
select OF
|
select OF
|
||||||
select OF_EARLY_FLATTREE
|
select OF_EARLY_FLATTREE
|
||||||
select IRQ_DOMAIN
|
select IRQ_DOMAIN
|
||||||
select HANDLE_DOMAIN_IRQ
|
|
||||||
select GPIOLIB
|
select GPIOLIB
|
||||||
select HAVE_ARCH_TRACEHOOK
|
select HAVE_ARCH_TRACEHOOK
|
||||||
select SPARSE_IRQ
|
select SPARSE_IRQ
|
||||||
|
@ -569,8 +569,8 @@ EXCEPTION_ENTRY(_external_irq_handler)
|
|||||||
#endif
|
#endif
|
||||||
CLEAR_LWA_FLAG(r3)
|
CLEAR_LWA_FLAG(r3)
|
||||||
l.addi r3,r1,0
|
l.addi r3,r1,0
|
||||||
l.movhi r8,hi(do_IRQ)
|
l.movhi r8,hi(generic_handle_arch_irq)
|
||||||
l.ori r8,r8,lo(do_IRQ)
|
l.ori r8,r8,lo(generic_handle_arch_irq)
|
||||||
l.jalr r8
|
l.jalr r8
|
||||||
l.nop
|
l.nop
|
||||||
l.j _ret_from_intr
|
l.j _ret_from_intr
|
||||||
|
@ -36,8 +36,3 @@ void __init init_IRQ(void)
|
|||||||
{
|
{
|
||||||
irqchip_init();
|
irqchip_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void __irq_entry do_IRQ(struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
handle_arch_irq(regs);
|
|
||||||
}
|
|
||||||
|
@ -62,7 +62,6 @@ config RISCV
|
|||||||
select GENERIC_SCHED_CLOCK
|
select GENERIC_SCHED_CLOCK
|
||||||
select GENERIC_SMP_IDLE_THREAD
|
select GENERIC_SMP_IDLE_THREAD
|
||||||
select GENERIC_TIME_VSYSCALL if MMU && 64BIT
|
select GENERIC_TIME_VSYSCALL if MMU && 64BIT
|
||||||
select HANDLE_DOMAIN_IRQ
|
|
||||||
select HAVE_ARCH_AUDITSYSCALL
|
select HAVE_ARCH_AUDITSYSCALL
|
||||||
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
|
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
|
||||||
select HAVE_ARCH_JUMP_LABEL_RELATIVE if !XIP_KERNEL
|
select HAVE_ARCH_JUMP_LABEL_RELATIVE if !XIP_KERNEL
|
||||||
|
@ -130,8 +130,7 @@ skip_context_tracking:
|
|||||||
|
|
||||||
/* Handle interrupts */
|
/* Handle interrupts */
|
||||||
move a0, sp /* pt_regs */
|
move a0, sp /* pt_regs */
|
||||||
la a1, handle_arch_irq
|
la a1, generic_handle_arch_irq
|
||||||
REG_L a1, (a1)
|
|
||||||
jr a1
|
jr a1
|
||||||
1:
|
1:
|
||||||
/*
|
/*
|
||||||
|
@ -140,12 +140,9 @@ void arch_irq_work_raise(void)
|
|||||||
|
|
||||||
void handle_IPI(struct pt_regs *regs)
|
void handle_IPI(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
|
||||||
unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
|
unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
|
||||||
unsigned long *stats = ipi_data[smp_processor_id()].stats;
|
unsigned long *stats = ipi_data[smp_processor_id()].stats;
|
||||||
|
|
||||||
irq_enter();
|
|
||||||
|
|
||||||
riscv_clear_ipi();
|
riscv_clear_ipi();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -156,7 +153,7 @@ void handle_IPI(struct pt_regs *regs)
|
|||||||
|
|
||||||
ops = xchg(pending_ipis, 0);
|
ops = xchg(pending_ipis, 0);
|
||||||
if (ops == 0)
|
if (ops == 0)
|
||||||
goto done;
|
return;
|
||||||
|
|
||||||
if (ops & (1 << IPI_RESCHEDULE)) {
|
if (ops & (1 << IPI_RESCHEDULE)) {
|
||||||
stats[IPI_RESCHEDULE]++;
|
stats[IPI_RESCHEDULE]++;
|
||||||
@ -189,10 +186,6 @@ void handle_IPI(struct pt_regs *regs)
|
|||||||
/* Order data access and bit testing. */
|
/* Order data access and bit testing. */
|
||||||
mb();
|
mb();
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
|
||||||
irq_exit();
|
|
||||||
set_irq_regs(old_regs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char * const ipi_names[] = {
|
static const char * const ipi_names[] = {
|
||||||
|
@ -185,6 +185,7 @@
|
|||||||
IRQ_CONSTRAINTS, regs, vector); \
|
IRQ_CONSTRAINTS, regs, vector); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_PREEMPT_RT
|
||||||
#define ASM_CALL_SOFTIRQ \
|
#define ASM_CALL_SOFTIRQ \
|
||||||
"call %P[__func] \n"
|
"call %P[__func] \n"
|
||||||
|
|
||||||
@ -201,6 +202,8 @@
|
|||||||
__this_cpu_write(hardirq_stack_inuse, false); \
|
__this_cpu_write(hardirq_stack_inuse, false); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#else /* CONFIG_X86_64 */
|
#else /* CONFIG_X86_64 */
|
||||||
/* System vector handlers always run on the stack they interrupted. */
|
/* System vector handlers always run on the stack they interrupted. */
|
||||||
#define run_sysvec_on_irqstack_cond(func, regs) \
|
#define run_sysvec_on_irqstack_cond(func, regs) \
|
||||||
|
@ -132,6 +132,7 @@ int irq_init_percpu_irqstack(unsigned int cpu)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_PREEMPT_RT
|
||||||
void do_softirq_own_stack(void)
|
void do_softirq_own_stack(void)
|
||||||
{
|
{
|
||||||
struct irq_stack *irqstk;
|
struct irq_stack *irqstk;
|
||||||
@ -148,6 +149,7 @@ void do_softirq_own_stack(void)
|
|||||||
|
|
||||||
call_on_stack(__do_softirq, isp);
|
call_on_stack(__do_softirq, isp);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void __handle_irq(struct irq_desc *desc, struct pt_regs *regs)
|
void __handle_irq(struct irq_desc *desc, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
@ -115,18 +115,24 @@ config BCM6345_L1_IRQ
|
|||||||
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||||
|
|
||||||
config BCM7038_L1_IRQ
|
config BCM7038_L1_IRQ
|
||||||
bool
|
tristate "Broadcom STB 7038-style L1/L2 interrupt controller driver"
|
||||||
|
depends on ARCH_BRCMSTB || BMIPS_GENERIC
|
||||||
|
default ARCH_BRCMSTB || BMIPS_GENERIC
|
||||||
select GENERIC_IRQ_CHIP
|
select GENERIC_IRQ_CHIP
|
||||||
select IRQ_DOMAIN
|
select IRQ_DOMAIN
|
||||||
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||||
|
|
||||||
config BCM7120_L2_IRQ
|
config BCM7120_L2_IRQ
|
||||||
bool
|
tristate "Broadcom STB 7120-style L2 interrupt controller driver"
|
||||||
|
depends on ARCH_BRCMSTB || BMIPS_GENERIC
|
||||||
|
default ARCH_BRCMSTB || BMIPS_GENERIC
|
||||||
select GENERIC_IRQ_CHIP
|
select GENERIC_IRQ_CHIP
|
||||||
select IRQ_DOMAIN
|
select IRQ_DOMAIN
|
||||||
|
|
||||||
config BRCMSTB_L2_IRQ
|
config BRCMSTB_L2_IRQ
|
||||||
bool
|
tristate "Broadcom STB generic L2 interrupt controller driver"
|
||||||
|
depends on ARCH_BCM2835 || ARCH_BRCMSTB || BMIPS_GENERIC
|
||||||
|
default ARCH_BCM2835 || ARCH_BRCMSTB || BMIPS_GENERIC
|
||||||
select GENERIC_IRQ_CHIP
|
select GENERIC_IRQ_CHIP
|
||||||
select IRQ_DOMAIN
|
select IRQ_DOMAIN
|
||||||
|
|
||||||
@ -400,8 +406,9 @@ config IRQ_UNIPHIER_AIDET
|
|||||||
Support for the UniPhier AIDET (ARM Interrupt Detector).
|
Support for the UniPhier AIDET (ARM Interrupt Detector).
|
||||||
|
|
||||||
config MESON_IRQ_GPIO
|
config MESON_IRQ_GPIO
|
||||||
bool "Meson GPIO Interrupt Multiplexer"
|
tristate "Meson GPIO Interrupt Multiplexer"
|
||||||
depends on ARCH_MESON
|
depends on ARCH_MESON || COMPILE_TEST
|
||||||
|
default ARCH_MESON
|
||||||
select IRQ_DOMAIN_HIERARCHY
|
select IRQ_DOMAIN_HIERARCHY
|
||||||
help
|
help
|
||||||
Support Meson SoC Family GPIO Interrupt Multiplexer
|
Support Meson SoC Family GPIO Interrupt Multiplexer
|
||||||
@ -602,4 +609,12 @@ config APPLE_AIC
|
|||||||
Support for the Apple Interrupt Controller found on Apple Silicon SoCs,
|
Support for the Apple Interrupt Controller found on Apple Silicon SoCs,
|
||||||
such as the M1.
|
such as the M1.
|
||||||
|
|
||||||
|
config MCHP_EIC
|
||||||
|
bool "Microchip External Interrupt Controller"
|
||||||
|
depends on ARCH_AT91 || COMPILE_TEST
|
||||||
|
select IRQ_DOMAIN
|
||||||
|
select IRQ_DOMAIN_HIERARCHY
|
||||||
|
help
|
||||||
|
Support for Microchip External Interrupt Controller.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
@ -116,3 +116,4 @@ obj-$(CONFIG_MACH_REALTEK_RTL) += irq-realtek-rtl.o
|
|||||||
obj-$(CONFIG_WPCM450_AIC) += irq-wpcm450-aic.o
|
obj-$(CONFIG_WPCM450_AIC) += irq-wpcm450-aic.o
|
||||||
obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o
|
obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o
|
||||||
obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o
|
obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o
|
||||||
|
obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o
|
||||||
|
@ -245,7 +245,7 @@ static void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
|
|||||||
irq = FIELD_GET(AIC_EVENT_NUM, event);
|
irq = FIELD_GET(AIC_EVENT_NUM, event);
|
||||||
|
|
||||||
if (type == AIC_EVENT_TYPE_HW)
|
if (type == AIC_EVENT_TYPE_HW)
|
||||||
handle_domain_irq(aic_irqc->hw_domain, irq, regs);
|
generic_handle_domain_irq(aic_irqc->hw_domain, irq);
|
||||||
else if (type == AIC_EVENT_TYPE_IPI && irq == 1)
|
else if (type == AIC_EVENT_TYPE_IPI && irq == 1)
|
||||||
aic_handle_ipi(regs);
|
aic_handle_ipi(regs);
|
||||||
else if (event != 0)
|
else if (event != 0)
|
||||||
@ -392,25 +392,25 @@ static void __exception_irq_entry aic_handle_fiq(struct pt_regs *regs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (TIMER_FIRING(read_sysreg(cntp_ctl_el0)))
|
if (TIMER_FIRING(read_sysreg(cntp_ctl_el0)))
|
||||||
handle_domain_irq(aic_irqc->hw_domain,
|
generic_handle_domain_irq(aic_irqc->hw_domain,
|
||||||
aic_irqc->nr_hw + AIC_TMR_EL0_PHYS, regs);
|
aic_irqc->nr_hw + AIC_TMR_EL0_PHYS);
|
||||||
|
|
||||||
if (TIMER_FIRING(read_sysreg(cntv_ctl_el0)))
|
if (TIMER_FIRING(read_sysreg(cntv_ctl_el0)))
|
||||||
handle_domain_irq(aic_irqc->hw_domain,
|
generic_handle_domain_irq(aic_irqc->hw_domain,
|
||||||
aic_irqc->nr_hw + AIC_TMR_EL0_VIRT, regs);
|
aic_irqc->nr_hw + AIC_TMR_EL0_VIRT);
|
||||||
|
|
||||||
if (is_kernel_in_hyp_mode()) {
|
if (is_kernel_in_hyp_mode()) {
|
||||||
uint64_t enabled = read_sysreg_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2);
|
uint64_t enabled = read_sysreg_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2);
|
||||||
|
|
||||||
if ((enabled & VM_TMR_FIQ_ENABLE_P) &&
|
if ((enabled & VM_TMR_FIQ_ENABLE_P) &&
|
||||||
TIMER_FIRING(read_sysreg_s(SYS_CNTP_CTL_EL02)))
|
TIMER_FIRING(read_sysreg_s(SYS_CNTP_CTL_EL02)))
|
||||||
handle_domain_irq(aic_irqc->hw_domain,
|
generic_handle_domain_irq(aic_irqc->hw_domain,
|
||||||
aic_irqc->nr_hw + AIC_TMR_EL02_PHYS, regs);
|
aic_irqc->nr_hw + AIC_TMR_EL02_PHYS);
|
||||||
|
|
||||||
if ((enabled & VM_TMR_FIQ_ENABLE_V) &&
|
if ((enabled & VM_TMR_FIQ_ENABLE_V) &&
|
||||||
TIMER_FIRING(read_sysreg_s(SYS_CNTV_CTL_EL02)))
|
TIMER_FIRING(read_sysreg_s(SYS_CNTV_CTL_EL02)))
|
||||||
handle_domain_irq(aic_irqc->hw_domain,
|
generic_handle_domain_irq(aic_irqc->hw_domain,
|
||||||
aic_irqc->nr_hw + AIC_TMR_EL02_VIRT, regs);
|
aic_irqc->nr_hw + AIC_TMR_EL02_VIRT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((read_sysreg_s(SYS_IMP_APL_PMCR0_EL1) & (PMCR0_IMODE | PMCR0_IACT)) ==
|
if ((read_sysreg_s(SYS_IMP_APL_PMCR0_EL1) & (PMCR0_IMODE | PMCR0_IACT)) ==
|
||||||
@ -674,7 +674,7 @@ static void aic_handle_ipi(struct pt_regs *regs)
|
|||||||
firing = atomic_fetch_andnot(enabled, this_cpu_ptr(&aic_vipi_flag)) & enabled;
|
firing = atomic_fetch_andnot(enabled, this_cpu_ptr(&aic_vipi_flag)) & enabled;
|
||||||
|
|
||||||
for_each_set_bit(i, &firing, AIC_NR_SWIPI)
|
for_each_set_bit(i, &firing, AIC_NR_SWIPI)
|
||||||
handle_domain_irq(aic_irqc->ipi_domain, i, regs);
|
generic_handle_domain_irq(aic_irqc->ipi_domain, i);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No ordering needed here; at worst this just changes the timing of
|
* No ordering needed here; at worst this just changes the timing of
|
||||||
|
@ -589,12 +589,7 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
|
|||||||
|
|
||||||
irq = msinr - PCI_MSI_DOORBELL_START;
|
irq = msinr - PCI_MSI_DOORBELL_START;
|
||||||
|
|
||||||
if (is_chained)
|
generic_handle_domain_irq(armada_370_xp_msi_inner_domain, irq);
|
||||||
generic_handle_domain_irq(armada_370_xp_msi_inner_domain,
|
|
||||||
irq);
|
|
||||||
else
|
|
||||||
handle_domain_irq(armada_370_xp_msi_inner_domain,
|
|
||||||
irq, regs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -646,8 +641,8 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (irqnr > 1) {
|
if (irqnr > 1) {
|
||||||
handle_domain_irq(armada_370_xp_mpic_domain,
|
generic_handle_domain_irq(armada_370_xp_mpic_domain,
|
||||||
irqnr, regs);
|
irqnr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,7 +661,7 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
|
|||||||
& IPI_DOORBELL_MASK;
|
& IPI_DOORBELL_MASK;
|
||||||
|
|
||||||
for_each_set_bit(ipi, &ipimask, IPI_DOORBELL_END)
|
for_each_set_bit(ipi, &ipimask, IPI_DOORBELL_END)
|
||||||
handle_domain_irq(ipi_domain, ipi, regs);
|
generic_handle_domain_irq(ipi_domain, ipi);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ static void __exception_irq_entry avic_handle_irq(struct pt_regs *regs)
|
|||||||
if (stat == 0)
|
if (stat == 0)
|
||||||
break;
|
break;
|
||||||
irq += ffs(stat) - 1;
|
irq += ffs(stat) - 1;
|
||||||
handle_domain_irq(vic->dom, irq, regs);
|
generic_handle_domain_irq(vic->dom, irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,11 +5,14 @@
|
|||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/hardirq.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irqdomain.h>
|
#include <linux/irqdomain.h>
|
||||||
#include <linux/irqchip.h>
|
#include <linux/irqchip.h>
|
||||||
#include <nds32_intrinsic.h>
|
#include <nds32_intrinsic.h>
|
||||||
|
|
||||||
|
#include <asm/irq_regs.h>
|
||||||
|
|
||||||
unsigned long wake_mask;
|
unsigned long wake_mask;
|
||||||
|
|
||||||
static void ativic32_ack_irq(struct irq_data *data)
|
static void ativic32_ack_irq(struct irq_data *data)
|
||||||
@ -103,10 +106,25 @@ static irq_hw_number_t get_intr_src(void)
|
|||||||
- NDS32_VECTOR_offINTERRUPT;
|
- NDS32_VECTOR_offINTERRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage void asm_do_IRQ(struct pt_regs *regs)
|
static void ativic32_handle_irq(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
irq_hw_number_t hwirq = get_intr_src();
|
irq_hw_number_t hwirq = get_intr_src();
|
||||||
handle_domain_irq(root_domain, hwirq, regs);
|
generic_handle_domain_irq(root_domain, hwirq);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: convert nds32 to GENERIC_IRQ_MULTI_HANDLER so that this entry logic
|
||||||
|
* can live in arch code.
|
||||||
|
*/
|
||||||
|
asmlinkage void asm_do_IRQ(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct pt_regs *old_regs;
|
||||||
|
|
||||||
|
irq_enter();
|
||||||
|
old_regs = set_irq_regs(regs);
|
||||||
|
ativic32_handle_irq(regs);
|
||||||
|
set_irq_regs(old_regs);
|
||||||
|
irq_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
int __init ativic32_init_irq(struct device_node *node, struct device_node *parent)
|
int __init ativic32_init_irq(struct device_node *node, struct device_node *parent)
|
||||||
|
@ -71,7 +71,7 @@ aic_handle(struct pt_regs *regs)
|
|||||||
if (!irqstat)
|
if (!irqstat)
|
||||||
irq_reg_writel(gc, 0, AT91_AIC_EOICR);
|
irq_reg_writel(gc, 0, AT91_AIC_EOICR);
|
||||||
else
|
else
|
||||||
handle_domain_irq(aic_domain, irqnr, regs);
|
generic_handle_domain_irq(aic_domain, irqnr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int aic_retrigger(struct irq_data *d)
|
static int aic_retrigger(struct irq_data *d)
|
||||||
|
@ -80,7 +80,7 @@ aic5_handle(struct pt_regs *regs)
|
|||||||
if (!irqstat)
|
if (!irqstat)
|
||||||
irq_reg_writel(bgc, 0, AT91_AIC5_EOICR);
|
irq_reg_writel(bgc, 0, AT91_AIC5_EOICR);
|
||||||
else
|
else
|
||||||
handle_domain_irq(aic5_domain, irqnr, regs);
|
generic_handle_domain_irq(aic5_domain, irqnr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aic5_mask(struct irq_data *d)
|
static void aic5_mask(struct irq_data *d)
|
||||||
|
@ -246,7 +246,7 @@ static void __exception_irq_entry bcm2835_handle_irq(
|
|||||||
u32 hwirq;
|
u32 hwirq;
|
||||||
|
|
||||||
while ((hwirq = get_next_armctrl_hwirq()) != ~0)
|
while ((hwirq = get_next_armctrl_hwirq()) != ~0)
|
||||||
handle_domain_irq(intc.domain, hwirq, regs);
|
generic_handle_domain_irq(intc.domain, hwirq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bcm2836_chained_handle_irq(struct irq_desc *desc)
|
static void bcm2836_chained_handle_irq(struct irq_desc *desc)
|
||||||
|
@ -143,7 +143,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
|
|||||||
if (stat) {
|
if (stat) {
|
||||||
u32 hwirq = ffs(stat) - 1;
|
u32 hwirq = ffs(stat) - 1;
|
||||||
|
|
||||||
handle_domain_irq(intc.domain, hwirq, regs);
|
generic_handle_domain_irq(intc.domain, hwirq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,16 +132,12 @@ static void bcm6345_l1_irq_handle(struct irq_desc *desc)
|
|||||||
int base = idx * IRQS_PER_WORD;
|
int base = idx * IRQS_PER_WORD;
|
||||||
unsigned long pending;
|
unsigned long pending;
|
||||||
irq_hw_number_t hwirq;
|
irq_hw_number_t hwirq;
|
||||||
unsigned int irq;
|
|
||||||
|
|
||||||
pending = __raw_readl(cpu->map_base + reg_status(intc, idx));
|
pending = __raw_readl(cpu->map_base + reg_status(intc, idx));
|
||||||
pending &= __raw_readl(cpu->map_base + reg_enable(intc, idx));
|
pending &= __raw_readl(cpu->map_base + reg_enable(intc, idx));
|
||||||
|
|
||||||
for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
|
for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
|
||||||
irq = irq_linear_revmap(intc->domain, base + hwirq);
|
if (generic_handle_domain_irq(intc->domain, base + hwirq))
|
||||||
if (irq)
|
|
||||||
do_IRQ(irq);
|
|
||||||
else
|
|
||||||
spurious_interrupt();
|
spurious_interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,6 @@
|
|||||||
#include <linux/irqchip.h>
|
#include <linux/irqchip.h>
|
||||||
#include <linux/irqchip/chained_irq.h>
|
#include <linux/irqchip/chained_irq.h>
|
||||||
#include <linux/syscore_ops.h>
|
#include <linux/syscore_ops.h>
|
||||||
#ifdef CONFIG_ARM
|
|
||||||
#include <asm/smp_plat.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define IRQS_PER_WORD 32
|
#define IRQS_PER_WORD 32
|
||||||
#define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 4)
|
#define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 4)
|
||||||
@ -127,7 +124,7 @@ static void bcm7038_l1_irq_handle(struct irq_desc *desc)
|
|||||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||||
unsigned int idx;
|
unsigned int idx;
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
|
||||||
cpu = intc->cpus[cpu_logical_map(smp_processor_id())];
|
cpu = intc->cpus[cpu_logical_map(smp_processor_id())];
|
||||||
#else
|
#else
|
||||||
cpu = intc->cpus[0];
|
cpu = intc->cpus[0];
|
||||||
@ -194,6 +191,7 @@ static void bcm7038_l1_mask(struct irq_data *d)
|
|||||||
raw_spin_unlock_irqrestore(&intc->lock, flags);
|
raw_spin_unlock_irqrestore(&intc->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_MIPS) && defined(CONFIG_SMP)
|
||||||
static int bcm7038_l1_set_affinity(struct irq_data *d,
|
static int bcm7038_l1_set_affinity(struct irq_data *d,
|
||||||
const struct cpumask *dest,
|
const struct cpumask *dest,
|
||||||
bool force)
|
bool force)
|
||||||
@ -220,32 +218,6 @@ static int bcm7038_l1_set_affinity(struct irq_data *d,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
static void bcm7038_l1_cpu_offline(struct irq_data *d)
|
|
||||||
{
|
|
||||||
struct cpumask *mask = irq_data_get_affinity_mask(d);
|
|
||||||
int cpu = smp_processor_id();
|
|
||||||
cpumask_t new_affinity;
|
|
||||||
|
|
||||||
/* This CPU was not on the affinity mask */
|
|
||||||
if (!cpumask_test_cpu(cpu, mask))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (cpumask_weight(mask) > 1) {
|
|
||||||
/*
|
|
||||||
* Multiple CPU affinity, remove this CPU from the affinity
|
|
||||||
* mask
|
|
||||||
*/
|
|
||||||
cpumask_copy(&new_affinity, mask);
|
|
||||||
cpumask_clear_cpu(cpu, &new_affinity);
|
|
||||||
} else {
|
|
||||||
/* Only CPU, put on the lowest online CPU */
|
|
||||||
cpumask_clear(&new_affinity);
|
|
||||||
cpumask_set_cpu(cpumask_first(cpu_online_mask), &new_affinity);
|
|
||||||
}
|
|
||||||
irq_set_affinity_locked(d, &new_affinity, false);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int __init bcm7038_l1_init_one(struct device_node *dn,
|
static int __init bcm7038_l1_init_one(struct device_node *dn,
|
||||||
@ -328,7 +300,7 @@ static int bcm7038_l1_suspend(void)
|
|||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
/* Wakeup interrupt should only come from the boot cpu */
|
/* Wakeup interrupt should only come from the boot cpu */
|
||||||
#ifdef CONFIG_SMP
|
#if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
|
||||||
boot_cpu = cpu_logical_map(0);
|
boot_cpu = cpu_logical_map(0);
|
||||||
#else
|
#else
|
||||||
boot_cpu = 0;
|
boot_cpu = 0;
|
||||||
@ -352,7 +324,7 @@ static void bcm7038_l1_resume(void)
|
|||||||
struct bcm7038_l1_chip *intc;
|
struct bcm7038_l1_chip *intc;
|
||||||
int boot_cpu, word;
|
int boot_cpu, word;
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
|
||||||
boot_cpu = cpu_logical_map(0);
|
boot_cpu = cpu_logical_map(0);
|
||||||
#else
|
#else
|
||||||
boot_cpu = 0;
|
boot_cpu = 0;
|
||||||
@ -395,9 +367,8 @@ static struct irq_chip bcm7038_l1_irq_chip = {
|
|||||||
.name = "bcm7038-l1",
|
.name = "bcm7038-l1",
|
||||||
.irq_mask = bcm7038_l1_mask,
|
.irq_mask = bcm7038_l1_mask,
|
||||||
.irq_unmask = bcm7038_l1_unmask,
|
.irq_unmask = bcm7038_l1_unmask,
|
||||||
|
#if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
|
||||||
.irq_set_affinity = bcm7038_l1_set_affinity,
|
.irq_set_affinity = bcm7038_l1_set_affinity,
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
.irq_cpu_offline = bcm7038_l1_cpu_offline,
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
.irq_set_wake = bcm7038_l1_set_wake,
|
.irq_set_wake = bcm7038_l1_set_wake,
|
||||||
@ -416,7 +387,7 @@ static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq,
|
|||||||
|
|
||||||
irq_set_chip_and_handler(virq, &bcm7038_l1_irq_chip, handle_level_irq);
|
irq_set_chip_and_handler(virq, &bcm7038_l1_irq_chip, handle_level_irq);
|
||||||
irq_set_chip_data(virq, d->host_data);
|
irq_set_chip_data(virq, d->host_data);
|
||||||
irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq)));
|
irqd_set_single_target(irq_get_irq_data(virq));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,4 +455,8 @@ static int __init bcm7038_l1_of_init(struct device_node *dn,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
IRQCHIP_DECLARE(bcm7038_l1, "brcm,bcm7038-l1-intc", bcm7038_l1_of_init);
|
IRQCHIP_PLATFORM_DRIVER_BEGIN(bcm7038_l1)
|
||||||
|
IRQCHIP_MATCH("brcm,bcm7038-l1-intc", bcm7038_l1_of_init)
|
||||||
|
IRQCHIP_PLATFORM_DRIVER_END(bcm7038_l1)
|
||||||
|
MODULE_DESCRIPTION("Broadcom STB 7038-style L1/L2 interrupt controller");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
@ -220,6 +220,7 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn,
|
|||||||
{
|
{
|
||||||
unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
|
unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
|
||||||
struct bcm7120_l2_intc_data *data;
|
struct bcm7120_l2_intc_data *data;
|
||||||
|
struct platform_device *pdev;
|
||||||
struct irq_chip_generic *gc;
|
struct irq_chip_generic *gc;
|
||||||
struct irq_chip_type *ct;
|
struct irq_chip_type *ct;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -230,7 +231,13 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn,
|
|||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
data->num_parent_irqs = of_irq_count(dn);
|
pdev = of_find_device_by_node(dn);
|
||||||
|
if (!pdev) {
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto out_free_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->num_parent_irqs = platform_irq_count(pdev);
|
||||||
if (data->num_parent_irqs <= 0) {
|
if (data->num_parent_irqs <= 0) {
|
||||||
pr_err("invalid number of parent interrupts\n");
|
pr_err("invalid number of parent interrupts\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
@ -329,6 +336,7 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn,
|
|||||||
if (data->map_base[idx])
|
if (data->map_base[idx])
|
||||||
iounmap(data->map_base[idx]);
|
iounmap(data->map_base[idx]);
|
||||||
}
|
}
|
||||||
|
out_free_data:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -347,8 +355,9 @@ static int __init bcm7120_l2_intc_probe_3380(struct device_node *dn,
|
|||||||
"BCM3380 L2");
|
"BCM3380 L2");
|
||||||
}
|
}
|
||||||
|
|
||||||
IRQCHIP_DECLARE(bcm7120_l2_intc, "brcm,bcm7120-l2-intc",
|
IRQCHIP_PLATFORM_DRIVER_BEGIN(bcm7120_l2)
|
||||||
bcm7120_l2_intc_probe_7120);
|
IRQCHIP_MATCH("brcm,bcm7120-l2-intc", bcm7120_l2_intc_probe_7120)
|
||||||
|
IRQCHIP_MATCH("brcm,bcm3380-l2-intc", bcm7120_l2_intc_probe_3380)
|
||||||
IRQCHIP_DECLARE(bcm3380_l2_intc, "brcm,bcm3380-l2-intc",
|
IRQCHIP_PLATFORM_DRIVER_END(bcm7120_l2)
|
||||||
bcm7120_l2_intc_probe_3380);
|
MODULE_DESCRIPTION("Broadcom STB 7120-style L2 interrupt controller driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
@ -275,16 +275,18 @@ static int __init brcmstb_l2_edge_intc_of_init(struct device_node *np,
|
|||||||
{
|
{
|
||||||
return brcmstb_l2_intc_of_init(np, parent, &l2_edge_intc_init);
|
return brcmstb_l2_intc_of_init(np, parent, &l2_edge_intc_init);
|
||||||
}
|
}
|
||||||
IRQCHIP_DECLARE(brcmstb_l2_intc, "brcm,l2-intc", brcmstb_l2_edge_intc_of_init);
|
|
||||||
IRQCHIP_DECLARE(brcmstb_hif_spi_l2_intc, "brcm,hif-spi-l2-intc",
|
|
||||||
brcmstb_l2_edge_intc_of_init);
|
|
||||||
IRQCHIP_DECLARE(brcmstb_upg_aux_aon_l2_intc, "brcm,upg-aux-aon-l2-intc",
|
|
||||||
brcmstb_l2_edge_intc_of_init);
|
|
||||||
|
|
||||||
static int __init brcmstb_l2_lvl_intc_of_init(struct device_node *np,
|
static int __init brcmstb_l2_lvl_intc_of_init(struct device_node *np,
|
||||||
struct device_node *parent)
|
struct device_node *parent)
|
||||||
{
|
{
|
||||||
return brcmstb_l2_intc_of_init(np, parent, &l2_lvl_intc_init);
|
return brcmstb_l2_intc_of_init(np, parent, &l2_lvl_intc_init);
|
||||||
}
|
}
|
||||||
IRQCHIP_DECLARE(bcm7271_l2_intc, "brcm,bcm7271-l2-intc",
|
|
||||||
brcmstb_l2_lvl_intc_of_init);
|
IRQCHIP_PLATFORM_DRIVER_BEGIN(brcmstb_l2)
|
||||||
|
IRQCHIP_MATCH("brcm,l2-intc", brcmstb_l2_edge_intc_of_init)
|
||||||
|
IRQCHIP_MATCH("brcm,hif-spi-l2-intc", brcmstb_l2_edge_intc_of_init)
|
||||||
|
IRQCHIP_MATCH("brcm,upg-aux-aon-l2-intc", brcmstb_l2_edge_intc_of_init)
|
||||||
|
IRQCHIP_MATCH("brcm,bcm7271-l2-intc", brcmstb_l2_lvl_intc_of_init)
|
||||||
|
IRQCHIP_PLATFORM_DRIVER_END(brcmstb_l2)
|
||||||
|
MODULE_DESCRIPTION("Broadcom STB generic L2 interrupt controller");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
@ -77,14 +77,14 @@ static asmlinkage void __exception_irq_entry clps711x_irqh(struct pt_regs *regs)
|
|||||||
irqstat = readw_relaxed(clps711x_intc->intmr[0]) &
|
irqstat = readw_relaxed(clps711x_intc->intmr[0]) &
|
||||||
readw_relaxed(clps711x_intc->intsr[0]);
|
readw_relaxed(clps711x_intc->intsr[0]);
|
||||||
if (irqstat)
|
if (irqstat)
|
||||||
handle_domain_irq(clps711x_intc->domain,
|
generic_handle_domain_irq(clps711x_intc->domain,
|
||||||
fls(irqstat) - 1, regs);
|
fls(irqstat) - 1);
|
||||||
|
|
||||||
irqstat = readw_relaxed(clps711x_intc->intmr[1]) &
|
irqstat = readw_relaxed(clps711x_intc->intmr[1]) &
|
||||||
readw_relaxed(clps711x_intc->intsr[1]);
|
readw_relaxed(clps711x_intc->intsr[1]);
|
||||||
if (irqstat)
|
if (irqstat)
|
||||||
handle_domain_irq(clps711x_intc->domain,
|
generic_handle_domain_irq(clps711x_intc->domain,
|
||||||
fls(irqstat) - 1 + 16, regs);
|
fls(irqstat) - 1 + 16);
|
||||||
} while (irqstat);
|
} while (irqstat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ static inline bool handle_irq_perbit(struct pt_regs *regs, u32 hwirq,
|
|||||||
if (hwirq == 0)
|
if (hwirq == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
handle_domain_irq(root_domain, irq_base + __fls(hwirq), regs);
|
generic_handle_domain_irq(root_domain, irq_base + __fls(hwirq));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -74,8 +74,8 @@ static void csky_mpintc_handler(struct pt_regs *regs)
|
|||||||
{
|
{
|
||||||
void __iomem *reg_base = this_cpu_read(intcl_reg);
|
void __iomem *reg_base = this_cpu_read(intcl_reg);
|
||||||
|
|
||||||
handle_domain_irq(root_domain,
|
generic_handle_domain_irq(root_domain,
|
||||||
readl_relaxed(reg_base + INTCL_RDYIR), regs);
|
readl_relaxed(reg_base + INTCL_RDYIR));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void csky_mpintc_enable(struct irq_data *d)
|
static void csky_mpintc_enable(struct irq_data *d)
|
||||||
|
@ -73,7 +73,7 @@ davinci_aintc_handle_irq(struct pt_regs *regs)
|
|||||||
irqnr >>= 2;
|
irqnr >>= 2;
|
||||||
irqnr -= 1;
|
irqnr -= 1;
|
||||||
|
|
||||||
handle_domain_irq(davinci_aintc_irq_domain, irqnr, regs);
|
generic_handle_domain_irq(davinci_aintc_irq_domain, irqnr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARM Interrupt Controller Initialization */
|
/* ARM Interrupt Controller Initialization */
|
||||||
|
@ -135,7 +135,7 @@ davinci_cp_intc_handle_irq(struct pt_regs *regs)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_domain_irq(davinci_cp_intc_irq_domain, irqnr, regs);
|
generic_handle_domain_irq(davinci_cp_intc_irq_domain, irqnr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int davinci_cp_intc_host_map(struct irq_domain *h, unsigned int virq,
|
static int davinci_cp_intc_host_map(struct irq_domain *h, unsigned int virq,
|
||||||
|
@ -50,7 +50,7 @@ static void __exception_irq_entry digicolor_handle_irq(struct pt_regs *regs)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_domain_irq(digicolor_irq_domain, hwirq, regs);
|
generic_handle_domain_irq(digicolor_irq_domain, hwirq);
|
||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ static void __irq_entry dw_apb_ictl_handle_irq(struct pt_regs *regs)
|
|||||||
while (stat) {
|
while (stat) {
|
||||||
u32 hwirq = ffs(stat) - 1;
|
u32 hwirq = ffs(stat) - 1;
|
||||||
|
|
||||||
handle_domain_irq(d, hwirq, regs);
|
generic_handle_domain_irq(d, hwirq);
|
||||||
stat &= ~BIT(hwirq);
|
stat &= ~BIT(hwirq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ asmlinkage void __exception_irq_entry ft010_irqchip_handle_irq(struct pt_regs *r
|
|||||||
|
|
||||||
while ((status = readl(FT010_IRQ_STATUS(f->base)))) {
|
while ((status = readl(FT010_IRQ_STATUS(f->base)))) {
|
||||||
irq = ffs(status) - 1;
|
irq = ffs(status) - 1;
|
||||||
handle_domain_irq(f->domain, irq, regs);
|
generic_handle_domain_irq(f->domain, irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -660,7 +660,7 @@ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
|
|||||||
* PSR.I will be restored when we ERET to the
|
* PSR.I will be restored when we ERET to the
|
||||||
* interrupted context.
|
* interrupted context.
|
||||||
*/
|
*/
|
||||||
err = handle_domain_nmi(gic_data.domain, irqnr, regs);
|
err = generic_handle_domain_nmi(gic_data.domain, irqnr);
|
||||||
if (err)
|
if (err)
|
||||||
gic_deactivate_unhandled(irqnr);
|
gic_deactivate_unhandled(irqnr);
|
||||||
|
|
||||||
@ -728,7 +728,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
|
|||||||
else
|
else
|
||||||
isb();
|
isb();
|
||||||
|
|
||||||
if (handle_domain_irq(gic_data.domain, irqnr, regs)) {
|
if (generic_handle_domain_irq(gic_data.domain, irqnr)) {
|
||||||
WARN_ONCE(true, "Unexpected interrupt received!\n");
|
WARN_ONCE(true, "Unexpected interrupt received!\n");
|
||||||
gic_deactivate_unhandled(irqnr);
|
gic_deactivate_unhandled(irqnr);
|
||||||
}
|
}
|
||||||
|
@ -369,7 +369,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
|
|||||||
this_cpu_write(sgi_intid, irqstat);
|
this_cpu_write(sgi_intid, irqstat);
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_domain_irq(gic->domain, irqnr, regs);
|
generic_handle_domain_irq(gic->domain, irqnr);
|
||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs)
|
|||||||
irqnr = irqstat & GICC_IAR_INT_ID_MASK;
|
irqnr = irqstat & GICC_IAR_INT_ID_MASK;
|
||||||
|
|
||||||
if (irqnr <= HIP04_MAX_IRQS)
|
if (irqnr <= HIP04_MAX_IRQS)
|
||||||
handle_domain_irq(hip04_data.domain, irqnr, regs);
|
generic_handle_domain_irq(hip04_data.domain, irqnr);
|
||||||
} while (irqnr > HIP04_MAX_IRQS);
|
} while (irqnr > HIP04_MAX_IRQS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ asmlinkage void __exception_irq_entry ixp4xx_handle_irq(struct pt_regs *regs)
|
|||||||
|
|
||||||
status = __raw_readl(ixi->irqbase + IXP4XX_ICIP);
|
status = __raw_readl(ixi->irqbase + IXP4XX_ICIP);
|
||||||
for_each_set_bit(i, &status, 32)
|
for_each_set_bit(i, &status, 32)
|
||||||
handle_domain_irq(ixi->domain, i, regs);
|
generic_handle_domain_irq(ixi->domain, i);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IXP465/IXP435 has an upper IRQ status register
|
* IXP465/IXP435 has an upper IRQ status register
|
||||||
@ -122,7 +122,7 @@ asmlinkage void __exception_irq_entry ixp4xx_handle_irq(struct pt_regs *regs)
|
|||||||
if (ixi->is_356) {
|
if (ixi->is_356) {
|
||||||
status = __raw_readl(ixi->irqbase + IXP4XX_ICIP2);
|
status = __raw_readl(ixi->irqbase + IXP4XX_ICIP2);
|
||||||
for_each_set_bit(i, &status, 32)
|
for_each_set_bit(i, &status, 32)
|
||||||
handle_domain_irq(ixi->domain, i + 32, regs);
|
generic_handle_domain_irq(ixi->domain, i + 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ static void __exception_irq_entry lpc32xx_handle_irq(struct pt_regs *regs)
|
|||||||
while (hwirq) {
|
while (hwirq) {
|
||||||
irq = __ffs(hwirq);
|
irq = __ffs(hwirq);
|
||||||
hwirq &= ~BIT(irq);
|
hwirq &= ~BIT(irq);
|
||||||
handle_domain_irq(lpc32xx_mic_irqc->domain, irq, regs);
|
generic_handle_domain_irq(lpc32xx_mic_irqc->domain, irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
280
drivers/irqchip/irq-mchp-eic.c
Normal file
280
drivers/irqchip/irq-mchp-eic.c
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Microchip External Interrupt Controller driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Microchip Technology Inc. and its subsidiaries
|
||||||
|
*
|
||||||
|
* Author: Claudiu Beznea <claudiu.beznea@microchip.com>
|
||||||
|
*/
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/irqchip.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
#include <linux/syscore_ops.h>
|
||||||
|
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
|
||||||
|
#define MCHP_EIC_GFCS (0x0)
|
||||||
|
#define MCHP_EIC_SCFG(x) (0x4 + (x) * 0x4)
|
||||||
|
#define MCHP_EIC_SCFG_EN BIT(16)
|
||||||
|
#define MCHP_EIC_SCFG_LVL BIT(9)
|
||||||
|
#define MCHP_EIC_SCFG_POL BIT(8)
|
||||||
|
|
||||||
|
#define MCHP_EIC_NIRQ (2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct mchp_eic - EIC private data structure
|
||||||
|
* @base: base address
|
||||||
|
* @clk: peripheral clock
|
||||||
|
* @domain: irq domain
|
||||||
|
* @irqs: irqs b/w eic and gic
|
||||||
|
* @scfg: backup for scfg registers (necessary for backup and self-refresh mode)
|
||||||
|
* @wakeup_source: wakeup source mask
|
||||||
|
*/
|
||||||
|
struct mchp_eic {
|
||||||
|
void __iomem *base;
|
||||||
|
struct clk *clk;
|
||||||
|
struct irq_domain *domain;
|
||||||
|
u32 irqs[MCHP_EIC_NIRQ];
|
||||||
|
u32 scfg[MCHP_EIC_NIRQ];
|
||||||
|
u32 wakeup_source;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mchp_eic *eic;
|
||||||
|
|
||||||
|
static void mchp_eic_irq_mask(struct irq_data *d)
|
||||||
|
{
|
||||||
|
unsigned int tmp;
|
||||||
|
|
||||||
|
tmp = readl_relaxed(eic->base + MCHP_EIC_SCFG(d->hwirq));
|
||||||
|
tmp &= ~MCHP_EIC_SCFG_EN;
|
||||||
|
writel_relaxed(tmp, eic->base + MCHP_EIC_SCFG(d->hwirq));
|
||||||
|
|
||||||
|
irq_chip_mask_parent(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mchp_eic_irq_unmask(struct irq_data *d)
|
||||||
|
{
|
||||||
|
unsigned int tmp;
|
||||||
|
|
||||||
|
tmp = readl_relaxed(eic->base + MCHP_EIC_SCFG(d->hwirq));
|
||||||
|
tmp |= MCHP_EIC_SCFG_EN;
|
||||||
|
writel_relaxed(tmp, eic->base + MCHP_EIC_SCFG(d->hwirq));
|
||||||
|
|
||||||
|
irq_chip_unmask_parent(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mchp_eic_irq_set_type(struct irq_data *d, unsigned int type)
|
||||||
|
{
|
||||||
|
unsigned int parent_irq_type;
|
||||||
|
unsigned int tmp;
|
||||||
|
|
||||||
|
tmp = readl_relaxed(eic->base + MCHP_EIC_SCFG(d->hwirq));
|
||||||
|
tmp &= ~(MCHP_EIC_SCFG_POL | MCHP_EIC_SCFG_LVL);
|
||||||
|
switch (type) {
|
||||||
|
case IRQ_TYPE_LEVEL_HIGH:
|
||||||
|
tmp |= MCHP_EIC_SCFG_POL | MCHP_EIC_SCFG_LVL;
|
||||||
|
parent_irq_type = IRQ_TYPE_LEVEL_HIGH;
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_LEVEL_LOW:
|
||||||
|
tmp |= MCHP_EIC_SCFG_LVL;
|
||||||
|
parent_irq_type = IRQ_TYPE_LEVEL_HIGH;
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_EDGE_RISING:
|
||||||
|
parent_irq_type = IRQ_TYPE_EDGE_RISING;
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_EDGE_FALLING:
|
||||||
|
tmp |= MCHP_EIC_SCFG_POL;
|
||||||
|
parent_irq_type = IRQ_TYPE_EDGE_RISING;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel_relaxed(tmp, eic->base + MCHP_EIC_SCFG(d->hwirq));
|
||||||
|
|
||||||
|
return irq_chip_set_type_parent(d, parent_irq_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mchp_eic_irq_set_wake(struct irq_data *d, unsigned int on)
|
||||||
|
{
|
||||||
|
irq_set_irq_wake(eic->irqs[d->hwirq], on);
|
||||||
|
if (on)
|
||||||
|
eic->wakeup_source |= BIT(d->hwirq);
|
||||||
|
else
|
||||||
|
eic->wakeup_source &= ~BIT(d->hwirq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mchp_eic_irq_suspend(void)
|
||||||
|
{
|
||||||
|
unsigned int hwirq;
|
||||||
|
|
||||||
|
for (hwirq = 0; hwirq < MCHP_EIC_NIRQ; hwirq++)
|
||||||
|
eic->scfg[hwirq] = readl_relaxed(eic->base +
|
||||||
|
MCHP_EIC_SCFG(hwirq));
|
||||||
|
|
||||||
|
if (!eic->wakeup_source)
|
||||||
|
clk_disable_unprepare(eic->clk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mchp_eic_irq_resume(void)
|
||||||
|
{
|
||||||
|
unsigned int hwirq;
|
||||||
|
|
||||||
|
if (!eic->wakeup_source)
|
||||||
|
clk_prepare_enable(eic->clk);
|
||||||
|
|
||||||
|
for (hwirq = 0; hwirq < MCHP_EIC_NIRQ; hwirq++)
|
||||||
|
writel_relaxed(eic->scfg[hwirq], eic->base +
|
||||||
|
MCHP_EIC_SCFG(hwirq));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct syscore_ops mchp_eic_syscore_ops = {
|
||||||
|
.suspend = mchp_eic_irq_suspend,
|
||||||
|
.resume = mchp_eic_irq_resume,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct irq_chip mchp_eic_chip = {
|
||||||
|
.name = "eic",
|
||||||
|
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SET_TYPE_MASKED,
|
||||||
|
.irq_mask = mchp_eic_irq_mask,
|
||||||
|
.irq_unmask = mchp_eic_irq_unmask,
|
||||||
|
.irq_set_type = mchp_eic_irq_set_type,
|
||||||
|
.irq_ack = irq_chip_ack_parent,
|
||||||
|
.irq_eoi = irq_chip_eoi_parent,
|
||||||
|
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
||||||
|
.irq_set_wake = mchp_eic_irq_set_wake,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mchp_eic_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||||
|
unsigned int nr_irqs, void *data)
|
||||||
|
{
|
||||||
|
struct irq_fwspec *fwspec = data;
|
||||||
|
struct irq_fwspec parent_fwspec;
|
||||||
|
irq_hw_number_t hwirq;
|
||||||
|
unsigned int type;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (WARN_ON(nr_irqs != 1))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type);
|
||||||
|
if (ret || hwirq >= MCHP_EIC_NIRQ)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case IRQ_TYPE_EDGE_RISING:
|
||||||
|
case IRQ_TYPE_LEVEL_HIGH:
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_EDGE_FALLING:
|
||||||
|
type = IRQ_TYPE_EDGE_RISING;
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_LEVEL_LOW:
|
||||||
|
type = IRQ_TYPE_LEVEL_HIGH;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &mchp_eic_chip, eic);
|
||||||
|
|
||||||
|
parent_fwspec.fwnode = domain->parent->fwnode;
|
||||||
|
parent_fwspec.param_count = 3;
|
||||||
|
parent_fwspec.param[0] = GIC_SPI;
|
||||||
|
parent_fwspec.param[1] = eic->irqs[hwirq];
|
||||||
|
parent_fwspec.param[2] = type;
|
||||||
|
|
||||||
|
return irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct irq_domain_ops mchp_eic_domain_ops = {
|
||||||
|
.translate = irq_domain_translate_twocell,
|
||||||
|
.alloc = mchp_eic_domain_alloc,
|
||||||
|
.free = irq_domain_free_irqs_common,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mchp_eic_init(struct device_node *node, struct device_node *parent)
|
||||||
|
{
|
||||||
|
struct irq_domain *parent_domain = NULL;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
eic = kzalloc(sizeof(*eic), GFP_KERNEL);
|
||||||
|
if (!eic)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
eic->base = of_iomap(node, 0);
|
||||||
|
if (!eic->base) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent_domain = irq_find_host(parent);
|
||||||
|
if (!parent_domain) {
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto unmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
eic->clk = of_clk_get_by_name(node, "pclk");
|
||||||
|
if (IS_ERR(eic->clk)) {
|
||||||
|
ret = PTR_ERR(eic->clk);
|
||||||
|
goto unmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(eic->clk);
|
||||||
|
if (ret)
|
||||||
|
goto unmap;
|
||||||
|
|
||||||
|
for (i = 0; i < MCHP_EIC_NIRQ; i++) {
|
||||||
|
struct of_phandle_args irq;
|
||||||
|
|
||||||
|
/* Disable it, if any. */
|
||||||
|
writel_relaxed(0UL, eic->base + MCHP_EIC_SCFG(i));
|
||||||
|
|
||||||
|
ret = of_irq_parse_one(node, i, &irq);
|
||||||
|
if (ret)
|
||||||
|
goto clk_unprepare;
|
||||||
|
|
||||||
|
if (WARN_ON(irq.args_count != 3)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto clk_unprepare;
|
||||||
|
}
|
||||||
|
|
||||||
|
eic->irqs[i] = irq.args[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
eic->domain = irq_domain_add_hierarchy(parent_domain, 0, MCHP_EIC_NIRQ,
|
||||||
|
node, &mchp_eic_domain_ops, eic);
|
||||||
|
if (!eic->domain) {
|
||||||
|
pr_err("%pOF: Failed to add domain\n", node);
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto clk_unprepare;
|
||||||
|
}
|
||||||
|
|
||||||
|
register_syscore_ops(&mchp_eic_syscore_ops);
|
||||||
|
|
||||||
|
pr_info("%pOF: EIC registered, nr_irqs %u\n", node, MCHP_EIC_NIRQ);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
clk_unprepare:
|
||||||
|
clk_disable_unprepare(eic->clk);
|
||||||
|
unmap:
|
||||||
|
iounmap(eic->base);
|
||||||
|
free:
|
||||||
|
kfree(eic);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
IRQCHIP_PLATFORM_DRIVER_BEGIN(mchp_eic)
|
||||||
|
IRQCHIP_MATCH("microchip,sama7g5-eic", mchp_eic_init)
|
||||||
|
IRQCHIP_PLATFORM_DRIVER_END(mchp_eic)
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Microchip External Interrupt Controller");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea@microchip.com>");
|
@ -436,8 +436,7 @@ static const struct irq_domain_ops meson_gpio_irq_domain_ops = {
|
|||||||
.translate = meson_gpio_irq_domain_translate,
|
.translate = meson_gpio_irq_domain_translate,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init meson_gpio_irq_parse_dt(struct device_node *node,
|
static int meson_gpio_irq_parse_dt(struct device_node *node, struct meson_gpio_irq_controller *ctl)
|
||||||
struct meson_gpio_irq_controller *ctl)
|
|
||||||
{
|
{
|
||||||
const struct of_device_id *match;
|
const struct of_device_id *match;
|
||||||
int ret;
|
int ret;
|
||||||
@ -463,8 +462,7 @@ static int __init meson_gpio_irq_parse_dt(struct device_node *node,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init meson_gpio_irq_of_init(struct device_node *node,
|
static int meson_gpio_irq_of_init(struct device_node *node, struct device_node *parent)
|
||||||
struct device_node *parent)
|
|
||||||
{
|
{
|
||||||
struct irq_domain *domain, *parent_domain;
|
struct irq_domain *domain, *parent_domain;
|
||||||
struct meson_gpio_irq_controller *ctl;
|
struct meson_gpio_irq_controller *ctl;
|
||||||
@ -521,5 +519,10 @@ static int __init meson_gpio_irq_of_init(struct device_node *node,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
IRQCHIP_DECLARE(meson_gpio_intc, "amlogic,meson-gpio-intc",
|
IRQCHIP_PLATFORM_DRIVER_BEGIN(meson_gpio_intc)
|
||||||
meson_gpio_irq_of_init);
|
IRQCHIP_MATCH("amlogic,meson-gpio-intc", meson_gpio_irq_of_init)
|
||||||
|
IRQCHIP_PLATFORM_DRIVER_END(meson_gpio_intc)
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_ALIAS("platform:meson-gpio-intc");
|
||||||
|
@ -381,24 +381,35 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d)
|
|||||||
spin_unlock_irqrestore(&gic_lock, flags);
|
spin_unlock_irqrestore(&gic_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gic_all_vpes_irq_cpu_online(struct irq_data *d)
|
static void gic_all_vpes_irq_cpu_online(void)
|
||||||
{
|
{
|
||||||
struct gic_all_vpes_chip_data *cd;
|
static const unsigned int local_intrs[] = {
|
||||||
unsigned int intr;
|
GIC_LOCAL_INT_TIMER,
|
||||||
|
GIC_LOCAL_INT_PERFCTR,
|
||||||
|
GIC_LOCAL_INT_FDC,
|
||||||
|
};
|
||||||
|
unsigned long flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
|
spin_lock_irqsave(&gic_lock, flags);
|
||||||
cd = irq_data_get_irq_chip_data(d);
|
|
||||||
|
|
||||||
write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map);
|
for (i = 0; i < ARRAY_SIZE(local_intrs); i++) {
|
||||||
if (cd->mask)
|
unsigned int intr = local_intrs[i];
|
||||||
write_gic_vl_smask(BIT(intr));
|
struct gic_all_vpes_chip_data *cd;
|
||||||
|
|
||||||
|
cd = &gic_all_vpes_chip_data[intr];
|
||||||
|
write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map);
|
||||||
|
if (cd->mask)
|
||||||
|
write_gic_vl_smask(BIT(intr));
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&gic_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_chip gic_all_vpes_local_irq_controller = {
|
static struct irq_chip gic_all_vpes_local_irq_controller = {
|
||||||
.name = "MIPS GIC Local",
|
.name = "MIPS GIC Local",
|
||||||
.irq_mask = gic_mask_local_irq_all_vpes,
|
.irq_mask = gic_mask_local_irq_all_vpes,
|
||||||
.irq_unmask = gic_unmask_local_irq_all_vpes,
|
.irq_unmask = gic_unmask_local_irq_all_vpes,
|
||||||
.irq_cpu_online = gic_all_vpes_irq_cpu_online,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __gic_irq_dispatch(void)
|
static void __gic_irq_dispatch(void)
|
||||||
@ -477,6 +488,10 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
|||||||
intr = GIC_HWIRQ_TO_LOCAL(hwirq);
|
intr = GIC_HWIRQ_TO_LOCAL(hwirq);
|
||||||
map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
|
map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If adding support for more per-cpu interrupts, keep the the
|
||||||
|
* array in gic_all_vpes_irq_cpu_online() in sync.
|
||||||
|
*/
|
||||||
switch (intr) {
|
switch (intr) {
|
||||||
case GIC_LOCAL_INT_TIMER:
|
case GIC_LOCAL_INT_TIMER:
|
||||||
/* CONFIG_MIPS_CMP workaround (see __gic_init) */
|
/* CONFIG_MIPS_CMP workaround (see __gic_init) */
|
||||||
@ -663,8 +678,8 @@ static int gic_cpu_startup(unsigned int cpu)
|
|||||||
/* Clear all local IRQ masks (ie. disable all local interrupts) */
|
/* Clear all local IRQ masks (ie. disable all local interrupts) */
|
||||||
write_gic_vl_rmask(~0);
|
write_gic_vl_rmask(~0);
|
||||||
|
|
||||||
/* Invoke irq_cpu_online callbacks to enable desired interrupts */
|
/* Enable desired interrupts */
|
||||||
irq_cpu_online();
|
gic_all_vpes_irq_cpu_online();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -230,7 +230,7 @@ static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
|
|||||||
if (!(hwirq & SEL_INT_PENDING))
|
if (!(hwirq & SEL_INT_PENDING))
|
||||||
return;
|
return;
|
||||||
hwirq &= SEL_INT_NUM_MASK;
|
hwirq &= SEL_INT_NUM_MASK;
|
||||||
handle_domain_irq(icu_data[0].domain, hwirq, regs);
|
generic_handle_domain_irq(icu_data[0].domain, hwirq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs)
|
static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs)
|
||||||
@ -241,7 +241,7 @@ static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs)
|
|||||||
if (!(hwirq & SEL_INT_PENDING))
|
if (!(hwirq & SEL_INT_PENDING))
|
||||||
return;
|
return;
|
||||||
hwirq &= SEL_INT_NUM_MASK;
|
hwirq &= SEL_INT_NUM_MASK;
|
||||||
handle_domain_irq(icu_data[0].domain, hwirq, regs);
|
generic_handle_domain_irq(icu_data[0].domain, hwirq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MMP (ARMv5) */
|
/* MMP (ARMv5) */
|
||||||
|
@ -347,7 +347,6 @@ builtin_platform_driver(mvebu_icu_subset_driver);
|
|||||||
static int mvebu_icu_probe(struct platform_device *pdev)
|
static int mvebu_icu_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct mvebu_icu *icu;
|
struct mvebu_icu *icu;
|
||||||
struct resource *res;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu),
|
icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu),
|
||||||
@ -357,8 +356,7 @@ static int mvebu_icu_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
icu->dev = &pdev->dev;
|
icu->dev = &pdev->dev;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
icu->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
icu->base = devm_ioremap_resource(&pdev->dev, res);
|
|
||||||
if (IS_ERR(icu->base))
|
if (IS_ERR(icu->base))
|
||||||
return PTR_ERR(icu->base);
|
return PTR_ERR(icu->base);
|
||||||
|
|
||||||
|
@ -121,14 +121,12 @@ static int mvebu_pic_probe(struct platform_device *pdev)
|
|||||||
struct device_node *node = pdev->dev.of_node;
|
struct device_node *node = pdev->dev.of_node;
|
||||||
struct mvebu_pic *pic;
|
struct mvebu_pic *pic;
|
||||||
struct irq_chip *irq_chip;
|
struct irq_chip *irq_chip;
|
||||||
struct resource *res;
|
|
||||||
|
|
||||||
pic = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pic), GFP_KERNEL);
|
pic = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pic), GFP_KERNEL);
|
||||||
if (!pic)
|
if (!pic)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
pic->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
pic->base = devm_ioremap_resource(&pdev->dev, res);
|
|
||||||
if (IS_ERR(pic->base))
|
if (IS_ERR(pic->base))
|
||||||
return PTR_ERR(pic->base);
|
return PTR_ERR(pic->base);
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
|
|||||||
|
|
||||||
irqnr = __raw_readl(icoll_priv.stat);
|
irqnr = __raw_readl(icoll_priv.stat);
|
||||||
__raw_writel(irqnr, icoll_priv.vector);
|
__raw_writel(irqnr, icoll_priv.vector);
|
||||||
handle_domain_irq(icoll_domain, irqnr, regs);
|
generic_handle_domain_irq(icoll_domain, irqnr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||||
|
@ -37,10 +37,25 @@
|
|||||||
|
|
||||||
static struct irq_domain *nvic_irq_domain;
|
static struct irq_domain *nvic_irq_domain;
|
||||||
|
|
||||||
|
static void __nvic_handle_irq(irq_hw_number_t hwirq)
|
||||||
|
{
|
||||||
|
generic_handle_domain_irq(nvic_irq_domain, hwirq);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: restructure the ARMv7M entry logic so that this entry logic can live
|
||||||
|
* in arch code.
|
||||||
|
*/
|
||||||
asmlinkage void __exception_irq_entry
|
asmlinkage void __exception_irq_entry
|
||||||
nvic_handle_irq(irq_hw_number_t hwirq, struct pt_regs *regs)
|
nvic_handle_irq(irq_hw_number_t hwirq, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
handle_domain_irq(nvic_irq_domain, hwirq, regs);
|
struct pt_regs *old_regs;
|
||||||
|
|
||||||
|
irq_enter();
|
||||||
|
old_regs = set_irq_regs(regs);
|
||||||
|
__nvic_handle_irq(hwirq);
|
||||||
|
set_irq_regs(old_regs);
|
||||||
|
irq_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
static int nvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||||
|
@ -357,7 +357,7 @@ omap_intc_handle_irq(struct pt_regs *regs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
irqnr &= ACTIVEIRQ_MASK;
|
irqnr &= ACTIVEIRQ_MASK;
|
||||||
handle_domain_irq(domain, irqnr, regs);
|
generic_handle_domain_irq(domain, irqnr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init intc_of_init(struct device_node *node,
|
static int __init intc_of_init(struct device_node *node,
|
||||||
|
@ -116,7 +116,7 @@ static void or1k_pic_handle_irq(struct pt_regs *regs)
|
|||||||
int irq = -1;
|
int irq = -1;
|
||||||
|
|
||||||
while ((irq = pic_get_irq(irq + 1)) != NO_IRQ)
|
while ((irq = pic_get_irq(irq + 1)) != NO_IRQ)
|
||||||
handle_domain_irq(root_domain, irq, regs);
|
generic_handle_domain_irq(root_domain, irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
|
static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
|
||||||
|
@ -42,8 +42,8 @@ __exception_irq_entry orion_handle_irq(struct pt_regs *regs)
|
|||||||
gc->mask_cache;
|
gc->mask_cache;
|
||||||
while (stat) {
|
while (stat) {
|
||||||
u32 hwirq = __fls(stat);
|
u32 hwirq = __fls(stat);
|
||||||
handle_domain_irq(orion_irq_domain,
|
generic_handle_domain_irq(orion_irq_domain,
|
||||||
gc->irq_base + hwirq, regs);
|
gc->irq_base + hwirq);
|
||||||
stat &= ~(1 << hwirq);
|
stat &= ~(1 << hwirq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ static void __exception_irq_entry rda_handle_irq(struct pt_regs *regs)
|
|||||||
|
|
||||||
while (stat) {
|
while (stat) {
|
||||||
hwirq = __fls(stat);
|
hwirq = __fls(stat);
|
||||||
handle_domain_irq(rda_irq_domain, hwirq, regs);
|
generic_handle_domain_irq(rda_irq_domain, hwirq);
|
||||||
stat &= ~BIT(hwirq);
|
stat &= ~BIT(hwirq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ static asmlinkage void riscv_intc_irq(struct pt_regs *regs)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
handle_domain_irq(intc_domain, cause, regs);
|
generic_handle_domain_irq(intc_domain, cause);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,8 +140,8 @@ sa1100_handle_irq(struct pt_regs *regs)
|
|||||||
if (mask == 0)
|
if (mask == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
handle_domain_irq(sa1100_normal_irqdomain,
|
generic_handle_domain_irq(sa1100_normal_irqdomain,
|
||||||
ffs(mask) - 1, regs);
|
ffs(mask) - 1);
|
||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,7 +850,6 @@ static int stm32_exti_probe(struct platform_device *pdev)
|
|||||||
struct irq_domain *parent_domain, *domain;
|
struct irq_domain *parent_domain, *domain;
|
||||||
struct stm32_exti_host_data *host_data;
|
struct stm32_exti_host_data *host_data;
|
||||||
const struct stm32_exti_drv_data *drv_data;
|
const struct stm32_exti_drv_data *drv_data;
|
||||||
struct resource *res;
|
|
||||||
|
|
||||||
host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL);
|
host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL);
|
||||||
if (!host_data)
|
if (!host_data)
|
||||||
@ -888,8 +887,7 @@ static int stm32_exti_probe(struct platform_device *pdev)
|
|||||||
if (!host_data->chips_data)
|
if (!host_data->chips_data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
host_data->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
host_data->base = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(host_data->base))
|
if (IS_ERR(host_data->base))
|
||||||
return PTR_ERR(host_data->base);
|
return PTR_ERR(host_data->base);
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
handle_domain_irq(irq_ic_data->irq_domain, hwirq, regs);
|
generic_handle_domain_irq(irq_ic_data->irq_domain, hwirq);
|
||||||
hwirq = readl(irq_ic_data->irq_base +
|
hwirq = readl(irq_ic_data->irq_base +
|
||||||
SUN4I_IRQ_VECTOR_REG) >> 2;
|
SUN4I_IRQ_VECTOR_REG) >> 2;
|
||||||
} while (hwirq != 0);
|
} while (hwirq != 0);
|
||||||
|
@ -650,7 +650,6 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
|
|||||||
struct device_node *parent_node, *node;
|
struct device_node *parent_node, *node;
|
||||||
struct ti_sci_inta_irq_domain *inta;
|
struct ti_sci_inta_irq_domain *inta;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct resource *res;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
node = dev_of_node(dev);
|
node = dev_of_node(dev);
|
||||||
@ -694,8 +693,7 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
|
|||||||
return PTR_ERR(inta->global_event);
|
return PTR_ERR(inta->global_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
inta->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
inta->base = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(inta->base))
|
if (IS_ERR(inta->base))
|
||||||
return PTR_ERR(inta->base);
|
return PTR_ERR(inta->base);
|
||||||
|
|
||||||
|
@ -93,15 +93,13 @@ static int ts4800_ic_probe(struct platform_device *pdev)
|
|||||||
struct device_node *node = pdev->dev.of_node;
|
struct device_node *node = pdev->dev.of_node;
|
||||||
struct ts4800_irq_data *data;
|
struct ts4800_irq_data *data;
|
||||||
struct irq_chip *irq_chip;
|
struct irq_chip *irq_chip;
|
||||||
struct resource *res;
|
|
||||||
int parent_irq;
|
int parent_irq;
|
||||||
|
|
||||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
data->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
data->base = devm_ioremap_resource(&pdev->dev, res);
|
|
||||||
if (IS_ERR(data->base))
|
if (IS_ERR(data->base))
|
||||||
return PTR_ERR(data->base);
|
return PTR_ERR(data->base);
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ static int handle_one_fpga(struct fpga_irq_data *f, struct pt_regs *regs)
|
|||||||
|
|
||||||
while ((status = readl(f->base + IRQ_STATUS))) {
|
while ((status = readl(f->base + IRQ_STATUS))) {
|
||||||
irq = ffs(status) - 1;
|
irq = ffs(status) - 1;
|
||||||
handle_domain_irq(f->domain, irq, regs);
|
generic_handle_domain_irq(f->domain, irq);
|
||||||
handled = 1;
|
handled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
|
|||||||
|
|
||||||
while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
|
while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
|
||||||
irq = ffs(stat) - 1;
|
irq = ffs(stat) - 1;
|
||||||
handle_domain_irq(vic->domain, irq, regs);
|
generic_handle_domain_irq(vic->domain, irq);
|
||||||
handled = 1;
|
handled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_domain_irq(intc[i].domain, irqnr, regs);
|
generic_handle_domain_irq(intc[i].domain, irqnr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ static void __exception_irq_entry wpcm450_aic_handle_irq(struct pt_regs *regs)
|
|||||||
/* Read IPER to signal that nIRQ can be de-asserted */
|
/* Read IPER to signal that nIRQ can be de-asserted */
|
||||||
hwirq = readl(aic->regs + AIC_IPER) / 4;
|
hwirq = readl(aic->regs + AIC_IPER) / 4;
|
||||||
|
|
||||||
handle_domain_irq(aic->domain, hwirq, regs);
|
generic_handle_domain_irq(aic->domain, hwirq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wpcm450_aic_eoi(struct irq_data *d)
|
static void wpcm450_aic_eoi(struct irq_data *d)
|
||||||
|
@ -50,7 +50,7 @@ static void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
|
|||||||
|
|
||||||
while (readl(zevio_irq_io + IO_STATUS)) {
|
while (readl(zevio_irq_io + IO_STATUS)) {
|
||||||
irqnr = readl(zevio_irq_io + IO_CURRENT);
|
irqnr = readl(zevio_irq_io + IO_CURRENT);
|
||||||
handle_domain_irq(zevio_irq_domain, irqnr, regs);
|
generic_handle_domain_irq(zevio_irq_domain, irqnr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,9 +524,10 @@ struct irq_chip {
|
|||||||
void (*irq_bus_lock)(struct irq_data *data);
|
void (*irq_bus_lock)(struct irq_data *data);
|
||||||
void (*irq_bus_sync_unlock)(struct irq_data *data);
|
void (*irq_bus_sync_unlock)(struct irq_data *data);
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEPRECATED_IRQ_CPU_ONOFFLINE
|
||||||
void (*irq_cpu_online)(struct irq_data *data);
|
void (*irq_cpu_online)(struct irq_data *data);
|
||||||
void (*irq_cpu_offline)(struct irq_data *data);
|
void (*irq_cpu_offline)(struct irq_data *data);
|
||||||
|
#endif
|
||||||
void (*irq_suspend)(struct irq_data *data);
|
void (*irq_suspend)(struct irq_data *data);
|
||||||
void (*irq_resume)(struct irq_data *data);
|
void (*irq_resume)(struct irq_data *data);
|
||||||
void (*irq_pm_shutdown)(struct irq_data *data);
|
void (*irq_pm_shutdown)(struct irq_data *data);
|
||||||
@ -606,8 +607,10 @@ struct irqaction;
|
|||||||
extern int setup_percpu_irq(unsigned int irq, struct irqaction *new);
|
extern int setup_percpu_irq(unsigned int irq, struct irqaction *new);
|
||||||
extern void remove_percpu_irq(unsigned int irq, struct irqaction *act);
|
extern void remove_percpu_irq(unsigned int irq, struct irqaction *act);
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEPRECATED_IRQ_CPU_ONOFFLINE
|
||||||
extern void irq_cpu_online(void);
|
extern void irq_cpu_online(void);
|
||||||
extern void irq_cpu_offline(void);
|
extern void irq_cpu_offline(void);
|
||||||
|
#endif
|
||||||
extern int irq_set_affinity_locked(struct irq_data *data,
|
extern int irq_set_affinity_locked(struct irq_data *data,
|
||||||
const struct cpumask *cpumask, bool force);
|
const struct cpumask *cpumask, bool force);
|
||||||
extern int irq_set_vcpu_affinity(unsigned int irq, void *vcpu_info);
|
extern int irq_set_vcpu_affinity(unsigned int irq, void *vcpu_info);
|
||||||
@ -1261,6 +1264,7 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *));
|
|||||||
* top-level IRQ handler.
|
* top-level IRQ handler.
|
||||||
*/
|
*/
|
||||||
extern void (*handle_arch_irq)(struct pt_regs *) __ro_after_init;
|
extern void (*handle_arch_irq)(struct pt_regs *) __ro_after_init;
|
||||||
|
asmlinkage void generic_handle_arch_irq(struct pt_regs *regs);
|
||||||
#else
|
#else
|
||||||
#ifndef set_handle_irq
|
#ifndef set_handle_irq
|
||||||
#define set_handle_irq(handle_irq) \
|
#define set_handle_irq(handle_irq) \
|
||||||
|
@ -14,8 +14,15 @@
|
|||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
/* Undefined on purpose */
|
||||||
|
extern of_irq_init_cb_t typecheck_irq_init_cb;
|
||||||
|
|
||||||
|
#define typecheck_irq_init_cb(fn) \
|
||||||
|
(__typecheck(typecheck_irq_init_cb, &fn) ? fn : fn)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This macro must be used by the different irqchip drivers to declare
|
* This macro must be used by the different irqchip drivers to declare
|
||||||
* the association between their DT compatible string and their
|
* the association between their DT compatible string and their
|
||||||
@ -23,24 +30,27 @@
|
|||||||
*
|
*
|
||||||
* @name: name that must be unique across all IRQCHIP_DECLARE of the
|
* @name: name that must be unique across all IRQCHIP_DECLARE of the
|
||||||
* same file.
|
* same file.
|
||||||
* @compstr: compatible string of the irqchip driver
|
* @compat: compatible string of the irqchip driver
|
||||||
* @fn: initialization function
|
* @fn: initialization function
|
||||||
*/
|
*/
|
||||||
#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
|
#define IRQCHIP_DECLARE(name, compat, fn) \
|
||||||
|
OF_DECLARE_2(irqchip, name, compat, typecheck_irq_init_cb(fn))
|
||||||
|
|
||||||
extern int platform_irqchip_probe(struct platform_device *pdev);
|
extern int platform_irqchip_probe(struct platform_device *pdev);
|
||||||
|
|
||||||
#define IRQCHIP_PLATFORM_DRIVER_BEGIN(drv_name) \
|
#define IRQCHIP_PLATFORM_DRIVER_BEGIN(drv_name) \
|
||||||
static const struct of_device_id drv_name##_irqchip_match_table[] = {
|
static const struct of_device_id drv_name##_irqchip_match_table[] = {
|
||||||
|
|
||||||
#define IRQCHIP_MATCH(compat, fn) { .compatible = compat, .data = fn },
|
#define IRQCHIP_MATCH(compat, fn) { .compatible = compat, \
|
||||||
|
.data = typecheck_irq_init_cb(fn), },
|
||||||
|
|
||||||
#define IRQCHIP_PLATFORM_DRIVER_END(drv_name) \
|
#define IRQCHIP_PLATFORM_DRIVER_END(drv_name) \
|
||||||
{}, \
|
{}, \
|
||||||
}; \
|
}; \
|
||||||
MODULE_DEVICE_TABLE(of, drv_name##_irqchip_match_table); \
|
MODULE_DEVICE_TABLE(of, drv_name##_irqchip_match_table); \
|
||||||
static struct platform_driver drv_name##_driver = { \
|
static struct platform_driver drv_name##_driver = { \
|
||||||
.probe = platform_irqchip_probe, \
|
.probe = IS_ENABLED(CONFIG_IRQCHIP) ? \
|
||||||
|
platform_irqchip_probe : NULL, \
|
||||||
.driver = { \
|
.driver = { \
|
||||||
.name = #drv_name, \
|
.name = #drv_name, \
|
||||||
.owner = THIS_MODULE, \
|
.owner = THIS_MODULE, \
|
||||||
|
@ -168,14 +168,7 @@ int generic_handle_irq(unsigned int irq);
|
|||||||
* conversion failed.
|
* conversion failed.
|
||||||
*/
|
*/
|
||||||
int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq);
|
int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq);
|
||||||
|
int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq);
|
||||||
#ifdef CONFIG_HANDLE_DOMAIN_IRQ
|
|
||||||
int handle_domain_irq(struct irq_domain *domain,
|
|
||||||
unsigned int hwirq, struct pt_regs *regs);
|
|
||||||
|
|
||||||
int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq,
|
|
||||||
struct pt_regs *regs);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Test to see if a driver has successfully requested an irq */
|
/* Test to see if a driver has successfully requested an irq */
|
||||||
|
@ -97,9 +97,6 @@ config GENERIC_MSI_IRQ_DOMAIN
|
|||||||
config IRQ_MSI_IOMMU
|
config IRQ_MSI_IOMMU
|
||||||
bool
|
bool
|
||||||
|
|
||||||
config HANDLE_DOMAIN_IRQ
|
|
||||||
bool
|
|
||||||
|
|
||||||
config IRQ_TIMINGS
|
config IRQ_TIMINGS
|
||||||
bool
|
bool
|
||||||
|
|
||||||
@ -144,3 +141,10 @@ config GENERIC_IRQ_MULTI_HANDLER
|
|||||||
bool
|
bool
|
||||||
help
|
help
|
||||||
Allow to specify the low level IRQ handler at run time.
|
Allow to specify the low level IRQ handler at run time.
|
||||||
|
|
||||||
|
# Cavium Octeon is the last system to use this deprecated option
|
||||||
|
# Do not even think of enabling this on any new platform
|
||||||
|
config DEPRECATED_IRQ_CPU_ONOFFLINE
|
||||||
|
bool
|
||||||
|
depends on CAVIUM_OCTEON_SOC
|
||||||
|
default CAVIUM_OCTEON_SOC
|
||||||
|
@ -1122,6 +1122,7 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(irq_modify_status);
|
EXPORT_SYMBOL_GPL(irq_modify_status);
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEPRECATED_IRQ_CPU_ONOFFLINE
|
||||||
/**
|
/**
|
||||||
* irq_cpu_online - Invoke all irq_cpu_online functions.
|
* irq_cpu_online - Invoke all irq_cpu_online functions.
|
||||||
*
|
*
|
||||||
@ -1181,6 +1182,7 @@ void irq_cpu_offline(void)
|
|||||||
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
|
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ static DEFINE_RAW_SPINLOCK(gc_lock);
|
|||||||
void irq_gc_noop(struct irq_data *d)
|
void irq_gc_noop(struct irq_data *d)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_gc_noop);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* irq_gc_mask_disable_reg - Mask chip via disable register
|
* irq_gc_mask_disable_reg - Mask chip via disable register
|
||||||
@ -44,6 +45,7 @@ void irq_gc_mask_disable_reg(struct irq_data *d)
|
|||||||
*ct->mask_cache &= ~mask;
|
*ct->mask_cache &= ~mask;
|
||||||
irq_gc_unlock(gc);
|
irq_gc_unlock(gc);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_gc_mask_disable_reg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* irq_gc_mask_set_bit - Mask chip via setting bit in mask register
|
* irq_gc_mask_set_bit - Mask chip via setting bit in mask register
|
||||||
@ -103,6 +105,7 @@ void irq_gc_unmask_enable_reg(struct irq_data *d)
|
|||||||
*ct->mask_cache |= mask;
|
*ct->mask_cache |= mask;
|
||||||
irq_gc_unlock(gc);
|
irq_gc_unlock(gc);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_gc_unmask_enable_reg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* irq_gc_ack_set_bit - Ack pending interrupt via setting bit
|
* irq_gc_ack_set_bit - Ack pending interrupt via setting bit
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/kernel_stat.h>
|
#include <linux/kernel_stat.h>
|
||||||
|
|
||||||
|
#include <asm/irq_regs.h>
|
||||||
|
|
||||||
#include <trace/events/irq.h>
|
#include <trace/events/irq.h>
|
||||||
|
|
||||||
#include "internals.h"
|
#include "internals.h"
|
||||||
@ -226,4 +228,20 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
|
|||||||
handle_arch_irq = handle_irq;
|
handle_arch_irq = handle_irq;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generic_handle_arch_irq - root irq handler for architectures which do no
|
||||||
|
* entry accounting themselves
|
||||||
|
* @regs: Register file coming from the low-level handling code
|
||||||
|
*/
|
||||||
|
asmlinkage void noinstr generic_handle_arch_irq(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct pt_regs *old_regs;
|
||||||
|
|
||||||
|
irq_enter();
|
||||||
|
old_regs = set_irq_regs(regs);
|
||||||
|
handle_arch_irq(regs);
|
||||||
|
set_irq_regs(old_regs);
|
||||||
|
irq_exit();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -646,13 +646,16 @@ int handle_irq_desc(struct irq_desc *desc)
|
|||||||
generic_handle_irq_desc(desc);
|
generic_handle_irq_desc(desc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(handle_irq_desc);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generic_handle_irq - Invoke the handler for a particular irq
|
* generic_handle_irq - Invoke the handler for a particular irq
|
||||||
* @irq: The irq number to handle
|
* @irq: The irq number to handle
|
||||||
*
|
*
|
||||||
*/
|
* Returns: 0 on success, or -EINVAL if conversion has failed
|
||||||
|
*
|
||||||
|
* This function must be called from an IRQ context with irq regs
|
||||||
|
* initialized.
|
||||||
|
*/
|
||||||
int generic_handle_irq(unsigned int irq)
|
int generic_handle_irq(unsigned int irq)
|
||||||
{
|
{
|
||||||
return handle_irq_desc(irq_to_desc(irq));
|
return handle_irq_desc(irq_to_desc(irq));
|
||||||
@ -662,89 +665,39 @@ EXPORT_SYMBOL_GPL(generic_handle_irq);
|
|||||||
#ifdef CONFIG_IRQ_DOMAIN
|
#ifdef CONFIG_IRQ_DOMAIN
|
||||||
/**
|
/**
|
||||||
* generic_handle_domain_irq - Invoke the handler for a HW irq belonging
|
* generic_handle_domain_irq - Invoke the handler for a HW irq belonging
|
||||||
* to a domain, usually for a non-root interrupt
|
* to a domain.
|
||||||
* controller
|
|
||||||
* @domain: The domain where to perform the lookup
|
* @domain: The domain where to perform the lookup
|
||||||
* @hwirq: The HW irq number to convert to a logical one
|
* @hwirq: The HW irq number to convert to a logical one
|
||||||
*
|
*
|
||||||
* Returns: 0 on success, or -EINVAL if conversion has failed
|
* Returns: 0 on success, or -EINVAL if conversion has failed
|
||||||
*
|
*
|
||||||
|
* This function must be called from an IRQ context with irq regs
|
||||||
|
* initialized.
|
||||||
*/
|
*/
|
||||||
int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq)
|
int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq)
|
||||||
{
|
{
|
||||||
|
WARN_ON_ONCE(!in_irq());
|
||||||
return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
|
return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(generic_handle_domain_irq);
|
EXPORT_SYMBOL_GPL(generic_handle_domain_irq);
|
||||||
|
|
||||||
#ifdef CONFIG_HANDLE_DOMAIN_IRQ
|
|
||||||
/**
|
/**
|
||||||
* handle_domain_irq - Invoke the handler for a HW irq belonging to a domain,
|
* generic_handle_domain_nmi - Invoke the handler for a HW nmi belonging
|
||||||
* usually for a root interrupt controller
|
* to a domain.
|
||||||
* @domain: The domain where to perform the lookup
|
* @domain: The domain where to perform the lookup
|
||||||
* @hwirq: The HW irq number to convert to a logical one
|
* @hwirq: The HW irq number to convert to a logical one
|
||||||
* @regs: Register file coming from the low-level handling code
|
|
||||||
*
|
*
|
||||||
* Returns: 0 on success, or -EINVAL if conversion has failed
|
* Returns: 0 on success, or -EINVAL if conversion has failed
|
||||||
*/
|
|
||||||
int handle_domain_irq(struct irq_domain *domain,
|
|
||||||
unsigned int hwirq, struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
|
||||||
struct irq_desc *desc;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
irq_enter();
|
|
||||||
|
|
||||||
/* The irqdomain code provides boundary checks */
|
|
||||||
desc = irq_resolve_mapping(domain, hwirq);
|
|
||||||
if (likely(desc))
|
|
||||||
handle_irq_desc(desc);
|
|
||||||
else
|
|
||||||
ret = -EINVAL;
|
|
||||||
|
|
||||||
irq_exit();
|
|
||||||
set_irq_regs(old_regs);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* handle_domain_nmi - Invoke the handler for a HW irq belonging to a domain
|
|
||||||
* @domain: The domain where to perform the lookup
|
|
||||||
* @hwirq: The HW irq number to convert to a logical one
|
|
||||||
* @regs: Register file coming from the low-level handling code
|
|
||||||
*
|
*
|
||||||
* This function must be called from an NMI context.
|
* This function must be called from an NMI context with irq regs
|
||||||
*
|
* initialized.
|
||||||
* Returns: 0 on success, or -EINVAL if conversion has failed
|
**/
|
||||||
*/
|
int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq)
|
||||||
int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq,
|
|
||||||
struct pt_regs *regs)
|
|
||||||
{
|
{
|
||||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
WARN_ON_ONCE(!in_nmi());
|
||||||
struct irq_desc *desc;
|
return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NMI context needs to be setup earlier in order to deal with tracing.
|
|
||||||
*/
|
|
||||||
WARN_ON(!in_nmi());
|
|
||||||
|
|
||||||
desc = irq_resolve_mapping(domain, hwirq);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ack_bad_irq is not NMI-safe, just report
|
|
||||||
* an invalid interrupt.
|
|
||||||
*/
|
|
||||||
if (likely(desc))
|
|
||||||
handle_irq_desc(desc);
|
|
||||||
else
|
|
||||||
ret = -EINVAL;
|
|
||||||
|
|
||||||
set_irq_regs(old_regs);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Dynamic interrupt handling */
|
/* Dynamic interrupt handling */
|
||||||
|
|
||||||
|
@ -1259,6 +1259,8 @@ static int irq_thread(void *data)
|
|||||||
irqreturn_t (*handler_fn)(struct irq_desc *desc,
|
irqreturn_t (*handler_fn)(struct irq_desc *desc,
|
||||||
struct irqaction *action);
|
struct irqaction *action);
|
||||||
|
|
||||||
|
sched_set_fifo(current);
|
||||||
|
|
||||||
if (force_irqthreads() && test_bit(IRQTF_FORCED_THREAD,
|
if (force_irqthreads() && test_bit(IRQTF_FORCED_THREAD,
|
||||||
&action->thread_flags))
|
&action->thread_flags))
|
||||||
handler_fn = irq_forced_thread_fn;
|
handler_fn = irq_forced_thread_fn;
|
||||||
@ -1424,8 +1426,6 @@ setup_irq_thread(struct irqaction *new, unsigned int irq, bool secondary)
|
|||||||
if (IS_ERR(t))
|
if (IS_ERR(t))
|
||||||
return PTR_ERR(t);
|
return PTR_ERR(t);
|
||||||
|
|
||||||
sched_set_fifo(t);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We keep the reference to the task struct even if
|
* We keep the reference to the task struct even if
|
||||||
* the thread dies to avoid that the interrupt code
|
* the thread dies to avoid that the interrupt code
|
||||||
@ -2827,7 +2827,7 @@ EXPORT_SYMBOL_GPL(irq_get_irqchip_state);
|
|||||||
* This call sets the internal irqchip state of an interrupt,
|
* This call sets the internal irqchip state of an interrupt,
|
||||||
* depending on the value of @which.
|
* depending on the value of @which.
|
||||||
*
|
*
|
||||||
* This function should be called with preemption disabled if the
|
* This function should be called with migration disabled if the
|
||||||
* interrupt controller has per-cpu registers.
|
* interrupt controller has per-cpu registers.
|
||||||
*/
|
*/
|
||||||
int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which,
|
int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which,
|
||||||
|
@ -447,6 +447,10 @@ MODULE_PARM_DESC(noirqdebug, "Disable irq lockup detection when true");
|
|||||||
|
|
||||||
static int __init irqfixup_setup(char *str)
|
static int __init irqfixup_setup(char *str)
|
||||||
{
|
{
|
||||||
|
if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
|
||||||
|
pr_warn("irqfixup boot option not supported with PREEMPT_RT\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
irqfixup = 1;
|
irqfixup = 1;
|
||||||
printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n");
|
printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n");
|
||||||
printk(KERN_WARNING "This may impact system performance.\n");
|
printk(KERN_WARNING "This may impact system performance.\n");
|
||||||
@ -459,6 +463,10 @@ module_param(irqfixup, int, 0644);
|
|||||||
|
|
||||||
static int __init irqpoll_setup(char *str)
|
static int __init irqpoll_setup(char *str)
|
||||||
{
|
{
|
||||||
|
if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
|
||||||
|
pr_warn("irqpoll boot option not supported with PREEMPT_RT\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
irqfixup = 2;
|
irqfixup = 2;
|
||||||
printk(KERN_WARNING "Misrouted IRQ fixup and polling support "
|
printk(KERN_WARNING "Misrouted IRQ fixup and polling support "
|
||||||
"enabled\n");
|
"enabled\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user