
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/release-management/issues/IBV2E4 -------------------------------- When enter idle state, the actlr register will reset to an architecturally UNKNOWN value on warm reset. So save and restore actlr_el1 and actlr_el2 register value when enter and exit idle state. Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com> --- arch/arm64/include/asm/cpufeature.h | 8 ++++++++ arch/arm64/include/asm/cpuidle.h | 32 +++++++++++++++++++++++++++++ arch/arm64/kernel/idle.c | 31 ++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index dd758b04fd54..88cdf27fe701 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -831,6 +831,14 @@ static inline bool system_has_full_ptr_auth(void) return system_supports_address_auth() && system_supports_generic_auth(); } +#ifdef CONFIG_ACTLR_XCALL_XINT +static __always_inline bool system_uses_xcall_xint(void) +{ + return IS_ENABLED(CONFIG_ACTLR_XCALL_XINT) && + cpus_have_const_cap(ARM64_HAS_HW_XCALL_XINT); +} +#endif + static __always_inline bool system_uses_irq_prio_masking(void) { return IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && diff --git a/arch/arm64/include/asm/cpuidle.h b/arch/arm64/include/asm/cpuidle.h index 2047713e097d..ae2c108880dd 100644 --- a/arch/arm64/include/asm/cpuidle.h +++ b/arch/arm64/include/asm/cpuidle.h @@ -38,4 +38,36 @@ struct arm_cpuidle_irq_context { }; #define arm_cpuidle_save_irq_context(c) (void)c #define arm_cpuidle_restore_irq_context(c) (void)c #endif + +#ifdef CONFIG_ACTLR_XCALL_XINT +struct arm_cpuidle_xcall_xint_context { + unsigned long actlr_el1; + unsigned long actlr_el2; +}; + +#define arm_cpuidle_save_xcall_xint_context(__c) \ + do { \ + struct arm_cpuidle_xcall_xint_context *c = __c; \ + if (system_uses_xcall_xint()) { \ + c->actlr_el1 = read_sysreg(actlr_el1); \ + if (read_sysreg(CurrentEL) == CurrentEL_EL2) \ + c->actlr_el2 = read_sysreg(actlr_el2); \ + } \ + } while (0) + +#define arm_cpuidle_restore_xcall_xint_context(__c) \ + do { \ + struct arm_cpuidle_xcall_xint_context *c = __c; \ + if (system_uses_xcall_xint()) { \ + write_sysreg(c->actlr_el1, actlr_el1); \ + if (read_sysreg(CurrentEL) == CurrentEL_EL2) \ + write_sysreg(c->actlr_el2, actlr_el2); \ + } \ + } while (0) +#else +struct arm_cpuidle_xcall_xint_context { }; + +#define arm_cpuidle_save_xcall_xint_context(c) (void)c +#define arm_cpuidle_restore_xcall_xint_context(c) (void)c +#endif #endif diff --git a/arch/arm64/kernel/idle.c b/arch/arm64/kernel/idle.c index 3a0b59aa12e2..6876392948b3 100644 --- a/arch/arm64/kernel/idle.c +++ b/arch/arm64/kernel/idle.c @@ -44,3 +44,34 @@ void noinstr arch_cpu_idle(void) cpu_do_idle(); } EXPORT_SYMBOL_GPL(arch_cpu_idle); + +#ifdef CONFIG_ACTLR_XCALL_XINT +DEFINE_PER_CPU_ALIGNED(struct arm_cpuidle_xcall_xint_context, contexts); + +void arch_cpu_idle_enter(void) +{ + struct arm_cpuidle_xcall_xint_context *context; + + if (!system_uses_xcall_xint()) + return; + + context = &get_cpu_var(contexts); + arm_cpuidle_save_xcall_xint_context(context); + put_cpu_var(contexts); +} + +void arch_cpu_idle_exit(void) +{ + struct arm_cpuidle_xcall_xint_context *context; + + if (!system_uses_xcall_xint()) + return; + + context = &get_cpu_var(contexts); + arm_cpuidle_restore_xcall_xint_context(context); + put_cpu_var(contexts); +} +#else +void arch_cpu_idle_enter(void) {} +void arch_cpu_idle_exit(void) {} +#endif -- 2.34.1