aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/fpsimd.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/kernel/fpsimd.c')
-rw-r--r--arch/arm64/kernel/fpsimd.c139
1 files changed, 96 insertions, 43 deletions
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 0cfcf5c237c5..eec4776ae5f0 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -82,7 +82,8 @@
82 * To prevent this from racing with the manipulation of the task's FPSIMD state 82 * To prevent this from racing with the manipulation of the task's FPSIMD state
83 * from task context and thereby corrupting the state, it is necessary to 83 * from task context and thereby corrupting the state, it is necessary to
84 * protect any manipulation of a task's fpsimd_state or TIF_FOREIGN_FPSTATE 84 * protect any manipulation of a task's fpsimd_state or TIF_FOREIGN_FPSTATE
85 * flag with local_bh_disable() unless softirqs are already masked. 85 * flag with {, __}get_cpu_fpsimd_context(). This will still allow softirqs to
86 * run but prevent them to use FPSIMD.
86 * 87 *
87 * For a certain task, the sequence may look something like this: 88 * For a certain task, the sequence may look something like this:
88 * - the task gets scheduled in; if both the task's fpsimd_cpu field 89 * - the task gets scheduled in; if both the task's fpsimd_cpu field
@@ -145,6 +146,56 @@ extern void __percpu *efi_sve_state;
145 146
146#endif /* ! CONFIG_ARM64_SVE */ 147#endif /* ! CONFIG_ARM64_SVE */
147 148
149DEFINE_PER_CPU(bool, fpsimd_context_busy);
150EXPORT_PER_CPU_SYMBOL(fpsimd_context_busy);
151
152static void __get_cpu_fpsimd_context(void)
153{
154 bool busy = __this_cpu_xchg(fpsimd_context_busy, true);
155
156 WARN_ON(busy);
157}
158
159/*
160 * Claim ownership of the CPU FPSIMD context for use by the calling context.
161 *
162 * The caller may freely manipulate the FPSIMD context metadata until
163 * put_cpu_fpsimd_context() is called.
164 *
165 * The double-underscore version must only be called if you know the task
166 * can't be preempted.
167 */
168static void get_cpu_fpsimd_context(void)
169{
170 preempt_disable();
171 __get_cpu_fpsimd_context();
172}
173
174static void __put_cpu_fpsimd_context(void)
175{
176 bool busy = __this_cpu_xchg(fpsimd_context_busy, false);
177
178 WARN_ON(!busy); /* No matching get_cpu_fpsimd_context()? */
179}
180
181/*
182 * Release the CPU FPSIMD context.
183 *
184 * Must be called from a context in which get_cpu_fpsimd_context() was
185 * previously called, with no call to put_cpu_fpsimd_context() in the
186 * meantime.
187 */
188static void put_cpu_fpsimd_context(void)
189{
190 __put_cpu_fpsimd_context();
191 preempt_enable();
192}
193
194static bool have_cpu_fpsimd_context(void)
195{
196 return !preemptible() && __this_cpu_read(fpsimd_context_busy);
197}
198
148/* 199/*
149 * Call __sve_free() directly only if you know task can't be scheduled 200 * Call __sve_free() directly only if you know task can't be scheduled
150 * or preempted. 201 * or preempted.
@@ -215,12 +266,10 @@ static void sve_free(struct task_struct *task)
215 * This function should be called only when the FPSIMD/SVE state in 266 * This function should be called only when the FPSIMD/SVE state in
216 * thread_struct is known to be up to date, when preparing to enter 267 * thread_struct is known to be up to date, when preparing to enter
217 * userspace. 268 * userspace.
218 *
219 * Softirqs (and preemption) must be disabled.
220 */ 269 */
221static void task_fpsimd_load(void) 270static void task_fpsimd_load(void)
222{ 271{
223 WARN_ON(!in_softirq() && !irqs_disabled()); 272 WARN_ON(!have_cpu_fpsimd_context());
224 273
225 if (system_supports_sve() && test_thread_flag(TIF_SVE)) 274 if (system_supports_sve() && test_thread_flag(TIF_SVE))
226 sve_load_state(sve_pffr(&current->thread), 275 sve_load_state(sve_pffr(&current->thread),
@@ -233,16 +282,14 @@ static void task_fpsimd_load(void)
233/* 282/*
234 * Ensure FPSIMD/SVE storage in memory for the loaded context is up to 283 * Ensure FPSIMD/SVE storage in memory for the loaded context is up to
235 * date with respect to the CPU registers. 284 * date with respect to the CPU registers.
236 *
237 * Softirqs (and preemption) must be disabled.
238 */ 285 */
239void fpsimd_save(void) 286static void fpsimd_save(void)
240{ 287{
241 struct fpsimd_last_state_struct const *last = 288 struct fpsimd_last_state_struct const *last =
242 this_cpu_ptr(&fpsimd_last_state); 289 this_cpu_ptr(&fpsimd_last_state);
243 /* set by fpsimd_bind_task_to_cpu() or fpsimd_bind_state_to_cpu() */ 290 /* set by fpsimd_bind_task_to_cpu() or fpsimd_bind_state_to_cpu() */
244 291
245 WARN_ON(!in_softirq() && !irqs_disabled()); 292 WARN_ON(!have_cpu_fpsimd_context());
246 293
247 if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) { 294 if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {
248 if (system_supports_sve() && test_thread_flag(TIF_SVE)) { 295 if (system_supports_sve() && test_thread_flag(TIF_SVE)) {
@@ -364,7 +411,8 @@ static __uint128_t arm64_cpu_to_le128(__uint128_t x)
364 * task->thread.sve_state. 411 * task->thread.sve_state.
365 * 412 *
366 * Task can be a non-runnable task, or current. In the latter case, 413 * Task can be a non-runnable task, or current. In the latter case,
367 * softirqs (and preemption) must be disabled. 414 * the caller must have ownership of the cpu FPSIMD context before calling
415 * this function.
368 * task->thread.sve_state must point to at least sve_state_size(task) 416 * task->thread.sve_state must point to at least sve_state_size(task)
369 * bytes of allocated kernel memory. 417 * bytes of allocated kernel memory.
370 * task->thread.uw.fpsimd_state must be up to date before calling this 418 * task->thread.uw.fpsimd_state must be up to date before calling this
@@ -393,7 +441,8 @@ static void fpsimd_to_sve(struct task_struct *task)
393 * task->thread.uw.fpsimd_state. 441 * task->thread.uw.fpsimd_state.
394 * 442 *
395 * Task can be a non-runnable task, or current. In the latter case, 443 * Task can be a non-runnable task, or current. In the latter case,
396 * softirqs (and preemption) must be disabled. 444 * the caller must have ownership of the cpu FPSIMD context before calling
445 * this function.
397 * task->thread.sve_state must point to at least sve_state_size(task) 446 * task->thread.sve_state must point to at least sve_state_size(task)
398 * bytes of allocated kernel memory. 447 * bytes of allocated kernel memory.
399 * task->thread.sve_state must be up to date before calling this function. 448 * task->thread.sve_state must be up to date before calling this function.
@@ -557,7 +606,7 @@ int sve_set_vector_length(struct task_struct *task,
557 * non-SVE thread. 606 * non-SVE thread.
558 */ 607 */
559 if (task == current) { 608 if (task == current) {
560 local_bh_disable(); 609 get_cpu_fpsimd_context();
561 610
562 fpsimd_save(); 611 fpsimd_save();
563 } 612 }
@@ -567,7 +616,7 @@ int sve_set_vector_length(struct task_struct *task,
567 sve_to_fpsimd(task); 616 sve_to_fpsimd(task);
568 617
569 if (task == current) 618 if (task == current)
570 local_bh_enable(); 619 put_cpu_fpsimd_context();
571 620
572 /* 621 /*
573 * Force reallocation of task SVE state to the correct size 622 * Force reallocation of task SVE state to the correct size
@@ -880,7 +929,7 @@ asmlinkage void do_sve_acc(unsigned int esr, struct pt_regs *regs)
880 929
881 sve_alloc(current); 930 sve_alloc(current);
882 931
883 local_bh_disable(); 932 get_cpu_fpsimd_context();
884 933
885 fpsimd_save(); 934 fpsimd_save();
886 935
@@ -891,7 +940,7 @@ asmlinkage void do_sve_acc(unsigned int esr, struct pt_regs *regs)
891 if (test_and_set_thread_flag(TIF_SVE)) 940 if (test_and_set_thread_flag(TIF_SVE))
892 WARN_ON(1); /* SVE access shouldn't have trapped */ 941 WARN_ON(1); /* SVE access shouldn't have trapped */
893 942
894 local_bh_enable(); 943 put_cpu_fpsimd_context();
895} 944}
896 945
897/* 946/*
@@ -935,6 +984,8 @@ void fpsimd_thread_switch(struct task_struct *next)
935 if (!system_supports_fpsimd()) 984 if (!system_supports_fpsimd())
936 return; 985 return;
937 986
987 __get_cpu_fpsimd_context();
988
938 /* Save unsaved fpsimd state, if any: */ 989 /* Save unsaved fpsimd state, if any: */
939 fpsimd_save(); 990 fpsimd_save();
940 991
@@ -949,6 +1000,8 @@ void fpsimd_thread_switch(struct task_struct *next)
949 1000
950 update_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE, 1001 update_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE,
951 wrong_task || wrong_cpu); 1002 wrong_task || wrong_cpu);
1003
1004 __put_cpu_fpsimd_context();
952} 1005}
953 1006
954void fpsimd_flush_thread(void) 1007void fpsimd_flush_thread(void)
@@ -958,7 +1011,7 @@ void fpsimd_flush_thread(void)
958 if (!system_supports_fpsimd()) 1011 if (!system_supports_fpsimd())
959 return; 1012 return;
960 1013
961 local_bh_disable(); 1014 get_cpu_fpsimd_context();
962 1015
963 fpsimd_flush_task_state(current); 1016 fpsimd_flush_task_state(current);
964 memset(&current->thread.uw.fpsimd_state, 0, 1017 memset(&current->thread.uw.fpsimd_state, 0,
@@ -999,7 +1052,7 @@ void fpsimd_flush_thread(void)
999 current->thread.sve_vl_onexec = 0; 1052 current->thread.sve_vl_onexec = 0;
1000 } 1053 }
1001 1054
1002 local_bh_enable(); 1055 put_cpu_fpsimd_context();
1003} 1056}
1004 1057
1005/* 1058/*
@@ -1011,9 +1064,9 @@ void fpsimd_preserve_current_state(void)
1011 if (!system_supports_fpsimd()) 1064 if (!system_supports_fpsimd())
1012 return; 1065 return;
1013 1066
1014 local_bh_disable(); 1067 get_cpu_fpsimd_context();
1015 fpsimd_save(); 1068 fpsimd_save();
1016 local_bh_enable(); 1069 put_cpu_fpsimd_context();
1017} 1070}
1018 1071
1019/* 1072/*
@@ -1030,7 +1083,8 @@ void fpsimd_signal_preserve_current_state(void)
1030 1083
1031/* 1084/*
1032 * Associate current's FPSIMD context with this cpu 1085 * Associate current's FPSIMD context with this cpu
1033 * Preemption must be disabled when calling this function. 1086 * The caller must have ownership of the cpu FPSIMD context before calling
1087 * this function.
1034 */ 1088 */
1035void fpsimd_bind_task_to_cpu(void) 1089void fpsimd_bind_task_to_cpu(void)
1036{ 1090{
@@ -1076,14 +1130,14 @@ void fpsimd_restore_current_state(void)
1076 if (!system_supports_fpsimd()) 1130 if (!system_supports_fpsimd())
1077 return; 1131 return;
1078 1132
1079 local_bh_disable(); 1133 get_cpu_fpsimd_context();
1080 1134
1081 if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) { 1135 if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) {
1082 task_fpsimd_load(); 1136 task_fpsimd_load();
1083 fpsimd_bind_task_to_cpu(); 1137 fpsimd_bind_task_to_cpu();
1084 } 1138 }
1085 1139
1086 local_bh_enable(); 1140 put_cpu_fpsimd_context();
1087} 1141}
1088 1142
1089/* 1143/*
@@ -1096,7 +1150,7 @@ void fpsimd_update_current_state(struct user_fpsimd_state const *state)
1096 if (!system_supports_fpsimd()) 1150 if (!system_supports_fpsimd())
1097 return; 1151 return;
1098 1152
1099 local_bh_disable(); 1153 get_cpu_fpsimd_context();
1100 1154
1101 current->thread.uw.fpsimd_state = *state; 1155 current->thread.uw.fpsimd_state = *state;
1102 if (system_supports_sve() && test_thread_flag(TIF_SVE)) 1156 if (system_supports_sve() && test_thread_flag(TIF_SVE))
@@ -1107,7 +1161,7 @@ void fpsimd_update_current_state(struct user_fpsimd_state const *state)
1107 1161
1108 clear_thread_flag(TIF_FOREIGN_FPSTATE); 1162 clear_thread_flag(TIF_FOREIGN_FPSTATE);
1109 1163
1110 local_bh_enable(); 1164 put_cpu_fpsimd_context();
1111} 1165}
1112 1166
1113/* 1167/*
@@ -1133,18 +1187,29 @@ void fpsimd_flush_task_state(struct task_struct *t)
1133 1187
1134/* 1188/*
1135 * Invalidate any task's FPSIMD state that is present on this cpu. 1189 * Invalidate any task's FPSIMD state that is present on this cpu.
1136 * This function must be called with softirqs disabled. 1190 * The FPSIMD context should be acquired with get_cpu_fpsimd_context()
1191 * before calling this function.
1137 */ 1192 */
1138void fpsimd_flush_cpu_state(void) 1193static void fpsimd_flush_cpu_state(void)
1139{ 1194{
1140 __this_cpu_write(fpsimd_last_state.st, NULL); 1195 __this_cpu_write(fpsimd_last_state.st, NULL);
1141 set_thread_flag(TIF_FOREIGN_FPSTATE); 1196 set_thread_flag(TIF_FOREIGN_FPSTATE);
1142} 1197}
1143 1198
1144#ifdef CONFIG_KERNEL_MODE_NEON 1199/*
1200 * Save the FPSIMD state to memory and invalidate cpu view.
1201 * This function must be called with preemption disabled.
1202 */
1203void fpsimd_save_and_flush_cpu_state(void)
1204{
1205 WARN_ON(preemptible());
1206 __get_cpu_fpsimd_context();
1207 fpsimd_save();
1208 fpsimd_flush_cpu_state();
1209 __put_cpu_fpsimd_context();
1210}
1145 1211
1146DEFINE_PER_CPU(bool, kernel_neon_busy); 1212#ifdef CONFIG_KERNEL_MODE_NEON
1147EXPORT_PER_CPU_SYMBOL(kernel_neon_busy);
1148 1213
1149/* 1214/*
1150 * Kernel-side NEON support functions 1215 * Kernel-side NEON support functions
@@ -1170,19 +1235,13 @@ void kernel_neon_begin(void)
1170 1235
1171 BUG_ON(!may_use_simd()); 1236 BUG_ON(!may_use_simd());
1172 1237
1173 local_bh_disable(); 1238 get_cpu_fpsimd_context();
1174
1175 __this_cpu_write(kernel_neon_busy, true);
1176 1239
1177 /* Save unsaved fpsimd state, if any: */ 1240 /* Save unsaved fpsimd state, if any: */
1178 fpsimd_save(); 1241 fpsimd_save();
1179 1242
1180 /* Invalidate any task state remaining in the fpsimd regs: */ 1243 /* Invalidate any task state remaining in the fpsimd regs: */
1181 fpsimd_flush_cpu_state(); 1244 fpsimd_flush_cpu_state();
1182
1183 preempt_disable();
1184
1185 local_bh_enable();
1186} 1245}
1187EXPORT_SYMBOL(kernel_neon_begin); 1246EXPORT_SYMBOL(kernel_neon_begin);
1188 1247
@@ -1197,15 +1256,10 @@ EXPORT_SYMBOL(kernel_neon_begin);
1197 */ 1256 */
1198void kernel_neon_end(void) 1257void kernel_neon_end(void)
1199{ 1258{
1200 bool busy;
1201
1202 if (!system_supports_fpsimd()) 1259 if (!system_supports_fpsimd())
1203 return; 1260 return;
1204 1261
1205 busy = __this_cpu_xchg(kernel_neon_busy, false); 1262 put_cpu_fpsimd_context();
1206 WARN_ON(!busy); /* No matching kernel_neon_begin()? */
1207
1208 preempt_enable();
1209} 1263}
1210EXPORT_SYMBOL(kernel_neon_end); 1264EXPORT_SYMBOL(kernel_neon_end);
1211 1265
@@ -1297,8 +1351,7 @@ static int fpsimd_cpu_pm_notifier(struct notifier_block *self,
1297{ 1351{
1298 switch (cmd) { 1352 switch (cmd) {
1299 case CPU_PM_ENTER: 1353 case CPU_PM_ENTER:
1300 fpsimd_save(); 1354 fpsimd_save_and_flush_cpu_state();
1301 fpsimd_flush_cpu_state();
1302 break; 1355 break;
1303 case CPU_PM_EXIT: 1356 case CPU_PM_EXIT:
1304 break; 1357 break;