diff options
-rw-r--r-- | arch/arm/Kconfig | 7 | ||||
-rw-r--r-- | arch/arm/include/asm/neon.h | 36 | ||||
-rw-r--r-- | arch/arm/vfp/vfpmodule.c | 47 |
3 files changed, 90 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 136f263ed47b..d6068b435151 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -2197,6 +2197,13 @@ config NEON | |||
2197 | Say Y to include support code for NEON, the ARMv7 Advanced SIMD | 2197 | Say Y to include support code for NEON, the ARMv7 Advanced SIMD |
2198 | Extension. | 2198 | Extension. |
2199 | 2199 | ||
2200 | config KERNEL_MODE_NEON | ||
2201 | bool "Support for NEON in kernel mode" | ||
2202 | default n | ||
2203 | depends on NEON | ||
2204 | help | ||
2205 | Say Y to include support for NEON in kernel mode. | ||
2206 | |||
2200 | endmenu | 2207 | endmenu |
2201 | 2208 | ||
2202 | menu "Userspace binary formats" | 2209 | menu "Userspace binary formats" |
diff --git a/arch/arm/include/asm/neon.h b/arch/arm/include/asm/neon.h new file mode 100644 index 000000000000..8f730fe70093 --- /dev/null +++ b/arch/arm/include/asm/neon.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/include/asm/neon.h | ||
3 | * | ||
4 | * Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <asm/hwcap.h> | ||
12 | |||
13 | #define cpu_has_neon() (!!(elf_hwcap & HWCAP_NEON)) | ||
14 | |||
15 | #ifdef __ARM_NEON__ | ||
16 | |||
17 | /* | ||
18 | * If you are affected by the BUILD_BUG below, it probably means that you are | ||
19 | * using NEON code /and/ calling the kernel_neon_begin() function from the same | ||
20 | * compilation unit. To prevent issues that may arise from GCC reordering or | ||
21 | * generating(1) NEON instructions outside of these begin/end functions, the | ||
22 | * only supported way of using NEON code in the kernel is by isolating it in a | ||
23 | * separate compilation unit, and calling it from another unit from inside a | ||
24 | * kernel_neon_begin/kernel_neon_end pair. | ||
25 | * | ||
26 | * (1) Current GCC (4.7) might generate NEON instructions at O3 level if | ||
27 | * -mpfu=neon is set. | ||
28 | */ | ||
29 | |||
30 | #define kernel_neon_begin() \ | ||
31 | BUILD_BUG_ON_MSG(1, "kernel_neon_begin() called from NEON code") | ||
32 | |||
33 | #else | ||
34 | void kernel_neon_begin(void); | ||
35 | #endif | ||
36 | void kernel_neon_end(void); | ||
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 7620831a0c66..52b8f40b1c73 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/uaccess.h> | 21 | #include <linux/uaccess.h> |
22 | #include <linux/user.h> | 22 | #include <linux/user.h> |
23 | #include <linux/export.h> | ||
23 | 24 | ||
24 | #include <asm/cp15.h> | 25 | #include <asm/cp15.h> |
25 | #include <asm/cputype.h> | 26 | #include <asm/cputype.h> |
@@ -668,6 +669,52 @@ void vfp_kmode_exception(void) | |||
668 | pr_crit("BUG: FP instruction issued in kernel mode with FP unit disabled\n"); | 669 | pr_crit("BUG: FP instruction issued in kernel mode with FP unit disabled\n"); |
669 | } | 670 | } |
670 | 671 | ||
672 | #ifdef CONFIG_KERNEL_MODE_NEON | ||
673 | |||
674 | /* | ||
675 | * Kernel-side NEON support functions | ||
676 | */ | ||
677 | void kernel_neon_begin(void) | ||
678 | { | ||
679 | struct thread_info *thread = current_thread_info(); | ||
680 | unsigned int cpu; | ||
681 | u32 fpexc; | ||
682 | |||
683 | /* | ||
684 | * Kernel mode NEON is only allowed outside of interrupt context | ||
685 | * with preemption disabled. This will make sure that the kernel | ||
686 | * mode NEON register contents never need to be preserved. | ||
687 | */ | ||
688 | BUG_ON(in_interrupt()); | ||
689 | cpu = get_cpu(); | ||
690 | |||
691 | fpexc = fmrx(FPEXC) | FPEXC_EN; | ||
692 | fmxr(FPEXC, fpexc); | ||
693 | |||
694 | /* | ||
695 | * Save the userland NEON/VFP state. Under UP, | ||
696 | * the owner could be a task other than 'current' | ||
697 | */ | ||
698 | if (vfp_state_in_hw(cpu, thread)) | ||
699 | vfp_save_state(&thread->vfpstate, fpexc); | ||
700 | #ifndef CONFIG_SMP | ||
701 | else if (vfp_current_hw_state[cpu] != NULL) | ||
702 | vfp_save_state(vfp_current_hw_state[cpu], fpexc); | ||
703 | #endif | ||
704 | vfp_current_hw_state[cpu] = NULL; | ||
705 | } | ||
706 | EXPORT_SYMBOL(kernel_neon_begin); | ||
707 | |||
708 | void kernel_neon_end(void) | ||
709 | { | ||
710 | /* Disable the NEON/VFP unit. */ | ||
711 | fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); | ||
712 | put_cpu(); | ||
713 | } | ||
714 | EXPORT_SYMBOL(kernel_neon_end); | ||
715 | |||
716 | #endif /* CONFIG_KERNEL_MODE_NEON */ | ||
717 | |||
671 | /* | 718 | /* |
672 | * VFP support code initialisation. | 719 | * VFP support code initialisation. |
673 | */ | 720 | */ |