[PATCH v2] arm64: fix cleared E0POE bit after cpu_suspend()/resume()

Yeoreum Yun posted 1 patch 1 month ago
arch/arm64/include/asm/suspend.h | 2 +-
arch/arm64/mm/proc.S             | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletion(-)
[PATCH v2] arm64: fix cleared E0POE bit after cpu_suspend()/resume()
Posted by Yeoreum Yun 1 month ago
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}
Re: [PATCH v2] arm64: fix cleared E0POE bit after cpu_suspend()/resume()
Posted by Catalin Marinas 4 weeks ago
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
Re: [PATCH v2] arm64: fix cleared E0POE bit after cpu_suspend()/resume()
Posted by Anshuman Khandual 4 weeks, 1 day ago

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>
Re: [PATCH v2] arm64: fix cleared E0POE bit after cpu_suspend()/resume()
Posted by Kevin Brodsky 1 month ago
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}
>
Re: [PATCH v2] arm64: fix cleared E0POE bit after cpu_suspend()/resume()
Posted by Yeoreum Yun 1 month ago
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
Re: [PATCH v2] arm64: fix cleared E0POE bit after cpu_suspend()/resume()
Posted by Kevin Brodsky 3 weeks, 4 days ago
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