Skip to content

Commit c76c6c4

Browse files
ardbiesheuvelRussell King (Oracle)
authored andcommitted
ARM: 9294/2: vfp: Fix broken softirq handling with instrumentation enabled
Commit 62b95a7 ("ARM: 9282/1: vfp: Manipulate task VFP state with softirqs disabled") replaced the en/disable preemption calls inside the VFP state handling code with en/disabling of soft IRQs, which is necessary to allow kernel use of the VFP/SIMD unit when handling a soft IRQ. Unfortunately, when lockdep is enabled (or other instrumentation that enables TRACE_IRQFLAGS), the disable path implemented in asm fails to perform the lockdep and RCU related bookkeeping, resulting in spurious warnings and other badness. Set let's rework the VFP entry code a little bit so we can make the local_bh_disable() call from C, with all the instrumentations that happen to have been configured. Calling local_bh_enable() can be done from asm, as it is a simple wrapper around __local_bh_enable_ip(), which is always a callable function. Link: https://lore.kernel.org/all/ZBBYCSZUJOWBg1s8@localhost.localdomain/ Fixes: 62b95a7 ("ARM: 9282/1: vfp: Manipulate task VFP state with softirqs disabled") Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Tested-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
1 parent 3a2bdad commit c76c6c4

File tree

4 files changed

+29
-34
lines changed

4 files changed

+29
-34
lines changed

arch/arm/include/asm/assembler.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -244,19 +244,6 @@ THUMB( fpreg .req r7 )
244244
.endm
245245
#endif
246246

247-
.macro local_bh_disable, ti, tmp
248-
ldr \tmp, [\ti, #TI_PREEMPT]
249-
add \tmp, \tmp, #SOFTIRQ_DISABLE_OFFSET
250-
str \tmp, [\ti, #TI_PREEMPT]
251-
.endm
252-
253-
.macro local_bh_enable_ti, ti, tmp
254-
get_thread_info \ti
255-
ldr \tmp, [\ti, #TI_PREEMPT]
256-
sub \tmp, \tmp, #SOFTIRQ_DISABLE_OFFSET
257-
str \tmp, [\ti, #TI_PREEMPT]
258-
.endm
259-
260247
#define USERL(l, x...) \
261248
9999: x; \
262249
.pushsection __ex_table,"a"; \

arch/arm/vfp/entry.S

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,5 @@
2424
ENTRY(do_vfp)
2525
mov r1, r10
2626
mov r3, r9
27-
ldr r4, .LCvfp
28-
ldr pc, [r4] @ call VFP entry point
27+
b vfp_entry
2928
ENDPROC(do_vfp)
30-
31-
ENTRY(vfp_null_entry)
32-
ret lr
33-
ENDPROC(vfp_null_entry)
34-
35-
.align 2
36-
.LCvfp:
37-
.word vfp_vector

arch/arm/vfp/vfphw.S

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@
7575
@ lr = unrecognised instruction return address
7676
@ IRQs enabled.
7777
ENTRY(vfp_support_entry)
78-
local_bh_disable r1, r4
79-
8078
ldr r11, [r1, #TI_CPU] @ CPU number
8179
add r10, r1, #TI_VFPSTATE @ r10 = workspace
8280

@@ -179,9 +177,12 @@ vfp_hw_state_valid:
179177
@ else it's one 32-bit instruction, so
180178
@ always subtract 4 from the following
181179
@ instruction address.
182-
local_bh_enable_ti r10, r4
183-
ret r3 @ we think we have handled things
184180

181+
mov lr, r3 @ we think we have handled things
182+
local_bh_enable_and_ret:
183+
adr r0, .
184+
mov r1, #SOFTIRQ_DISABLE_OFFSET
185+
b __local_bh_enable_ip @ tail call
185186

186187
look_for_VFP_exceptions:
187188
@ Check for synchronous or asynchronous exception
@@ -204,8 +205,7 @@ skip:
204205
@ not recognised by VFP
205206

206207
DBGSTR "not VFP"
207-
local_bh_enable_ti r10, r4
208-
ret lr
208+
b local_bh_enable_and_ret
209209

210210
process_exception:
211211
DBGSTR "bounce"

arch/arm/vfp/vfpmodule.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,9 @@
3232
/*
3333
* Our undef handlers (in entry.S)
3434
*/
35-
asmlinkage void vfp_support_entry(void);
36-
asmlinkage void vfp_null_entry(void);
35+
asmlinkage void vfp_support_entry(u32, void *, u32, u32);
3736

38-
asmlinkage void (*vfp_vector)(void) = vfp_null_entry;
37+
static bool have_vfp __ro_after_init;
3938

4039
/*
4140
* Dual-use variable.
@@ -645,6 +644,25 @@ static int vfp_starting_cpu(unsigned int unused)
645644
return 0;
646645
}
647646

647+
/*
648+
* Entered with:
649+
*
650+
* r0 = instruction opcode (32-bit ARM or two 16-bit Thumb)
651+
* r1 = thread_info pointer
652+
* r2 = PC value to resume execution after successful emulation
653+
* r3 = normal "successful" return address
654+
* lr = unrecognised instruction return address
655+
*/
656+
asmlinkage void vfp_entry(u32 trigger, struct thread_info *ti, u32 resume_pc,
657+
u32 resume_return_address)
658+
{
659+
if (unlikely(!have_vfp))
660+
return;
661+
662+
local_bh_disable();
663+
vfp_support_entry(trigger, ti, resume_pc, resume_return_address);
664+
}
665+
648666
#ifdef CONFIG_KERNEL_MODE_NEON
649667

650668
static int vfp_kmode_exception(struct pt_regs *regs, unsigned int instr)
@@ -798,7 +816,6 @@ static int __init vfp_init(void)
798816
vfpsid = fmrx(FPSID);
799817
barrier();
800818
unregister_undef_hook(&vfp_detect_hook);
801-
vfp_vector = vfp_null_entry;
802819

803820
pr_info("VFP support v0.3: ");
804821
if (VFP_arch) {
@@ -883,7 +900,7 @@ static int __init vfp_init(void)
883900
"arm/vfp:starting", vfp_starting_cpu,
884901
vfp_dying_cpu);
885902

886-
vfp_vector = vfp_support_entry;
903+
have_vfp = true;
887904

888905
thread_register_notifier(&vfp_notifier_block);
889906
vfp_pm_init();

0 commit comments

Comments
 (0)