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:
Linus Torvalds 2021-11-01 13:09:10 -07:00
commit 5a47ebe98e
96 changed files with 701 additions and 330 deletions

View File

@ -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.

View File

@ -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";
};
...

View File

@ -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+

View File

@ -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

View File

@ -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

View File

@ -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();
} }

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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);
} }

View File

@ -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);
} }
} }

View File

@ -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);

View File

@ -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;
} }

View File

@ -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

View File

@ -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

View File

@ -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);
} }

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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>

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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();

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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:
/* /*

View File

@ -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[] = {

View File

@ -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) \

View File

@ -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)
{ {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
} }
} }

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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);
} }
} }

View File

@ -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();
} }
} }

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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);
} }

View File

@ -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;
} }

View File

@ -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)

View File

@ -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 */

View File

@ -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,

View File

@ -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);
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View 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>");

View File

@ -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");

View File

@ -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;
} }

View File

@ -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) */

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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)

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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;
} }
} }

View File

@ -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);
} }

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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);
} }
} }

View File

@ -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)

View File

@ -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);
} }
} }

View File

@ -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) \

View File

@ -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, \

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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,

View File

@ -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");