[PATCH dovetail 02/11] riscv: irq_pipeline: add IRQ pipelining core
From: Tobias Schaffner <tobias.schaffner@siemens.com>
Date: 2026-04-17 21:02:14
Subsystem:
risc-v architecture, the rest · Maintainers:
Paul Walmsley, Palmer Dabbelt, Albert Ou, Linus Torvalds
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 <tobias.schaffner@siemens.com> Co-authored-by: shannmu [off-list ref] Co-authored-by: Philippe Gerum [off-list ref] --- arch/riscv/Kconfig | 1 + 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 | 100 ++++++++++++++++- arch/riscv/mm/fault.c | 5 +- 13 files changed, 374 insertions(+), 40 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 90c531e6abf5c..0d8291a6c4da5 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/irq_pipeline.h b/arch/riscv/include/asm/irq_pipeline.h
new file mode 100644
index 0000000000000..d4d4b7e79c67d
--- /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 <tobias.schaffner@siemens.com>. + */ + +#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 *); + +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 6fd8cbfcfcc73..c3087b74752be 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 7ac80e9f22889..7877d62a0bb76 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 36918c9200c92..8a9e85c6e6316 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 4e310257499a1..fb51d1bc5e3a8 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 0000000000000..a478e9c3b3a4c
--- /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 <tobias.schaffner@siemens.com>. + */ +#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 99972a48e86bc..c4444577449ca 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 0cc5559c08d8f..600e2b51f1def 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 5ed5095320e66..8f842aec1e0e6 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 d85916a3660c3..5eae21d4a0a84 100644
--- a/arch/riscv/kernel/smpboot.c
+++ b/arch/riscv/kernel/smpboot.c@@ -263,6 +263,6 @@ asmlinkage __visible void smp_callin(void) * Disable preemption before enabling interrupts, so we don't try to * schedule a CPU that hasn't actually started yet. */ - 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 5fb57fad188a9..99634104ce084 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c@@ -112,10 +112,30 @@ void die(struct pt_regs *regs, const char *str) make_task_dead(SIGSEGV); } +static __always_inline +bool mark_trap_entry(int signo, struct pt_regs *regs) +{ + if (likely(running_inband())) { + hard_cond_local_irq_enable(); + return true; + } + + return false; +} + +static __always_inline +void mark_trap_exit(int signo, struct pt_regs *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(signo, 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 +147,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(signo, regs); } static void do_trap_error(struct pt_regs *regs, int signo, int code,
@@ -137,6 +159,12 @@ static void do_trap_error(struct pt_regs *regs, int signo, int code, if (user_mode(regs)) { do_trap(regs, signo, code, addr); } else { + /* + * Dovetail: If we trapped from kernel space, either + * we can fix up the situation, or we can't and we may + * happily crash with hard irqs off. Either way, don't + * bother. + */ if (!fixup_exception(regs)) die(regs, str); }
@@ -176,9 +204,12 @@ asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *re if (user_mode(regs)) { irqentry_enter_from_user_mode(regs); - local_irq_enable(); + hard_local_irq_enable(); handled = riscv_v_first_use_handler(regs); + + hard_local_irq_disable(); + if (!handled) do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->epc, "Oops - illegal instruction");
@@ -308,11 +339,12 @@ asmlinkage __visible __trap_section void do_trap_break(struct pt_regs *regs) { if (user_mode(regs)) { irqentry_enter_from_user_mode(regs); - local_irq_enable(); + hard_local_irq_enable(); handle_break(regs); - local_irq_disable(); + hard_local_irq_disable(); + irqentry_exit_to_user_mode(regs); } else { irqentry_state_t state = irqentry_nmi_enter(regs);
@@ -428,13 +460,69 @@ asmlinkage __visible noinstr void do_page_fault(struct pt_regs *regs) irqentry_state_t state = irqentry_enter(regs); handle_page_fault(regs); - - local_irq_disable(); + hard_local_irq_disable(); irqentry_exit(regs, state); } #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) +{ + if (IS_ENABLED(CONFIG_IRQ_STACKS) && this_cpu_inc_return(irq_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;
@@ -458,6 +546,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 04ed6f8acae4f..885e2f66515e3 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,
@@ -315,8 +316,8 @@ void handle_page_fault(struct pt_regs *regs) } /* Enable interrupts if they were enabled in the parent context. */ - if (!regs_irqs_disabled(regs)) - local_irq_enable(); + if (!regs_irqs_disabled(regs) && running_inband()) + local_irq_enable_full(); /* * If we're in an interrupt, have no user context, or are running
--
2.43.0