Skip to content

Commit 0033cd9

Browse files
brooniectmarinas
authored andcommitted
arm64/sme: Implement ZA context switching
Allocate space for storing ZA on first access to SME and use that to save and restore ZA state when context switching. We do this by using the vector form of the LDR and STR ZA instructions, these do not require streaming mode and have implementation recommendations that they avoid contention issues in shared SMCU implementations. Since ZA is architecturally guaranteed to be zeroed when enabled we do not need to explicitly zero ZA, either we will be restoring from a saved copy or trapping on first use of SME so we know that ZA must be 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 af7167d commit 0033cd9

File tree

7 files changed

+66
-9
lines changed

7 files changed

+66
-9
lines changed

arch/arm64/include/asm/fpsimd.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ 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,
4949
void *sve_state, unsigned int sve_vl,
50-
unsigned int sme_vl, u64 *svcr);
50+
void *za_state, unsigned int sme_vl,
51+
u64 *svcr);
5152

5253
extern void fpsimd_flush_task_state(struct task_struct *target);
5354
extern void fpsimd_save_and_flush_cpu_state(void);
@@ -90,6 +91,8 @@ extern void sve_flush_live(bool flush_ffr, unsigned long vq_minus_1);
9091
extern unsigned int sve_get_vl(void);
9192
extern void sve_set_vq(unsigned long vq_minus_1);
9293
extern void sme_set_vq(unsigned long vq_minus_1);
94+
extern void za_save_state(void *state);
95+
extern void za_load_state(void const *state);
9396

9497
struct arm64_cpu_capabilities;
9598
extern void sve_kernel_enable(const struct arm64_cpu_capabilities *__unused);

