All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 1/6] mac80211: agg-tx: call drv_wake_tx_queue in proper context
@ 2017-06-21 23:50 Johannes Berg
  2017-06-21 23:50 ` [RFC 2/6] mac80211: fix VLAN handling with TXQs Johannes Berg
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Johannes Berg @ 2017-06-21 23:50 UTC (permalink / raw)
  To: linux-wireless; +Cc: nbd, Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Since drv_wake_tx_queue() is normally called in the TX path, which
is already in an RCU critical section, we should call it the same
way in the aggregation code path, so if the driver expects to be
able to use RCU, it'll already be protected without having to enter
a nested critical section.

Additionally, disable soft-IRQs, since not doing so could cause
issues in a driver that relies on them already being disabled like
in the other path.

Fixes: ba8c3d6f16a1 ("mac80211: add an intermediate software queue implementation")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/agg-tx.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index cbd48762256c..4f9dd3e59091 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -226,7 +226,11 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
 		clear_bit(IEEE80211_TXQ_AMPDU, &txqi->flags);
 
 	clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
+	local_bh_disable();
+	rcu_read_lock();
 	drv_wake_tx_queue(sta->sdata->local, txqi);
+	rcu_read_unlock();
+	local_bh_enable();
 }
 
 /*
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 2/6] mac80211: fix VLAN handling with TXQs
  2017-06-21 23:50 [RFC 1/6] mac80211: agg-tx: call drv_wake_tx_queue in proper context Johannes Berg
@ 2017-06-21 23:50 ` Johannes Berg
  2017-06-21 23:50 ` [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames Johannes Berg
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Johannes Berg @ 2017-06-21 23:50 UTC (permalink / raw)
  To: linux-wireless; +Cc: nbd, Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

With TXQs, the AP_VLAN interfaces are resolved to their owner AP
interface when enqueuing the frame, which makes sense since the
frame really goes out on that as far as the driver is concerned.

However, this introduces a problem: frames to be encrypted with
a VLAN-specific GTK will now be encrypted with the AP GTK, since
the information about which virtual interface to use to select
the key is taken from the TXQ.

Fix this by preserving info->control.vif and using that in the
dequeue function. This now requires doing the driver-mapping
in the dequeue as well.

TODO: need to purge frames when stopping the AP_VLAN interface!!

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/mac80211.h | 15 ++-------------
 net/mac80211/tx.c      | 39 +++++++++++++++++++++++++++++++--------
 2 files changed, 33 insertions(+), 21 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index b2b5419467cc..263cb30d77c8 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -919,21 +919,10 @@ struct ieee80211_tx_info {
 				unsigned long jiffies;
 			};
 			/* NB: vif can be NULL for injected frames */
-			union {
-				/* NB: vif can be NULL for injected frames */
-				struct ieee80211_vif *vif;
-
-				/* When packets are enqueued on txq it's easy
-				 * to re-construct the vif pointer. There's no
-				 * more space in tx_info so it can be used to
-				 * store the necessary enqueue time for packet
-				 * sojourn time computation.
-				 */
-				codel_time_t enqueue_time;
-			};
+			struct ieee80211_vif *vif;
 			struct ieee80211_key_conf *hw_key;
 			u32 flags;
-			/* 4 bytes free */
+			codel_time_t enqueue_time;
 		} control;
 		struct {
 			u64 cookie;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 8858f4f185e9..bd609326d77c 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1276,11 +1276,6 @@ static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
 	IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
 }
 
-static void ieee80211_set_skb_vif(struct sk_buff *skb, struct txq_info *txqi)
-{
-	IEEE80211_SKB_CB(skb)->control.vif = txqi->txq.vif;
-}
-
 static u32 codel_skb_len_func(const struct sk_buff *skb)
 {
 	return skb->len;
@@ -3414,6 +3409,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
 	struct ieee80211_tx_info *info;
 	struct ieee80211_tx_data tx;
 	ieee80211_tx_result r;
+	struct ieee80211_vif *vif;
 
 	spin_lock_bh(&fq->lock);
 
@@ -3430,8 +3426,6 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
 	if (!skb)
 		goto out;
 
-	ieee80211_set_skb_vif(skb, txqi);
-
 	hdr = (struct ieee80211_hdr *)skb->data;
 	info = IEEE80211_SKB_CB(skb);
 
@@ -3439,7 +3433,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
 	__skb_queue_head_init(&tx.skbs);
 	tx.local = local;
 	tx.skb = skb;
-	tx.sdata = vif_to_sdata(info->control.vif);
+	if (info->control.vif)
+		tx.sdata = vif_to_sdata(info->control.vif);
 
 	if (txq->sta)
 		tx.sta = container_of(txq->sta, struct sta_info, sta);
@@ -3488,6 +3483,34 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
 		}
 	}
 
+	switch (tx.sdata->vif.type) {
+	case NL80211_IFTYPE_MONITOR:
+		if (tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
+			vif = &tx.sdata->vif;
+			break;
+		}
+		tx.sdata = rcu_dereference(local->monitor_sdata);
+		if (tx.sdata) {
+			vif = &tx.sdata->vif;
+			info->hw_queue =
+				vif->hw_queue[skb_get_queue_mapping(skb)];
+		} else if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) {
+			ieee80211_free_txskb(&local->hw, skb);
+			goto begin;
+		} else {
+			vif = NULL;
+		}
+		break;
+	case NL80211_IFTYPE_AP_VLAN:
+		tx.sdata = container_of(tx.sdata->bss,
+					struct ieee80211_sub_if_data, u.ap);
+		/* fall through */
+	default:
+		vif = &tx.sdata->vif;
+		break;
+	}
+
+	IEEE80211_SKB_CB(skb)->control.vif = vif;
 out:
 	spin_unlock_bh(&fq->lock);
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames
  2017-06-21 23:50 [RFC 1/6] mac80211: agg-tx: call drv_wake_tx_queue in proper context Johannes Berg
  2017-06-21 23:50 ` [RFC 2/6] mac80211: fix VLAN handling with TXQs Johannes Berg
@ 2017-06-21 23:50 ` Johannes Berg
  2017-06-22  0:02   ` Ben Greear
  2017-06-21 23:50 ` [RFC 4/6] mac80211: don't put null-data frames on the normal TXQ Johannes Berg
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Johannes Berg @ 2017-06-21 23:50 UTC (permalink / raw)
  To: linux-wireless; +Cc: nbd, Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Some drivers may want to also use the TXQ abstraction with
non-data packets that need powersave buffering, so add a
hardware flag to allow this.

Change ath9k/ath10k to use these by dequeuing the frames
immediately and invoking the normal TX path for them.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/net/wireless/ath/ath10k/mac.c  | 13 +++++++++++++
 drivers/net/wireless/ath/ath9k/ath9k.h |  2 ++
 drivers/net/wireless/ath/ath9k/main.c  |  5 ++---
 drivers/net/wireless/ath/ath9k/xmit.c  | 20 ++++++++++++++++++--
 include/net/mac80211.h                 | 13 ++++++++-----
 net/mac80211/debugfs_sta.c             |  4 ++--
 net/mac80211/rx.c                      |  2 +-
 net/mac80211/tx.c                      | 16 +++++++++++-----
 8 files changed, 57 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 16cf250f6c39..ee11a01e4f61 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4236,6 +4236,19 @@ static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw,
 	int ret = 0;
 	int max = 16;
 
+	if (unlikely(txq->tid == IEEE80211_NUM_TIDS)) {
+		struct sk_buff *skb = ieee80211_tx_dequeue(hw, txq);
+		struct ieee80211_tx_control control = {
+			.sta = txq->sta,
+		};
+
+		if (WARN_ON(!skb))
+			return;
+
+		ath10k_mac_op_tx(hw, &control, skb);
+		return;
+	}
+
 	spin_lock_bh(&ar->txqs_lock);
 	if (list_empty(&artxq->list))
 		list_add_tail(&artxq->list, &ar->txqs);
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index cf076719c27e..4a427248e9fe 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -618,6 +618,8 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
 				   u16 tids, int nframes,
 				   enum ieee80211_frame_release_type reason,
 				   bool more_data);
+void ath9k_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
+	      struct sk_buff *skb);
 void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue);
 
 /********/
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 9e65d14e7b1e..6ddb01d26ac6 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -740,9 +740,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	return 0;
 }
 
-static void ath9k_tx(struct ieee80211_hw *hw,
-		     struct ieee80211_tx_control *control,
-		     struct sk_buff *skb)
+void ath9k_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
+	      struct sk_buff *skb)
 {
 	struct ath_softc *sc = hw->priv;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 396bf05c6bf6..8ff00ebff261 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -154,8 +154,24 @@ void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
 {
 	struct ath_softc *sc = hw->priv;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
-	struct ath_txq *txq = tid->txq;
+	struct ath_atx_tid *tid;
+	struct ath_txq *txq;
+
+	if (unlikely(queue->tid == IEEE80211_NUM_TIDS)) {
+		struct sk_buff *skb = ieee80211_tx_dequeue(hw, queue);
+		struct ieee80211_tx_control control = {
+			.sta = queue->sta,
+		};
+
+		if (WARN_ON(!skb))
+			return;
+
+		ath9k_tx(hw, &control, skb);
+		return;
+	}
+
+	tid = (struct ath_atx_tid *) queue->drv_priv;
+	txq = tid->txq;
 
 	ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
 		queue->sta ? queue->sta->addr : queue->vif->addr,
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 263cb30d77c8..871e4399a999 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -99,8 +99,9 @@
  * Drivers indicate that they use this model by implementing the .wake_tx_queue
  * driver operation.
  *
- * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with a
- * single per-vif queue for multicast data frames.
+ * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with
+ * another per-sta for non-data/non-mgmt and bufferable management frames, and
+ * a single per-vif queue for multicast data frames.
  *
  * The driver is expected to initialize its private per-queue data for stations
  * and interfaces in the .add_interface and .sta_add ops.
@@ -1783,7 +1784,8 @@ struct ieee80211_sta_rates {
  *	unlimited.
  * @support_p2p_ps: indicates whether the STA supports P2P PS mechanism or not.
  * @max_rc_amsdu_len: Maximum A-MSDU size in bytes recommended by rate control.
- * @txq: per-TID data TX queues (if driver uses the TXQ abstraction)
+ * @txq: per-TID data TX queues (if driver uses the TXQ abstraction); note that
+ *	the last entry (%IEEE80211_NUM_TIDS) is used for non-data frames
  */
 struct ieee80211_sta {
 	u32 supp_rates[NUM_NL80211_BANDS];
@@ -1823,7 +1825,7 @@ struct ieee80211_sta {
 	bool support_p2p_ps;
 	u16 max_rc_amsdu_len;
 
-	struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
+	struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1];
 
 	/* must be last */
 	u8 drv_priv[0] __aligned(sizeof(void *));
@@ -1857,7 +1859,8 @@ struct ieee80211_tx_control {
  *
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @sta: station table entry, %NULL for per-vif queue
- * @tid: the TID for this queue (unused for per-vif queue)
+ * @tid: the TID for this queue (unused for per-vif queue),
+ *	%IEEE80211_NUM_TIDS for non-data (if enabled)
  * @ac: the AC for this queue
  * @drv_priv: driver private area, sized by hw->txq_data_size
  *
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index b15412c21ac9..d046c17ea48d 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -140,7 +140,7 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
 {
 	struct sta_info *sta = file->private_data;
 	struct ieee80211_local *local = sta->local;
-	size_t bufsz = AQM_TXQ_ENTRY_LEN*(IEEE80211_NUM_TIDS+1);
+	size_t bufsz = AQM_TXQ_ENTRY_LEN * (IEEE80211_NUM_TIDS + 2);
 	char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
 	struct txq_info *txqi;
 	ssize_t rv;
@@ -162,7 +162,7 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
 		       bufsz+buf-p,
 		       "tid ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n");
 
-	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+	for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
 		txqi = to_txq_info(sta->sta.txq[i]);
 		p += scnprintf(p, bufsz+buf-p,
 			       "%d %d %u %u %u %u %u %u %u %u %u\n",
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 70e9d2ca8bbe..0444e2f0169f 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1387,7 +1387,7 @@ static void sta_ps_start(struct sta_info *sta)
 	if (!sta->sta.txq[0])
 		return;
 
-	for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
+	for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
 		if (txq_has_queue(sta->sta.txq[tid]))
 			set_bit(tid, &sta->txq_buffered_tids);
 		else
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index bd609326d77c..1b3ac635fbdd 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4,6 +4,7 @@
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright 2017	Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1251,10 +1252,12 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
 	    (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
 		return NULL;
 
-	if (!ieee80211_is_data(hdr->frame_control))
-		return NULL;
-
-	if (sta) {
+	if (!ieee80211_is_data(hdr->frame_control)) {
+		if ((!ieee80211_is_mgmt(hdr->frame_control) ||
+		     ieee80211_is_bufferable_mmpdu(hdr->frame_control)) &&
+		    sta && sta->uploaded)
+			txq = sta->sta.txq[IEEE80211_NUM_TIDS];
+	} else if (sta) {
 		u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
 
 		if (!sta->uploaded)
@@ -1412,7 +1415,10 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
 		txqi->txq.sta = &sta->sta;
 		sta->sta.txq[tid] = &txqi->txq;
 		txqi->txq.tid = tid;
-		txqi->txq.ac = ieee80211_ac_from_tid(tid);
+		if (tid == IEEE80211_NUM_TIDS)
+			txqi->txq.ac = IEEE80211_AC_VO;
+		else
+			txqi->txq.ac = ieee80211_ac_from_tid(tid);
 	} else {
 		sdata->vif.txq = &txqi->txq;
 		txqi->txq.tid = 0;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 4/6] mac80211: don't put null-data frames on the normal TXQ
  2017-06-21 23:50 [RFC 1/6] mac80211: agg-tx: call drv_wake_tx_queue in proper context Johannes Berg
  2017-06-21 23:50 ` [RFC 2/6] mac80211: fix VLAN handling with TXQs Johannes Berg
  2017-06-21 23:50 ` [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames Johannes Berg
@ 2017-06-21 23:50 ` Johannes Berg
  2017-06-21 23:50 ` [RFC 5/6] mac80211: add a general fallback TXQ Johannes Berg
  2017-06-21 23:50 ` [RFC 6/6] mac80211: always go through txqs Johannes Berg
  4 siblings, 0 replies; 15+ messages in thread
From: Johannes Berg @ 2017-06-21 23:50 UTC (permalink / raw)
  To: linux-wireless; +Cc: nbd, Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Since (QoS) NDP frames shouldn't be put into aggregation nor are
assigned real sequence numbers, etc. it's better to treat them as
non-data packets and not put them on the normal TXQs.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/tx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1b3ac635fbdd..d2a91594312d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1252,7 +1252,7 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
 	    (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
 		return NULL;
 
-	if (!ieee80211_is_data(hdr->frame_control)) {
+	if (!ieee80211_is_data_present(hdr->frame_control)) {
 		if ((!ieee80211_is_mgmt(hdr->frame_control) ||
 		     ieee80211_is_bufferable_mmpdu(hdr->frame_control)) &&
 		    sta && sta->uploaded)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 5/6] mac80211: add a general fallback TXQ
  2017-06-21 23:50 [RFC 1/6] mac80211: agg-tx: call drv_wake_tx_queue in proper context Johannes Berg
                   ` (2 preceding siblings ...)
  2017-06-21 23:50 ` [RFC 4/6] mac80211: don't put null-data frames on the normal TXQ Johannes Berg
@ 2017-06-21 23:50 ` Johannes Berg
  2017-06-22  8:48   ` Johannes Berg
  2017-06-21 23:50 ` [RFC 6/6] mac80211: always go through txqs Johannes Berg
  4 siblings, 1 reply; 15+ messages in thread
From: Johannes Berg @ 2017-06-21 23:50 UTC (permalink / raw)
  To: linux-wireless; +Cc: nbd, Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

In a number of cases, like management frames, mac80211 will not
put the frame on any TXQ but immediately TX it to the driver.
It'd be nicer to be able to use TXQs for all frames, so add a
"fallback" TXQ. This will serve as a container to be able to
remove all the non-TXQ queueing in mac80211.

For ath9k/ath10k, extend the code that already handles the STA
mgmt TXQ by code to handle the per-HW fallback queue. Since that
may now carry fragmented frames, extend the logic a bit.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/net/wireless/ath/ath10k/mac.c | 10 +++---
 drivers/net/wireless/ath/ath9k/xmit.c | 10 +++---
 include/net/mac80211.h                | 15 +++++++--
 net/mac80211/driver-ops.h             |  7 ++--
 net/mac80211/ieee80211_i.h            |  3 +-
 net/mac80211/iface.c                  |  2 +-
 net/mac80211/main.c                   | 18 +++++++++++
 net/mac80211/sta_info.c               |  2 +-
 net/mac80211/tx.c                     | 60 +++++++++++++++++++----------------
 9 files changed, 79 insertions(+), 48 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index ee11a01e4f61..437906c6df77 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4236,16 +4236,14 @@ static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw,
 	int ret = 0;
 	int max = 16;
 
-	if (unlikely(txq->tid == IEEE80211_NUM_TIDS)) {
-		struct sk_buff *skb = ieee80211_tx_dequeue(hw, txq);
+	if (unlikely(txq == hw->txq || txq->tid == IEEE80211_NUM_TIDS)) {
 		struct ieee80211_tx_control control = {
 			.sta = txq->sta,
 		};
+		struct sk_buff *skb;
 
-		if (WARN_ON(!skb))
-			return;
-
-		ath10k_mac_op_tx(hw, &control, skb);
+		while ((skb = ieee80211_tx_dequeue(hw, txq)))
+			ath10k_mac_op_tx(hw, &control, skb);
 		return;
 	}
 
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 8ff00ebff261..5dbf4fcd66c3 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -157,16 +157,14 @@ void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
 	struct ath_atx_tid *tid;
 	struct ath_txq *txq;
 
-	if (unlikely(queue->tid == IEEE80211_NUM_TIDS)) {
-		struct sk_buff *skb = ieee80211_tx_dequeue(hw, queue);
+	if (unlikely(queue == hw->txq || queue->tid == IEEE80211_NUM_TIDS)) {
 		struct ieee80211_tx_control control = {
 			.sta = queue->sta,
 		};
+		struct sk_buff *skb;
 
-		if (WARN_ON(!skb))
-			return;
-
-		ath9k_tx(hw, &control, skb);
+		while ((skb = ieee80211_tx_dequeue(hw, queue)))
+			ath9k_tx(hw, &control, skb);
 		return;
 	}
 
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 871e4399a999..f2c6f0e0f928 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -101,10 +101,12 @@
  *
  * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with
  * another per-sta for non-data/non-mgmt and bufferable management frames, and
- * a single per-vif queue for multicast data frames.
+ * a single per-vif queue for multicast data frames and one additional queue
+ * for the HW for all other frames.
  *
  * The driver is expected to initialize its private per-queue data for stations
- * and interfaces in the .add_interface and .sta_add ops.
+ * and interfaces in the .add_interface and .sta_add ops or before calling
+ * ieee80211_register_hw() (for the general HW queue).
  *
  * The driver can't access the queue directly. To dequeue a frame, it calls
  * ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a queue, it
@@ -1857,7 +1859,9 @@ struct ieee80211_tx_control {
 /**
  * struct ieee80211_txq - Software intermediate tx queue
  *
- * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @hw: &struct ieee80211_hw pointer for the device this is used on
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback,
+ *	%NULL for the "fallback" TXQ (in &struct ieee80211_hw)
  * @sta: station table entry, %NULL for per-vif queue
  * @tid: the TID for this queue (unused for per-vif queue),
  *	%IEEE80211_NUM_TIDS for non-data (if enabled)
@@ -1868,6 +1872,7 @@ struct ieee80211_tx_control {
  * ieee80211_tx_dequeue().
  */
 struct ieee80211_txq {
+	struct ieee80211_hw *hw;
 	struct ieee80211_vif *vif;
 	struct ieee80211_sta *sta;
 	u8 tid;
@@ -2216,6 +2221,8 @@ enum ieee80211_hw_flags {
  *	supported by HW.
  * @max_nan_de_entries: maximum number of NAN DE functions supported by the
  *	device.
+ *
+ * @txq: TXQ for (management) frames not otherwise handled on station/vif TXQs
  */
 struct ieee80211_hw {
 	struct ieee80211_conf conf;
@@ -2251,6 +2258,8 @@ struct ieee80211_hw {
 	u8 n_cipher_schemes;
 	const struct ieee80211_cipher_scheme *cipher_schemes;
 	u8 max_nan_de_entries;
+
+	struct ieee80211_txq *txq;
 };
 
 static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 09f77e4a8a79..0299f73d5122 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1160,9 +1160,12 @@ drv_tdls_recv_channel_switch(struct ieee80211_local *local,
 static inline void drv_wake_tx_queue(struct ieee80211_local *local,
 				     struct txq_info *txq)
 {
-	struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif);
+	struct ieee80211_sub_if_data *sdata = NULL;
 
-	if (!check_sdata_in_driver(sdata))
+	if (txq->txq.vif)
+		sdata = vif_to_sdata(txq->txq.vif);
+
+	if (sdata && !check_sdata_in_driver(sdata))
 		return;
 
 	trace_drv_wake_tx_queue(local, sdata, txq);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 2197c62a0a6e..011c18077e21 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2000,7 +2000,8 @@ static inline bool ieee80211_can_run_worker(struct ieee80211_local *local)
 
 int ieee80211_txq_setup_flows(struct ieee80211_local *local);
 void ieee80211_txq_teardown_flows(struct ieee80211_local *local);
-void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
+void ieee80211_txq_init(struct ieee80211_local *local,
+			struct ieee80211_sub_if_data *sdata,
 			struct sta_info *sta,
 			struct txq_info *txq, int tid);
 void ieee80211_txq_purge(struct ieee80211_local *local,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 9228ac73c429..492cc65b9871 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1814,7 +1814,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 
 		if (txq_size) {
 			txqi = netdev_priv(ndev) + size;
-			ieee80211_txq_init(sdata, NULL, txqi, 0);
+			ieee80211_txq_init(local, sdata, NULL, txqi, 0);
 		}
 
 		sdata->dev = ndev;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 8aa1f5b6a051..8c33c07e47a5 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -666,6 +666,17 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
 	local->hw.radiotap_timestamp.units_pos = -1;
 	local->hw.radiotap_timestamp.accuracy = -1;
 
+	if (ops->wake_tx_queue) {
+		int txq_size = sizeof(struct txq_info) +
+			       local->hw.txq_data_size;
+		struct txq_info *txqi;
+
+		txqi = kzalloc(txq_size, GFP_KERNEL);
+		if (!txqi)
+			goto err_free;
+		ieee80211_txq_init(local, NULL, NULL, txqi, 0);
+	}
+
 	return &local->hw;
  err_free:
 	wiphy_free(wiphy);
@@ -1234,6 +1245,13 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
 
 	ieee80211_free_led_names(local);
 
+	if (local->hw.txq) {
+		struct txq_info *txqi = to_txq_info(local->hw.txq);
+
+		ieee80211_txq_purge(local, txqi);
+		kfree(txqi);
+	}
+
 	wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 69615016d5bf..e99da54c2270 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -370,7 +370,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 		for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
 			struct txq_info *txq = txq_data + i * size;
 
-			ieee80211_txq_init(sdata, sta, txq, i);
+			ieee80211_txq_init(local, sdata, sta, txq, i);
 		}
 	}
 
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index d2a91594312d..ce78ac4d781e 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1246,29 +1246,35 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_txq *txq = NULL;
+	struct ieee80211_txq *txq;
 
 	if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
-	    (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
-		return NULL;
-
-	if (!ieee80211_is_data_present(hdr->frame_control)) {
+	    (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) {
+		txq = NULL;
+	} else if (!ieee80211_is_data_present(hdr->frame_control)) {
 		if ((!ieee80211_is_mgmt(hdr->frame_control) ||
 		     ieee80211_is_bufferable_mmpdu(hdr->frame_control)) &&
 		    sta && sta->uploaded)
 			txq = sta->sta.txq[IEEE80211_NUM_TIDS];
+		else
+			txq = NULL;
 	} else if (sta) {
 		u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
 
-		if (!sta->uploaded)
-			return NULL;
-
-		txq = sta->sta.txq[tid];
+		if (sta->uploaded)
+			txq = sta->sta.txq[tid];
+		else
+			txq = NULL;
 	} else if (vif) {
 		txq = vif->txq;
+	} else {
+		txq = NULL;
 	}
 
 	if (!txq)
+		txq = local->hw.txq;
+
+	if (!txq)
 		return NULL;
 
 	return to_txq_info(txq);
@@ -1295,15 +1301,11 @@ static codel_time_t codel_skb_time_func(const struct sk_buff *skb)
 static struct sk_buff *codel_dequeue_func(struct codel_vars *cvars,
 					  void *ctx)
 {
-	struct ieee80211_local *local;
-	struct txq_info *txqi;
-	struct fq *fq;
+	struct txq_info *txqi = ctx;
+	struct ieee80211_local *local = hw_to_local(txqi->txq.hw);
+	struct fq *fq = &local->fq;
 	struct fq_flow *flow;
 
-	txqi = ctx;
-	local = vif_to_sdata(txqi->txq.vif)->local;
-	fq = &local->fq;
-
 	if (cvars == &txqi->def_cvars)
 		flow = &txqi->def_flow;
 	else
@@ -1315,15 +1317,9 @@ static struct sk_buff *codel_dequeue_func(struct codel_vars *cvars,
 static void codel_drop_func(struct sk_buff *skb,
 			    void *ctx)
 {
-	struct ieee80211_local *local;
-	struct ieee80211_hw *hw;
-	struct txq_info *txqi;
-
-	txqi = ctx;
-	local = vif_to_sdata(txqi->txq.vif)->local;
-	hw = &local->hw;
+	struct txq_info *txqi = ctx;
 
-	ieee80211_free_txskb(hw, skb);
+	ieee80211_free_txskb(txqi->txq.hw, skb);
 }
 
 static struct sk_buff *fq_tin_dequeue_func(struct fq *fq,
@@ -1399,7 +1395,8 @@ static void ieee80211_txq_enqueue(struct ieee80211_local *local,
 		       fq_flow_get_default_func);
 }
 
-void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
+void ieee80211_txq_init(struct ieee80211_local *local,
+			struct ieee80211_sub_if_data *sdata,
 			struct sta_info *sta,
 			struct txq_info *txqi, int tid)
 {
@@ -1409,7 +1406,10 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
 	codel_stats_init(&txqi->cstats);
 	__skb_queue_head_init(&txqi->frags);
 
-	txqi->txq.vif = &sdata->vif;
+	txqi->txq.hw = &local->hw;
+
+	if (sdata)
+		txqi->txq.vif = &sdata->vif;
 
 	if (sta) {
 		txqi->txq.sta = &sta->sta;
@@ -1419,10 +1419,14 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
 			txqi->txq.ac = IEEE80211_AC_VO;
 		else
 			txqi->txq.ac = ieee80211_ac_from_tid(tid);
-	} else {
+	} else if (sdata) {
 		sdata->vif.txq = &txqi->txq;
 		txqi->txq.tid = 0;
 		txqi->txq.ac = IEEE80211_AC_BE;
+	} else {
+		local->hw.txq = &txqi->txq;
+		txqi->txq.tid = 0;
+		txqi->txq.ac = IEEE80211_AC_BE;
 	}
 }
 
@@ -1523,7 +1527,7 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
 	vif = &sdata->vif;
 	txqi = ieee80211_get_txq(local, vif, sta, skb);
 
-	if (!txqi)
+	if (WARN_ON(!txqi))
 		return false;
 
 	spin_lock_bh(&fq->lock);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 6/6] mac80211: always go through txqs
  2017-06-21 23:50 [RFC 1/6] mac80211: agg-tx: call drv_wake_tx_queue in proper context Johannes Berg
                   ` (3 preceding siblings ...)
  2017-06-21 23:50 ` [RFC 5/6] mac80211: add a general fallback TXQ Johannes Berg
@ 2017-06-21 23:50 ` Johannes Berg
  4 siblings, 0 replies; 15+ messages in thread
From: Johannes Berg @ 2017-06-21 23:50 UTC (permalink / raw)
  To: linux-wireless; +Cc: nbd, Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/net/wireless/mac80211_hwsim.c |  1 +
 include/net/mac80211.h                |  6 ++-
 net/mac80211/debugfs.c                |  2 +-
 net/mac80211/debugfs_netdev.c         |  2 +-
 net/mac80211/debugfs_sta.c            |  2 +-
 net/mac80211/ieee80211_i.h            |  2 +
 net/mac80211/iface.c                  | 17 +++----
 net/mac80211/main.c                   |  8 ++++
 net/mac80211/sta_info.c               |  3 --
 net/mac80211/tx.c                     | 83 +++++++++++++++++++----------------
 net/mac80211/util.c                   |  4 +-
 11 files changed, 71 insertions(+), 59 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index c8852acc1462..1f11c5ccc880 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2299,6 +2299,7 @@ static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw,
 
 #define HWSIM_COMMON_OPS					\
 	.tx = mac80211_hwsim_tx,				\
+	.wake_tx_queue = ieee80211_wake_tx_queue,		\
 	.start = mac80211_hwsim_start,				\
 	.stop = mac80211_hwsim_stop,				\
 	.add_interface = mac80211_hwsim_add_interface,		\
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index f2c6f0e0f928..3fc92c0e8779 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -97,7 +97,8 @@
  * Other frames (e.g. control or management) are still pushed using drv_tx().
  *
  * Drivers indicate that they use this model by implementing the .wake_tx_queue
- * driver operation.
+ * driver operation; if they don't want to use this model they need to set the
+ * .wake_tx_queue operation to point to ieee80211_wake_tx_queue().
  *
  * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with
  * another per-sta for non-data/non-mgmt and bufferable management frames, and
@@ -5867,6 +5868,9 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid);
 struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
 				     struct ieee80211_txq *txq);
 
