Skip to content

Commit 7df56cb

Browse files
AndybnACTpalmer-dabbelt
authored andcommitted
riscv: sched: defer restoring Vector context for user
User will use its Vector registers only after the kernel really returns to the userspace. So we can delay restoring Vector registers as long as we are still running in kernel mode. So, add a thread flag to indicates the need of restoring Vector and do the restore at the last arch-specific exit-to-user hook. This save the context restoring cost when we switch over multiple processes that run V in kernel mode. For example, if the kernel performs a context swicth from A->B->C, and returns to C's userspace, then there is no need to restore B's V-register. Besides, this also prevents us from repeatedly restoring V context when executing kernel-mode Vector multiple times. The cost of this is that we must disable preemption and mark vector as busy during vstate_{save,restore}. Because then the V context will not get restored back immediately when a trap-causing context switch happens in the middle of vstate_{save,restore}. Signed-off-by: Andy Chiu <[email protected]> Acked-by: Conor Dooley <[email protected]> Tested-by: Björn Töpel <[email protected]> Tested-by: Lad Prabhakar <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent c5674d0 commit 7df56cb

File tree

8 files changed

+41
-5
lines changed

8 files changed

+41
-5
lines changed

arch/riscv/include/asm/entry-common.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,23 @@
44
#define _ASM_RISCV_ENTRY_COMMON_H
55

66
#include <asm/stacktrace.h>
7+
#include <asm/thread_info.h>
8+
#include <asm/vector.h>
9+
10+
static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
11+
unsigned long ti_work)
12+
{
13+
if (ti_work & _TIF_RISCV_V_DEFER_RESTORE) {
14+
clear_thread_flag(TIF_RISCV_V_DEFER_RESTORE);
15+
/*
16+
* We are already called with irq disabled, so go without
17+
* keeping track of riscv_v_flags.
18+
*/
19+
riscv_v_vstate_restore(current, regs);
20+
}
21+
}
22+
23+
#define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare
724

825
void handle_page_fault(struct pt_regs *regs);
926
void handle_break(struct pt_regs *regs);

arch/riscv/include/asm/thread_info.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,14 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
103103
#define TIF_NOTIFY_SIGNAL 9 /* signal notifications exist */
104104
#define TIF_UPROBE 10 /* uprobe breakpoint or singlestep */
105105
#define TIF_32BIT 11 /* compat-mode 32bit process */
106+
#define TIF_RISCV_V_DEFER_RESTORE 12 /* restore Vector before returing to user */
106107

107108
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
108109
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
109110
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
110111
#define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL)
111112
#define _TIF_UPROBE (1 << TIF_UPROBE)
113+
#define _TIF_RISCV_V_DEFER_RESTORE (1 << TIF_RISCV_V_DEFER_RESTORE)
112114

113115
#define _TIF_WORK_MASK \
114116
(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED | \

arch/riscv/include/asm/vector.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,14 +193,23 @@ static inline void riscv_v_vstate_restore(struct task_struct *task,
193193
}
194194
}
195195

196+
static inline void riscv_v_vstate_set_restore(struct task_struct *task,
197+
struct pt_regs *regs)
198+
{
199+
if ((regs->status & SR_VS) != SR_VS_OFF) {
200+
set_tsk_thread_flag(task, TIF_RISCV_V_DEFER_RESTORE);
201+
riscv_v_vstate_on(regs);
202+
}
203+
}
204+
196205
static inline void __switch_to_vector(struct task_struct *prev,
197206
struct task_struct *next)
198207
{
199208
struct pt_regs *regs;
200209

201210
regs = task_pt_regs(prev);
202211
riscv_v_vstate_save(prev, regs);
203-
riscv_v_vstate_restore(next, task_pt_regs(next));
212+
riscv_v_vstate_set_restore(next, task_pt_regs(next));
204213
}
205214

206215
void riscv_v_vstate_ctrl_init(struct task_struct *tsk);

arch/riscv/kernel/kernel_mode_vector.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ void kernel_vector_end(void)
117117
if (WARN_ON(!has_vector()))
118118
return;
119119

120-
riscv_v_vstate_restore(current, task_pt_regs(current));
120+
riscv_v_vstate_set_restore(current, task_pt_regs(current));
121121

122122
riscv_v_disable();
123123

arch/riscv/kernel/process.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ void flush_thread(void)
171171
riscv_v_vstate_off(task_pt_regs(current));
172172
kfree(current->thread.vstate.datap);
173173
memset(&current->thread.vstate, 0, sizeof(struct __riscv_v_ext_state));
174+
clear_tsk_thread_flag(current, TIF_RISCV_V_DEFER_RESTORE);
174175
#endif
175176
}
176177

@@ -187,6 +188,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
187188
*dst = *src;
188189
/* clear entire V context, including datap for a new task */
189190
memset(&dst->thread.vstate, 0, sizeof(struct __riscv_v_ext_state));
191+
clear_tsk_thread_flag(dst, TIF_RISCV_V_DEFER_RESTORE);
190192

191193
return 0;
192194
}

arch/riscv/kernel/ptrace.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,11 @@ static int riscv_vr_get(struct task_struct *target,
9999
* Ensure the vector registers have been saved to the memory before
100100
* copying them to membuf.
101101
*/
102-
if (target == current)
102+
if (target == current) {
103+
get_cpu_vector_context();
103104
riscv_v_vstate_save(current, task_pt_regs(current));
105+
put_cpu_vector_context();
106+
}
104107

105108
ptrace_vstate.vstart = vstate->vstart;
106109
ptrace_vstate.vl = vstate->vl;

arch/riscv/kernel/signal.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,10 @@ static long save_v_state(struct pt_regs *regs, void __user **sc_vec)
8686
/* datap is designed to be 16 byte aligned for better performance */
8787
WARN_ON(unlikely(!IS_ALIGNED((unsigned long)datap, 16)));
8888

89+
get_cpu_vector_context();
8990
riscv_v_vstate_save(current, regs);
91+
put_cpu_vector_context();
92+
9093
/* Copy everything of vstate but datap. */
9194
err = __copy_to_user(&state->v_state, &current->thread.vstate,
9295
offsetof(struct __riscv_v_ext_state, datap));
@@ -134,7 +137,7 @@ static long __restore_v_state(struct pt_regs *regs, void __user *sc_vec)
134137
if (unlikely(err))
135138
return err;
136139

137-
riscv_v_vstate_restore(current, regs);
140+
riscv_v_vstate_set_restore(current, regs);
138141

139142
return err;
140143
}

arch/riscv/kernel/vector.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ bool riscv_v_first_use_handler(struct pt_regs *regs)
167167
return true;
168168
}
169169
riscv_v_vstate_on(regs);
170-
riscv_v_vstate_restore(current, regs);
170+
riscv_v_vstate_set_restore(current, regs);
171171
return true;
172172
}
173173

0 commit comments

Comments
 (0)