aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/vfp
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2012-05-11 12:42:37 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-05-12 09:37:59 -0400
commit998de4acb2ba188d20768d1065658377a2e7d29b (patch)
treeb1c21f8cd96a6eb7cbce7e810eac65febf17982d /arch/arm/vfp
parentfde165b2a29673aabf18ceff14dea1f1cfb0daad (diff)
ARM: 7417/1: vfp: ensure preemption is disabled when enabling VFP access
The vfp_enable function enables access to the VFP co-processor register space (cp10 and cp11) on the current CPU and must be called with preemption disabled. Unfortunately, the vfp_init late initcall does not disable preemption and can lead to an oops during boot if thread migration occurs at the wrong time and we end up attempting to access the FPSID on a CPU with VFP access disabled. This patch fixes the initcall to call vfp_enable from a non-preemptible context on each CPU and adds a BUG_ON(preemptible) to ensure that any similar problems are easily spotted in the future. Cc: stable@vger.kernel.org Reported-by: Hyungwoo Yang <hwoo.yang@gmail.com> Signed-off-by: Hyungwoo Yang <hyungwooy@nvidia.com> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/vfp')
-rw-r--r--arch/arm/vfp/vfpmodule.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index bc683b8219b5..c5767b5a4318 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -11,6 +11,7 @@
11#include <linux/types.h> 11#include <linux/types.h>
12#include <linux/cpu.h> 12#include <linux/cpu.h>
13#include <linux/cpu_pm.h> 13#include <linux/cpu_pm.h>
14#include <linux/hardirq.h>
14#include <linux/kernel.h> 15#include <linux/kernel.h>
15#include <linux/notifier.h> 16#include <linux/notifier.h>
16#include <linux/signal.h> 17#include <linux/signal.h>
@@ -432,7 +433,10 @@ void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
432 433
433static void vfp_enable(void *unused) 434static void vfp_enable(void *unused)
434{ 435{
435 u32 access = get_copro_access(); 436 u32 access;
437
438 BUG_ON(preemptible());
439 access = get_copro_access();
436 440
437 /* 441 /*
438 * Enable full access to VFP (cp10 and cp11) 442 * Enable full access to VFP (cp10 and cp11)
@@ -657,7 +661,7 @@ static int __init vfp_init(void)
657 unsigned int cpu_arch = cpu_architecture(); 661 unsigned int cpu_arch = cpu_architecture();
658 662
659 if (cpu_arch >= CPU_ARCH_ARMv6) 663 if (cpu_arch >= CPU_ARCH_ARMv6)
660 vfp_enable(NULL); 664 on_each_cpu(vfp_enable, NULL, 1);
661 665
662 /* 666 /*
663 * First check that there is a VFP that we can use. 667 * First check that there is a VFP that we can use.
@@ -678,8 +682,6 @@ static int __init vfp_init(void)
678 } else { 682 } else {
679 hotcpu_notifier(vfp_hotplug, 0); 683 hotcpu_notifier(vfp_hotplug, 0);
680 684
681 smp_call_function(vfp_enable, NULL, 1);
682
683 VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */ 685 VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */
684 printk("implementor %02x architecture %d part %02x variant %x rev %x\n", 686 printk("implementor %02x architecture %d part %02x variant %x rev %x\n",
685 (vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT, 687 (vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT,