From: Benjamin Berg 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. type=feature ticket=none Signed-off-by: Benjamin Berg --- include/net/mac80211.h | 2 ++ net/mac80211/iface.c | 28 ++++++++++++++++++++++++++-- net/mac80211/tx.c | 16 +++++++++++++--- net/mac80211/util.c | 33 +++++++++++++++++++++++++-------- 4 files changed, 66 insertions(+), 13 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c2e49542626c..8874e5eeae7d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2034,6 +2034,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. */ @@ -2052,6 +2053,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; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 4f04d95c19d4..764f8acaacd8 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -678,6 +678,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) @@ -2200,10 +2204,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; @@ -2213,6 +2223,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 *)); @@ -2363,6 +2383,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); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9d8b0a25f73c..99b4fd51e28c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1321,6 +1321,10 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local, * 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; @@ -1513,9 +1517,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; } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0c46009a3d63..ef7ea78da736 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -326,7 +326,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 *to_wake[2] = {}; struct sta_info *sta; int i; @@ -345,6 +345,7 @@ 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 *txqi; if (!txq) continue; @@ -364,18 +365,34 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac) } } - if (!vif->txq) - goto out; + if (vif->txq) { + struct txq_info *txqi; - txqi = to_txq_info(vif->txq); + txqi = to_txq_info(vif->txq); - 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) + to_wake[0] = txqi; + } + + if (vif->txq_mgmt) { + struct txq_info *txqi; + + txqi = to_txq_info(vif->txq_mgmt); + + if (test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) && + ac == vif->txq->ac) + to_wake[1] = txqi; + } spin_unlock(&fq->lock); - drv_wake_tx_queue(local, txqi); + if (to_wake[0]) + drv_wake_tx_queue(local, to_wake[0]); + if (to_wake[1]) + drv_wake_tx_queue(local, to_wake[0]); + local_bh_enable(); return; out: -- 2.51.1