+void ieee80211_wake_tx_queue(struct ieee80211_hw *hw,
+			     struct ieee80211_txq *txq);
+
 /**
  * ieee80211_txq_get_depth - get pending frame/byte count of given txq
  *
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 5fae001f286c..9ab432bde8b4 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -373,7 +373,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
 	DEBUGFS_ADD(user_power);
 	DEBUGFS_ADD(power);
 
-	if (local->ops->wake_tx_queue)
+	if (local->ops->wake_tx_queue != ieee80211_wake_tx_queue)
 		DEBUGFS_ADD_MODE(aqm, 0600);
 
 	statsd = debugfs_create_dir("statistics", phyd);
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index c813207bb123..2098767353ac 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -659,7 +659,7 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata)
 	DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
 	DEBUGFS_ADD(hw_queues);
 
-	if (sdata->local->ops->wake_tx_queue)
+	if (sdata->local->ops->wake_tx_queue != ieee80211_wake_tx_queue)
 		DEBUGFS_ADD(aqm);
 }
 
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index d046c17ea48d..80194f82f6a9 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -539,7 +539,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
 	DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments);
 	DEBUGFS_ADD_COUNTER(tx_filtered, status_stats.filtered);
 
-	if (local->ops->wake_tx_queue)
+	if (local->ops->wake_tx_queue != ieee80211_wake_tx_queue)
 		DEBUGFS_ADD(aqm);
 
 	if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 011c18077e21..3413a1f6408e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -815,6 +815,8 @@ enum txq_info_flags {
 	IEEE80211_TXQ_STOP,
 	IEEE80211_TXQ_AMPDU,
 	IEEE80211_TXQ_NO_AMSDU,
+	IEEE80211_TXQ_PENDING,
+	IEEE80211_TXQ_RESULT,
 };
 
 /**
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 492cc65b9871..b2545899bc6b 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -729,7 +729,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 
 	if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
 	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
-	    local->ops->wake_tx_queue) {
+	    local->ops->wake_tx_queue != ieee80211_wake_tx_queue) {
 		/* XXX: for AP_VLAN, actually track AP queues */
 		netif_tx_start_all_queues(dev);
 	} else if (dev) {
@@ -1756,13 +1756,10 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 	} else {
 		int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size,
 				 sizeof(void *));
