From 0ec58c0ad539e1e8d347b5527ce66cf847782338 Mon Sep 17 00:00:00 2001 From: Markus Fritsche Date: Fri, 8 May 2026 06:40:00 +0200 Subject: [PATCH] =?UTF-8?q?bes2600:=20Patch=20C2=20=E2=80=94=20replace=20i?= =?UTF-8?q?eee80211=5Frx=5Firqsafe=20with=20ieee80211=5Frx=5Fni?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per Phase 4 plan PR #14 + kerneldoc audit (Task #19). Six call sites deferred per-RX-frame mac80211 dispatch via tasklet; replace with the synchronous-from-process-context API ieee80211_rx_ni() which does its own local_bh_disable wrap. Why _ni and not _list: Phase 4 plan originally targeted ieee80211_rx_list for batch delivery. Mining mt76 mainline (the only driver using _list) showed the canonical pattern requires threading a struct list_head through the per-frame call chain. bes2600s WSM dispatcher (wsm_handle_rx -> bes2600_rx_cb / wsm.c beacon path) sits between the bh threads SDIO read and the mac80211 hand-off; threading a list_head through the dispatcher is a non-trivial refactor. ieee80211_rx_ni() is the simpler drop-in: no list management, still removes the tasklet hop. Per-call local_bh_disable cost is trivial vs the saved tasklet schedule. Future refactor can revisit _list if measurements warrant. Sites converted: - ap.c:96 (bes2600_sta_add link-id rx_queue drain on AP-mode STA add). Was inside spin_lock_bh(&ps_state_lock); refactored to splice the queue under the lock then deliver after unlock — _ni runs the synchronous mac80211 RX path inline, would otherwise hold the lock across mac80211 dispatch. splice via skb_queue_splice_init into a local sk_buff_head. - sta.c:1487 (deauth-frame inject in inactivity-event handler). Not under any lock; direct conversion. - txrx.c:1960 (early-data + pm_unsupported branch from Patch E). - txrx.c:1967 (early-data + LINK_SOFT-not-set branch). - txrx.c:1971 (normal RX path in bes2600_rx_cb). - wsm.c:2415 (beacon delivery in scan-complete WSM handler). beacon SKB ownership is preserved by the existing skb_copy(beacon, GFP_ATOMIC) -> beacon_bkp pattern; no lifecycle change needed. Mixing constraint (kerneldoc include/net/mac80211.h:5399-5430): ieee80211_rx_ni() cannot mix with ieee80211_rx_irqsafe() for a single hardware. All 6 sites convert atomically; no mixed state. Build verified clean on ohm sandbox: srcversion 619A51E61BF5479AAC146E6. Predicted Phase 7 delta: +5-15% over v3+D+E baseline (2.35 MB/s mean on v3 alone; D+E single-rep was 3.22 MB/s). Modest improvement expected from removing the tasklet schedule per RX frame. Smaller deltas would still be a net win for upstream-cleanliness — the kernel.org submission story benefits from not using _irqsafe from process context. --- bes2600/ap.c | 15 +++++++++++++-- bes2600/sta.c | 2 +- bes2600/txrx.c | 6 +++--- bes2600/wsm.c | 2 +- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/bes2600/ap.c b/bes2600/ap.c index 0a23790..6d4428c 100644 --- a/bes2600/ap.c +++ b/bes2600/ap.c @@ -62,8 +62,11 @@ int bes2600_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct bes2600_vif *priv = cw12xx_get_vif_from_ieee80211(vif); struct bes2600_link_entry *entry; struct sk_buff *skb; + struct sk_buff_head local_drain; struct bes2600_common *hw_priv = hw->priv; + __skb_queue_head_init(&local_drain); + #ifdef P2P_MULTIVIF WARN_ON(priv->if_id == CW12XX_GENERIC_IF_ID); #endif @@ -92,9 +95,17 @@ int bes2600_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) priv->sta_asleep_mask |= BIT(sta_priv->link_id); entry->status = BES2600_LINK_HARD; - while ((skb = skb_dequeue(&entry->rx_queue))) - ieee80211_rx_irqsafe(priv->hw, skb); + /* + * Patch C2: splice the rx_queue out under the lock then deliver + * after unlock. ieee80211_rx_ni() runs the mac80211 RX path + * synchronously (formerly ieee80211_rx_irqsafe deferred to a + * tasklet); calling it from inside spin_lock_bh would hold the + * lock across mac80211's full RX dispatch. + */ + skb_queue_splice_init(&entry->rx_queue, &local_drain); spin_unlock_bh(&priv->ps_state_lock); + while ((skb = __skb_dequeue(&local_drain))) + ieee80211_rx_ni(priv->hw, skb); #ifdef AP_AGGREGATE_FW_FIX hw_priv->connected_sta_cnt++; if(hw_priv->connected_sta_cnt>1) { diff --git a/bes2600/sta.c b/bes2600/sta.c index 7caeb4b..e64841a 100644 --- a/bes2600/sta.c +++ b/bes2600/sta.c @@ -1484,7 +1484,7 @@ void bes2600_event_handler(struct work_struct *work) IEEE80211_STYPE_DEAUTH | IEEE80211_FCTL_TODS); deauth->u.deauth.reason_code = WLAN_REASON_DEAUTH_LEAVING; deauth->seq_ctrl = 0; - ieee80211_rx_irqsafe(priv->hw, skb); + ieee80211_rx_ni(priv->hw, skb); bes_devel(" Inactivity Deauth Frame sent for MAC SA %pM \t and DA %pM\n", deauth->sa, deauth->da); queue_work(priv->hw_priv->workqueue, &priv->set_tim_work); break; diff --git a/bes2600/txrx.c b/bes2600/txrx.c index bf17777..de521a3 100644 --- a/bes2600/txrx.c +++ b/bes2600/txrx.c @@ -1957,18 +1957,18 @@ void bes2600_rx_cb(struct bes2600_vif *priv, * path is taken. */ if (hw_priv->bes_power.pm_unsupported) { - ieee80211_rx_irqsafe(priv->hw, skb); + ieee80211_rx_ni(priv->hw, skb); } else { spin_lock_bh(&priv->ps_state_lock); /* Double-check status with lock held */ if (entry->status == BES2600_LINK_SOFT) skb_queue_tail(&entry->rx_queue, skb); else - ieee80211_rx_irqsafe(priv->hw, skb); + ieee80211_rx_ni(priv->hw, skb); spin_unlock_bh(&priv->ps_state_lock); } } else { - ieee80211_rx_irqsafe(priv->hw, skb); + ieee80211_rx_ni(priv->hw, skb); } *skb_p = NULL; diff --git a/bes2600/wsm.c b/bes2600/wsm.c index 908c965..2424181 100644 --- a/bes2600/wsm.c +++ b/bes2600/wsm.c @@ -2412,7 +2412,7 @@ int wsm_handle_rx(struct bes2600_common *hw_priv, int id, if (!hw_priv->beacon_bkp) hw_priv->beacon_bkp = \ skb_copy(hw_priv->beacon, GFP_ATOMIC); - ieee80211_rx_irqsafe(hw_priv->hw, hw_priv->beacon); + ieee80211_rx_ni(hw_priv->hw, hw_priv->beacon); hw_priv->beacon = hw_priv->beacon_bkp; hw_priv->beacon_bkp = NULL;