Skip to content

Commit 2632e25

Browse files
ardbiesheuvelwilldeacon
authored andcommitted
arm64: fpsimd: Implement lazy restore for kernel mode FPSIMD
Now that kernel mode FPSIMD state is context switched along with other task state, we can enable the existing logic that keeps track of which task's FPSIMD state the CPU is holding in its registers. If it is the context of the task that we are switching to, we can elide the reload of the FPSIMD state from memory. Note that we also need to check whether the FPSIMD state on this CPU is the most recent: if a task gets migrated away and back again, the state in memory may be more recent than the state in the CPU. So add another CPU id field to task_struct to keep track of this. (We could reuse the existing CPU id field used for user mode context, but that might result in user state to be discarded unnecessarily, given that two distinct CPUs could be holding the most recent user mode state and the most recent kernel mode state) Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Reviewed-by: Mark Brown <broonie@kernel.org> Acked-by: Mark Rutland <mark.rutland@arm.com> Link: https://lore.kernel.org/r/20231208113218.3001940-9-ardb@google.com Signed-off-by: Will Deacon <will@kernel.org>
1 parent aefbab8 commit 2632e25

2 files changed

Lines changed: 19 additions & 0 deletions

File tree

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
struct debug_info debug; /* debugging */
170170

171171
struct user_fpsimd_state kernel_fpsimd_state;
172+
unsigned int kernel_fpsimd_cpu;
172173
#ifdef CONFIG_ARM64_PTR_AUTH
173174
struct ptrauth_keys_user keys_user;
174175
#ifdef CONFIG_ARM64_PTR_AUTH_KERNEL

arch/arm64/kernel/fpsimd.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1476,12 +1476,30 @@ void do_fpsimd_exc(unsigned long esr, struct pt_regs *regs)
14761476

14771477
static void fpsimd_load_kernel_state(struct task_struct *task)
14781478
{
1479+
struct cpu_fp_state *last = this_cpu_ptr(&fpsimd_last_state);
1480+
1481+
/*
1482+
* Elide the load if this CPU holds the most recent kernel mode
1483+
* FPSIMD context of the current task.
1484+
*/
1485+
if (last->st == &task->thread.kernel_fpsimd_state &&
1486+
task->thread.kernel_fpsimd_cpu == smp_processor_id())
1487+
return;
1488+
14791489
fpsimd_load_state(&task->thread.kernel_fpsimd_state);
14801490
}
14811491

14821492
static void fpsimd_save_kernel_state(struct task_struct *task)
14831493
{
1494+
struct cpu_fp_state cpu_fp_state = {
1495+
.st = &task->thread.kernel_fpsimd_state,
1496+
.to_save = FP_STATE_FPSIMD,
1497+
};
1498+
14841499
fpsimd_save_state(&task->thread.kernel_fpsimd_state);
1500+
fpsimd_bind_state_to_cpu(&cpu_fp_state);
1501+
1502+
task->thread.kernel_fpsimd_cpu = smp_processor_id();
14851503
}
14861504

14871505
void fpsimd_thread_switch(struct task_struct *next)

0 commit comments

Comments
 (0)