bes2600: Patch C2 — replace ieee80211_rx_irqsafe with ieee80211_rx_ni

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.
This commit is contained in:
2026-05-08 06:40:00 +02:00
parent 42fd0ceab6
commit 0ec58c0ad5
4 changed files with 18 additions and 7 deletions
+13 -2
View File
@@ -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_vif *priv = cw12xx_get_vif_from_ieee80211(vif);
struct bes2600_link_entry *entry; struct bes2600_link_entry *entry;
struct sk_buff *skb; struct sk_buff *skb;
struct sk_buff_head local_drain;
struct bes2600_common *hw_priv = hw->priv; struct bes2600_common *hw_priv = hw->priv;
__skb_queue_head_init(&local_drain);
#ifdef P2P_MULTIVIF #ifdef P2P_MULTIVIF
WARN_ON(priv->if_id == CW12XX_GENERIC_IF_ID); WARN_ON(priv->if_id == CW12XX_GENERIC_IF_ID);
#endif #endif
@@ -92,9 +95,17 @@ int bes2600_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
priv->sta_asleep_mask |= BIT(sta_priv->link_id); priv->sta_asleep_mask |= BIT(sta_priv->link_id);
entry->status = BES2600_LINK_HARD; 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); spin_unlock_bh(&priv->ps_state_lock);
while ((skb = __skb_dequeue(&local_drain)))
ieee80211_rx_ni(priv->hw, skb);
#ifdef AP_AGGREGATE_FW_FIX #ifdef AP_AGGREGATE_FW_FIX
hw_priv->connected_sta_cnt++; hw_priv->connected_sta_cnt++;
if(hw_priv->connected_sta_cnt>1) { if(hw_priv->connected_sta_cnt>1) {
+1 -1
View File
@@ -1484,7 +1484,7 @@ void bes2600_event_handler(struct work_struct *work)
IEEE80211_STYPE_DEAUTH | IEEE80211_FCTL_TODS); IEEE80211_STYPE_DEAUTH | IEEE80211_FCTL_TODS);
deauth->u.deauth.reason_code = WLAN_REASON_DEAUTH_LEAVING; deauth->u.deauth.reason_code = WLAN_REASON_DEAUTH_LEAVING;
deauth->seq_ctrl = 0; 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); 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); queue_work(priv->hw_priv->workqueue, &priv->set_tim_work);
break; break;
+3 -3
View File
@@ -1957,18 +1957,18 @@ void bes2600_rx_cb(struct bes2600_vif *priv,
* path is taken. * path is taken.
*/ */
if (hw_priv->bes_power.pm_unsupported) { if (hw_priv->bes_power.pm_unsupported) {
ieee80211_rx_irqsafe(priv->hw, skb); ieee80211_rx_ni(priv->hw, skb);
} else { } else {
spin_lock_bh(&priv->ps_state_lock); spin_lock_bh(&priv->ps_state_lock);
/* Double-check status with lock held */ /* Double-check status with lock held */
if (entry->status == BES2600_LINK_SOFT) if (entry->status == BES2600_LINK_SOFT)
skb_queue_tail(&entry->rx_queue, skb); skb_queue_tail(&entry->rx_queue, skb);
else else
ieee80211_rx_irqsafe(priv->hw, skb); ieee80211_rx_ni(priv->hw, skb);
spin_unlock_bh(&priv->ps_state_lock); spin_unlock_bh(&priv->ps_state_lock);
} }
} else { } else {
ieee80211_rx_irqsafe(priv->hw, skb); ieee80211_rx_ni(priv->hw, skb);
} }
*skb_p = NULL; *skb_p = NULL;
+1 -1
View File
@@ -2412,7 +2412,7 @@ int wsm_handle_rx(struct bes2600_common *hw_priv, int id,
if (!hw_priv->beacon_bkp) if (!hw_priv->beacon_bkp)
hw_priv->beacon_bkp = \ hw_priv->beacon_bkp = \
skb_copy(hw_priv->beacon, GFP_ATOMIC); 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 = hw_priv->beacon_bkp;
hw_priv->beacon_bkp = NULL; hw_priv->beacon_bkp = NULL;