-		int txq_size = 0;
+		int txq_size = sizeof(struct txq_info) +
+			       local->hw.txq_data_size;
 
-		if (local->ops->wake_tx_queue)
-			txq_size += sizeof(struct txq_info) +
-				    local->hw.txq_data_size;
-
-		if (local->ops->wake_tx_queue)
+		if (local->ops->wake_tx_queue != ieee80211_wake_tx_queue)
 			if_setup = ieee80211_if_setup_no_queue;
 		else
 			if_setup = ieee80211_if_setup;
@@ -1812,10 +1809,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 		memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN);
 		memcpy(sdata->name, ndev->name, IFNAMSIZ);
 
-		if (txq_size) {
-			txqi = netdev_priv(ndev) + size;
-			ieee80211_txq_init(local, sdata, NULL, txqi, 0);
-		}
+		txqi = netdev_priv(ndev) + size;
+		ieee80211_txq_init(local, sdata, NULL, txqi, 0);
 
 		sdata->dev = ndev;
 	}
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 8c33c07e47a5..8eaac8e29bb4 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -508,6 +508,9 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
 		return NULL;
 	use_chanctx = i == 5;
 
+	if (WARN_ON(!ops->wake_tx_queue))
+		return NULL;
+
 	/* Ensure 32-byte alignment of our private data and hw private data.
 	 * We use the wiphy priv data for both our ieee80211_local and for
 	 * the driver's private data
@@ -849,6 +852,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 		return -EINVAL;
 #endif
 
+	if (local->ops->wake_tx_queue == ieee80211_wake_tx_queue) {
+		if (WARN_ON(local->hw.txq_data_size))
+			return -EINVAL;
+	}
+
 	if (!local->use_chanctx) {
 		for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
 			const struct ieee80211_iface_combination *comb;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index e99da54c2270..c1c73125bcd9 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2319,9 +2319,6 @@ unsigned long ieee80211_sta_last_active(struct sta_info *sta)
 
 static void sta_update_codel_params(struct sta_info *sta, u32 thr)
 {
-	if (!sta->sdata->local->ops->wake_tx_queue)
-		return;
-
 	if (thr && thr < STA_SLOW_THRESHOLD * sta->local->num_sta) {
 		sta->cparams.target = MS2TIME(50);
 		sta->cparams.interval = MS2TIME(300);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index ce78ac4d781e..7f8b8cb60109 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1248,7 +1248,8 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_txq *txq;
 
-	if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
+	if (vif->type == NL80211_IFTYPE_MONITOR ||
+	    (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
 	    (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) {
 		txq = NULL;
 	} else if (!ieee80211_is_data_present(hdr->frame_control)) {
@@ -1448,9 +1449,6 @@ int ieee80211_txq_setup_flows(struct ieee80211_local *local)
 	bool supp_vht = false;
 	enum nl80211_band band;
 
-	if (!local->ops->wake_tx_queue)
-		return 0;
-
 	ret = fq_init(fq, 4096);
 	if (ret)
 		return ret;
@@ -1496,9 +1494,6 @@ void ieee80211_txq_teardown_flows(struct ieee80211_local *local)
 {
 	struct fq *fq = &local->fq;
 
-	if (!local->ops->wake_tx_queue)
-		return;
-
 	kfree(local->cvars);
 	local->cvars = NULL;
 
@@ -1509,17 +1504,13 @@ void ieee80211_txq_teardown_flows(struct ieee80211_local *local)
 
 static bool ieee80211_queue_skb(struct ieee80211_local *local,
 				struct ieee80211_sub_if_data *sdata,
-				struct sta_info *sta,
-				struct sk_buff *skb)
+				struct sta_info *sta, struct sk_buff *skb,
+				bool txpending)
 {
 	struct fq *fq = &local->fq;
 	struct ieee80211_vif *vif;
 	struct txq_info *txqi;
 
-	if (!local->ops->wake_tx_queue ||
-	    sdata->vif.type == NL80211_IFTYPE_MONITOR)
-		return false;
-
 	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 		sdata = container_of(sdata->bss,
 				     struct ieee80211_sub_if_data, u.ap);
@@ -1527,16 +1518,23 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
 	vif = &sdata->vif;
 	txqi = ieee80211_get_txq(local, vif, sta, skb);
 
-	if (WARN_ON(!txqi))
-		return false;
+	if (WARN_ON(!txqi)) {
+		ieee80211_free_txskb(&local->hw, skb);
+		return true;
+	}
 
 	spin_lock_bh(&fq->lock);
 	ieee80211_txq_enqueue(local, txqi, skb);
 	spin_unlock_bh(&fq->lock);
 
+	if (txpending)
+		set_bit(IEEE80211_TXQ_PENDING, &txqi->flags);
+	else
+		clear_bit(IEEE80211_TXQ_PENDING, &txqi->flags);
+	set_bit(IEEE80211_TXQ_RESULT, &txqi->flags);
 	drv_wake_tx_queue(local, txqi);
-
-	return true;
+	clear_bit(IEEE80211_TXQ_PENDING, &txqi->flags);
+	return test_bit(IEEE80211_TXQ_RESULT, &txqi->flags);
 }
 
 static bool ieee80211_tx_frags(struct ieee80211_local *local,
@@ -1820,8 +1818,6 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_tx_data tx;
 	ieee80211_tx_result res_prepare;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	bool result = true;
-	int led_len;
 
 	if (unlikely(skb->len < 10)) {
 		dev_kfree_skb(skb);
@@ -1829,7 +1825,6 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
 	}
 
 	/* initialises tx */
