summaryrefslogtreecommitdiffstats
path: root/arch/arm64/include/asm/simd.h
diff options
context:
space:
mode:
authorDave Martin <Dave.Martin@arm.com>2017-08-03 18:23:23 +0200
committerCatalin Marinas <catalin.marinas@arm.com>2017-08-04 16:00:57 +0200
commitcb84d11e1625aa3a081d898ca2640bf3a9ca0e96 (patch)
tree514af7380143b4950fd3a158d5c0b0d2a90cc56b /arch/arm64/include/asm/simd.h
parentarm64: neon: Allow EFI runtime services to use FPSIMD in irq context (diff)
downloadlinux-cb84d11e1625aa3a081d898ca2640bf3a9ca0e96.tar.xz
linux-cb84d11e1625aa3a081d898ca2640bf3a9ca0e96.zip
arm64: neon: Remove support for nested or hardirq kernel-mode NEON
Support for kernel-mode NEON to be nested and/or used in hardirq context adds significant complexity, and the benefits may be marginal. In practice, kernel-mode NEON is not used in hardirq context, and is rarely used in softirq context (by certain mac80211 drivers). This patch implements an arm64 may_use_simd() function to allow clients to check whether kernel-mode NEON is usable in the current context, and simplifies kernel_neon_{begin,end}() to handle only saving of the task FPSIMD state (if any). Without nesting, there is no other state to save. The partial fpsimd save/restore functions become redundant as a result of these changes, so they are removed too. The save/restore model is changed to operate directly on task_struct without additional percpu storage. This simplifies the code and saves a bit of memory, but means that softirqs must now be disabled when manipulating the task fpsimd state from task context: correspondingly, preempt_{en,dis}sable() calls are upgraded to local_bh_{en,dis}able() as appropriate. fpsimd_thread_switch() already runs with hardirqs disabled and so is already protected from softirqs. These changes should make it easier to support kernel-mode NEON in the presence of the Scalable Vector extension in the future. Signed-off-by: Dave Martin <Dave.Martin@arm.com> Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64/include/asm/simd.h')
-rw-r--r--arch/arm64/include/asm/simd.h33
1 files changed, 32 insertions, 1 deletions
diff --git a/arch/arm64/include/asm/simd.h b/arch/arm64/include/asm/simd.h
index 96959b52afae..5a1a927b74a2 100644
--- a/arch/arm64/include/asm/simd.h
+++ b/arch/arm64/include/asm/simd.h
@@ -9,15 +9,46 @@
#ifndef __ASM_SIMD_H
#define __ASM_SIMD_H
+#include <linux/compiler.h>
+#include <linux/percpu.h>
+#include <linux/preempt.h>
#include <linux/types.h>
+#ifdef CONFIG_KERNEL_MODE_NEON
+
+DECLARE_PER_CPU(bool, kernel_neon_busy);
+
/*
* may_use_simd - whether it is allowable at this time to issue SIMD
* instructions or access the SIMD register file
+ *
+ * Callers must not assume that the result remains true beyond the next
+ * preempt_enable() or return from softirq context.
*/
static __must_check inline bool may_use_simd(void)
{
- return true;
+ /*
+ * The raw_cpu_read() is racy if called with preemption enabled.
+ * This is not a bug: kernel_neon_busy is only set when
+ * preemption is disabled, so we cannot migrate to another CPU
+ * while it is set, nor can we migrate to a CPU where it is set.
+ * So, if we find it clear on some CPU then we're guaranteed to
+ * find it clear on any CPU we could migrate to.
+ *
+ * If we are in between kernel_neon_begin()...kernel_neon_end(),
+ * the flag will be set, but preemption is also disabled, so we
+ * can't migrate to another CPU and spuriously see it become
+ * false.
+ */
+ return !in_irq() && !in_nmi() && !raw_cpu_read(kernel_neon_busy);
}
+#else /* ! CONFIG_KERNEL_MODE_NEON */
+
+static __must_check inline bool may_use_simd(void) {
+ return false;
+}
+
+#endif /* ! CONFIG_KERNEL_MODE_NEON */
+
#endif