summaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2021-10-19 18:22:09 +0100
committerWill Deacon <will@kernel.org>2021-10-21 10:18:17 +0100
commit9f5848665788a0f07bc175cb2cdd06d367b7556e (patch)
tree1dac56919c1e02594e369ce832f8c4ce1447a136 /arch/arm64/kernel
parent12cc2352bfb34dbdf97e51b006c32a8bd0d13bcb (diff)
downloadlinux-stable-9f5848665788a0f07bc175cb2cdd06d367b7556e.tar.gz
linux-stable-9f5848665788a0f07bc175cb2cdd06d367b7556e.tar.bz2
linux-stable-9f5848665788a0f07bc175cb2cdd06d367b7556e.zip
arm64/sve: Make access to FFR optional
SME introduces streaming SVE mode in which FFR is not present and the instructions for accessing it UNDEF. In preparation for handling this update the low level SVE state access functions to take a flag specifying if FFR should be handled. When saving the register state we store a zero for FFR to guard against uninitialized data being read. No behaviour change should be introduced by this patch. Signed-off-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20211019172247.3045838-5-broonie@kernel.org Signed-off-by: Will Deacon <will@kernel.org>
Diffstat (limited to 'arch/arm64/kernel')
-rw-r--r--arch/arm64/kernel/entry-fpsimd.S19
-rw-r--r--arch/arm64/kernel/fpsimd.c10
2 files changed, 18 insertions, 11 deletions
diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S
index afbf7dc47e1d..f588c214d44b 100644
--- a/arch/arm64/kernel/entry-fpsimd.S
+++ b/arch/arm64/kernel/entry-fpsimd.S
@@ -38,9 +38,10 @@ SYM_FUNC_END(fpsimd_load_state)
*
* x0 - pointer to buffer for state
* x1 - pointer to storage for FPSR
+ * x2 - Save FFR if non-zero
*/
SYM_FUNC_START(sve_save_state)
- sve_save 0, x1, 2
+ sve_save 0, x1, x2, 3
ret
SYM_FUNC_END(sve_save_state)
@@ -49,10 +50,11 @@ SYM_FUNC_END(sve_save_state)
*
* x0 - pointer to buffer for state
* x1 - pointer to storage for FPSR
- * x2 - VQ-1
+ * x2 - Restore FFR if non-zero
+ * x3 - VQ-1
*/
SYM_FUNC_START(sve_load_state)
- sve_load 0, x1, x2, 3, x4
+ sve_load 0, x1, x2, x3, 4, x5
ret
SYM_FUNC_END(sve_load_state)
@@ -72,13 +74,16 @@ SYM_FUNC_END(sve_set_vq)
* VQ must already be configured by caller, any further updates of VQ
* will need to ensure that the register state remains valid.
*
- * x0 = VQ - 1
+ * x0 = include FFR?
+ * x1 = VQ - 1
*/
SYM_FUNC_START(sve_flush_live)
- cbz x0, 1f // A VQ-1 of 0 is 128 bits so no extra Z state
+ cbz x1, 1f // A VQ-1 of 0 is 128 bits so no extra Z state
sve_flush_z
-1: sve_flush_p_ffr
- ret
+1: sve_flush_p
+ tbz x0, #0, 2f
+ sve_flush_ffr
+2: ret
SYM_FUNC_END(sve_flush_live)
#endif /* CONFIG_ARM64_SVE */
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 0f6df1ece618..3d5d243c3f1c 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -289,7 +289,7 @@ static void task_fpsimd_load(void)
if (IS_ENABLED(CONFIG_ARM64_SVE) && test_thread_flag(TIF_SVE))
sve_load_state(sve_pffr(&current->thread),
- &current->thread.uw.fpsimd_state.fpsr,
+ &current->thread.uw.fpsimd_state.fpsr, true,
sve_vq_from_vl(current->thread.sve_vl) - 1);
else
fpsimd_load_state(&current->thread.uw.fpsimd_state);
@@ -325,7 +325,7 @@ static void fpsimd_save(void)
sve_save_state((char *)last->sve_state +
sve_ffr_offset(last->sve_vl),
- &last->st->fpsr);
+ &last->st->fpsr, true);
} else {
fpsimd_save_state(last->st);
}
@@ -962,7 +962,7 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs)
unsigned long vq_minus_one =
sve_vq_from_vl(current->thread.sve_vl) - 1;
sve_set_vq(vq_minus_one);
- sve_flush_live(vq_minus_one);
+ sve_flush_live(true, vq_minus_one);
fpsimd_bind_task_to_cpu();
} else {
fpsimd_to_sve(current);
@@ -1356,7 +1356,8 @@ void __efi_fpsimd_begin(void)
__this_cpu_write(efi_sve_state_used, true);
sve_save_state(sve_state + sve_ffr_offset(sve_max_vl),
- &this_cpu_ptr(&efi_fpsimd_state)->fpsr);
+ &this_cpu_ptr(&efi_fpsimd_state)->fpsr,
+ true);
} else {
fpsimd_save_state(this_cpu_ptr(&efi_fpsimd_state));
}
@@ -1382,6 +1383,7 @@ void __efi_fpsimd_end(void)
sve_load_state(sve_state + sve_ffr_offset(sve_max_vl),
&this_cpu_ptr(&efi_fpsimd_state)->fpsr,
+ true,
sve_vq_from_vl(sve_get_vl()) - 1);
__this_cpu_write(efi_sve_state_used, false);