-	led_len = skb->len;
 	res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb);
 
 	if (unlikely(res_prepare == TX_DROP)) {
@@ -1848,14 +1843,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
 	if (invoke_tx_handlers_early(&tx))
 		return false;
 
-	if (ieee80211_queue_skb(local, sdata, tx.sta, tx.skb))
-		return true;
-
-	if (!invoke_tx_handlers_late(&tx))
-		result = __ieee80211_tx(local, &tx.skbs, led_len,
-					tx.sta, txpending);
-
-	return result;
+	return ieee80211_queue_skb(local, sdata, tx.sta, tx.skb, txpending);
 }
 
 /* device xmit handlers */
@@ -3300,6 +3288,8 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
 	struct tid_ampdu_tx *tid_tx = NULL;
 	u8 tid = IEEE80211_NUM_TIDS;
 
+	return false;
+
 	/* control port protocol needs a lot of special handling */
 	if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
 		return false;
@@ -3392,18 +3382,8 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
-	if (ieee80211_queue_skb(local, sdata, sta, skb))
-		return true;
-
-	ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
-				   fast_tx->key, skb);
-
-	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-		sdata = container_of(sdata->bss,
-				     struct ieee80211_sub_if_data, u.ap);
+	ieee80211_queue_skb(local, sdata, sta, skb, false);
 
-	__skb_queue_tail(&tx.skbs, skb);
-	ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false);
 	return true;
 }
 
@@ -4704,3 +4684,28 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
 	ieee80211_xmit(sdata, NULL, skb);
 	local_bh_enable();
 }
+
+void ieee80211_wake_tx_queue(struct ieee80211_hw *hw,
+			     struct ieee80211_txq *txq)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct txq_info *txqi = container_of(txq, struct txq_info, txq);
+	struct sk_buff *skb;
+	struct sk_buff_head skbs;
+	struct sta_info *sta = NULL;
+
+	if (txq->sta)
+		sta = container_of(txq->sta, struct sta_info, sta);
+
+	while ((skb = ieee80211_tx_dequeue(hw, txq))) {
+		__skb_queue_head_init(&skbs);
+		__skb_queue_head(&skbs, skb);
+		skb_queue_splice_tail_init(&txqi->frags, &skbs);
+
+		/* use approximate length for fragmented frames for LED blinking */
+		if (!__ieee80211_tx(local, &skbs, skbs.qlen * skb->len, sta,
+				    test_bit(IEEE80211_TXQ_PENDING, &txqi->flags)))
+			clear_bit(IEEE80211_TXQ_RESULT, &txqi->flags);
+	}
+}
+EXPORT_SYMBOL_GPL(ieee80211_wake_tx_queue);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 259698de569f..ed2dba05f340 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -244,7 +244,7 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
 	struct ieee80211_sub_if_data *sdata;
 	int n_acs = IEEE80211_NUM_ACS;
 
-	if (local->ops->wake_tx_queue)
+	if (local->ops->wake_tx_queue != ieee80211_wake_tx_queue)
 		return;
 
 	if (local->hw.queues < IEEE80211_NUM_ACS)
@@ -350,7 +350,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
 	if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue]))
 		return;
 
