Skip to content

Commit a9d6915

Browse files
brooniectmarinas
authored andcommitted
arm64/sme: Implement support for TPIDR2
The Scalable Matrix Extension introduces support for a new thread specific data register TPIDR2 intended for use by libc. The kernel must save the value of TPIDR2 on context switch and should ensure that all new threads start off with a default value of 0. Add a field to the thread_struct to store TPIDR2 and context switch it with the other thread specific data. In case there are future extensions which also use TPIDR2 we introduce system_supports_tpidr2() and use that rather than system_supports_sme() for TPIDR2 handling. Signed-off-by: Mark Brown <[email protected]> Reviewed-by: Catalin Marinas <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent 9e4ab6c commit a9d6915

File tree

4 files changed

+22
-2
lines changed

4 files changed

+22
-2
lines changed

arch/arm64/include/asm/cpufeature.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,11 @@ static __always_inline bool system_supports_fa64(void)
778778
cpus_have_const_cap(ARM64_SME_FA64);
779779
}
780780

781+
static __always_inline bool system_supports_tpidr2(void)
782+
{
783+
return system_supports_sme();
784+
}
785+
781786
static __always_inline bool system_supports_cnp(void)
782787
{
783788
return IS_ENABLED(CONFIG_ARM64_CNP) &&

arch/arm64/include/asm/processor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ struct thread_struct {
169169
u64 mte_ctrl;
170170
#endif
171171
u64 sctlr_user;
172+
u64 tpidr2_el0;
172173
};
173174

174175
static inline unsigned int thread_get_vl(struct thread_struct *thread,

arch/arm64/kernel/fpsimd.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,10 @@ void sme_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p)
10981098
/* Allow SME in kernel */
10991099
write_sysreg(read_sysreg(CPACR_EL1) | CPACR_EL1_SMEN_EL1EN, CPACR_EL1);
11001100
isb();
1101+
1102+
/* Allow EL0 to access TPIDR2 */
1103+
write_sysreg(read_sysreg(SCTLR_EL1) | SCTLR_ELx_ENTP2, SCTLR_EL1);
1104+
isb();
11011105
}
11021106

11031107
/*

arch/arm64/kernel/process.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ void show_regs(struct pt_regs *regs)
250250
static void tls_thread_flush(void)
251251
{
252252
write_sysreg(0, tpidr_el0);
253+
if (system_supports_tpidr2())
254+
write_sysreg_s(0, SYS_TPIDR2_EL0);
253255

254256
if (is_compat_task()) {
255257
current->thread.uw.tp_value = 0;
@@ -343,6 +345,8 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
343345
* out-of-sync with the saved value.
344346
*/
345347
*task_user_tls(p) = read_sysreg(tpidr_el0);
348+
if (system_supports_tpidr2())
349+
p->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);
346350

347351
if (stack_start) {
348352
if (is_compat_thread(task_thread_info(p)))
@@ -353,10 +357,12 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
353357

354358
/*
355359
* If a TLS pointer was passed to clone, use it for the new
356-
* thread.
360+
* thread. We also reset TPIDR2 if it's in use.
357361
*/
358-
if (clone_flags & CLONE_SETTLS)
362+
if (clone_flags & CLONE_SETTLS) {
359363
p->thread.uw.tp_value = tls;
364+
p->thread.tpidr2_el0 = 0;
365+
}
360366
} else {
361367
/*
362368
* A kthread has no context to ERET to, so ensure any buggy
@@ -387,6 +393,8 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
387393
void tls_preserve_current_state(void)
388394
{
389395
*task_user_tls(current) = read_sysreg(tpidr_el0);
396+
if (system_supports_tpidr2() && !is_compat_task())
397+
current->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);
390398
}
391399

392400
static void tls_thread_switch(struct task_struct *next)
@@ -399,6 +407,8 @@ static void tls_thread_switch(struct task_struct *next)
399407
write_sysreg(0, tpidrro_el0);
400408

401409
write_sysreg(*task_user_tls(next), tpidr_el0);
410+
if (system_supports_tpidr2())
411+
write_sysreg_s(next->thread.tpidr2_el0, SYS_TPIDR2_EL0);
402412
}
403413

404414
/*

0 commit comments

Comments
 (0)