arch/arm64/include/asm/suspend.h | 2 +- arch/arm64/mm/proc.S | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-)
TCR2_ELx.E0POE is set during smp_init().
However, this bit is not reprogrammed when the CPU enters suspension and
later resumes via cpu_resume(), as __cpu_setup() does not re-enable E0POE
and there is no save/restore logic for the TCR2_ELx system register.
As a result, the E0POE feature no longer works after cpu_resume().
To address this, save and restore TCR2_EL1 in the cpu_suspend()/cpu_resume()
path, rather than adding related logic to __cpu_setup(), taking into account
possible future extensions of the TCR2_ELx feature.
Cc: stable@vger.kernel.org
Fixes: bf83dae90fbc ("arm64: enable the Permission Overlay Extension for EL0")
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
Patch History
==============
from v1 to v2:
- following @Kevin Brodsky suggestion.
- https://lore.kernel.org/all/20260105200707.2071169-1-yeoreum.yun@arm.com/
NOTE:
This patch based on v6.19-rc4
---
arch/arm64/include/asm/suspend.h | 2 +-
arch/arm64/mm/proc.S | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h
index e65f33edf9d6..e9ce68d50ba4 100644
--- a/arch/arm64/include/asm/suspend.h
+++ b/arch/arm64/include/asm/suspend.h
@@ -2,7 +2,7 @@
#ifndef __ASM_SUSPEND_H
#define __ASM_SUSPEND_H
-#define NR_CTX_REGS 13
+#define NR_CTX_REGS 14
#define NR_CALLEE_SAVED_REGS 12
/*
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 01e868116448..5d907ce3b6d3 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -110,6 +110,10 @@ SYM_FUNC_START(cpu_do_suspend)
* call stack.
*/
str x18, [x0, #96]
+alternative_if ARM64_HAS_TCR2
+ mrs x2, REG_TCR2_EL1
+ str x2, [x0, #104]
+alternative_else_nop_endif
ret
SYM_FUNC_END(cpu_do_suspend)
@@ -144,6 +148,10 @@ SYM_FUNC_START(cpu_do_resume)
msr tcr_el1, x8
msr vbar_el1, x9
msr mdscr_el1, x10
+alternative_if ARM64_HAS_TCR2
+ ldr x2, [x0, #104]
+ msr REG_TCR2_EL1, x2
+alternative_else_nop_endif
msr sctlr_el1, x12
set_this_cpu_offset x13
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
On Wed, 07 Jan 2026 16:21:15 +0000, Yeoreum Yun wrote:
> TCR2_ELx.E0POE is set during smp_init().
> However, this bit is not reprogrammed when the CPU enters suspension and
> later resumes via cpu_resume(), as __cpu_setup() does not re-enable E0POE
> and there is no save/restore logic for the TCR2_ELx system register.
>
> As a result, the E0POE feature no longer works after cpu_resume().
>
> [...]
Applied to arm64 (for-next/fixes), thanks!
[1/1] arm64: fix cleared E0POE bit after cpu_suspend()/resume()
https://git.kernel.org/arm64/c/bdf3f4176092
--
Catalin
On 07/01/26 9:51 PM, Yeoreum Yun wrote:
> TCR2_ELx.E0POE is set during smp_init().
> However, this bit is not reprogrammed when the CPU enters suspension and
> later resumes via cpu_resume(), as __cpu_setup() does not re-enable E0POE
> and there is no save/restore logic for the TCR2_ELx system register.
>
> As a result, the E0POE feature no longer works after cpu_resume().
>
> To address this, save and restore TCR2_EL1 in the cpu_suspend()/cpu_resume()
> path, rather than adding related logic to __cpu_setup(), taking into account
> possible future extensions of the TCR2_ELx feature.
>
> Cc: stable@vger.kernel.org
> Fixes: bf83dae90fbc ("arm64: enable the Permission Overlay Extension for EL0")
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
>
> Patch History
> ==============
> from v1 to v2:
> - following @Kevin Brodsky suggestion.
> - https://lore.kernel.org/all/20260105200707.2071169-1-yeoreum.yun@arm.com/
>
> NOTE:
> This patch based on v6.19-rc4
> ---
> arch/arm64/include/asm/suspend.h | 2 +-
> arch/arm64/mm/proc.S | 8 ++++++++
> 2 files changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h
> index e65f33edf9d6..e9ce68d50ba4 100644
> --- a/arch/arm64/include/asm/suspend.h
> +++ b/arch/arm64/include/asm/suspend.h
> @@ -2,7 +2,7 @@
> #ifndef __ASM_SUSPEND_H
> #define __ASM_SUSPEND_H
>
> -#define NR_CTX_REGS 13
> +#define NR_CTX_REGS 14
> #define NR_CALLEE_SAVED_REGS 12
>
> /*
> diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
> index 01e868116448..5d907ce3b6d3 100644
> --- a/arch/arm64/mm/proc.S
> +++ b/arch/arm64/mm/proc.S
> @@ -110,6 +110,10 @@ SYM_FUNC_START(cpu_do_suspend)
> * call stack.
> */
> str x18, [x0, #96]
> +alternative_if ARM64_HAS_TCR2
> + mrs x2, REG_TCR2_EL1
> + str x2, [x0, #104]
> +alternative_else_nop_endif
> ret
> SYM_FUNC_END(cpu_do_suspend)
>
> @@ -144,6 +148,10 @@ SYM_FUNC_START(cpu_do_resume)
> msr tcr_el1, x8
> msr vbar_el1, x9
> msr mdscr_el1, x10
> +alternative_if ARM64_HAS_TCR2
> + ldr x2, [x0, #104]
> + msr REG_TCR2_EL1, x2
> +alternative_else_nop_endif
>
> msr sctlr_el1, x12
> set_this_cpu_offset x13
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>
LGTM
Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
On 07/01/2026 17:21, Yeoreum Yun wrote:
> TCR2_ELx.E0POE is set during smp_init().
> However, this bit is not reprogrammed when the CPU enters suspension and
> later resumes via cpu_resume(), as __cpu_setup() does not re-enable E0POE
> and there is no save/restore logic for the TCR2_ELx system register.
>
> As a result, the E0POE feature no longer works after cpu_resume().
>
> To address this, save and restore TCR2_EL1 in the cpu_suspend()/cpu_resume()
> path, rather than adding related logic to __cpu_setup(), taking into account
> possible future extensions of the TCR2_ELx feature.
>
> Cc: stable@vger.kernel.org
> Fixes: bf83dae90fbc ("arm64: enable the Permission Overlay Extension for EL0")
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
>
> Patch History
> ==============
> from v1 to v2:
> - following @Kevin Brodsky suggestion.
> - https://lore.kernel.org/all/20260105200707.2071169-1-yeoreum.yun@arm.com/
>
> NOTE:
> This patch based on v6.19-rc4
> ---
> arch/arm64/include/asm/suspend.h | 2 +-
> arch/arm64/mm/proc.S | 8 ++++++++
> 2 files changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h
> index e65f33edf9d6..e9ce68d50ba4 100644
> --- a/arch/arm64/include/asm/suspend.h
> +++ b/arch/arm64/include/asm/suspend.h
> @@ -2,7 +2,7 @@
> #ifndef __ASM_SUSPEND_H
> #define __ASM_SUSPEND_H
>
> -#define NR_CTX_REGS 13
> +#define NR_CTX_REGS 14
> #define NR_CALLEE_SAVED_REGS 12
>
> /*
> diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
> index 01e868116448..5d907ce3b6d3 100644
> --- a/arch/arm64/mm/proc.S
> +++ b/arch/arm64/mm/proc.S
> @@ -110,6 +110,10 @@ SYM_FUNC_START(cpu_do_suspend)
> * call stack.
> */
> str x18, [x0, #96]
> +alternative_if ARM64_HAS_TCR2
> + mrs x2, REG_TCR2_EL1
> + str x2, [x0, #104]
> +alternative_else_nop_endif
> ret
> SYM_FUNC_END(cpu_do_suspend)
>
> @@ -144,6 +148,10 @@ SYM_FUNC_START(cpu_do_resume)
> msr tcr_el1, x8
> msr vbar_el1, x9
> msr mdscr_el1, x10
> +alternative_if ARM64_HAS_TCR2
> + ldr x2, [x0, #104]
> + msr REG_TCR2_EL1, x2
> +alternative_else_nop_endif
Maybe this could be pushed further down cpu_do_resume, next to DISR_EL1
maybe (since it's also conditional)? Otherwise the diff LGTM:
Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
- Kevin
> msr sctlr_el1, x12
> set_this_cpu_offset x13
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>
Hi Kevin, [...] > > @@ -144,6 +148,10 @@ SYM_FUNC_START(cpu_do_resume) > > msr tcr_el1, x8 > > msr vbar_el1, x9 > > msr mdscr_el1, x10 > > +alternative_if ARM64_HAS_TCR2 > > + ldr x2, [x0, #104] > > + msr REG_TCR2_EL1, x2 > > +alternative_else_nop_endif > > Maybe this could be pushed further down cpu_do_resume, next to DISR_EL1 > maybe (since it's also conditional)? Otherwise the diff LGTM: Sorry but IIUC, currently there is no DISR_EL1 save/restore not yet? and I think current place is good where before restore SCTLR_EL1 which before MMU enabled. Am I missing something? Thanks. -- Sincerely, Yeoreum Yun
On 07/01/2026 18:30, Yeoreum Yun wrote: > Hi Kevin, > > [...] > >>> @@ -144,6 +148,10 @@ SYM_FUNC_START(cpu_do_resume) >>> msr tcr_el1, x8 >>> msr vbar_el1, x9 >>> msr mdscr_el1, x10 >>> +alternative_if ARM64_HAS_TCR2 >>> + ldr x2, [x0, #104] >>> + msr REG_TCR2_EL1, x2 >>> +alternative_else_nop_endif >> Maybe this could be pushed further down cpu_do_resume, next to DISR_EL1 >> maybe (since it's also conditional)? Otherwise the diff LGTM: > Sorry but IIUC, currently there is no DISR_EL1 save/restore not yet? It's zeroed at the end of cpu_do_resume, but yes it's not saved. > and I think current place is good where before restore SCTLR_EL1 which > before MMU enabled. Fair enough, and I can see that other registers are not restored in the same order as they're saved, so we're not breaking an existing pattern. Either way Catalin took the patch so this is settled :) - Kevin
© 2016 - 2026 Red Hat, Inc.