Commit 998de4acb2ba188d20768d1065658377a2e7d29b

Authored by Will Deacon
Committed by Russell King
1 parent fde165b2a2

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>

Showing 1 changed file with 6 additions and 4 deletions Side-by-side Diff

arch/arm/vfp/vfpmodule.c
... ... @@ -11,6 +11,7 @@
11 11 #include <linux/types.h>
12 12 #include <linux/cpu.h>
13 13 #include <linux/cpu_pm.h>
  14 +#include <linux/hardirq.h>
14 15 #include <linux/kernel.h>
15 16 #include <linux/notifier.h>
16 17 #include <linux/signal.h>
17 18  
... ... @@ -432,8 +433,11 @@
432 433  
433 434 static void vfp_enable(void *unused)
434 435 {
435   - u32 access = get_copro_access();
  436 + u32 access;
436 437  
  438 + BUG_ON(preemptible());
  439 + access = get_copro_access();
  440 +
437 441 /*
438 442 * Enable full access to VFP (cp10 and cp11)
439 443 */
... ... @@ -657,7 +661,7 @@
657 661 unsigned int cpu_arch = cpu_architecture();
658 662  
659 663 if (cpu_arch >= CPU_ARCH_ARMv6)
660   - vfp_enable(NULL);
  664 + on_each_cpu(vfp_enable, NULL, 1);
661 665  
662 666 /*
663 667 * First check that there is a VFP that we can use.
... ... @@ -677,8 +681,6 @@
677 681 printk("no double precision support\n");
678 682 } else {
679 683 hotcpu_notifier(vfp_hotplug, 0);
680   -
681   - smp_call_function(vfp_enable, NULL, 1);
682 684  
683 685 VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */
684 686 printk("implementor %02x architecture %d part %02x variant %x rev %x\n",