Commit b3cf0785 authored by Jinjie Ruan's avatar Jinjie Ruan Committed by Will Deacon
Browse files

arm64: entry: Switch to generic IRQ entry



Currently, x86, Riscv and Loongarch use the generic entry code, which
makes maintainer's work easier and code more elegant. Start converting
arm64 to use the generic entry infrastructure from kernel/entry/* by
switching it to generic IRQ entry, which removes 100+ lines of duplicate
code. arm64 will completely switch to generic entry in a later series.

The changes are below:
 - Remove *enter_from/exit_to_kernel_mode(), and wrap with generic
   irqentry_enter/exit() as their code and functionality are almost
   identical.

 - Define ARCH_EXIT_TO_USER_MODE_WORK and implement
   arch_exit_to_user_mode_work() to check arm64-specific thread flags
   "_TIF_MTE_ASYNC_FAULT" and "_TIF_FOREIGN_FPSTATE".
   So also remove *enter_from/exit_to_user_mode(), and wrap with
   generic enter_from/exit_to_user_mode() because they are
   exactly the same.

 - Remove arm64_enter/exit_nmi() and use generic irqentry_nmi_enter/exit()
   because they're exactly the same, so the temporary arm64 version
   irqentry_state can also be removed.

 - Remove PREEMPT_DYNAMIC code, as generic irqentry_exit_cond_resched()
   has the same functionality.

 - Implement arch_irqentry_exit_need_resched() with
   arm64_preempt_schedule_irq() for arm64 which will allow arm64 to do
   its architecture specific checks.

Tested-by: default avatarAda Couprie Diaz <ada.coupriediaz@arm.com>
Suggested-by: default avatarAda Couprie Diaz <ada.coupriediaz@arm.com>
Suggested-by: default avatarMark Rutland <mark.rutland@arm.com>
Signed-off-by: default avatarJinjie Ruan <ruanjinjie@huawei.com>
Acked-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 99eb057c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -151,6 +151,7 @@ config ARM64
	select GENERIC_EARLY_IOREMAP
	select GENERIC_IDLE_POLL_SETUP
	select GENERIC_IOREMAP
	select GENERIC_IRQ_ENTRY
	select GENERIC_IRQ_IPI
	select GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD
	select GENERIC_IRQ_PROBE
+57 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */

#ifndef _ASM_ARM64_ENTRY_COMMON_H
#define _ASM_ARM64_ENTRY_COMMON_H

#include <linux/thread_info.h>

#include <asm/cpufeature.h>
#include <asm/daifflags.h>
#include <asm/fpsimd.h>
#include <asm/mte.h>
#include <asm/stacktrace.h>

#define ARCH_EXIT_TO_USER_MODE_WORK (_TIF_MTE_ASYNC_FAULT | _TIF_FOREIGN_FPSTATE)

static __always_inline void arch_exit_to_user_mode_work(struct pt_regs *regs,
							unsigned long ti_work)
{
	if (ti_work & _TIF_MTE_ASYNC_FAULT) {
		clear_thread_flag(TIF_MTE_ASYNC_FAULT);
		send_sig_fault(SIGSEGV, SEGV_MTEAERR, (void __user *)NULL, current);
	}

	if (ti_work & _TIF_FOREIGN_FPSTATE)
		fpsimd_restore_current_state();
}

#define arch_exit_to_user_mode_work arch_exit_to_user_mode_work

static inline bool arch_irqentry_exit_need_resched(void)
{
	/*
	 * DAIF.DA are cleared at the start of IRQ/FIQ handling, and when GIC
	 * priority masking is used the GIC irqchip driver will clear DAIF.IF
	 * using gic_arch_enable_irqs() for normal IRQs. If anything is set in
	 * DAIF we must have handled an NMI, so skip preemption.
	 */
	if (system_uses_irq_prio_masking() && read_sysreg(daif))
		return false;

	/*
	 * Preempting a task from an IRQ means we leave copies of PSTATE
	 * on the stack. cpufeature's enable calls may modify PSTATE, but
	 * resuming one of these preempted tasks would undo those changes.
	 *
	 * Only allow a task to be preempted once cpufeatures have been
	 * enabled.
	 */
	if (!system_capabilities_finalized())
		return false;

	return true;
}

#define arch_irqentry_exit_need_resched arch_irqentry_exit_need_resched

#endif /* _ASM_ARM64_ENTRY_COMMON_H */
+0 −1
Original line number Diff line number Diff line
@@ -89,7 +89,6 @@ void do_el1_fpac(struct pt_regs *regs, unsigned long esr);
void do_el0_mops(struct pt_regs *regs, unsigned long esr);
void do_el1_mops(struct pt_regs *regs, unsigned long esr);
void do_serror(struct pt_regs *regs, unsigned long esr);
void do_signal(struct pt_regs *regs);

void __noreturn panic_bad_stack(struct pt_regs *regs, unsigned long esr, unsigned long far);
#endif	/* __ASM_EXCEPTION_H */
+0 −8
Original line number Diff line number Diff line
@@ -2,7 +2,6 @@
#ifndef __ASM_PREEMPT_H
#define __ASM_PREEMPT_H

#include <linux/jump_label.h>
#include <linux/thread_info.h>

#define PREEMPT_NEED_RESCHED	BIT(32)
@@ -85,26 +84,19 @@ static inline bool should_resched(int preempt_offset)
void preempt_schedule(void);
void preempt_schedule_notrace(void);

void raw_irqentry_exit_cond_resched(void);
#ifdef CONFIG_PREEMPT_DYNAMIC

DECLARE_STATIC_KEY_TRUE(sk_dynamic_irqentry_exit_cond_resched);
void dynamic_preempt_schedule(void);
#define __preempt_schedule()		dynamic_preempt_schedule()
void dynamic_preempt_schedule_notrace(void);
#define __preempt_schedule_notrace()	dynamic_preempt_schedule_notrace()
void dynamic_irqentry_exit_cond_resched(void);
#define irqentry_exit_cond_resched()	dynamic_irqentry_exit_cond_resched()

#else /* CONFIG_PREEMPT_DYNAMIC */

#define __preempt_schedule()		preempt_schedule()
#define __preempt_schedule_notrace()	preempt_schedule_notrace()
#define irqentry_exit_cond_resched()	raw_irqentry_exit_cond_resched()

#endif /* CONFIG_PREEMPT_DYNAMIC */
#else /* CONFIG_PREEMPTION */
#define irqentry_exit_cond_resched()	{}
#endif /* CONFIG_PREEMPTION */

#endif /* __ASM_PREEMPT_H */
+96 −282

File changed.

Preview size limit exceeded, changes collapsed.

Loading