Files
kernel-agent/patches/driver/bes2600/ba-lock-atomic-danctnix/0001-bes2600-Patch-D-atomicize-ba_lock-counters-drop-the-spinlock.patch
T
claude-noether 8b356aa11f patches/driver/bes2600/*-danctnix: reconstruct from cleanups (closes #29)
Replaces the 13 broken DKMS-path -danctnix mirrors from PR #17 + adds
9 new series-dirs for the c-stack patches that were never split
(Patches A/B/C-v3/F/D/E/C2/G/H) + retires the cumulative-c5x-danctnix
single-file interim from fleet/ohm.yaml.

Mechanism:
  cd marfrit/bes2600-dkms-mobian
  git format-patch fe73571..cleanups --no-merges -o /tmp/cleanups/
  git format-patch cleanups..bes2600/bh-c-fossil-cleanup --no-merges -o /tmp/h/
  for each commit: route to series-dir, sed-rewrite
                   a/bes2600/foo.c -> a/drivers/staging/bes2600/foo.c

The 29 cleanups commits + 1 Patch H commit map to 25 series-dirs (a
few series-dirs get multiple commits: lmac-recover gets c5.2 + c5.2.1
as 0001+0002; cw1200-fix-backports gets F3+F2+F1 as 0001-0003;
factory-series gets request_firmware + STANDARD_FACTORY_EFUSE_FLAG
as 0001+0002).

fleet/ohm.yaml apply order matches cleanups commit chronology, which
is what produced the working c5x interim. cumulative.patch from
ka-promote ohm now has 32 resolved patches (29 cleanups + 1 Patch H
+ scan-filter-5ghz + xor-neon SCS + besser#18-fix), 276 079 bytes,
b2sum 7418db5ddf8fe938b130bc9d0e9f7dc9060f3a13703cd50757835ac43140a13...

Apply order in cleanups + bh-c-fossil-cleanup:
  1   factory-series                       (c1 + factory-no-efuse-flag)
  3   factory-thread-dev
  4   pm-gate-on-handshake
  5   remove-chardev-user-interface
  6   enable-testmode
  7   tx-sdio-dma-oob-danctnix             (was 'staging-prep-series')
  8   factory-drop-kernel-write-danctnix
  9   drop-dpd-file-paths-danctnix
  10  drop-orphan-file-io-danctnix
  11  pm-timeout-silence-danctnix
  12  scan-defer-on-reject-danctnix        (c5.1)
  13  scan-defer-backoff-tune-danctnix     (c5.1.1)
  14  lmac-recover-via-mmc-hw-reset-danctnix  (c5.2 + c5.2.1)
  16  pm-state-resync-danctnix             (c6.1)
  17  pm-wake-consume-state-danctnix       (c6.2)
  18  pm-detect-firmware-unsupported-danctnix (c7)
  19  decrypt-storm-fast-recover-danctnix  (Patch A)
  20  connection-loss-fast-recover-danctnix (Patch B)
  21  cw1200-fix-backports-danctnix        (Patches F3 + F2 + F1)
  24  sdio-rx-no-relay-danctnix            (Patch C v3)
  25  license-spdx-restore-attribution-danctnix (Patch G)
  26  ba-lock-atomic-danctnix              (Patch D)
  27  ps-state-lock-skip-pm-disabled-danctnix (Patch E)
  28  rx-list-batch-delivery-danctnix      (Patch C2)
  29  bh-c-fossil-cleanup-danctnix         (Patch H)
  30  scan-filter-5ghz-danctnix            (besser#1)
  31  arch/arm64/xor-neon-...              (GCC 15 SCS)
  32  queue-pending-record-lock-bh-danctnix (besser#18)

Verification: pkgrel=6 build from this manifest in progress; if
srcversion == 26B0003FE9F2B05DCE838C4 (pkgrel=5's), source-tree is
byte-equivalent to the c5x interim + scan-filter + besser#18 stack
that's currently running on ohm.

Refs: #17 (the broken mirror), #28 (the interim PR that landed
cumulative-c5x), #31 (ka-promote trailer normalisation followup).
2026-05-19 06:41:37 +02:00

314 lines
12 KiB
Diff

From 44b296647be9246c6802a86c082c6507669810b0 Mon Sep 17 00:00:00 2001
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Fri, 8 May 2026 00:17:46 +0200
Subject: [PATCH 27/29] =?UTF-8?q?bes2600:=20Patch=20D=20=E2=80=94=20atomic?=
=?UTF-8?q?ize=20ba=5Flock=20counters,=20drop=20the=20spinlock?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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.
---
bes2600/bes2600.h | 26 ++++++++++------
bes2600/debug.c | 13 +++++---
bes2600/main.c | 2 +-
bes2600/sta.c | 77 ++++++++++++++++++++++++++++-------------------
bes2600/txrx.c | 23 ++++++++------
5 files changed, 85 insertions(+), 56 deletions(-)
diff --git a/drivers/staging/bes2600/bes2600.h b/drivers/staging/bes2600/bes2600.h
index ec41141..31a411b 100644
--- a/drivers/staging/bes2600/bes2600.h
+++ b/drivers/staging/bes2600/bes2600.h
@@ -356,15 +356,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/drivers/staging/bes2600/debug.c b/drivers/staging/bes2600/debug.c
index 0d68392..2d144ac 100644
--- a/drivers/staging/bes2600/debug.c
+++ b/drivers/staging/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/drivers/staging/bes2600/main.c b/drivers/staging/bes2600/main.c
index 90a8ff8..be375f5 100644
--- a/drivers/staging/bes2600/main.c
+++ b/drivers/staging/bes2600/main.c
@@ -490,7 +490,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/drivers/staging/bes2600/sta.c b/drivers/staging/bes2600/sta.c
index 81f88ed..d94dd2e 100644
--- a/drivers/staging/bes2600/sta.c
+++ b/drivers/staging/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/drivers/staging/bes2600/txrx.c b/drivers/staging/bes2600/txrx.c
index 346312c..82ef6fa 100644
--- a/drivers/staging/bes2600/txrx.c
+++ b/drivers/staging/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,
--
2.54.0