arch/arm64/include/asm/fpsimdmacros.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,25 @@
319319
ldr w\nxtmp, [\xpfpsr, #4]
320320
msr fpcr, x\nxtmp
321321
.endm
322+
323+
.macro sme_save_za nxbase, xvl, nw
324+
mov w\nw, #0
325+
326+
423:
327+
_sme_str_zav \nw, \nxbase
328+
add x\nxbase, x\nxbase, \xvl
329+
add x\nw, x\nw, #1
330+
cmp \xvl, x\nw
331+
bne 423b
332+
.endm
333+
334+
.macro sme_load_za nxbase, xvl, nw
335+
mov w\nw, #0
336+
337+
423:
338+
_sme_ldr_zav \nw, \nxbase
339+
add x\nxbase, x\nxbase, \xvl
340+
add x\nw, x\nw, #1
341+
cmp \xvl, x\nw
342+
bne 423b
343+
.endm

arch/arm64/include/asm/kvm_host.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,11 @@ struct vcpu_reset_state {
295295

296296
struct kvm_vcpu_arch {
297297
struct kvm_cpu_context ctxt;
298+
299+
/* Guest floating point state */
298300
void *sve_state;
299301
unsigned int sve_max_vl;
302+
u64 svcr;
300303

301304
/* Stage 2 paging state used by the hardware on next switch */
302305
struct kvm_s2_mmu *hw_mmu;

arch/arm64/include/asm/processor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ struct thread_struct {
154154

155155
unsigned int fpsimd_cpu;
156156
void *sve_state; /* SVE registers, if any */
157+
void *za_state; /* ZA register, if any */
157158
unsigned int vl[ARM64_VEC_MAX]; /* vector length */
158159
unsigned int vl_onexec[ARM64_VEC_MAX]; /* vl after next exec */
159160
unsigned long fault_address; /* fault info */

arch/arm64/kernel/entry-fpsimd.S

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,26 @@ SYM_FUNC_START(sme_set_vq)
9999
ret
100100
SYM_FUNC_END(sme_set_vq)
101101

102+
/*
103+
* Save the SME state
104+
*
105+
* x0 - pointer to buffer for state
106+
*/
107+
SYM_FUNC_START(za_save_state)
108+
_sme_rdsvl 1, 1 // x1 = VL/8
109+
sme_save_za 0, x1, 12
110+
ret
111+
SYM_FUNC_END(za_save_state)
112+
113+
/*
114+
* Load the SME state
115+
*
116+
* x0 - pointer to buffer for state
117+
*/
118+
SYM_FUNC_START(za_load_state)
119+
_sme_rdsvl 1, 1 // x1 = VL/8
120+
sme_load_za 0, x1, 12
121+
ret
122+
SYM_FUNC_END(za_load_state)
123+
102124
#endif /* CONFIG_ARM64_SME */

arch/arm64/kernel/fpsimd.c

Lines changed: 13 additions & 7 deletions
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+
void *za_state;
124125
u64 *svcr;
125126
unsigned int sve_vl;
126127
unsigned int sme_vl;
@@ -387,11 +388,15 @@ static void task_fpsimd_load(void)
387388
if (system_supports_sme()) {
388389
unsigned long sme_vl = task_get_sme_vl(current);
389390

391+
/* Ensure VL is set up for restoring data */
390392
if (test_thread_flag(TIF_SME))
391393
sme_set_vq(sve_vq_from_vl(sme_vl) - 1);
392394

393395
write_sysreg_s(current->thread.svcr, SYS_SVCR_EL0);
394396

397+
if (thread_za_enabled(&current->thread))
398+
za_load_state(current->thread.za_state);
399+
395400
if (thread_sm_enabled(&current->thread)) {
396401
restore_sve_regs = true;
397402
restore_ffr = system_supports_fa64();
@@ -441,11 +446,10 @@ static void fpsimd_save(void)
441446
u64 *svcr = last->svcr;
442447
*svcr = read_sysreg_s(SYS_SVCR_EL0);
443448

444-
if (thread_za_enabled(&current->thread)) {
445-
/* ZA state managment is not implemented yet */
446-
force_signal_inject(SIGKILL, SI_KERNEL, 0, 0);
447-
return;
448-
}
449+
*svcr = read_sysreg_s(SYS_SVCR_EL0);
450+
451+
if (*svcr & SYS_SVCR_EL0_ZA_MASK)
452+
za_save_state(last->za_state);
449453

450454
/* If we are in streaming mode override regular SVE. */
451455
if (*svcr & SYS_SVCR_EL0_SM_MASK) {
@@ -1483,6 +1487,7 @@ static void fpsimd_bind_task_to_cpu(void)
14831487
WARN_ON(!system_supports_fpsimd());
14841488
last->st = &current->thread.uw.fpsimd_state;
14851489
last->sve_state = current->thread.sve_state;
1490+
last->za_state = current->thread.za_state;
14861491
last->sve_vl = task_get_sve_vl(current);
14871492
last->sme_vl = task_get_sme_vl(current);
14881493
last->svcr = &current->thread.svcr;
@@ -1500,8 +1505,8 @@ static void fpsimd_bind_task_to_cpu(void)
15001505
}
15011506

15021507
void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state,
1503-
unsigned int sve_vl, unsigned int sme_vl,
1504-
u64 *svcr)
1508+
unsigned int sve_vl, void *za_state,
1509+
unsigned int sme_vl, u64 *svcr)
15051510
{
15061511
struct fpsimd_last_state_struct *last =
15071512
this_cpu_ptr(&fpsimd_last_state);
@@ -1512,6 +1517,7 @@ void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state,
15121517
last->st = st;
15131518
last->svcr = svcr;
15141519
last->sve_state = sve_state;
1520+
last->za_state = za_state;
15151521
last->sve_vl = sve_vl;
15161522
last->sme_vl = sme_vl;
15171523
}

arch/arm64/kvm/fpsimd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
116116
fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.fp_regs,
117117
vcpu->arch.sve_state,
118118
vcpu->arch.sve_max_vl,
119-
0, NULL);
119+
NULL, 0, &vcpu->arch.svcr);
120120

121121
clear_thread_flag(TIF_FOREIGN_FPSTATE);
122122
update_thread_flag(TIF_SVE, vcpu_has_sve(vcpu));

0 commit comments

Comments
 (0)