[PATCH dovetail v12 02/11] riscv: irq_pipeline: add IRQ pipelining core
Tobias Schaffner <[email protected]> Tue, 28 Jul 2026 13:12:13 +0200
| Newsgroups | dev.linux.lists.xenomai |
|---|---|
| Message-ID | <[email protected]> |
This patchset integrates IRQ pipelining into the RISC-V architecture, bringing it in line with the Dovetail/IRQ pipeline model used on other architectures. It adds the core pipelining infrastructure and adapts low-level primitives to cleanly separate in-band and out-of-band interrupt handling. Signed-off-by: Tobias Schaffner <[email protected]> Co-authored-by: Philippe Gerum <[email protected]> Signed-off-by: Philippe Gerum <[email protected]> --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/entry-common.h | 3 +- arch/riscv/include/asm/irq_pipeline.h | 143 +++++++++++++++++++++++++ arch/riscv/include/asm/irqflags.h | 32 ++++-- arch/riscv/include/asm/smp.h | 25 +++++ arch/riscv/include/asm/thread_info.h | 9 ++ arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/irq_pipeline.c | 26 +++++ arch/riscv/kernel/kernel_mode_vector.c | 2 +- arch/riscv/kernel/sbi-ipi.c | 12 ++- arch/riscv/kernel/smp.c | 56 ++++++---- arch/riscv/kernel/smpboot.c | 2 +- arch/riscv/kernel/traps.c | 86 +++++++++++++++ arch/riscv/mm/fault.c | 8 +- 14 files changed, 371 insertions(+), 35 deletions(-) create mode 100644 arch/riscv/include/asm/irq_pipeline.h create mode 100644 arch/riscv/kernel/irq_pipeline.c diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index c5754942cf85..7c58654c4ece 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -150,6 +150,7 @@ config RISCV select HAVE_ARCH_USERFAULTFD_MINOR if 64BIT && USERFAULTFD select HAVE_ARCH_USERFAULTFD_WP if 64BIT && MMU && USERFAULTFD && RISCV_ISA_SVRSW60T59B select HAVE_ARCH_VMAP_STACK if MMU && 64BIT + select HAVE_IRQ_PIPELINE select HAVE_ASM_MODVERSIONS select HAVE_CONTEXT_TRACKING_USER select HAVE_DEBUG_KMEMLEAK diff --git a/arch/riscv/include/asm/entry-common.h b/arch/riscv/include/asm/entry-common.h index 34ed149af5d1..28ea8090316d 100644 --- a/arch/riscv/include/asm/entry-common.h +++ b/arch/riscv/include/asm/entry-common.h @@ -22,7 +22,8 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs, #define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare -void handle_page_fault(struct pt_regs *regs); +struct irqentry_state; +void handle_page_fault(struct pt_regs *regs, struct irqentry_state state); void handle_break(struct pt_regs *regs); #ifdef CONFIG_RISCV_MISALIGNED diff --git a/arch/riscv/include/asm/irq_pipeline.h b/arch/riscv/include/asm/irq_pipeline.h new file mode 100644 index 000000000000..d6f548c525be --- /dev/null +++ b/arch/riscv/include/asm/irq_pipeline.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * IRQ Pipelining adapted from the ARM version. + * + * Copyright (C) 2024-2026 Siemens AG + * Author: Tobias Schaffner <[email protected]>. + */ + +#ifndef _ASM_RISCV_IRQ_PIPELINE_H +#define _ASM_RISCV_IRQ_PIPELINE_H + +#ifdef CONFIG_IRQ_PIPELINE + +#include <asm/ptrace.h> +#include <asm/smp.h> + +#define OOB_NR_IPI 3 + +extern int ipi_virq_base; + +#define CALL_FUNCTION_OOB_IPI (ipi_virq_base + OOB_CALL_FUNCTION_IPI) +#define RESCHEDULE_OOB_IPI (ipi_virq_base + OOB_RESCHEDULE_IPI) +#define TIMER_OOB_IPI (ipi_virq_base + OOB_TIMER_IPI) + +/* NOTE: Any bit should be fine as long as we don't hit SR_SIE or SR_MIE. */ +#define IRQMASK_i_POS 31 + +static inline notrace +unsigned long arch_irqs_virtual_to_native_flags(int stalled) +{ + if (!stalled) + return SR_IE; + return 0; +} + +static inline notrace +unsigned long arch_irqs_native_to_virtual_flags(unsigned long flags) +{ + return (!!native_irqs_disabled_flags(flags)) << IRQMASK_i_POS; +} + +static inline int arch_irqs_disabled_flags(unsigned long flags) +{ + return native_irqs_disabled_flags(flags); +} + +static inline notrace void arch_local_irq_enable(void) +{ + barrier(); + inband_irq_enable(); +} + +static inline notrace void arch_local_irq_disable(void) +{ + inband_irq_disable(); + barrier(); +} + +static inline notrace unsigned long arch_local_save_flags(void) +{ + int stalled = inband_irqs_disabled(); + + barrier(); + return arch_irqs_virtual_to_native_flags(stalled); +} + +static inline notrace unsigned long arch_local_irq_save(void) +{ + int stalled = inband_irq_save(); + + barrier(); + return arch_irqs_virtual_to_native_flags(stalled); +} + +/* set interrupt enabled status */ +static inline void arch_local_irq_restore(unsigned long flags) +{ + inband_irq_restore(arch_irqs_disabled_flags(flags)); + barrier(); +} + +static inline +void arch_save_timer_regs(struct pt_regs *dst, struct pt_regs *src) +{ + dst->status = src->status; + dst->epc = src->epc; +} + +#else /* !CONFIG_IRQ_PIPELINE */ + +static inline unsigned long arch_local_irq_save(void) +{ + return native_irq_save(); +} + +static inline void arch_local_irq_enable(void) +{ + native_irq_enable(); +} + +static inline void arch_local_irq_disable(void) +{ + native_irq_disable(); +} + +static inline unsigned long arch_local_save_flags(void) +{ + return native_save_flags(); +} + +static inline void arch_local_irq_restore(unsigned long flags) +{ + native_irq_restore(flags); +} + +static inline int arch_irqs_disabled_flags(unsigned long flags) +{ + return native_irqs_disabled_flags(flags); +} + +#endif /* !CONFIG_IRQ_PIPELINE */ + +/* test hardware interrupt enable bit */ +static inline int arch_irqs_disabled(void) +{ + return arch_irqs_disabled_flags(arch_local_save_flags()); +} + +struct pt_regs; + +extern void (*handle_arch_irq)(struct pt_regs *regs); + +static inline void arch_handle_irq_pipelined(struct pt_regs *regs) +{ + handle_arch_irq(regs); +} + +static inline int arch_enable_oob_stage(void) +{ + return 0; +} + +#endif /* _ASM_RISCV_IRQ_PIPELINE_H */ diff --git a/arch/riscv/include/asm/irqflags.h b/arch/riscv/include/asm/irqflags.h index 6fd8cbfcfcc7..c3087b74752b 100644 --- a/arch/riscv/include/asm/irqflags.h +++ b/arch/riscv/include/asm/irqflags.h @@ -10,45 +10,57 @@ #include <asm/csr.h> /* read interrupt enabled status */ -static inline unsigned long arch_local_save_flags(void) +static inline unsigned long native_save_flags(void) { - return csr_read(CSR_STATUS); + return csr_read(CSR_STATUS) & SR_IE; } /* unconditionally enable interrupts */ -static inline void arch_local_irq_enable(void) +static inline void native_irq_enable(void) { csr_set(CSR_STATUS, SR_IE); } /* unconditionally disable interrupts */ -static inline void arch_local_irq_disable(void) +static inline void native_irq_disable(void) { csr_clear(CSR_STATUS, SR_IE); } /* get status and disable interrupts */ -static inline unsigned long arch_local_irq_save(void) +static inline unsigned long native_irq_save(void) { return csr_read_clear(CSR_STATUS, SR_IE); } /* test flags */ -static inline int arch_irqs_disabled_flags(unsigned long flags) +static inline int native_irqs_disabled_flags(unsigned long flags) { return !(flags & SR_IE); } /* test hardware interrupt enable bit */ -static inline int arch_irqs_disabled(void) +static inline bool native_irqs_disabled(void) { - return arch_irqs_disabled_flags(arch_local_save_flags()); + return native_irqs_disabled_flags(native_save_flags()); } /* set interrupt enabled status */ -static inline void arch_local_irq_restore(unsigned long flags) +static inline void native_irq_restore(unsigned long flags) { - csr_set(CSR_STATUS, flags & SR_IE); + if (flags & SR_IE) + csr_set(CSR_STATUS, SR_IE); + else + csr_clear(CSR_STATUS, SR_IE); +} + +#include <asm/irq_pipeline.h> + +static inline void native_irq_sync(void) +{ + native_irq_enable(); + asm volatile("nop" : : : "memory"); + native_irq_disable(); } #endif /* _ASM_RISCV_IRQFLAGS_H */ diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h index 0ecc67641b09..8a409484d002 100644 --- a/arch/riscv/include/asm/smp.h +++ b/arch/riscv/include/asm/smp.h @@ -15,6 +15,31 @@ struct seq_file; extern unsigned long boot_cpu_hartid; +#ifdef CONFIG_IRQ_PIPELINE +extern int ipi_max; +#define IRQ_RISCV_IPI_MAX ipi_max +#else +#define IRQ_RISCV_IPI_MAX BITS_PER_BYTE +#endif + +enum ipi_message_type { + IPI_RESCHEDULE, + IPI_CALL_FUNC, + IPI_CPU_STOP, + IPI_CPU_CRASH_STOP, + IPI_IRQ_WORK, + IPI_TIMER, + IPI_CPU_BACKTRACE, + IPI_KGDB_ROUNDUP, +#ifdef CONFIG_IRQ_PIPELINE + OOB_TIMER_IPI, + OOB_RESCHEDULE_IPI, + OOB_CALL_FUNCTION_IPI, +#endif + IPI_MAX, + +}; + #ifdef CONFIG_SMP #include <linux/jump_label.h> diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h index 55019fdfa9ec..8bfb02064f48 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -52,6 +52,10 @@ */ struct thread_info { unsigned long flags; /* low level flags */ +#ifdef CONFIG_IRQ_PIPELINE + __u32 local_flags; /* local (synchronous) flags */ +#define ti_local_flags(__ti) ((__ti)->local_flags) +#endif int preempt_count; /* 0=>preemptible, <0=>BUG */ /* * These stack pointers are overwritten on every system call or @@ -124,4 +128,9 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); #define _TIF_RISCV_V_DEFER_RESTORE BIT(TIF_RISCV_V_DEFER_RESTORE) +/* + * Local (synchronous) thread flags. + */ +#define _TLF_OOB 0x0001 + #endif /* _ASM_RISCV_THREAD_INFO_H */ diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 4e310257499a..fb51d1bc5e3a 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o obj-$(CONFIG_CPU_PM) += suspend_entry.o suspend.o +obj-$(CONFIG_IRQ_PIPELINE) += irq_pipeline.o obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o diff --git a/arch/riscv/kernel/irq_pipeline.c b/arch/riscv/kernel/irq_pipeline.c new file mode 100644 index 000000000000..a478e9c3b3a4 --- /dev/null +++ b/arch/riscv/kernel/irq_pipeline.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IRQ Pipelining implementation adapted from the ARM version. + * + * Copyright (C) 2024-2026 Siemens AG + * Author: Tobias Schaffner <[email protected]>. + */ +#include <linux/irq.h> +#include <linux/irq_pipeline.h> + +void arch_do_IRQ_pipelined(struct irq_desc *desc) +{ + struct pt_regs *regs = raw_cpu_ptr(&irq_pipeline.tick_regs); + struct pt_regs *old_regs = set_irq_regs(regs); + + irq_enter_rcu(); + handle_irq_desc(desc); + irq_exit_rcu(); + + set_irq_regs(old_regs); +} + +void __init arch_irq_pipeline_init(void) +{ + /* no per-arch init. */ +} diff --git a/arch/riscv/kernel/kernel_mode_vector.c b/arch/riscv/kernel/kernel_mode_vector.c index 99972a48e86b..c4444577449c 100644 --- a/arch/riscv/kernel/kernel_mode_vector.c +++ b/arch/riscv/kernel/kernel_mode_vector.c @@ -171,7 +171,7 @@ asmlinkage void riscv_v_context_nesting_end(struct pt_regs *regs) struct __riscv_v_ext_state *vstate = ¤t->thread.kernel_vstate; u32 depth; - WARN_ON(!irqs_disabled()); + WARN_ON(!hard_irqs_disabled()); if (!riscv_preempt_v_started(current)) return; diff --git a/arch/riscv/kernel/sbi-ipi.c b/arch/riscv/kernel/sbi-ipi.c index 0cc5559c08d8..600e2b51f1de 100644 --- a/arch/riscv/kernel/sbi-ipi.c +++ b/arch/riscv/kernel/sbi-ipi.c @@ -57,7 +57,7 @@ void __init sbi_ipi_init(void) return; } - virq = ipi_mux_create(BITS_PER_BYTE, sbi_send_ipi); + virq = ipi_mux_create(IRQ_RISCV_IPI_MAX, sbi_send_ipi); if (virq <= 0) { pr_err("unable to create muxed IPIs\n"); irq_dispose_mapping(sbi_ipi_virq); @@ -75,12 +75,18 @@ void __init sbi_ipi_init(void) "irqchip/sbi-ipi:starting", sbi_ipi_starting_cpu, NULL); - riscv_ipi_set_virq_range(virq, BITS_PER_BYTE); + riscv_ipi_set_virq_range(virq, IRQ_RISCV_IPI_MAX); pr_info("providing IPIs using SBI IPI extension\n"); /* * Use the SBI remote fence extension to avoid * the extra context switch needed to handle IPIs. + * + * When the IRQ pipeline is enabled, avoid the SBI remote fence + * extension because SBI rfence traps to M-mode via ecall. + * Use the IPI-based fence path instead, which stays entirely in + * S-mode and can be preempted by OOB interrupts. */ - static_branch_enable(&riscv_sbi_for_rfence); + if (!irqs_pipelined()) + static_branch_enable(&riscv_sbi_for_rfence); } diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c index 5ed5095320e6..8f842aec1e0e 100644 --- a/arch/riscv/kernel/smp.c +++ b/arch/riscv/kernel/smp.c @@ -21,6 +21,7 @@ #include <linux/seq_file.h> #include <linux/delay.h> #include <linux/irq.h> +#include <linux/irq_pipeline.h> #include <linux/irq_work.h> #include <linux/nmi.h> @@ -28,18 +29,6 @@ #include <asm/cacheflush.h> #include <asm/cpu_ops.h> -enum ipi_message_type { - IPI_RESCHEDULE, - IPI_CALL_FUNC, - IPI_CPU_STOP, - IPI_CPU_CRASH_STOP, - IPI_IRQ_WORK, - IPI_TIMER, - IPI_CPU_BACKTRACE, - IPI_KGDB_ROUNDUP, - IPI_MAX -}; - static const char * const ipi_names[] = { [IPI_RESCHEDULE] = "Rescheduling interrupts", [IPI_CALL_FUNC] = "Function call interrupts", @@ -49,6 +38,11 @@ static const char * const ipi_names[] = { [IPI_TIMER] = "Timer broadcast interrupts", [IPI_CPU_BACKTRACE] = "CPU backtrace interrupts", [IPI_KGDB_ROUNDUP] = "KGDB roundup interrupts", +#ifdef CONFIG_IRQ_PIPELINE + [OOB_TIMER_IPI] = "OOB timer interrupts", + [OOB_RESCHEDULE_IPI] = "OOB reschedule interrupts", + [OOB_CALL_FUNCTION_IPI] = "OOB call function interrupts", +#endif }; unsigned long __cpuid_to_hartid_map[NR_CPUS] __ro_after_init = { @@ -63,11 +57,35 @@ void __init smp_setup_processor_id(void) pr_info("Booting Linux on hartid %lu\n", boot_cpu_hartid); } -static DEFINE_PER_CPU_READ_MOSTLY(int, ipi_dummy_dev); -static int ipi_virq_base __ro_after_init; +int ipi_virq_base __ro_after_init; static int nr_ipi __ro_after_init = IPI_MAX; static struct irq_desc *ipi_desc[IPI_MAX] __read_mostly; +#ifdef CONFIG_IRQ_PIPELINE +#define INBAND_IPI_MAX (IPI_MAX - OOB_NR_IPI) +int ipi_max __ro_after_init = IPI_MAX; + +void irq_send_oob_ipi(unsigned int irq, + const struct cpumask *cpumask) +{ + unsigned int op = irq - ipi_virq_base; + + if (WARN_ON(irq_pipeline_debug() && + (op < INBAND_IPI_MAX || + op >= IPI_MAX))) + return; + + /* Init oob ipis at first involve*/ + if (unlikely(ipi_desc[op] == NULL)) + ipi_desc[op] = irq_to_desc(irq); + + __ipi_send_mask(ipi_desc[op], cpumask); +} +EXPORT_SYMBOL_GPL(irq_send_oob_ipi); +#else +#define INBAND_IPI_MAX IPI_MAX +#endif + int riscv_hartid_to_cpuid(unsigned long hartid) { int i; @@ -95,7 +113,7 @@ static inline void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs) atomic_dec(&waiting_for_crash_ipi); - local_irq_disable(); + local_irq_disable_full(); #ifdef CONFIG_HOTPLUG_CPU if (cpu_has_hotplug(cpu)) @@ -209,9 +227,11 @@ void riscv_ipi_set_virq_range(int virq, int nr) /* Request IPIs */ for (i = 0; i < nr_ipi; i++) { - err = request_percpu_irq(ipi_virq_base + i, handle_IPI, - ipi_names[i], &ipi_dummy_dev); - WARN_ON(err); + if (i < INBAND_IPI_MAX) { + err = request_percpu_irq(ipi_virq_base + i, handle_IPI, + ipi_names[i], &irq_stat); + WARN_ON(err); + } ipi_desc[i] = irq_to_desc(ipi_virq_base + i); irq_set_status_flags(ipi_virq_base + i, IRQ_HIDDEN); diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index 8b628580fe11..3eda9cbb31c3 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -259,6 +259,6 @@ asmlinkage __visible void smp_callin(void) #ifndef CONFIG_HOTPLUG_PARALLEL complete(&cpu_running); #endif - local_irq_enable(); + local_irq_enable_full(); cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); } diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index 8c62c771a656..be87cd58e754 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c @@ -112,10 +112,32 @@ void die(struct pt_regs *regs, const char *str) make_task_dead(SIGSEGV); } +static __always_inline +bool mark_trap_entry(struct pt_regs *regs) +{ + if (likely(running_inband())) { + if (user_mode(regs)) + hard_cond_local_irq_enable(); + return true; + } + + return false; +} + +static __always_inline +void mark_trap_exit(struct pt_regs *regs) +{ + if (likely(running_inband()) && user_mode(regs)) + hard_cond_local_irq_disable(); +} + void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr) { struct task_struct *tsk = current; + if (!mark_trap_entry(regs)) + return; + if (show_unhandled_signals && unhandled_signal(tsk, signo) && printk_ratelimit()) { pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x" REG_FMT, @@ -127,6 +149,8 @@ void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr) } force_sig_fault(signo, code, (void __user *)addr); + + mark_trap_exit(regs); } static void do_trap_error(struct pt_regs *regs, int signo, int code, @@ -421,6 +445,66 @@ asmlinkage __visible noinstr void do_page_fault(struct pt_regs *regs) } #endif +#ifdef CONFIG_IRQ_PIPELINE + +extern void (*handle_arch_irq)(struct pt_regs *); + +static void noinstr handle_riscv_irq_pipelined(struct pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + + handle_arch_irq(regs); + set_irq_regs(old_regs); +} + +DEFINE_PER_CPU(int, irq_nesting); + +static void noinstr handle_riscv_irq_pipelined_on_stack(struct pt_regs *regs) +{ + int nesting = this_cpu_inc_return(irq_nesting); + + if (IS_ENABLED(CONFIG_IRQ_STACKS) && nesting == 1) + call_on_irq_stack(regs, handle_riscv_irq_pipelined); + else + handle_riscv_irq_pipelined(regs); + this_cpu_dec(irq_nesting); +} + +asmlinkage void noinstr do_irq(struct pt_regs *regs) +{ + irqentry_state_t state; + struct irq_stage_data *prevd; + + /* OOB fast path: Log the IRQ and return. */ + if (unlikely(running_oob() || irqs_disabled())) { + instrumentation_begin(); + prevd = handle_irq_pipelined_prepare(regs); + handle_riscv_irq_pipelined(regs); + handle_irq_pipelined_finish(prevd, regs); + if (running_inband() && user_mode(regs)) { + stall_inband_nocheck(); + irqentry_exit_to_user_mode(regs); + } + instrumentation_end(); + return; + } + + /* Handle inband IRQ. */ + state = irqentry_enter(regs); + instrumentation_begin(); + prevd = handle_irq_pipelined_prepare(regs); + handle_riscv_irq_pipelined_on_stack(regs); + trace_hardirqs_on(); + unstall_inband_nocheck(); + handle_irq_pipelined_finish(prevd, regs); + stall_inband_nocheck(); + trace_hardirqs_off(); + instrumentation_end(); + irqentry_exit(regs, state); +} + +#else /* !CONFIG_IRQ_PIPELINE */ + static void noinstr handle_riscv_irq(struct pt_regs *regs) { struct pt_regs *old_regs; @@ -444,6 +528,8 @@ asmlinkage void noinstr do_irq(struct pt_regs *regs) irqentry_exit(regs, state); } +#endif /* !CONFIG_IRQ_PIPELINE */ + #ifdef CONFIG_GENERIC_BUG int is_valid_bugaddr(unsigned long pc) { diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c index 04ed6f8acae4..c5709112c346 100644 --- a/arch/riscv/mm/fault.c +++ b/arch/riscv/mm/fault.c @@ -79,6 +79,7 @@ static void show_pte(unsigned long addr) static void die_kernel_fault(const char *msg, unsigned long addr, struct pt_regs *regs) { + irq_pipeline_oops(); bust_spinlocks(1); pr_alert("Unable to handle kernel %s at virtual address " REG_FMT "\n", msg, @@ -275,7 +276,7 @@ static inline bool access_error(unsigned long cause, struct vm_area_struct *vma) * This routine handles page faults. It determines the address and the * problem, and then passes it off to one of the appropriate routines. */ -void handle_page_fault(struct pt_regs *regs) +void handle_page_fault(struct pt_regs *regs, irqentry_state_t state) { struct task_struct *tsk; struct vm_area_struct *vma; @@ -315,8 +316,13 @@ void handle_page_fault(struct pt_regs *regs) } /* Enable interrupts if they were enabled in the parent context. */ +#ifdef CONFIG_IRQ_PIPELINE + if (state.stage_info != IRQENTRY_INBAND_STALLED) + local_irq_enable_full(); +#else if (!regs_irqs_disabled(regs)) local_irq_enable(); +#endif /* * If we're in an interrupt, have no user context, or are running -- 2.43.0