-	if (local->ops->wake_tx_queue)
+	if (local->ops->wake_tx_queue != ieee80211_wake_tx_queue)
 		return;
 
 	if (local->hw.queues < IEEE80211_NUM_ACS)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames
  2017-06-21 23:50 ` [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames Johannes Berg
@ 2017-06-22  0:02   ` Ben Greear
  2017-06-22  6:24     ` Johannes Berg
  0 siblings, 1 reply; 15+ messages in thread
From: Ben Greear @ 2017-06-22  0:02 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless; +Cc: nbd, Johannes Berg

On 06/21/2017 04:50 PM, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> Some drivers may want to also use the TXQ abstraction with
> non-data packets that need powersave buffering, so add a
> hardware flag to allow this.
>
> Change ath9k/ath10k to use these by dequeuing the frames
> immediately and invoking the normal TX path for them.
>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>

> --- a/drivers/net/wireless/ath/ath9k/xmit.c
> +++ b/drivers/net/wireless/ath/ath9k/xmit.c
> @@ -154,8 +154,24 @@ void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
>  {
>  	struct ath_softc *sc = hw->priv;
>  	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
> -	struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
> -	struct ath_txq *txq = tid->txq;
> +	struct ath_atx_tid *tid;
> +	struct ath_txq *txq;
> +
> +	if (unlikely(queue->tid == IEEE80211_NUM_TIDS)) {
> +		struct sk_buff *skb = ieee80211_tx_dequeue(hw, queue);
> +		struct ieee80211_tx_control control = {
> +			.sta = queue->sta,
> +		};
> +
> +		if (WARN_ON(!skb))
> +			return;
> +
> +		ath9k_tx(hw, &control, skb);
> +		return;
> +	}

I think a comment for the above code block would be warranted (and for ath10k as well).

I guess this is the part about dequeueing the frames immediately?

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames
  2017-06-22  0:02   ` Ben Greear
@ 2017-06-22  6:24     ` Johannes Berg
  2017-06-22 14:43       ` Ben Greear
  0 siblings, 1 reply; 15+ messages in thread
From: Johannes Berg @ 2017-06-22  6:24 UTC (permalink / raw)
  To: Ben Greear, linux-wireless; +Cc: nbd

On Wed, 2017-06-21 at 17:02 -0700, Ben Greear wrote:
> I think a comment for the above code block would be warranted (and
> for ath10k as well).
> 
> I guess this is the part about dequeueing the frames immediately?

Yeah, I figured it was pretty obvious, but I can add a comment :)

johannes

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 5/6] mac80211: add a general fallback TXQ
  2017-06-21 23:50 ` [RFC 5/6] mac80211: add a general fallback TXQ Johannes Berg
@ 2017-06-22  8:48   ` Johannes Berg
  0 siblings, 0 replies; 15+ messages in thread
From: Johannes Berg @ 2017-06-22  8:48 UTC (permalink / raw)
  To: linux-wireless; +Cc: nbd

On Thu, 2017-06-22 at 01:50 +0200, Johannes Berg wrote:

> In a number of cases, like management frames, mac80211 will not
> put the frame on any TXQ but immediately TX it to the driver.
> It'd be nicer to be able to use TXQs for all frames, so add a
> "fallback" TXQ. This will serve as a container to be able to
> remove all the non-TXQ queueing in mac80211.

This patch is completely broken right now.

When TXQs are enabled, there's still buffering of frames that are *not*
marked with IEEE80211_TX_INTFL_OFFCHAN_TX_OK, and that happens on the
ieee80211_tx_frags() path, using the queue_stop_reasons etc. In fact,
even the drivers can still ask to buffer such frames by stopping their
queues...

I want to move all of that over to the TXQs instead, so that we can get
rid of that buffering logic.

The way to do that would be to not return any frames from TXQs when
they're in off-channel state (and drivers can also stop scheduling the
queues in those cases).

However, if *everything* moves to TXQs, that means we need another TXQ
for those frames that are marked with IEEE80211_TX_INTFL_OFFCHAN_TX_OK,
so that they can go out at any time.

So I think the solution is to add *two* new TXQs in this patch, one for
on-channel frames and one for off-channel frames.

But that's also awkward when you take into account channel contexts,
since all those frames might still need to go to different ones.

Perhaps then the better solution would be to have a TXQ per channel
context, and one for more the remaining frames that. Yeah, this feels
slightly odd - why bother putting frames on a TXQ that shouldn't really
be buffered - but it fits better with the model (the hybrid push/pull
model we have now is somewhat awkward), and there are other reasons
than being off-channel to buffer frames, e.g. if the driver queue got
full, or the driver is doing something else where it can't easily
handle data frames etc.

Thoughts, anyone?

johannes

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames
  2017-06-22  6:24     ` Johannes Berg
@ 2017-06-22 14:43       ` Ben Greear
  2017-06-23  9:21         ` Johannes Berg
  0 siblings, 1 reply; 15+ messages in thread
From: Ben Greear @ 2017-06-22 14:43 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless; +Cc: nbd



On 06/21/2017 11:24 PM, Johannes Berg wrote:
> On Wed, 2017-06-21 at 17:02 -0700, Ben Greear wrote:
>> I think a comment for the above code block would be warranted (and
>> for ath10k as well).
>>
>> I guess this is the part about dequeueing the frames immediately?
>
> Yeah, I figured it was pretty obvious, but I can add a comment :)

It is fairly obvious today, but 6 months from now when someone tries yet again
to figure out WTF is ath10k doing, it will be one more piece of mystery code!

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames
  2017-06-22 14:43       ` Ben Greear
@ 2017-06-23  9:21         ` Johannes Berg
  2017-06-23 12:27           ` Ben Greear
  0 siblings, 1 reply; 15+ messages in thread
From: Johannes Berg @ 2017-06-23  9:21 UTC (permalink / raw)
  To: Ben Greear, linux-wireless; +Cc: nbd

On Thu, 2017-06-22 at 07:43 -0700, Ben Greear wrote:
> 
> On 06/21/2017 11:24 PM, Johannes Berg wrote:
> > On Wed, 2017-06-21 at 17:02 -0700, Ben Greear wrote:
> > > I think a comment for the above code block would be warranted
> > > (and
> > > for ath10k as well).
> > > 
> > > I guess this is the part about dequeueing the frames immediately?
> > 
> > Yeah, I figured it was pretty obvious, but I can add a comment :)
> 
> It is fairly obvious today, but 6 months from now when someone tries
> yet again to figure out WTF is ath10k doing, it will be one more
> piece of mystery code!

:-)

Turns out this won't work well, I had misunderstood the TXQ code.

We do need queueing for these frames, we just do it on the pending
thing in mac80211... that's rather awful, and means we have to
integrate much deeper with ath9k/ath10k to make any progress here.

