mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 17:23:36 +00:00
ARM: 9426/1: vfp: Move sending signals outside of vfp_state_hold()ed section.
VFP_bounce() is invoked from within vfp_support_entry() and may send a signal. Sending a signal uses spinlock_t which becomes a sleeping lock on PREEMPT_RT and must not be acquired within a preempt-disabled section. Move the vfp_raise_sigfpe() block outside of the vfp_state_hold() section. Reviewed-by: Ard Biesheuvel <ardb@kernel.org> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
This commit is contained in:
parent
27035c23ba
commit
c0b5195bad
@ -268,7 +268,7 @@ static void vfp_panic(char *reason, u32 inst)
|
|||||||
/*
|
/*
|
||||||
* Process bitmask of exception conditions.
|
* Process bitmask of exception conditions.
|
||||||
*/
|
*/
|
||||||
static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_regs *regs)
|
static int vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr)
|
||||||
{
|
{
|
||||||
int si_code = 0;
|
int si_code = 0;
|
||||||
|
|
||||||
@ -276,8 +276,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
|
|||||||
|
|
||||||
if (exceptions == VFP_EXCEPTION_ERROR) {
|
if (exceptions == VFP_EXCEPTION_ERROR) {
|
||||||
vfp_panic("unhandled bounce", inst);
|
vfp_panic("unhandled bounce", inst);
|
||||||
vfp_raise_sigfpe(FPE_FLTINV, regs);
|
return FPE_FLTINV;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -305,8 +304,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
|
|||||||
RAISE(FPSCR_OFC, FPSCR_OFE, FPE_FLTOVF);
|
RAISE(FPSCR_OFC, FPSCR_OFE, FPE_FLTOVF);
|
||||||
RAISE(FPSCR_IOC, FPSCR_IOE, FPE_FLTINV);
|
RAISE(FPSCR_IOC, FPSCR_IOE, FPE_FLTINV);
|
||||||
|
|
||||||
if (si_code)
|
return si_code;
|
||||||
vfp_raise_sigfpe(si_code, regs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -352,6 +350,8 @@ static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs)
|
|||||||
static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
|
static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
u32 fpscr, orig_fpscr, fpsid, exceptions;
|
u32 fpscr, orig_fpscr, fpsid, exceptions;
|
||||||
|
int si_code2 = 0;
|
||||||
|
int si_code = 0;
|
||||||
|
|
||||||
pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc);
|
pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc);
|
||||||
|
|
||||||
@ -397,8 +397,8 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
|
|||||||
* unallocated VFP instruction but with FPSCR.IXE set and not
|
* unallocated VFP instruction but with FPSCR.IXE set and not
|
||||||
* on VFP subarch 1.
|
* on VFP subarch 1.
|
||||||
*/
|
*/
|
||||||
vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs);
|
si_code = vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr);
|
||||||
return;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -422,14 +422,14 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
|
|||||||
*/
|
*/
|
||||||
exceptions = vfp_emulate_instruction(trigger, fpscr, regs);
|
exceptions = vfp_emulate_instruction(trigger, fpscr, regs);
|
||||||
if (exceptions)
|
if (exceptions)
|
||||||
vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
|
si_code2 = vfp_raise_exceptions(exceptions, trigger, orig_fpscr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there isn't a second FP instruction, exit now. Note that
|
* If there isn't a second FP instruction, exit now. Note that
|
||||||
* the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.
|
* the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.
|
||||||
*/
|
*/
|
||||||
if ((fpexc & (FPEXC_EX | FPEXC_FP2V)) != (FPEXC_EX | FPEXC_FP2V))
|
if ((fpexc & (FPEXC_EX | FPEXC_FP2V)) != (FPEXC_EX | FPEXC_FP2V))
|
||||||
return;
|
goto exit;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The barrier() here prevents fpinst2 being read
|
* The barrier() here prevents fpinst2 being read
|
||||||
@ -441,7 +441,13 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
|
|||||||
emulate:
|
emulate:
|
||||||
exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs);
|
exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs);
|
||||||
if (exceptions)
|
if (exceptions)
|
||||||
vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
|
si_code = vfp_raise_exceptions(exceptions, trigger, orig_fpscr);
|
||||||
|
exit:
|
||||||
|
vfp_state_release();
|
||||||
|
if (si_code2)
|
||||||
|
vfp_raise_sigfpe(si_code2, regs);
|
||||||
|
if (si_code)
|
||||||
|
vfp_raise_sigfpe(si_code, regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfp_enable(void *unused)
|
static void vfp_enable(void *unused)
|
||||||
@ -773,6 +779,7 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger)
|
|||||||
* replay the instruction that trapped.
|
* replay the instruction that trapped.
|
||||||
*/
|
*/
|
||||||
fmxr(FPEXC, fpexc);
|
fmxr(FPEXC, fpexc);
|
||||||
|
vfp_state_release();
|
||||||
} else {
|
} else {
|
||||||
/* Check for synchronous or asynchronous exceptions */
|
/* Check for synchronous or asynchronous exceptions */
|
||||||
if (!(fpexc & (FPEXC_EX | FPEXC_DEX))) {
|
if (!(fpexc & (FPEXC_EX | FPEXC_DEX))) {
|
||||||
@ -794,10 +801,10 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
bounce: regs->ARM_pc += 4;
|
bounce: regs->ARM_pc += 4;
|
||||||
|
/* VFP_bounce() will invoke vfp_state_release() */
|
||||||
VFP_bounce(trigger, fpexc, regs);
|
VFP_bounce(trigger, fpexc, regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
vfp_state_release();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user