The block-ack policy uses 4 int counters (ba_acc, ba_cnt, ba_acc_rx,
ba_cnt_rx) bumped per data frame in the TX and RX hot paths under
spin_lock_bh(&hw_priv->ba_lock). The lock was the heaviest per-frame
synchronization cost remaining after Patch C v3 (which fixed the
sdio_rx_work relay). Per the Opus structural critique (PR #8), this
pattern matches mac80211 driver convention for per-frame statistics:
atomic_t suffices, no lock needed.
Field-by-field changes in struct bes2600_common:
ba_acc, ba_cnt, ba_acc_rx, ba_cnt_rx: int -> atomic_t
ba_armed: new atomic_t (timer-arm flag)
ba_ena: bool -> atomic_t
ba_lock: removed (spinlock_t deleted)
ba_hist: int (single-writer = ba_timer)
Producer hot path (txrx.c TX submit + RX receive):
- atomic_add for the byte accumulator
- atomic_inc for the frame counter
- atomic_cmpxchg(&ba_armed, 0, 1) to claim the once-per-window
mod_timer arm — at most ONE producer succeeds; race-free
- no spin_lock_bh
Consumer paths (sta.c bes2600_ba_timer, sta.c disconnect-reset, sta.c
bes2600_ba_work, debug.c debugfs reader):
- atomic_read snapshots all 4 counters into locals; the threshold
predicate (acc/cnt >= THLD) tolerates approximate snapshots — the
timer fires periodically, a single misclassification just delays
the policy update by one tick
- atomic_set zeroes the counters at end of timer-callback window;
racing producer increments after the snapshot are lost (acceptable
for stats; same approximation the original lock allowed under
contention)
- atomic_set(&ba_armed, 0) re-enables the next window's arm
Followup-amenable simplification: ba_hist remains int because only
the single ba_timer callback writes it; multiple writers would need
to upgrade it too.
This patch follows the cw1200-mainline-idiom established by Patch C v3
(structural fix, not bandaid). The cw1200 reference doesn't have a
similar lock to compare; bes2600 inherited this from a later
Bestechnic addition rather than the upstream tree.