johannes

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames
  2017-06-23  9:21         ` Johannes Berg
@ 2017-06-23 12:27           ` Ben Greear
  2017-06-26 11:00             ` Johannes Berg
  0 siblings, 1 reply; 15+ messages in thread
From: Ben Greear @ 2017-06-23 12:27 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless; +Cc: nbd



On 06/23/2017 02:21 AM, Johannes Berg wrote:
> On Thu, 2017-06-22 at 07:43 -0700, Ben Greear wrote:
>>
>> On 06/21/2017 11:24 PM, Johannes Berg wrote:
>>> On Wed, 2017-06-21 at 17:02 -0700, Ben Greear wrote:
>>>> I think a comment for the above code block would be warranted
>>>> (and
>>>> for ath10k as well).
>>>>
>>>> I guess this is the part about dequeueing the frames immediately?
>>>
>>> Yeah, I figured it was pretty obvious, but I can add a comment :)
>>
>> It is fairly obvious today, but 6 months from now when someone tries
>> yet again to figure out WTF is ath10k doing, it will be one more
>> piece of mystery code!
>
> :-)
>
> Turns out this won't work well, I had misunderstood the TXQ code.
>
> We do need queueing for these frames, we just do it on the pending
> thing in mac80211... that's rather awful, and means we have to
> integrate much deeper with ath9k/ath10k to make any progress here.

I don't understand the code well enough to know if this matters or not,
but the ath10k wave-2 stuff has some txq prefetch logic in the firmware
(and support in the driver).  But, it doesn't prefetch for the mgt tid
as far as I can tell.  It somehow all mostly works anyway, but possibly this
would have some effect on your changes.  wave-1 (QCA 9880, etc) doesn't
do txq prefetch at all.  Any tricky changes to this logic would need to
test with both chipsets.

There are also NAPI deadlocks possible when firmware crashes at a bad time.
I am not sure there is anyone left working on ath10k with knowledge and time
to really dig into this in detail.

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames
  2017-06-23 12:27           ` Ben Greear
@ 2017-06-26 11:00             ` Johannes Berg
  2017-06-26 14:15               ` Ben Greear
  0 siblings, 1 reply; 15+ messages in thread
From: Johannes Berg @ 2017-06-26 11:00 UTC (permalink / raw)
  To: Ben Greear, linux-wireless; +Cc: nbd

On Fri, 2017-06-23 at 05:27 -0700, Ben Greear wrote:

> I don't understand the code well enough to know if this matters or
> not, but the ath10k wave-2 stuff has some txq prefetch logic in the
> firmware (and support in the driver).  But, it doesn't prefetch for
> the mgt tid as far as I can tell.  It somehow all mostly works
> anyway, but possibly this would have some effect on your
> changes.  wave-1 (QCA 9880, etc) doesn't do txq prefetch at all.  Any
> tricky changes to this logic would need to test with both chipsets.

I don't think this matters. The issue at hand is that the driver still
relies on mac80211 buffering.

This *can* be solved, even in this piece of code I inserted here, but
it'd have to keep state about the queues and then insert some hooks
elsewhere. I'm pretty sure I can solve that, but don't have the time
(or even hardware) to test this (easily, I have ath10k in a few
routers, but ...).

johannes

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames
  2017-06-26 11:00             ` Johannes Berg
@ 2017-06-26 14:15               ` Ben Greear
  2017-06-26 14:27                 ` Johannes Berg
  0 siblings, 1 reply; 15+ messages in thread
From: Ben Greear @ 2017-06-26 14:15 UTC (permalink / raw)
  To: Johannes Berg, linux-wireless; +Cc: nbd



On 06/26/2017 04:00 AM, Johannes Berg wrote:
> On Fri, 2017-06-23 at 05:27 -0700, Ben Greear wrote:
>
>> I don't understand the code well enough to know if this matters or
>> not, but the ath10k wave-2 stuff has some txq prefetch logic in the
>> firmware (and support in the driver).  But, it doesn't prefetch for
>> the mgt tid as far as I can tell.  It somehow all mostly works
>> anyway, but possibly this would have some effect on your
>> changes.  wave-1 (QCA 9880, etc) doesn't do txq prefetch at all.  Any
>> tricky changes to this logic would need to test with both chipsets.
>
> I don't think this matters. The issue at hand is that the driver still
> relies on mac80211 buffering.
>
> This *can* be solved, even in this piece of code I inserted here, but
> it'd have to keep state about the queues and then insert some hooks
> elsewhere. I'm pretty sure I can solve that, but don't have the time
> (or even hardware) to test this (easily, I have ath10k in a few
> routers, but ...).

What/how is it relying on buffering?

I'd be happy to send you plenty of ath10k mini-pcie NICs if that would help.

Just let me know.

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames
  2017-06-26 14:15               ` Ben Greear
@ 2017-06-26 14:27                 ` Johannes Berg
  0 siblings, 0 replies; 15+ messages in thread
From: Johannes Berg @ 2017-06-26 14:27 UTC (permalink / raw)
  To: Ben Greear, linux-wireless; +Cc: nbd

On Mon, 2017-06-26 at 07:15 -0700, Ben Greear wrote:

> > This *can* be solved, even in this piece of code I inserted here,
> > but it'd have to keep state about the queues and then insert some
> > hooks elsewhere. I'm pretty sure I can solve that, but don't have
> > the time (or even hardware) to test this (easily, I have ath10k in
> > a few routers, but ...).
> 
> What/how is it relying on buffering?

So with the TXQs, I thought we were only buffering in mac80211 on the
TXQs themselves. This isn't true though!

We still have the local->pending queues, and the drivers will still
rely on this for all the frames that are *not* going through a TXQ,
which currently is:
 * all non-data frames
 * multicast data frames if they need to be sent after DTIM
   (not sure why this is - doesn't make much sense to me to
    differentiate immediate and after-DTIM transmissions)
 * data frames to stations the driver doesn't know about (yet)

In this case, the driver can still call ieee80211_stop_queue() or
similar, and expect frames to be buffered. I completely failed to take
that into account in this patchset; the dequeue logic I added to ath9k
and ath10k would have to take that into account and not dequeue if the
corresponding queue was stopped.

I think we'll probably have to put this logic into the current
driver(s); I was planning to put it into mac80211 for non-TXQ drivers,
but the ones already using TXQs would have to deal with it, since it'd
be really hard to make mac80211 logic kick in only partially for some
TXQs and not for others.

However, due to all the different levels of buffering we need more TXQs
than I introduced in this patchset (except I really don't want to
introduce one for per-vif-multicast-dtim-buffered-data ...)

> I'd be happy to send you plenty of ath10k mini-pcie NICs if that
> would help.

No need; I have no doubt that I could obtain them, but now I'll be
going on sabbatical for 2 months anyway :-)

johannes

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2017-06-26 14:27 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-21 23:50 [RFC 1/6] mac80211: agg-tx: call drv_wake_tx_queue in proper context Johannes Berg
2017-06-21 23:50 ` [RFC 2/6] mac80211: fix VLAN handling with TXQs Johannes Berg
2017-06-21 23:50 ` [RFC 3/6] mac80211: add a TXQ for other powersave-buffered frames Johannes Berg
2017-06-22  0:02   ` Ben Greear
2017-06-22  6:24     ` Johannes Berg
2017-06-22 14:43       ` Ben Greear
2017-06-23  9:21         ` Johannes Berg
2017-06-23 12:27           ` Ben Greear
2017-06-26 11:00             ` Johannes Berg
2017-06-26 14:15               ` Ben Greear
2017-06-26 14:27                 ` Johannes Berg
2017-06-21 23:50 ` [RFC 4/6] mac80211: don't put null-data frames on the normal TXQ Johannes Berg
2017-06-21 23:50 ` [RFC 5/6] mac80211: add a general fallback TXQ Johannes Berg
2017-06-22  8:48   ` Johannes Berg
2017-06-21 23:50 ` [RFC 6/6] mac80211: always go through txqs Johannes Berg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.