bes2600: Patch D — atomicize ba_lock counters, drop the spinlock
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.
This commit is contained in:
+13
-10
@@ -995,14 +995,18 @@ bes2600_tx_h_ba_stat(struct bes2600_vif *priv,
|
||||
if (!ieee80211_is_data(t->hdr->frame_control))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&hw_priv->ba_lock);
|
||||
hw_priv->ba_acc += t->skb->len - t->hdrlen;
|
||||
if (!(hw_priv->ba_cnt_rx || hw_priv->ba_cnt)) {
|
||||
/*
|
||||
* Patch D: lock-free hot-path BA accounting. atomic_inc + atomic_add
|
||||
* each per-frame; the once-per-window timer-arm uses cmpxchg on
|
||||
* ba_armed so concurrent TX/RX can't both try to set the timer and
|
||||
* we don't need cross-counter coherency on the ba_cnt/ba_cnt_rx pair.
|
||||
*/
|
||||
atomic_add(t->skb->len - t->hdrlen, &hw_priv->ba_acc);
|
||||
atomic_inc(&hw_priv->ba_cnt);
|
||||
if (atomic_cmpxchg(&hw_priv->ba_armed, 0, 1) == 0) {
|
||||
mod_timer(&hw_priv->ba_timer,
|
||||
jiffies + BES2600_BLOCK_ACK_INTERVAL);
|
||||
}
|
||||
hw_priv->ba_cnt++;
|
||||
spin_unlock_bh(&hw_priv->ba_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1629,14 +1633,13 @@ bes2600_rx_h_ba_stat(struct bes2600_vif *priv,
|
||||
if (!priv->setbssparams_done)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&hw_priv->ba_lock);
|
||||
hw_priv->ba_acc_rx += skb_len - hdrlen;
|
||||
if (!(hw_priv->ba_cnt_rx || hw_priv->ba_cnt)) {
|
||||
/* Patch D: lock-free hot-path BA accounting; see TX side comment. */
|
||||
atomic_add(skb_len - hdrlen, &hw_priv->ba_acc_rx);
|
||||
atomic_inc(&hw_priv->ba_cnt_rx);
|
||||
if (atomic_cmpxchg(&hw_priv->ba_armed, 0, 1) == 0) {
|
||||
mod_timer(&hw_priv->ba_timer,
|
||||
jiffies + BES2600_BLOCK_ACK_INTERVAL);
|
||||
}
|
||||
hw_priv->ba_cnt_rx++;
|
||||
spin_unlock_bh(&hw_priv->ba_lock);
|
||||
}
|
||||
|
||||
void bes2600_rx_cb(struct bes2600_vif *priv,
|
||||
|
||||
Reference in New Issue
Block a user