mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-01 10:42:11 +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
|
||||
- generic_handle_domain_irq() handles an interrupt described by a
|
||||
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
|
||||
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-r8a774b1 # RZ/G2N
|
||||
- renesas,intc-ex-r8a774c0 # RZ/G2E
|
||||
- renesas,intc-ex-r8a774e1 # RZ/G2H
|
||||
- renesas,intc-ex-r8a7795 # R-Car H3
|
||||
- renesas,intc-ex-r8a7796 # 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>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
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
|
||||
|
||||
ARM SMC WATCHDOG DRIVER
|
||||
@ -12270,6 +12270,12 @@ L: linux-crypto@vger.kernel.org
|
||||
S: Maintained
|
||||
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
|
||||
M: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
|
@ -40,7 +40,6 @@ config ARC
|
||||
select HAVE_KRETPROBES
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select HAVE_PERF_EVENTS
|
||||
select HANDLE_DOMAIN_IRQ
|
||||
select IRQ_DOMAIN
|
||||
select MODULES_USE_ELF_RELA
|
||||
select OF
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <asm/mach_desc.h>
|
||||
|
||||
#include <asm/irq_regs.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)
|
||||
{
|
||||
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_SCHED_CLOCK
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select HANDLE_DOMAIN_IRQ
|
||||
select HARDIRQS_SW_RESEND
|
||||
select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT
|
||||
select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
|
||||
|
@ -38,14 +38,11 @@
|
||||
*/
|
||||
.macro irq_handler
|
||||
#ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER
|
||||
ldr r1, =handle_arch_irq
|
||||
mov r0, sp
|
||||
badr lr, 9997f
|
||||
ldr pc, [r1]
|
||||
bl generic_handle_arch_irq
|
||||
#else
|
||||
arch_irq_handler_default
|
||||
#endif
|
||||
9997:
|
||||
.endm
|
||||
|
||||
.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)
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
struct irq_desc *desc;
|
||||
|
||||
irq_enter();
|
||||
|
||||
/*
|
||||
* Some hardware gives randomly wrong interrupts. Rather
|
||||
* than crashing, do something sensible.
|
||||
@ -81,9 +78,6 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs)
|
||||
handle_irq_desc(desc);
|
||||
else
|
||||
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
|
||||
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);
|
||||
|
||||
set_irq_regs(old_regs);
|
||||
irq_exit();
|
||||
}
|
||||
|
||||
void __init init_IRQ(void)
|
||||
|
@ -161,7 +161,6 @@ config ARCH_BCM2835
|
||||
select ARM_TIMER_SP804
|
||||
select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
|
||||
select BCM2835_TIMER
|
||||
select BRCMSTB_L2_IRQ
|
||||
select PINCTRL
|
||||
select PINCTRL_BCM2835
|
||||
select MFD_CORE
|
||||
@ -209,9 +208,6 @@ config ARCH_BRCMSTB
|
||||
select ARM_GIC
|
||||
select ARM_ERRATA_798181 if SMP
|
||||
select HAVE_ARM_ARCH_TIMER
|
||||
select BCM7038_L1_IRQ
|
||||
select BRCMSTB_L2_IRQ
|
||||
select BCM7120_L2_IRQ
|
||||
select ZONE_DMA if ARM_LPAE
|
||||
select SOC_BRCMSTB
|
||||
select SOC_BUS
|
||||
|
@ -154,7 +154,7 @@ static void __exception_irq_entry avic_handle_irq(struct pt_regs *regs)
|
||||
if (nivector == 0xffff)
|
||||
break;
|
||||
|
||||
handle_domain_irq(domain, nivector, regs);
|
||||
generic_handle_domain_irq(domain, nivector);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ static void __exception_irq_entry tzic_handle_irq(struct pt_regs *regs)
|
||||
while (stat) {
|
||||
handled = 1;
|
||||
irqofs = fls(stat) - 1;
|
||||
handle_domain_irq(domain, irqofs + i * 32, regs);
|
||||
generic_handle_domain_irq(domain, irqofs + i * 32);
|
||||
stat &= ~(1 << irqofs);
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ asmlinkage void __exception_irq_entry omap1_handle_irq(struct pt_regs *regs)
|
||||
}
|
||||
irq:
|
||||
if (irqnr)
|
||||
handle_domain_irq(domain, irqnr, regs);
|
||||
generic_handle_domain_irq(domain, irqnr);
|
||||
else
|
||||
break;
|
||||
} while (irqnr);
|
||||
|
@ -354,7 +354,7 @@ static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
|
||||
if (!(pnd & (1 << offset)))
|
||||
offset = __ffs(pnd);
|
||||
|
||||
handle_domain_irq(intc->domain, intc_offset + offset, regs);
|
||||
generic_handle_domain_irq(intc->domain, intc_offset + offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,6 @@ config ARM64
|
||||
select GENERIC_TIME_VSYSCALL
|
||||
select GENERIC_GETTIMEOFDAY
|
||||
select GENERIC_VDSO_TIME_NS
|
||||
select HANDLE_DOMAIN_IRQ
|
||||
select HARDIRQS_SW_RESEND
|
||||
select HAVE_MOVE_PMD
|
||||
select HAVE_MOVE_PUD
|
||||
|
@ -44,7 +44,6 @@ config ARCH_BCM2835
|
||||
select ARM_AMBA
|
||||
select ARM_GIC
|
||||
select ARM_TIMER_SP804
|
||||
select BRCMSTB_L2_IRQ
|
||||
help
|
||||
This enables support for the Broadcom BCM2837 and BCM2711 SoC.
|
||||
These SoCs are used in the Raspberry Pi 3 and 4 devices.
|
||||
@ -82,8 +81,6 @@ config ARCH_BITMAIN
|
||||
config ARCH_BRCMSTB
|
||||
bool "Broadcom Set-Top-Box SoCs"
|
||||
select ARCH_HAS_RESET_CONTROLLER
|
||||
select BCM7038_L1_IRQ
|
||||
select BRCMSTB_L2_IRQ
|
||||
select GENERIC_IRQ_CHIP
|
||||
select PINCTRL
|
||||
help
|
||||
@ -167,7 +164,6 @@ config ARCH_MEDIATEK
|
||||
config ARCH_MESON
|
||||
bool "Amlogic Platforms"
|
||||
select COMMON_CLK
|
||||
select MESON_IRQ_GPIO
|
||||
help
|
||||
This enables support for the arm64 based Amlogic SoCs
|
||||
such as the s905, S905X/D, S912, A113X/D or S905X/D2
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <asm/daifflags.h>
|
||||
#include <asm/esr.h>
|
||||
#include <asm/exception.h>
|
||||
#include <asm/irq_regs.h>
|
||||
#include <asm/kprobes.h>
|
||||
#include <asm/mmu.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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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,
|
||||
void (*handler)(struct pt_regs *))
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
|
||||
if (on_thread_stack())
|
||||
call_on_irq_stack(regs, handler);
|
||||
else
|
||||
handler(regs);
|
||||
|
||||
set_irq_regs(old_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,
|
||||
void (*handler)(struct pt_regs *))
|
||||
static __always_inline void __el1_pnmi(struct pt_regs *regs,
|
||||
void (*handler)(struct pt_regs *))
|
||||
{
|
||||
write_sysreg(DAIF_PROCCTX_NOIRQ, daif);
|
||||
|
||||
enter_el1_irq_or_nmi(regs);
|
||||
arm64_enter_nmi(regs);
|
||||
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
|
||||
@ -449,7 +447,17 @@ static void noinstr el1_interrupt(struct pt_regs *regs,
|
||||
READ_ONCE(current_thread_info()->preempt_count) == 0)
|
||||
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)
|
||||
@ -667,7 +675,9 @@ static void noinstr el0_interrupt(struct pt_regs *regs,
|
||||
if (regs->pc & BIT(55))
|
||||
arm64_apply_bp_hardening();
|
||||
|
||||
irq_enter_rcu();
|
||||
do_interrupt_handler(regs, handler);
|
||||
irq_exit_rcu();
|
||||
|
||||
exit_to_user_mode(regs);
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ config CSKY
|
||||
select CSKY_APB_INTC
|
||||
select DMA_DIRECT_REMAP
|
||||
select IRQ_DOMAIN
|
||||
select HANDLE_DOMAIN_IRQ
|
||||
select DW_APB_TIMER_OF
|
||||
select GENERIC_IOREMAP
|
||||
select GENERIC_LIB_ASHLDI3
|
||||
|
@ -249,7 +249,7 @@ ENTRY(csky_irq)
|
||||
|
||||
|
||||
mov a0, sp
|
||||
jbsr csky_do_IRQ
|
||||
jbsr generic_handle_arch_irq
|
||||
|
||||
jmpi ret_from_exception
|
||||
|
||||
|
@ -15,8 +15,3 @@ void __init init_IRQ(void)
|
||||
setup_smp_ipi();
|
||||
#endif
|
||||
}
|
||||
|
||||
asmlinkage void __irq_entry csky_do_IRQ(struct pt_regs *regs)
|
||||
{
|
||||
handle_arch_irq(regs);
|
||||
}
|
||||
|
@ -2,8 +2,6 @@
|
||||
#ifndef _H8300_IRQ_H_
|
||||
#define _H8300_IRQ_H_
|
||||
|
||||
#include <linux/irqchip.h>
|
||||
|
||||
#if defined(CONFIG_CPU_H8300H)
|
||||
#define NR_IRQS 64
|
||||
#define IRQ_CHIP h8300h_irq_chip
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <asm/traps.h>
|
||||
|
@ -47,7 +47,6 @@ config MIPS
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select GENERIC_TIME_VSYSCALL
|
||||
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_JUMP_LABEL
|
||||
select HAVE_ARCH_KGDB if MIPS_FP_SUPPORT
|
||||
@ -1782,6 +1781,7 @@ config CPU_BMIPS
|
||||
select CPU_HAS_PREFETCH
|
||||
select CPU_SUPPORTS_CPUFREQ
|
||||
select MIPS_EXTERNAL_TIMER
|
||||
select GENERIC_IRQ_MIGRATION if HOTPLUG_CPU
|
||||
help
|
||||
Support for BMIPS32/3300/4350/4380 and BMIPS5000 processors.
|
||||
|
||||
|
@ -2609,7 +2609,10 @@ static void octeon_irq_ciu3_ip2(void)
|
||||
else
|
||||
hw = intsn;
|
||||
|
||||
ret = handle_domain_irq(domain, hw, NULL);
|
||||
irq_enter();
|
||||
ret = generic_handle_domain_irq(domain, hw);
|
||||
irq_exit();
|
||||
|
||||
if (ret < 0) {
|
||||
union cvmx_ciu3_iscx_w1c isc_w1c;
|
||||
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
|
||||
void __irq_entry do_domain_IRQ(struct irq_domain *domain, unsigned int hwirq)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
|
||||
irq_enter();
|
||||
check_stack_overflow();
|
||||
|
||||
desc = irq_resolve_mapping(domain, hwirq);
|
||||
if (likely(desc))
|
||||
handle_irq_desc(desc);
|
||||
|
||||
generic_handle_domain_irq(domain, hwirq);
|
||||
irq_exit();
|
||||
}
|
||||
#endif
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/time.h>
|
||||
#include <asm/processor.h>
|
||||
@ -373,7 +374,7 @@ static int bmips_cpu_disable(void)
|
||||
|
||||
set_cpu_online(cpu, false);
|
||||
calculate_cpu_foreign_map();
|
||||
irq_cpu_offline();
|
||||
irq_migrate_all_off_this_cpu();
|
||||
clear_c0_status(IE_IRQ5);
|
||||
|
||||
local_flush_tlb_all();
|
||||
|
@ -550,7 +550,6 @@ static int loongson3_cpu_disable(void)
|
||||
set_cpu_online(cpu, false);
|
||||
calculate_cpu_foreign_map();
|
||||
local_irq_save(flags);
|
||||
irq_cpu_offline();
|
||||
clear_c0_status(ST0_IM);
|
||||
local_irq_restore(flags);
|
||||
local_flush_tlb_all();
|
||||
|
@ -27,7 +27,6 @@ config NDS32
|
||||
select GENERIC_LIB_MULDI3
|
||||
select GENERIC_LIB_UCMPDI2
|
||||
select GENERIC_TIME_VSYSCALL
|
||||
select HANDLE_DOMAIN_IRQ
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
select HAVE_DEBUG_KMEMLEAK
|
||||
select HAVE_EXIT_THREAD
|
||||
|
@ -13,7 +13,6 @@ config OPENRISC
|
||||
select OF
|
||||
select OF_EARLY_FLATTREE
|
||||
select IRQ_DOMAIN
|
||||
select HANDLE_DOMAIN_IRQ
|
||||
select GPIOLIB
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
select SPARSE_IRQ
|
||||
|
@ -569,8 +569,8 @@ EXCEPTION_ENTRY(_external_irq_handler)
|
||||
#endif
|
||||
CLEAR_LWA_FLAG(r3)
|
||||
l.addi r3,r1,0
|
||||
l.movhi r8,hi(do_IRQ)
|
||||
l.ori r8,r8,lo(do_IRQ)
|
||||
l.movhi r8,hi(generic_handle_arch_irq)
|
||||
l.ori r8,r8,lo(generic_handle_arch_irq)
|
||||
l.jalr r8
|
||||
l.nop
|
||||
l.j _ret_from_intr
|
||||
|
@ -36,8 +36,3 @@ void __init init_IRQ(void)
|
||||
{
|
||||
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_SMP_IDLE_THREAD
|
||||
select GENERIC_TIME_VSYSCALL if MMU && 64BIT
|
||||
select HANDLE_DOMAIN_IRQ
|
||||
select HAVE_ARCH_AUDITSYSCALL
|
||||
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
|
||||
select HAVE_ARCH_JUMP_LABEL_RELATIVE if !XIP_KERNEL
|
||||
|
@ -130,8 +130,7 @@ skip_context_tracking:
|
||||
|
||||
/* Handle interrupts */
|
||||
move a0, sp /* pt_regs */
|
||||
la a1, handle_arch_irq
|
||||
REG_L a1, (a1)
|
||||
la a1, generic_handle_arch_irq
|
||||
jr a1
|
||||
1:
|
||||
/*
|
||||
|
@ -140,12 +140,9 @@ void arch_irq_work_raise(void)
|
||||
|
||||
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 *stats = ipi_data[smp_processor_id()].stats;
|
||||
|
||||
irq_enter();
|
||||
|
||||
riscv_clear_ipi();
|
||||
|
||||
while (true) {
|
||||
@ -156,7 +153,7 @@ void handle_IPI(struct pt_regs *regs)
|
||||
|
||||
ops = xchg(pending_ipis, 0);
|
||||
if (ops == 0)
|
||||
goto done;
|
||||
return;
|
||||
|
||||
if (ops & (1 << IPI_RESCHEDULE)) {
|
||||
stats[IPI_RESCHEDULE]++;
|
||||
@ -189,10 +186,6 @@ void handle_IPI(struct pt_regs *regs)
|
||||
/* Order data access and bit testing. */
|
||||
mb();
|
||||
}
|
||||
|
||||
done:
|
||||
irq_exit();
|
||||
set_irq_regs(old_regs);
|
||||
}
|
||||
|
||||
static const char * const ipi_names[] = {
|
||||
|
@ -185,6 +185,7 @@
|
||||
IRQ_CONSTRAINTS, regs, vector); \
|
||||
}
|
||||
|
||||
#ifndef CONFIG_PREEMPT_RT
|
||||
#define ASM_CALL_SOFTIRQ \
|
||||
"call %P[__func] \n"
|
||||
|
||||
@ -201,6 +202,8 @@
|
||||
__this_cpu_write(hardirq_stack_inuse, false); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else /* CONFIG_X86_64 */
|
||||
/* System vector handlers always run on the stack they interrupted. */
|
||||
#define run_sysvec_on_irqstack_cond(func, regs) \
|
||||
|
@ -132,6 +132,7 @@ int irq_init_percpu_irqstack(unsigned int cpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_PREEMPT_RT
|
||||
void do_softirq_own_stack(void)
|
||||
{
|
||||
struct irq_stack *irqstk;
|
||||
@ -148,6 +149,7 @@ void do_softirq_own_stack(void)
|
||||
|
||||
call_on_stack(__do_softirq, isp);
|
||||
}
|
||||
#endif
|
||||
|
||||
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
|
||||
|
||||
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 IRQ_DOMAIN
|
||||
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||
|
||||
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 IRQ_DOMAIN
|
||||
|
||||
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 IRQ_DOMAIN
|
||||
|
||||
@ -400,8 +406,9 @@ config IRQ_UNIPHIER_AIDET
|
||||
Support for the UniPhier AIDET (ARM Interrupt Detector).
|
||||
|
||||
config MESON_IRQ_GPIO
|
||||
bool "Meson GPIO Interrupt Multiplexer"
|
||||
depends on ARCH_MESON
|
||||
tristate "Meson GPIO Interrupt Multiplexer"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
default ARCH_MESON
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
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,
|
||||
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
|
||||
|
@ -116,3 +116,4 @@ obj-$(CONFIG_MACH_REALTEK_RTL) += irq-realtek-rtl.o
|
||||
obj-$(CONFIG_WPCM450_AIC) += irq-wpcm450-aic.o
|
||||
obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.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);
|
||||
|
||||
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)
|
||||
aic_handle_ipi(regs);
|
||||
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)))
|
||||
handle_domain_irq(aic_irqc->hw_domain,
|
||||
aic_irqc->nr_hw + AIC_TMR_EL0_PHYS, regs);
|
||||
generic_handle_domain_irq(aic_irqc->hw_domain,
|
||||
aic_irqc->nr_hw + AIC_TMR_EL0_PHYS);
|
||||
|
||||
if (TIMER_FIRING(read_sysreg(cntv_ctl_el0)))
|
||||
handle_domain_irq(aic_irqc->hw_domain,
|
||||
aic_irqc->nr_hw + AIC_TMR_EL0_VIRT, regs);
|
||||
generic_handle_domain_irq(aic_irqc->hw_domain,
|
||||
aic_irqc->nr_hw + AIC_TMR_EL0_VIRT);
|
||||
|
||||
if (is_kernel_in_hyp_mode()) {
|
||||
uint64_t enabled = read_sysreg_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2);
|
||||
|
||||
if ((enabled & VM_TMR_FIQ_ENABLE_P) &&
|
||||
TIMER_FIRING(read_sysreg_s(SYS_CNTP_CTL_EL02)))
|
||||
handle_domain_irq(aic_irqc->hw_domain,
|
||||
aic_irqc->nr_hw + AIC_TMR_EL02_PHYS, regs);
|
||||
generic_handle_domain_irq(aic_irqc->hw_domain,
|
||||
aic_irqc->nr_hw + AIC_TMR_EL02_PHYS);
|
||||
|
||||
if ((enabled & VM_TMR_FIQ_ENABLE_V) &&
|
||||
TIMER_FIRING(read_sysreg_s(SYS_CNTV_CTL_EL02)))
|
||||
handle_domain_irq(aic_irqc->hw_domain,
|
||||
aic_irqc->nr_hw + AIC_TMR_EL02_VIRT, regs);
|
||||
generic_handle_domain_irq(aic_irqc->hw_domain,
|
||||
aic_irqc->nr_hw + AIC_TMR_EL02_VIRT);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
|
@ -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;
|
||||
|
||||
if (is_chained)
|
||||
generic_handle_domain_irq(armada_370_xp_msi_inner_domain,
|
||||
irq);
|
||||
else
|
||||
handle_domain_irq(armada_370_xp_msi_inner_domain,
|
||||
irq, regs);
|
||||
generic_handle_domain_irq(armada_370_xp_msi_inner_domain, irq);
|
||||
}
|
||||
}
|
||||
#else
|
||||
@ -646,8 +641,8 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
|
||||
break;
|
||||
|
||||
if (irqnr > 1) {
|
||||
handle_domain_irq(armada_370_xp_mpic_domain,
|
||||
irqnr, regs);
|
||||
generic_handle_domain_irq(armada_370_xp_mpic_domain,
|
||||
irqnr);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -666,7 +661,7 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
|
||||
& IPI_DOORBELL_MASK;
|
||||
|
||||
for_each_set_bit(ipi, &ipimask, IPI_DOORBELL_END)
|
||||
handle_domain_irq(ipi_domain, ipi, regs);
|
||||
generic_handle_domain_irq(ipi_domain, ipi);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -100,7 +100,7 @@ static void __exception_irq_entry avic_handle_irq(struct pt_regs *regs)
|
||||
if (stat == 0)
|
||||
break;
|
||||
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_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <nds32_intrinsic.h>
|
||||
|
||||
#include <asm/irq_regs.h>
|
||||
|
||||
unsigned long wake_mask;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
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)
|
||||
|
@ -71,7 +71,7 @@ aic_handle(struct pt_regs *regs)
|
||||
if (!irqstat)
|
||||
irq_reg_writel(gc, 0, AT91_AIC_EOICR);
|
||||
else
|
||||
handle_domain_irq(aic_domain, irqnr, regs);
|
||||
generic_handle_domain_irq(aic_domain, irqnr);
|
||||
}
|
||||
|
||||
static int aic_retrigger(struct irq_data *d)
|
||||
|
@ -80,7 +80,7 @@ aic5_handle(struct pt_regs *regs)
|
||||
if (!irqstat)
|
||||
irq_reg_writel(bgc, 0, AT91_AIC5_EOICR);
|
||||
else
|
||||
handle_domain_irq(aic5_domain, irqnr, regs);
|
||||
generic_handle_domain_irq(aic5_domain, irqnr);
|
||||
}
|
||||
|
||||
static void aic5_mask(struct irq_data *d)
|
||||
|
@ -246,7 +246,7 @@ static void __exception_irq_entry bcm2835_handle_irq(
|
||||
u32 hwirq;
|
||||
|
||||
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)
|
||||
|
@ -143,7 +143,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
|
||||
if (stat) {
|
||||
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;
|
||||
unsigned long pending;
|
||||
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_enable(intc, idx));
|
||||
|
||||
for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
|
||||
irq = irq_linear_revmap(intc->domain, base + hwirq);
|
||||
if (irq)
|
||||
do_IRQ(irq);
|
||||
else
|
||||
if (generic_handle_domain_irq(intc->domain, base + hwirq))
|
||||
spurious_interrupt();
|
||||
}
|
||||
}
|
||||
|
@ -28,9 +28,6 @@
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#ifdef CONFIG_ARM
|
||||
#include <asm/smp_plat.h>
|
||||
#endif
|
||||
|
||||
#define IRQS_PER_WORD 32
|
||||
#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);
|
||||
unsigned int idx;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
|
||||
cpu = intc->cpus[cpu_logical_map(smp_processor_id())];
|
||||
#else
|
||||
cpu = intc->cpus[0];
|
||||
@ -194,6 +191,7 @@ static void bcm7038_l1_mask(struct irq_data *d)
|
||||
raw_spin_unlock_irqrestore(&intc->lock, flags);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MIPS) && defined(CONFIG_SMP)
|
||||
static int bcm7038_l1_set_affinity(struct irq_data *d,
|
||||
const struct cpumask *dest,
|
||||
bool force)
|
||||
@ -220,32 +218,6 @@ static int bcm7038_l1_set_affinity(struct irq_data *d,
|
||||
|
||||
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
|
||||
|
||||
static int __init bcm7038_l1_init_one(struct device_node *dn,
|
||||
@ -328,7 +300,7 @@ static int bcm7038_l1_suspend(void)
|
||||
u32 val;
|
||||
|
||||
/* 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);
|
||||
#else
|
||||
boot_cpu = 0;
|
||||
@ -352,7 +324,7 @@ static void bcm7038_l1_resume(void)
|
||||
struct bcm7038_l1_chip *intc;
|
||||
int boot_cpu, word;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
|
||||
boot_cpu = cpu_logical_map(0);
|
||||
#else
|
||||
boot_cpu = 0;
|
||||
@ -395,9 +367,8 @@ static struct irq_chip bcm7038_l1_irq_chip = {
|
||||
.name = "bcm7038-l1",
|
||||
.irq_mask = bcm7038_l1_mask,
|
||||
.irq_unmask = bcm7038_l1_unmask,
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
|
||||
.irq_set_affinity = bcm7038_l1_set_affinity,
|
||||
#ifdef CONFIG_SMP
|
||||
.irq_cpu_offline = bcm7038_l1_cpu_offline,
|
||||
#endif
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.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_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;
|
||||
}
|
||||
|
||||
@ -484,4 +455,8 @@ static int __init bcm7038_l1_of_init(struct device_node *dn,
|
||||
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;
|
||||
struct bcm7120_l2_intc_data *data;
|
||||
struct platform_device *pdev;
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
int ret = 0;
|
||||
@ -230,7 +231,13 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn,
|
||||
if (!data)
|
||||
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) {
|
||||
pr_err("invalid number of parent interrupts\n");
|
||||
ret = -ENOMEM;
|
||||
@ -329,6 +336,7 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn,
|
||||
if (data->map_base[idx])
|
||||
iounmap(data->map_base[idx]);
|
||||
}
|
||||
out_free_data:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
@ -347,8 +355,9 @@ static int __init bcm7120_l2_intc_probe_3380(struct device_node *dn,
|
||||
"BCM3380 L2");
|
||||
}
|
||||
|
||||
IRQCHIP_DECLARE(bcm7120_l2_intc, "brcm,bcm7120-l2-intc",
|
||||
bcm7120_l2_intc_probe_7120);
|
||||
|
||||
IRQCHIP_DECLARE(bcm3380_l2_intc, "brcm,bcm3380-l2-intc",
|
||||
bcm7120_l2_intc_probe_3380);
|
||||
IRQCHIP_PLATFORM_DRIVER_BEGIN(bcm7120_l2)
|
||||
IRQCHIP_MATCH("brcm,bcm7120-l2-intc", bcm7120_l2_intc_probe_7120)
|
||||
IRQCHIP_MATCH("brcm,bcm3380-l2-intc", bcm7120_l2_intc_probe_3380)
|
||||
IRQCHIP_PLATFORM_DRIVER_END(bcm7120_l2)
|
||||
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);
|
||||
}
|
||||
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,
|
||||
struct device_node *parent)
|
||||
{
|
||||
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]) &
|
||||
readw_relaxed(clps711x_intc->intsr[0]);
|
||||
if (irqstat)
|
||||
handle_domain_irq(clps711x_intc->domain,
|
||||
fls(irqstat) - 1, regs);
|
||||
generic_handle_domain_irq(clps711x_intc->domain,
|
||||
fls(irqstat) - 1);
|
||||
|
||||
irqstat = readw_relaxed(clps711x_intc->intmr[1]) &
|
||||
readw_relaxed(clps711x_intc->intsr[1]);
|
||||
if (irqstat)
|
||||
handle_domain_irq(clps711x_intc->domain,
|
||||
fls(irqstat) - 1 + 16, regs);
|
||||
generic_handle_domain_irq(clps711x_intc->domain,
|
||||
fls(irqstat) - 1 + 16);
|
||||
} while (irqstat);
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,7 @@ static inline bool handle_irq_perbit(struct pt_regs *regs, u32 hwirq,
|
||||
if (hwirq == 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;
|
||||
}
|
||||
|
@ -74,8 +74,8 @@ static void csky_mpintc_handler(struct pt_regs *regs)
|
||||
{
|
||||
void __iomem *reg_base = this_cpu_read(intcl_reg);
|
||||
|
||||
handle_domain_irq(root_domain,
|
||||
readl_relaxed(reg_base + INTCL_RDYIR), regs);
|
||||
generic_handle_domain_irq(root_domain,
|
||||
readl_relaxed(reg_base + INTCL_RDYIR));
|
||||
}
|
||||
|
||||
static void csky_mpintc_enable(struct irq_data *d)
|
||||
|
@ -73,7 +73,7 @@ davinci_aintc_handle_irq(struct pt_regs *regs)
|
||||
irqnr >>= 2;
|
||||
irqnr -= 1;
|
||||
|
||||
handle_domain_irq(davinci_aintc_irq_domain, irqnr, regs);
|
||||
generic_handle_domain_irq(davinci_aintc_irq_domain, irqnr);
|
||||
}
|
||||
|
||||
/* ARM Interrupt Controller Initialization */
|
||||
|
@ -135,7 +135,7 @@ davinci_cp_intc_handle_irq(struct pt_regs *regs)
|
||||
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,
|
||||
|
@ -50,7 +50,7 @@ static void __exception_irq_entry digicolor_handle_irq(struct pt_regs *regs)
|
||||
return;
|
||||
}
|
||||
|
||||
handle_domain_irq(digicolor_irq_domain, hwirq, regs);
|
||||
generic_handle_domain_irq(digicolor_irq_domain, hwirq);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ static void __irq_entry dw_apb_ictl_handle_irq(struct pt_regs *regs)
|
||||
while (stat) {
|
||||
u32 hwirq = ffs(stat) - 1;
|
||||
|
||||
handle_domain_irq(d, hwirq, regs);
|
||||
generic_handle_domain_irq(d, 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)))) {
|
||||
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
|
||||
* interrupted context.
|
||||
*/
|
||||
err = handle_domain_nmi(gic_data.domain, irqnr, regs);
|
||||
err = generic_handle_domain_nmi(gic_data.domain, irqnr);
|
||||
if (err)
|
||||
gic_deactivate_unhandled(irqnr);
|
||||
|
||||
@ -728,7 +728,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
|
||||
else
|
||||
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");
|
||||
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);
|
||||
}
|
||||
|
||||
handle_domain_irq(gic->domain, irqnr, regs);
|
||||
generic_handle_domain_irq(gic->domain, irqnr);
|
||||
} 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ asmlinkage void __exception_irq_entry ixp4xx_handle_irq(struct pt_regs *regs)
|
||||
|
||||
status = __raw_readl(ixi->irqbase + IXP4XX_ICIP);
|
||||
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
|
||||
@ -122,7 +122,7 @@ asmlinkage void __exception_irq_entry ixp4xx_handle_irq(struct pt_regs *regs)
|
||||
if (ixi->is_356) {
|
||||
status = __raw_readl(ixi->irqbase + IXP4XX_ICIP2);
|
||||
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) {
|
||||
irq = __ffs(hwirq);
|
||||
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,
|
||||
};
|
||||
|
||||
static int __init meson_gpio_irq_parse_dt(struct device_node *node,
|
||||
struct meson_gpio_irq_controller *ctl)
|
||||
static int meson_gpio_irq_parse_dt(struct device_node *node, struct meson_gpio_irq_controller *ctl)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
int ret;
|
||||
@ -463,8 +462,7 @@ static int __init meson_gpio_irq_parse_dt(struct device_node *node,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init meson_gpio_irq_of_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
static int meson_gpio_irq_of_init(struct device_node *node, struct device_node *parent)
|
||||
{
|
||||
struct irq_domain *domain, *parent_domain;
|
||||
struct meson_gpio_irq_controller *ctl;
|
||||
@ -521,5 +519,10 @@ static int __init meson_gpio_irq_of_init(struct device_node *node,
|
||||
return ret;
|
||||
}
|
||||
|
||||
IRQCHIP_DECLARE(meson_gpio_intc, "amlogic,meson-gpio-intc",
|
||||
meson_gpio_irq_of_init);
|
||||
IRQCHIP_PLATFORM_DRIVER_BEGIN(meson_gpio_intc)
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
unsigned int intr;
|
||||
static const unsigned int local_intrs[] = {
|
||||
GIC_LOCAL_INT_TIMER,
|
||||
GIC_LOCAL_INT_PERFCTR,
|
||||
GIC_LOCAL_INT_FDC,
|
||||
};
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
|
||||
cd = irq_data_get_irq_chip_data(d);
|
||||
spin_lock_irqsave(&gic_lock, flags);
|
||||
|
||||
write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map);
|
||||
if (cd->mask)
|
||||
write_gic_vl_smask(BIT(intr));
|
||||
for (i = 0; i < ARRAY_SIZE(local_intrs); i++) {
|
||||
unsigned int intr = local_intrs[i];
|
||||
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 = {
|
||||
.name = "MIPS GIC Local",
|
||||
.irq_mask = gic_mask_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)
|
||||
@ -477,6 +488,10 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||
intr = GIC_HWIRQ_TO_LOCAL(hwirq);
|
||||
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) {
|
||||
case GIC_LOCAL_INT_TIMER:
|
||||
/* 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) */
|
||||
write_gic_vl_rmask(~0);
|
||||
|
||||
/* Invoke irq_cpu_online callbacks to enable desired interrupts */
|
||||
irq_cpu_online();
|
||||
/* Enable desired interrupts */
|
||||
gic_all_vpes_irq_cpu_online();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
|
||||
if (!(hwirq & SEL_INT_PENDING))
|
||||
return;
|
||||
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)
|
||||
@ -241,7 +241,7 @@ static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs)
|
||||
if (!(hwirq & SEL_INT_PENDING))
|
||||
return;
|
||||
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) */
|
||||
|
@ -347,7 +347,6 @@ builtin_platform_driver(mvebu_icu_subset_driver);
|
||||
static int mvebu_icu_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mvebu_icu *icu;
|
||||
struct resource *res;
|
||||
int i;
|
||||
|
||||
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;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
icu->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
icu->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_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 mvebu_pic *pic;
|
||||
struct irq_chip *irq_chip;
|
||||
struct resource *res;
|
||||
|
||||
pic = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pic), GFP_KERNEL);
|
||||
if (!pic)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pic->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
pic->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_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);
|
||||
__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,
|
||||
|
@ -37,10 +37,25 @@
|
||||
|
||||
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
|
||||
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,
|
||||
|
@ -357,7 +357,7 @@ omap_intc_handle_irq(struct pt_regs *regs)
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -116,7 +116,7 @@ static void or1k_pic_handle_irq(struct pt_regs *regs)
|
||||
int irq = -1;
|
||||
|
||||
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)
|
||||
|
@ -42,8 +42,8 @@ __exception_irq_entry orion_handle_irq(struct pt_regs *regs)
|
||||
gc->mask_cache;
|
||||
while (stat) {
|
||||
u32 hwirq = __fls(stat);
|
||||
handle_domain_irq(orion_irq_domain,
|
||||
gc->irq_base + hwirq, regs);
|
||||
generic_handle_domain_irq(orion_irq_domain,
|
||||
gc->irq_base + hwirq);
|
||||
stat &= ~(1 << hwirq);
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ static void __exception_irq_entry rda_handle_irq(struct pt_regs *regs)
|
||||
|
||||
while (stat) {
|
||||
hwirq = __fls(stat);
|
||||
handle_domain_irq(rda_irq_domain, hwirq, regs);
|
||||
generic_handle_domain_irq(rda_irq_domain, hwirq);
|
||||
stat &= ~BIT(hwirq);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ static asmlinkage void riscv_intc_irq(struct pt_regs *regs)
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
handle_domain_irq(intc_domain, cause, regs);
|
||||
generic_handle_domain_irq(intc_domain, cause);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -140,8 +140,8 @@ sa1100_handle_irq(struct pt_regs *regs)
|
||||
if (mask == 0)
|
||||
break;
|
||||
|
||||
handle_domain_irq(sa1100_normal_irqdomain,
|
||||
ffs(mask) - 1, regs);
|
||||
generic_handle_domain_irq(sa1100_normal_irqdomain,
|
||||
ffs(mask) - 1);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
|
@ -850,7 +850,6 @@ static int stm32_exti_probe(struct platform_device *pdev)
|
||||
struct irq_domain *parent_domain, *domain;
|
||||
struct stm32_exti_host_data *host_data;
|
||||
const struct stm32_exti_drv_data *drv_data;
|
||||
struct resource *res;
|
||||
|
||||
host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL);
|
||||
if (!host_data)
|
||||
@ -888,8 +887,7 @@ static int stm32_exti_probe(struct platform_device *pdev)
|
||||
if (!host_data->chips_data)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
host_data->base = devm_ioremap_resource(dev, res);
|
||||
host_data->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_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;
|
||||
|
||||
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 +
|
||||
SUN4I_IRQ_VECTOR_REG) >> 2;
|
||||
} 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 ti_sci_inta_irq_domain *inta;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
inta->base = devm_ioremap_resource(dev, res);
|
||||
inta->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_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 ts4800_irq_data *data;
|
||||
struct irq_chip *irq_chip;
|
||||
struct resource *res;
|
||||
int parent_irq;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
data->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
data->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_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))) {
|
||||
irq = ffs(status) - 1;
|
||||
handle_domain_irq(f->domain, irq, regs);
|
||||
generic_handle_domain_irq(f->domain, irq);
|
||||
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))) {
|
||||
irq = ffs(stat) - 1;
|
||||
handle_domain_irq(vic->domain, irq, regs);
|
||||
generic_handle_domain_irq(vic->domain, irq);
|
||||
handled = 1;
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,7 @@ static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
|
||||
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 */
|
||||
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)
|
||||
|
@ -50,7 +50,7 @@ static void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
|
||||
|
||||
while (readl(zevio_irq_io + IO_STATUS)) {
|
||||
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_sync_unlock)(struct irq_data *data);
|
||||
|
||||
#ifdef CONFIG_DEPRECATED_IRQ_CPU_ONOFFLINE
|
||||
void (*irq_cpu_online)(struct irq_data *data);
|
||||
void (*irq_cpu_offline)(struct irq_data *data);
|
||||
|
||||
#endif
|
||||
void (*irq_suspend)(struct irq_data *data);
|
||||
void (*irq_resume)(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 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_offline(void);
|
||||
#endif
|
||||
extern int irq_set_affinity_locked(struct irq_data *data,
|
||||
const struct cpumask *cpumask, bool force);
|
||||
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.
|
||||
*/
|
||||
extern void (*handle_arch_irq)(struct pt_regs *) __ro_after_init;
|
||||
asmlinkage void generic_handle_arch_irq(struct pt_regs *regs);
|
||||
#else
|
||||
#ifndef set_handle_irq
|
||||
#define set_handle_irq(handle_irq) \
|
||||
|
@ -14,8 +14,15 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.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
|
||||
* 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
|
||||
* same file.
|
||||
* @compstr: compatible string of the irqchip driver
|
||||
* @compat: compatible string of the irqchip driver
|
||||
* @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);
|
||||
|
||||
#define IRQCHIP_PLATFORM_DRIVER_BEGIN(drv_name) \
|
||||
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) \
|
||||
{}, \
|
||||
}; \
|
||||
MODULE_DEVICE_TABLE(of, drv_name##_irqchip_match_table); \
|
||||
static struct platform_driver drv_name##_driver = { \
|
||||
.probe = platform_irqchip_probe, \
|
||||
static struct platform_driver drv_name##_driver = { \
|
||||
.probe = IS_ENABLED(CONFIG_IRQCHIP) ? \
|
||||
platform_irqchip_probe : NULL, \
|
||||
.driver = { \
|
||||
.name = #drv_name, \
|
||||
.owner = THIS_MODULE, \
|
||||
|
@ -168,14 +168,7 @@ int generic_handle_irq(unsigned int irq);
|
||||
* conversion failed.
|
||||
*/
|
||||
int generic_handle_domain_irq(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
|
||||
int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq);
|
||||
#endif
|
||||
|
||||
/* Test to see if a driver has successfully requested an irq */
|
||||
|
@ -97,9 +97,6 @@ config GENERIC_MSI_IRQ_DOMAIN
|
||||
config IRQ_MSI_IOMMU
|
||||
bool
|
||||
|
||||
config HANDLE_DOMAIN_IRQ
|
||||
bool
|
||||
|
||||
config IRQ_TIMINGS
|
||||
bool
|
||||
|
||||
@ -144,3 +141,10 @@ config GENERIC_IRQ_MULTI_HANDLER
|
||||
bool
|
||||
help
|
||||
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);
|
||||
|
||||
#ifdef CONFIG_DEPRECATED_IRQ_CPU_ONOFFLINE
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
|
||||
|
||||
|
@ -25,6 +25,7 @@ static DEFINE_RAW_SPINLOCK(gc_lock);
|
||||
void irq_gc_noop(struct irq_data *d)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_gc_noop);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
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
|
||||
@ -103,6 +105,7 @@ void irq_gc_unmask_enable_reg(struct irq_data *d)
|
||||
*ct->mask_cache |= mask;
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_gc_unmask_enable_reg);
|
||||
|
||||
/**
|
||||
* irq_gc_ack_set_bit - Ack pending interrupt via setting bit
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
|
||||
#include <asm/irq_regs.h>
|
||||
|
||||
#include <trace/events/irq.h>
|
||||
|
||||
#include "internals.h"
|
||||
@ -226,4 +228,20 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
|
||||
handle_arch_irq = handle_irq;
|
||||
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
|
||||
|
@ -646,13 +646,16 @@ int handle_irq_desc(struct irq_desc *desc)
|
||||
generic_handle_irq_desc(desc);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(handle_irq_desc);
|
||||
|
||||
/**
|
||||
* generic_handle_irq - Invoke the handler for a particular irq
|
||||
* @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)
|
||||
{
|
||||
return handle_irq_desc(irq_to_desc(irq));
|
||||
@ -662,89 +665,39 @@ EXPORT_SYMBOL_GPL(generic_handle_irq);
|
||||
#ifdef CONFIG_IRQ_DOMAIN
|
||||
/**
|
||||
* generic_handle_domain_irq - Invoke the handler for a HW irq belonging
|
||||
* to a domain, usually for a non-root interrupt
|
||||
* controller
|
||||
* to a domain.
|
||||
* @domain: The domain where to perform the lookup
|
||||
* @hwirq: The HW irq number to convert to a logical one
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
WARN_ON_ONCE(!in_irq());
|
||||
return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
|
||||
}
|
||||
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,
|
||||
* usually for a root interrupt controller
|
||||
* generic_handle_domain_nmi - Invoke the handler for a HW nmi 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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Returns: 0 on success, or -EINVAL if conversion has failed
|
||||
*/
|
||||
int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq,
|
||||
struct pt_regs *regs)
|
||||
* This function must be called from an NMI context with irq regs
|
||||
* initialized.
|
||||
**/
|
||||
int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq)
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
struct irq_desc *desc;
|
||||
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;
|
||||
WARN_ON_ONCE(!in_nmi());
|
||||
return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Dynamic interrupt handling */
|
||||
|
||||
|
@ -1259,6 +1259,8 @@ static int irq_thread(void *data)
|
||||
irqreturn_t (*handler_fn)(struct irq_desc *desc,
|
||||
struct irqaction *action);
|
||||
|
||||
sched_set_fifo(current);
|
||||
|
||||
if (force_irqthreads() && test_bit(IRQTF_FORCED_THREAD,
|
||||
&action->thread_flags))
|
||||
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))
|
||||
return PTR_ERR(t);
|
||||
|
||||
sched_set_fifo(t);
|
||||
|
||||
/*
|
||||
* We keep the reference to the task struct even if
|
||||
* 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,
|
||||
* 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.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
|
||||
pr_warn("irqfixup boot option not supported with PREEMPT_RT\n");
|
||||
return 1;
|
||||
}
|
||||
irqfixup = 1;
|
||||
printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\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)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
|
||||
pr_warn("irqpoll boot option not supported with PREEMPT_RT\n");
|
||||
return 1;
|
||||
}
|
||||
irqfixup = 2;
|
||||
printk(KERN_WARNING "Misrouted IRQ fixup and polling support "
|
||||
"enabled\n");
|
||||
|
Loading…
Reference in New Issue
Block a user