Skip to content

Commit 8e9872a

Browse files
Nicolas Pitrefabiobaltieri
Nicolas Pitre
authored andcommitted
arm64: prevent possible deadlock on SMP with FPU sharing
Let's consider CPU1 waiting on a spinlock already taken by CPU2. It is possible for CPU2 to invoke the FPU and trigger an FPU exception when the FPU context for CPU2 is not live on that CPU. If the FPU context for the thread on CPU2 is still held in CPU1's FPU then an IPI is sent to CPU1 asking to flush its FPU to memory. But if CPU1 is spinning on a lock already taken by CPU2, it won't see the pending IPI as IRQs are disabled. CPU2 won't get its FPU state restored and won't complete the required work to release the lock. Let's prevent this deadlock scenario by looking for pending FPU IPI from the spinlock loop using the arch_spin_relax() hook. Signed-off-by: Nicolas Pitre <[email protected]>
1 parent 894f1b1 commit 8e9872a

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

arch/arm64/core/smp.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,25 @@ void z_arm64_flush_fpu_ipi(unsigned int cpu)
225225

226226
gic_raise_sgi(SGI_FPU_IPI, mpidr, 1 << aff0);
227227
}
228+
229+
/*
230+
* Make sure there is no pending FPU flush request for this CPU while
231+
* waiting for a contended spinlock to become available. This prevents
232+
* a deadlock when the lock we need is already taken by another CPU
233+
* that also wants its FPU content to be reinstated while such content
234+
* is still live in this CPU's FPU.
235+
*/
236+
void arch_spin_relax(void)
237+
{
238+
if (arm_gic_irq_is_pending(SGI_FPU_IPI)) {
239+
arm_gic_irq_clear_pending(SGI_FPU_IPI);
240+
/*
241+
* We may not be in IRQ context here hence cannot use
242+
* z_arm64_flush_local_fpu() directly.
243+
*/
244+
arch_float_disable(_current_cpu->arch.fpu_owner);
245+
}
246+
}
228247
#endif
229248

230249
static int arm64_smp_init(void)

0 commit comments

Comments
 (0)