brcmf_txfinalize() decrements pend_8021x_cnt before a lockless waitqueue_active() check. atomic_dec() does not order the decrement against the check. The waiter can therefore observe a nonzero count while the waker observes an empty queue, losing the final wakeup and delaying key installation until the 950 ms timeout. Add smp_mb__after_atomic() to order the decrement before the queue check. wait_event_timeout() provides the matching barrier. LKMM confirms that this forbids the lost-wakeup outcome. Fixes: 21fff75d2fb6 ("brcmfmac: use wait_event_timeout for 8021x pending count") Assisted-by: Claude:claude-fable-5 Signed-off-by: Karl Mehltretter --- LKMM results with herdtools7 7.58: C brcmf-wakeup-buggy { atomic_t cnt = ATOMIC_INIT(1); } P0(atomic_t *cnt, int *wq) { int r0; atomic_dec(cnt); r0 = READ_ONCE(*wq); } P1(atomic_t *cnt, int *wq) { int r1; WRITE_ONCE(*wq, 1); smp_mb(); r1 = atomic_read(cnt); } exists (0:r0=0 /\ 1:r1=1) The fixed variant adds smp_mb__after_atomic() immediately after atomic_dec(). Observation brcmf-wakeup-buggy Sometimes 1 3 Observation brcmf-wakeup-fixed Never 0 3 drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index dad6f4563d146..b192947ab4735 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -555,6 +555,8 @@ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success) if (type == ETH_P_PAE) { atomic_dec(&ifp->pend_8021x_cnt); + /* Order the decrement before waitqueue_active() */ + smp_mb__after_atomic(); if (waitqueue_active(&ifp->pend_8021x_wait)) wake_up(&ifp->pend_8021x_wait); } -- 2.53.0