sparc32: order sun4m and sun4d cross-call flag resets before sending the IPI
Subsystems (2)
PATCH 1/1 sparc32: order sun4m and sun4d cross-call flag resets before sending the IPI
sun4m_cross_call() and sun4d_cross_call() clear processors_in[]/ processors_out[] for each target and then raise the cross-call interrupt. sun4m sends it through sbus_writel(), a volatile C store, which orders it only against other volatile accesses; sun4d sends it through cc_set_igen(), an asm volatile with no "memory" clobber. ccall_info is not volatile, so in both paths the compiler may sink the two resets below the send; gcc 14 does it for sun4m. A target that takes the interrupt and runs smp4m_cross_call_irq() or smp4d_cross_call_irq() before the resets land has its flags cleared behind it, and the sender spins forever on processors_in[] with cross_call_lock held.
Add a wmb() before sending the IPI in both cross-call paths.
sun4m has raised the IPI inline since the commit below; before it, set_cpu_int() was an out-of-line call. sun4d has had the same gap since 2.1.97.
---
Notes:
- gcc 14 moves the resets past the send in sun4m_cross_call() and keeps them ahead of it in sun4d_cross_call(); the barrier is missing in both.
- leon_cross_call() needs no change: leon_store_reg() already carries a "memory" clobber.
arch/sparc/kernel/sun4d_smp.c | 6 ++++++ arch/sparc/kernel/sun4m_smp.c | 6 ++++++ 2 files changed, 12 insertions(+)
arch/sparc/kernel/sun4d_smp.c +6 -0
@@ -321,6 +321,12 @@ static void sun4d_cross_call(void *func, cpumask_t mask, unsigned long arg1,if (cpumask_test_cpu (i, &mask)) { ccall_info.processors_in[i] =0 ; ccall_info.processors_out[i] =0 ; +/* +* The target may run the handler as soon +* as the IPI lands, so the resets must be +* visible before it is sent. +*/ +wmb ();sun4d_send_ipi (i,IRQ_CROSS_CALL ); } }
arch/sparc/kernel/sun4m_smp.c +6 -0
@@ -197,6 +197,12 @@ static void sun4m_cross_call(void *func, cpumask_t mask, unsigned long arg1,if (cpumask_test_cpu (i, &mask)) { ccall_info.processors_in[i] =0 ; ccall_info.processors_out[i] =0 ; +/* +* The target may run the handler as soon +* as the IPI lands, so the resets must be +* visible before it is sent. +*/ +wmb ();sun4m_send_ipi (i,IRQ_CROSS_CALL ); }else { ccall_info.processors_in[i] =1 ;
base-commit: 62f4c998b297cf233997a2b4cd6fc2d2df0319c9
Signature · 1 line
2.47.3
Hi Imre,
Quoted 15 lines · Imre Kaloz
sun4m_cross_call()andsun4d_cross_call()clear processors_in[]/ processors_out[] for each target and then raise the cross-call interrupt. sun4m sends it throughsbus_writel(), a volatile C store, which orders it only against other volatile accesses; sun4d sends it throughcc_set_igen(), an asm volatile with no "memory" clobber.ccall_infois not volatile, so in both paths the compiler may sink the two resets below the send; gcc 14 does it for sun4m. A target that takes the interrupt and runssmp4m_cross_call_irq()orsmp4d_cross_call_irq()before the resets land has its flags cleared behind it, and the sender spins forever on processors_in[] withcross_call_lockheld.Add a
wmb()before sending the IPI in both cross-call paths.
Quoted 9 lines
sun4m has raised the IPI inline since the commit below; before it,
set_cpu_int()was an out-of-line call. sun4d has had the same gap since 2.1.97.Fixes 4ba22b16bbf3 ("sparc32: move smp ipi to method ops")Signed-off-by Imre Kaloz <[email protected]>---
You have gcc 14 sinking them for sun4m; the other end of the range, for the
record: gcc 9.5.0 (crosstool-NG, sparc-linux-gnu) does not. Adding your wmb() at exactly this spot leaves sun4m_smp.o byte-identical, and wmb() is barrier() on sparc32, so that compiler was already keeping the resets ahead of the send.
Might be worth a line in the changelog for the stable side: older toolchains build correct code today and the patch is a no-op for them. Still obviously right to add the barrier.
Magnus
Quoted 51 lines
Notes:
- gcc 14 moves the resets past the send insun4m_cross_call()and keeps them ahead of it insun4d_cross_call(); the barrier is missing in both.
-leon_cross_call()needs no change:leon_store_reg()already carries a "memory" clobber.arch/sparc/kernel/sun4d_smp.c | 6 ++++++ arch/sparc/kernel/sun4m_smp.c | 6 ++++++ 2 files changed, 12 insertions(+)arch/sparc/kernel/sun4d_smp.c +6
-0@@ -321,6 +321,12 @@ static void sun4d_cross_call(void *func, cpumask_t mask, unsigned long arg1,if (cpumask_test_cpu (i, &mask)) { ccall_info.processors_in[i] =0 ; ccall_info.processors_out[i] =0 ; +/* +* The target may run the handler as soon +* as the IPI lands, so the resets must be +* visible before it is sent. +*/ +wmb ();sun4d_send_ipi (i,IRQ_CROSS_CALL ); } }arch/sparc/kernel/sun4m_smp.c +6
-0@@ -197,6 +197,12 @@ static void sun4m_cross_call(void *func, cpumask_t mask, unsigned long arg1,if (cpumask_test_cpu (i, &mask)) { ccall_info.processors_in[i] =0 ; ccall_info.processors_out[i] =0 ; +/* +* The target may run the handler as soon +* as the IPI lands, so the resets must be +* visible before it is sent. +*/ +wmb ();sun4m_send_ipi (i,IRQ_CROSS_CALL ); }else { ccall_info.processors_in[i] =1 ;base-commit:
62f4c998b297cf233997a2b4cd6fc2d2df0319c9--
2.47.3