Skip to content

Commit 53ce332

Browse files
author
Nicolas Pitre
committed
riscv: 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 a pending FPU IPI from the arch_spin_relax() hook and honor it. Signed-off-by: Nicolas Pitre <[email protected]>
1 parent d379c0d commit 53ce332

File tree

1 file changed

+22
-0
lines changed

1 file changed

+22
-0
lines changed

arch/riscv/core/smp.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,28 @@ static void ipi_handler(const void *unused)
118118
#endif
119119
}
120120

121+
#ifdef CONFIG_FPU_SHARING
122+
/*
123+
* Make sure there is no pending FPU flush request for this CPU while
124+
* waiting for a contended spinlock to become available. This prevents
125+
* a deadlock when the lock we need is already taken by another CPU
126+
* that also wants its FPU content to be reinstated while such content
127+
* is still live in this CPU's FPU.
128+
*/
129+
void arch_spin_relax(void)
130+
{
131+
atomic_val_t *pending_ipi = &cpu_pending_ipi[_current_cpu->id];
132+
133+
if (atomic_test_and_clear_bit(pending_ipi, IPI_FPU_FLUSH)) {
134+
/*
135+
* We may not be in IRQ context here hence cannot use
136+
* z_riscv_flush_local_fpu() directly.
137+
*/
138+
arch_float_disable(_current_cpu->arch.fpu_owner);
139+
}
140+
}
141+
#endif
142+
121143
static int riscv_smp_init(void)
122144
{
123145

0 commit comments

Comments
 (0)