diff --git a/bes2600/bes2600.h b/bes2600/bes2600.h index 84059c7..32bce5e 100644 --- a/bes2600/bes2600.h +++ b/bes2600/bes2600.h @@ -353,15 +353,23 @@ struct bes2600_common { * Keeping in common structure for the time being. Will be moved to VIFF * after the mechanism is clear */ u8 ba_tid_mask; - int ba_acc; /*TODO: Same as above */ - int ba_cnt; /*TODO: Same as above */ - int ba_cnt_rx; /*TODO: Same as above */ - int ba_acc_rx; /*TODO: Same as above */ - int ba_hist; /*TODO: Same as above */ - struct timer_list ba_timer;/*TODO: Same as above */ - spinlock_t ba_lock; /*TODO: Same as above */ - bool ba_ena; /*TODO: Same as above */ - struct work_struct ba_work; /*TODO: Same as above */ + /* + * Patch D: ba_lock removed. Per-frame TX/RX hot-path bumped these + * counters under spin_lock_bh; the lock did not protect any + * compound invariant that atomic ops can't satisfy. Counters are + * now atomic_t; ba_armed gates the once-per-window mod_timer + * arm via cmpxchg so concurrent TX/RX at a fresh window each + * try to claim the arm and exactly one succeeds. + */ + atomic_t ba_acc; + atomic_t ba_cnt; + atomic_t ba_cnt_rx; + atomic_t ba_acc_rx; + atomic_t ba_armed; + int ba_hist; + struct timer_list ba_timer; + atomic_t ba_ena; + struct work_struct ba_work; bool is_BT_Present; bool is_go_thru_go_neg; u8 conf_listen_interval; diff --git a/bes2600/debug.c b/bes2600/debug.c index 47e27be..0ab79c0 100644 --- a/bes2600/debug.c +++ b/bes2600/debug.c @@ -110,17 +110,20 @@ static int bes2600_status_show_common(struct seq_file *seq, void *v) int ba_cnt, ba_acc, ba_cnt_rx, ba_acc_rx, ba_avg = 0, ba_avg_rx = 0; bool ba_ena; - spin_lock_bh(&hw_priv->ba_lock); - ba_cnt = hw_priv->debug->ba_cnt; - ba_acc = hw_priv->debug->ba_acc; + /* + * Patch D: ba_lock removed. hw_priv->debug->ba_* are written only + * by the timer callback (single writer); reading without a lock is + * fine for stats. ba_ena is atomic_t. + */ + ba_cnt = hw_priv->debug->ba_cnt; + ba_acc = hw_priv->debug->ba_acc; ba_cnt_rx = hw_priv->debug->ba_cnt_rx; ba_acc_rx = hw_priv->debug->ba_acc_rx; - ba_ena = hw_priv->ba_ena; + ba_ena = !!atomic_read(&hw_priv->ba_ena); if (ba_cnt) ba_avg = ba_acc / ba_cnt; if (ba_cnt_rx) ba_avg_rx = ba_acc_rx / ba_cnt_rx; - spin_unlock_bh(&hw_priv->ba_lock); seq_puts(seq, "BES2600 Wireless LAN driver status\n"); seq_printf(seq, "Hardware: %d.%d\n", diff --git a/bes2600/main.c b/bes2600/main.c index 19f196f..b52a4f6 100644 --- a/bes2600/main.c +++ b/bes2600/main.c @@ -496,7 +496,7 @@ static struct ieee80211_hw *bes2600_init_common(size_t hw_priv_data_len) INIT_LIST_HEAD(&hw_priv->event_queue); INIT_WORK(&hw_priv->event_handler, bes2600_event_handler); INIT_WORK(&hw_priv->ba_work, bes2600_ba_work); - spin_lock_init(&hw_priv->ba_lock); + /* Patch D: ba_lock removed; ba_acc/ba_cnt/etc are atomic_t. */ timer_setup(&hw_priv->ba_timer, bes2600_ba_timer, 0); if (unlikely(bes2600_queue_stats_init(&hw_priv->tx_queue_stats, diff --git a/bes2600/sta.c b/bes2600/sta.c index bfd8ae9..7caeb4b 100644 --- a/bes2600/sta.c +++ b/bes2600/sta.c @@ -2342,14 +2342,19 @@ void bes2600_join_work(struct work_struct *work) //WARN_ON(wsm_reset(hw_priv, &reset, priv->if_id)); WARN_ON(wsm_set_block_ack_policy(hw_priv, 0, hw_priv->ba_tid_mask, priv->if_id)); - spin_lock_bh(&hw_priv->ba_lock); - hw_priv->ba_ena = false; - hw_priv->ba_cnt = 0; - hw_priv->ba_acc = 0; + /* + * Patch D: ba_lock removed. Disconnect-reset clears the + * counters and the arm flag; producers racing here cannot + * cause harm — at worst they re-arm the timer and bump + * counters that will be cleared on the next timer tick. + */ + atomic_set(&hw_priv->ba_ena, 0); + atomic_set(&hw_priv->ba_cnt, 0); + atomic_set(&hw_priv->ba_acc, 0); hw_priv->ba_hist = 0; - hw_priv->ba_cnt_rx = 0; - hw_priv->ba_acc_rx = 0; - spin_unlock_bh(&hw_priv->ba_lock); + atomic_set(&hw_priv->ba_cnt_rx, 0); + atomic_set(&hw_priv->ba_acc_rx, 0); + atomic_set(&hw_priv->ba_armed, 0); mgmt_policy.protectedMgmtEnable = 0; mgmt_policy.unprotectedMgmtFramesAllowed = 1; @@ -2629,10 +2634,11 @@ void bes2600_ba_work(struct work_struct *work) return;*/ bes_devel("BA work****\n"); - spin_lock_bh(&hw_priv->ba_lock); -// tx_ba_tid_mask = hw_priv->ba_ena ? hw_priv->ba_tid_mask : 0; + /* + * Patch D: ba_lock removed. ba_tid_mask is u8 set once at init + * (main.c); reading it without a lock is fine. + */ tx_ba_tid_mask = hw_priv->ba_tid_mask; - spin_unlock_bh(&hw_priv->ba_lock); wsm_lock_tx(hw_priv); @@ -2645,37 +2651,49 @@ void bes2600_ba_work(struct work_struct *work) void bes2600_ba_timer(struct timer_list *t) { bool ba_ena; + int cnt, acc, cnt_rx, acc_rx; struct bes2600_common *hw_priv = from_timer(hw_priv, t, ba_timer); - spin_lock_bh(&hw_priv->ba_lock); - bes2600_debug_ba(hw_priv, hw_priv->ba_cnt, hw_priv->ba_acc, - hw_priv->ba_cnt_rx, hw_priv->ba_acc_rx); + /* + * Patch D: ba_lock removed. Snapshot atomic counters into locals + * for the predicate evaluation; producers may race incrementing + * after the snapshot but the resulting decision is approximate + * which the policy already tolerates (next timer tick re-evaluates). + */ + cnt = atomic_read(&hw_priv->ba_cnt); + acc = atomic_read(&hw_priv->ba_acc); + cnt_rx = atomic_read(&hw_priv->ba_cnt_rx); + acc_rx = atomic_read(&hw_priv->ba_acc_rx); + + bes2600_debug_ba(hw_priv, cnt, acc, cnt_rx, acc_rx); if (atomic_read(&hw_priv->scan.in_progress)) { - hw_priv->ba_cnt = 0; - hw_priv->ba_acc = 0; - hw_priv->ba_cnt_rx = 0; - hw_priv->ba_acc_rx = 0; - goto skip_statistic_update; + atomic_set(&hw_priv->ba_cnt, 0); + atomic_set(&hw_priv->ba_acc, 0); + atomic_set(&hw_priv->ba_cnt_rx, 0); + atomic_set(&hw_priv->ba_acc_rx, 0); + atomic_set(&hw_priv->ba_armed, 0); + return; } - if (hw_priv->ba_cnt >= BES2600_BLOCK_ACK_CNT && - (hw_priv->ba_acc / hw_priv->ba_cnt >= BES2600_BLOCK_ACK_THLD || - (hw_priv->ba_cnt_rx >= BES2600_BLOCK_ACK_CNT && - hw_priv->ba_acc_rx / hw_priv->ba_cnt_rx >= + if (cnt >= BES2600_BLOCK_ACK_CNT && + (acc / cnt >= BES2600_BLOCK_ACK_THLD || + (cnt_rx >= BES2600_BLOCK_ACK_CNT && + acc_rx / cnt_rx >= BES2600_BLOCK_ACK_THLD))) ba_ena = true; else ba_ena = false; - hw_priv->ba_cnt = 0; - hw_priv->ba_acc = 0; - hw_priv->ba_cnt_rx = 0; - hw_priv->ba_acc_rx = 0; + atomic_set(&hw_priv->ba_cnt, 0); + atomic_set(&hw_priv->ba_acc, 0); + atomic_set(&hw_priv->ba_cnt_rx, 0); + atomic_set(&hw_priv->ba_acc_rx, 0); + atomic_set(&hw_priv->ba_armed, 0); - if (ba_ena != hw_priv->ba_ena) { + if (ba_ena != !!atomic_read(&hw_priv->ba_ena)) { if (ba_ena || ++hw_priv->ba_hist >= BES2600_BLOCK_ACK_HIST) { - hw_priv->ba_ena = ba_ena; + atomic_set(&hw_priv->ba_ena, ba_ena ? 1 : 0); hw_priv->ba_hist = 0; #if 0 bes_devel("[STA] %s block ACK:\n", @@ -2685,9 +2703,6 @@ void bes2600_ba_timer(struct timer_list *t) } } else if (hw_priv->ba_hist) --hw_priv->ba_hist; - -skip_statistic_update: - spin_unlock_bh(&hw_priv->ba_lock); } int bes2600_vif_setup(struct bes2600_vif *priv) diff --git a/bes2600/txrx.c b/bes2600/txrx.c index 7cdb7de..84c34bc 100644 --- a/bes2600/txrx.c +++ b/bes2600/txrx.c @@ -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,