]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: mac80211: add a TXQ for management frames on NAN devices
authorBenjamin Berg <benjamin.berg@intel.com>
Thu, 26 Mar 2026 10:14:31 +0000 (12:14 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 7 Apr 2026 13:36:02 +0000 (15:36 +0200)
Currently there is no TXQ for non-data frames. Add a new txq_mgmt for
this purpose and create one of these on NAN devices. On NAN devices,
these frames may only be transmitted during the discovery window and it
is therefore helpful to schedule them using a queue.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260326121156.32eddd986bd2.Iee95758287c276155fbd7779d3f263339308e083@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/mac80211.h
net/mac80211/iface.c
net/mac80211/tx.c
net/mac80211/util.c

index 72395895dc0e2b0f5103252c5c1859e56b7088b9..b1c412eabf2b1fd0fb48a211d3b456d4e394e7ab 100644 (file)
@@ -2074,6 +2074,7 @@ enum ieee80211_neg_ttlm_res {
  * @drv_priv: data area for driver use, will always be aligned to
  *     sizeof(void \*).
  * @txq: the multicast data TX queue
+ * @txq_mgmt: the mgmt frame TX queue, currently only exists for NAN devices
  * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
  *     &enum ieee80211_offload_flags.
  */
@@ -2092,6 +2093,7 @@ struct ieee80211_vif {
        u8 hw_queue[IEEE80211_NUM_ACS];
 
        struct ieee80211_txq *txq;
+       struct ieee80211_txq *txq_mgmt;
 
        netdev_features_t netdev_features;
        u32 driver_flags;
index 125897717a4c9290bd4d0bbb097c5383361e521d..7518dcbcdf1c6ceccc8603766638211e63288678 100644 (file)
@@ -682,6 +682,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
        if (sdata->vif.txq)
                ieee80211_txq_purge(sdata->local, to_txq_info(sdata->vif.txq));
 
+       if (sdata->vif.txq_mgmt)
+               ieee80211_txq_purge(sdata->local,
+                                   to_txq_info(sdata->vif.txq_mgmt));
+
        sdata->bss = NULL;
 
        if (local->open_count == 0)
@@ -2223,10 +2227,16 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
        lockdep_assert_wiphy(local->hw.wiphy);
 
        if (type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN) {
+               int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size,
+                                sizeof(void *));
                struct wireless_dev *wdev;
+               int txq_size = 0;
+
+               if (type == NL80211_IFTYPE_NAN)
+                       txq_size = sizeof(struct txq_info) +
+                                  local->hw.txq_data_size;
 
-               sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size,
-                               GFP_KERNEL);
+               sdata = kzalloc(size + txq_size, GFP_KERNEL);
                if (!sdata)
                        return -ENOMEM;
                wdev = &sdata->wdev;
@@ -2236,6 +2246,16 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                ieee80211_assign_perm_addr(local, wdev->address, type);
                memcpy(sdata->vif.addr, wdev->address, ETH_ALEN);
                ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
+
+               /*
+                * Add a management TXQ for NAN devices which includes frames
+                * that will only be transmitted during discovery windows (DWs)
+                */
+               if (type == NL80211_IFTYPE_NAN) {
+                       txqi = (struct txq_info *)((unsigned long)sdata + size);
+                       ieee80211_txq_init(sdata, NULL, txqi,
+                                          IEEE80211_NUM_TIDS);
+               }
        } else {
                int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size,
                                 sizeof(void *));
@@ -2386,6 +2406,10 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
        if (sdata->vif.txq)
                ieee80211_txq_purge(sdata->local, to_txq_info(sdata->vif.txq));
 
+       if (sdata->vif.txq_mgmt)
+               ieee80211_txq_purge(sdata->local,
+                                   to_txq_info(sdata->vif.txq_mgmt));
+
        synchronize_rcu();
 
        cfg80211_unregister_wdev(&sdata->wdev);
index e0091a6196fc2958db9b3142736151b493eef4c9..f0f23e94db0433fd4a86b62394f5d991d3b6119c 100644 (file)
@@ -1313,13 +1313,19 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
            unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
                if ((!ieee80211_is_mgmt(hdr->frame_control) ||
                     ieee80211_is_bufferable_mmpdu(skb) ||
-                    vif->type == NL80211_IFTYPE_STATION) &&
+                    vif->type == NL80211_IFTYPE_STATION ||
+                    vif->type == NL80211_IFTYPE_NAN ||
+                    vif->type == NL80211_IFTYPE_NAN_DATA) &&
                    sta && sta->uploaded) {
                        /*
                         * This will be NULL if the driver didn't set the
                         * opt-in hardware flag.
                         */
                        txq = sta->sta.txq[IEEE80211_NUM_TIDS];
+               } else if ((!ieee80211_is_mgmt(hdr->frame_control) ||
+                           ieee80211_is_bufferable_mmpdu(skb)) &&
+                          !sta) {
+                       txq = vif->txq_mgmt;
                }
        } else if (sta) {
                u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
@@ -1512,9 +1518,15 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
        txqi->txq.vif = &sdata->vif;
 
        if (!sta) {
-               sdata->vif.txq = &txqi->txq;
-               txqi->txq.tid = 0;
-               txqi->txq.ac = IEEE80211_AC_BE;
+               txqi->txq.tid = tid;
+
+               if (tid == IEEE80211_NUM_TIDS) {
+                       sdata->vif.txq_mgmt = &txqi->txq;
+                       txqi->txq.ac = IEEE80211_AC_VO;
+               } else {
+                       sdata->vif.txq = &txqi->txq;
+                       txqi->txq.ac = IEEE80211_AC_BE;
+               }
 
                return;
        }
index 8987a450452002859d9cf811d774d1305cc308ed..72e73f4f79c5f6ff2bd0eb98ef03ef72fd71fb10 100644 (file)
@@ -325,7 +325,7 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
        struct ieee80211_vif *vif = &sdata->vif;
        struct fq *fq = &local->fq;
        struct ps_data *ps = NULL;
-       struct txq_info *txqi;
+       struct txq_info *txqi = NULL;
        struct sta_info *sta;
        int i;
 
@@ -344,37 +344,49 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
 
                for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
                        struct ieee80211_txq *txq = sta->sta.txq[i];
+                       struct txq_info *sta_txqi;
 
                        if (!txq)
                                continue;
 
-                       txqi = to_txq_info(txq);
+                       sta_txqi = to_txq_info(txq);
 
                        if (ac != txq->ac)
                                continue;
 
                        if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY,
-                                               &txqi->flags))
+                                               &sta_txqi->flags))
                                continue;
 
                        spin_unlock(&fq->lock);
-                       drv_wake_tx_queue(local, txqi);
+                       drv_wake_tx_queue(local, sta_txqi);
                        spin_lock(&fq->lock);
                }
        }
 
-       if (!vif->txq)
-               goto out;
+       if (vif->txq) {
+               txqi = to_txq_info(vif->txq);
 
-       txqi = to_txq_info(vif->txq);
+               /* txq and txq_mgmt are mutually exclusive */
+               WARN_ON_ONCE(vif->txq_mgmt);
 
-       if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ||
-           (ps && atomic_read(&ps->num_sta_ps)) || ac != vif->txq->ac)
-               goto out;
+               if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ||
+                   (ps && atomic_read(&ps->num_sta_ps)) ||
+                   ac != vif->txq->ac)
+                       txqi = NULL;
+       } else if (vif->txq_mgmt) {
+               txqi = to_txq_info(vif->txq_mgmt);
+
+               if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ||
+                   ac != vif->txq_mgmt->ac)
+                       txqi = NULL;
+       }
 
        spin_unlock(&fq->lock);
 
-       drv_wake_tx_queue(local, txqi);
+       if (txqi)
+               drv_wake_tx_queue(local, txqi);
+
        local_bh_enable();
        return;
 out: