Skip to content

Commit b40c559

Browse files
brooniectmarinas
authored andcommitted
arm64/sme: Implement SVCR context switching
In SME the use of both streaming SVE mode and ZA are tracked through PSTATE.SM and PSTATE.ZA, visible through the system register SVCR. In order to context switch the floating point state for SME we need to context switch the contents of this register as part of context switching the floating point state. Since changing the vector length exits streaming SVE mode and disables ZA we also make sure we update SVCR appropriately when setting vector length, and similarly ensure that new threads have streaming SVE mode and ZA disabled. 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 a9d6915 commit b40c559

File tree

6 files changed

+29
-3
lines changed

6 files changed

+29
-3
lines changed

arch/arm64/include/asm/fpsimd.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ extern void fpsimd_restore_current_state(void);
4646
extern void fpsimd_update_current_state(struct user_fpsimd_state const *state);
4747

4848
extern void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *state,
49-
void *sve_state, unsigned int sve_vl);
49+
void *sve_state, unsigned int sve_vl,
50+
u64 *svcr);
5051

5152
extern void fpsimd_flush_task_state(struct task_struct *target);
5253
extern void fpsimd_save_and_flush_cpu_state(void);

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 svcr;
172173
u64 tpidr2_el0;
173174
};
174175

arch/arm64/include/asm/thread_info.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ int arch_dup_task_struct(struct task_struct *dst,
8282
#define TIF_SVE_VL_INHERIT 24 /* Inherit SVE vl_onexec across exec */
8383
#define TIF_SSBD 25 /* Wants SSB mitigation */
8484
#define TIF_TAGGED_ADDR 26 /* Allow tagged user addresses */
85+
#define TIF_SME 27 /* SME in use */
8586
#define TIF_SME_VL_INHERIT 28 /* Inherit SME vl_onexec across exec */
8687

8788
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)

arch/arm64/kernel/fpsimd.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
struct fpsimd_last_state_struct {
122122
struct user_fpsimd_state *st;
123123
void *sve_state;
124+
u64 *svcr;
124125
unsigned int sve_vl;
125126
};
126127

@@ -359,6 +360,9 @@ static void task_fpsimd_load(void)
359360
WARN_ON(!system_supports_fpsimd());
360361
WARN_ON(!have_cpu_fpsimd_context());
361362

363+
if (IS_ENABLED(CONFIG_ARM64_SME) && test_thread_flag(TIF_SME))
364+
write_sysreg_s(current->thread.svcr, SYS_SVCR_EL0);
365+
362366
if (IS_ENABLED(CONFIG_ARM64_SVE) && test_thread_flag(TIF_SVE)) {
363367
sve_set_vq(sve_vq_from_vl(task_get_sve_vl(current)) - 1);
364368
sve_load_state(sve_pffr(&current->thread),
@@ -390,6 +394,12 @@ static void fpsimd_save(void)
390394
if (test_thread_flag(TIF_FOREIGN_FPSTATE))
391395
return;
392396

397+
if (IS_ENABLED(CONFIG_ARM64_SME) &&
398+
test_thread_flag(TIF_SME)) {
399+
u64 *svcr = last->svcr;
400+
*svcr = read_sysreg_s(SYS_SVCR_EL0);
401+
}
402+
393403
if (IS_ENABLED(CONFIG_ARM64_SVE) &&
394404
test_thread_flag(TIF_SVE)) {
395405
if (WARN_ON(sve_get_vl() != last->sve_vl)) {
@@ -741,6 +751,10 @@ int vec_set_vector_length(struct task_struct *task, enum vec_type type,
741751
if (test_and_clear_tsk_thread_flag(task, TIF_SVE))
742752
sve_to_fpsimd(task);
743753

754+
if (system_supports_sme() && type == ARM64_VEC_SME)
755+
task->thread.svcr &= ~(SYS_SVCR_EL0_SM_MASK |
756+
SYS_SVCR_EL0_ZA_MASK);
757+
744758
if (task == current)
745759
put_cpu_fpsimd_context();
746760

@@ -1404,6 +1418,7 @@ static void fpsimd_bind_task_to_cpu(void)
14041418
last->st = &current->thread.uw.fpsimd_state;
14051419
last->sve_state = current->thread.sve_state;
14061420
last->sve_vl = task_get_sve_vl(current);
1421+
last->svcr = &current->thread.svcr;
14071422
current->thread.fpsimd_cpu = smp_processor_id();
14081423

14091424
if (system_supports_sve()) {
@@ -1418,7 +1433,7 @@ static void fpsimd_bind_task_to_cpu(void)
14181433
}
14191434

14201435
void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state,
1421-
unsigned int sve_vl)
1436+
unsigned int sve_vl, u64 *svcr)
14221437
{
14231438
struct fpsimd_last_state_struct *last =
14241439
this_cpu_ptr(&fpsimd_last_state);
@@ -1427,6 +1442,7 @@ void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state,
14271442
WARN_ON(!in_softirq() && !irqs_disabled());
14281443

14291444
last->st = st;
1445+
last->svcr = svcr;
14301446
last->sve_state = sve_state;
14311447
last->sve_vl = sve_vl;
14321448
}

arch/arm64/kernel/process.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
310310
dst->thread.sve_state = NULL;
311311
clear_tsk_thread_flag(dst, TIF_SVE);
312312

313+
dst->thread.svcr = 0;
314+
313315
/* clear any pending asynchronous tag fault raised by the parent */
314316
clear_tsk_thread_flag(dst, TIF_MTE_ASYNC_FAULT);
315317

arch/arm64/kvm/fpsimd.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,14 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
109109
WARN_ON_ONCE(!irqs_disabled());
110110

111111
if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
112+
/*
113+
* Currently we do not support SME guests so SVCR is
114+
* always 0 and we just need a variable to point to.
115+
*/
112116
fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.fp_regs,
113117
vcpu->arch.sve_state,
114-
vcpu->arch.sve_max_vl);
118+
vcpu->arch.sve_max_vl,
119+
NULL);
115120

116121
clear_thread_flag(TIF_FOREIGN_FPSTATE);
117122
update_thread_flag(TIF_SVE, vcpu_has_sve(vcpu));

0 commit comments

Comments
 (0)