summaryrefslogtreecommitdiffstats
path: root/arch/arm64/include/asm/simd.h
diff options
context:
space:
mode:
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