All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] wifi: mac80211: Proper mark iTXQs for resumption
@ 2022-12-30 12:18 Alexander Wetzel
  2022-12-30 12:18 ` [PATCH] wifi: mac80211: sdata can be NULL during AMPDU start Alexander Wetzel
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Alexander Wetzel @ 2022-12-30 12:18 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Alexander Wetzel

When a running wake_tx_queue() call is aborted due to a hw queue stop
the corresponding iTXQ is not always correctly marked for resumption:
wake_tx_push_queue() can stops the queue run without setting
@IEEE80211_TXQ_STOP_NETIF_TX.

Without the @IEEE80211_TXQ_STOP_NETIF_TX flag __ieee80211_wake_txqs()
will not schedule a new queue run and remaining frames in the queue get
stuck till another frame is queued to it.

Fix the issue for all drivers - also the ones with custom wake_tx_queue
callbacks - by moving the logic into ieee80211_tx_dequeue() and drop the
redundant @txqs_stopped.

@IEEE80211_TXQ_STOP_NETIF_TX is also renamed to @IEEE80211_TXQ_DIRTY to
better describe the flag.

Fixes: c850e31f79f0 ("wifi: mac80211: add internal handler for wake_tx_queue")
Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
---
 include/net/mac80211.h     |  4 ----
 net/mac80211/debugfs_sta.c |  5 +++--
 net/mac80211/driver-ops.h  |  2 +-
 net/mac80211/ieee80211_i.h |  2 +-
 net/mac80211/tx.c          | 20 +++++++++++-------
 net/mac80211/util.c        | 42 +++-----------------------------------
 6 files changed, 21 insertions(+), 54 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 689da327ce2e..e3235b9c02c2 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1832,8 +1832,6 @@ struct ieee80211_vif_cfg {
  * @drv_priv: data area for driver use, will always be aligned to
  *	sizeof(void \*).
  * @txq: the multicast data TX queue
- * @txqs_stopped: per AC flag to indicate that intermediate TXQs are stopped,
- *	protected by fq->lock.
  * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
  *	&enum ieee80211_offload_flags.
  * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled.
@@ -1863,8 +1861,6 @@ struct ieee80211_vif {
 	bool probe_req_reg;
 	bool rx_mcast_action_reg;
 
-	bool txqs_stopped[IEEE80211_NUM_ACS];
-
 	struct ieee80211_vif *mbssid_tx_vif;
 
 	/* must be last */
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 7a3d7893e19d..f1914bf39f0e 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -167,7 +167,7 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
 			continue;
 		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 0x%lx(%s%s%s)\n",
+			       "%d %d %u %u %u %u %u %u %u %u %u 0x%lx(%s%s%s%s)\n",
 			       txqi->txq.tid,
 			       txqi->txq.ac,
 			       txqi->tin.backlog_bytes,
@@ -182,7 +182,8 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
 			       txqi->flags,
 			       test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ? "STOP" : "RUN",
 			       test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags) ? " AMPDU" : "",
-			       test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags) ? " NO-AMSDU" : "");
+			       test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags) ? " NO-AMSDU" : "",
+			       test_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ? " DIRTY" : "");
 	}
 
 	rcu_read_unlock();
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 809bad53e15b..5d13a3dfd366 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1199,7 +1199,7 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local,
 
 	/* In reconfig don't transmit now, but mark for waking later */
 	if (local->in_reconfig) {
-		set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txq->flags);
+		set_bit(IEEE80211_TXQ_DIRTY, &txq->flags);
 		return;
 	}
 
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 63ff0d2524b6..d16606e84e22 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -838,7 +838,7 @@ enum txq_info_flags {
 	IEEE80211_TXQ_STOP,
 	IEEE80211_TXQ_AMPDU,
 	IEEE80211_TXQ_NO_AMSDU,
-	IEEE80211_TXQ_STOP_NETIF_TX,
+	IEEE80211_TXQ_DIRTY,
 };
 
 /**
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 2171cd1ca807..178043f84489 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3783,6 +3783,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
 	struct ieee80211_tx_data tx;
 	ieee80211_tx_result r;
 	struct ieee80211_vif *vif = txq->vif;
+	int q = vif->hw_queue[txq->ac];
+	bool q_stopped;
 
 	WARN_ON_ONCE(softirq_count() == 0);
 
@@ -3790,16 +3792,20 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
 		return NULL;
 
 begin:
-	spin_lock_bh(&fq->lock);
+	spin_lock(&local->queue_stop_reason_lock);
+	q_stopped = local->queue_stop_reasons[q];
+	spin_unlock(&local->queue_stop_reason_lock);
 
-	if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ||
-	    test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags))
-		goto out;
+	if (unlikely(q_stopped)) {
+		/* mark for waking later */
+		set_bit(IEEE80211_TXQ_DIRTY, &txqi->flags);
+		return NULL;
+	}
 
-	if (vif->txqs_stopped[txq->ac]) {
-		set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags);
+	spin_lock_bh(&fq->lock);
+
+	if (unlikely(test_bit(IEEE80211_TXQ_STOP, &txqi->flags)))
 		goto out;
-	}
 
 	/* Make sure fragments stay together. */
 	skb = __skb_dequeue(&txqi->frags);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 6f5407038459..261ac667887f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -292,22 +292,12 @@ static void wake_tx_push_queue(struct ieee80211_local *local,
 			       struct ieee80211_sub_if_data *sdata,
 			       struct ieee80211_txq *queue)
 {
-	int q = sdata->vif.hw_queue[queue->ac];
 	struct ieee80211_tx_control control = {
 		.sta = queue->sta,
 	};
 	struct sk_buff *skb;
-	unsigned long flags;
-	bool q_stopped;
 
 	while (1) {
-		spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-		q_stopped = local->queue_stop_reasons[q];
-		spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
-		if (q_stopped)
-			break;
-
 		skb = ieee80211_tx_dequeue(&local->hw, queue);
 		if (!skb)
 			break;
@@ -347,8 +337,6 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
 	local_bh_disable();
 	spin_lock(&fq->lock);
 
-	sdata->vif.txqs_stopped[ac] = false;
-
 	if (!test_bit(SDATA_STATE_RUNNING, &sdata->state))
 		goto out;
 
@@ -370,7 +358,7 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
 			if (ac != txq->ac)
 				continue;
 
-			if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX,
+			if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY,
 						&txqi->flags))
 				continue;
 
@@ -385,7 +373,7 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
 
 	txqi = to_txq_info(vif->txq);
 
-	if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags) ||
+	if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ||
 	    (ps && atomic_read(&ps->num_sta_ps)) || ac != vif->txq->ac)
 		goto out;
 
@@ -517,8 +505,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
 				   bool refcounted)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_sub_if_data *sdata;
-	int n_acs = IEEE80211_NUM_ACS;
 
 	trace_stop_queue(local, queue, reason);
 
@@ -530,29 +516,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
 	else
 		local->q_stop_reasons[queue][reason]++;
 
-	if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue]))
-		return;
-
-	if (local->hw.queues < IEEE80211_NUM_ACS)
-		n_acs = 1;
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-		int ac;
-
-		if (!sdata->dev)
-			continue;
-
-		for (ac = 0; ac < n_acs; ac++) {
-			if (sdata->vif.hw_queue[ac] == queue ||
-			    sdata->vif.cab_queue == queue) {
-				spin_lock(&local->fq.lock);
-				sdata->vif.txqs_stopped[ac] = true;
-				spin_unlock(&local->fq.lock);
-			}
-		}
-	}
-	rcu_read_unlock();
+	set_bit(reason, &local->queue_stop_reasons[queue]);
 }
 
 void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
-- 
2.39.0


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

* [PATCH] wifi: mac80211: sdata can be NULL during AMPDU start
  2022-12-30 12:18 [PATCH] wifi: mac80211: Proper mark iTXQs for resumption Alexander Wetzel
@ 2022-12-30 12:18 ` Alexander Wetzel
  2023-01-10 19:33 ` [PATCH] wifi: mac80211: Proper mark iTXQs for resumption Bryan O'Donoghue
  2023-01-10 19:35 ` Bryan O'Donoghue
  2 siblings, 0 replies; 4+ messages in thread
From: Alexander Wetzel @ 2022-12-30 12:18 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, Alexander Wetzel

ieee80211_tx_ba_session_handle_start() may get NULL for sdata when a
deauthentication is ongoing.

Here a trace triggering the race with the hostapd test
multi_ap_fronthaul_on_ap:

(gdb) list *drv_ampdu_action+0x46
0x8b16 is in drv_ampdu_action (net/mac80211/driver-ops.c:396).
391             int ret = -EOPNOTSUPP;
392
393             might_sleep();
394
395             sdata = get_bss_sdata(sdata);
396             if (!check_sdata_in_driver(sdata))
397                     return -EIO;
398
399             trace_drv_ampdu_action(local, sdata, params);
400

wlan0: moving STA 02:00:00:00:03:00 to state 3
wlan0: associated
wlan0: deauthenticating from 02:00:00:00:03:00 by local choice (Reason: 3=DEAUTH_LEAVING)
wlan3.sta1: Open BA session requested for 02:00:00:00:00:00 tid 0
wlan3.sta1: dropped frame to 02:00:00:00:00:00 (unauthorized port)
wlan0: moving STA 02:00:00:00:03:00 to state 2
wlan0: moving STA 02:00:00:00:03:00 to state 1
wlan0: Removed STA 02:00:00:00:03:00
wlan0: Destroyed STA 02:00:00:00:03:00
BUG: unable to handle page fault for address: fffffffffffffb48
PGD 11814067 P4D 11814067 PUD 11816067 PMD 0
Oops: 0000 [#1] PREEMPT SMP PTI
CPU: 2 PID: 133397 Comm: kworker/u16:1 Tainted: G        W          6.1.0-rc8-wt+ #59
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.0-20220807_005459-localhost 04/01/2014
Workqueue: phy3 ieee80211_ba_session_work [mac80211]
RIP: 0010:drv_ampdu_action+0x46/0x280 [mac80211]
Code: 53 48 89 f3 be 89 01 00 00 e8 d6 43 bf ef e8 21 46 81 f0 83 bb a0 1b 00 00 04 75 0e 48 8b 9b 28 0d 00 00 48 81 eb 10 0e 00 00 <8b> 93 58 09 00 00 f6 c2 20 0f 84 3b 01 00 00 8b 05 dd 1c 0f 00 85
RSP: 0018:ffffc900025ebd20 EFLAGS: 00010287
RAX: 0000000000000000 RBX: fffffffffffff1f0 RCX: ffff888102228240
RDX: 0000000080000000 RSI: ffffffff918c5de0 RDI: ffff888102228b40
RBP: ffffc900025ebd40 R08: 0000000000000001 R09: 0000000000000001
R10: 0000000000000001 R11: 0000000000000000 R12: ffff888118c18ec0
R13: 0000000000000000 R14: ffffc900025ebd60 R15: ffff888018b7efb8
FS:  0000000000000000(0000) GS:ffff88817a600000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: fffffffffffffb48 CR3: 0000000105228006 CR4: 0000000000170ee0
Call Trace:
 <TASK>
 ieee80211_tx_ba_session_handle_start+0xd0/0x190 [mac80211]
 ieee80211_ba_session_work+0xff/0x2e0 [mac80211]
 process_one_work+0x29f/0x620
 worker_thread+0x4d/0x3d0
 ? process_one_work+0x620/0x620
 kthread+0xfb/0x120
 ? kthread_complete_and_exit+0x20/0x20
 ret_from_fork+0x22/0x30
 </TASK>

Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>

---
The fix is not perfect, we still dereference sdata and use it without
any strong guarantee that it's still valid. But I don't see another
solution here without fundamental changes. With the patch I'm unable to
trigger the issue any longer. Other attempts to fix it failed in that
regard...

Alexander
---
 net/mac80211/agg-tx.c     | 6 +++++-
 net/mac80211/driver-ops.c | 3 +++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 9c40f8d3bce8..3dbb724d7dc4 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -491,7 +491,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 {
 	struct tid_ampdu_tx *tid_tx;
 	struct ieee80211_local *local = sta->local;
-	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_ampdu_params params = {
 		.sta = &sta->sta,
 		.action = IEEE80211_AMPDU_TX_START,
@@ -521,6 +521,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 	 */
 	synchronize_net();
 
+	sdata = sta->sdata;
 	params.ssn = sta->tid_seq[tid] >> 4;
 	ret = drv_ampdu_action(local, sdata, &params);
 	tid_tx->ssn = params.ssn;
@@ -534,6 +535,9 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 		 */
 		set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state);
 	} else if (ret) {
+		if (!sdata)
+			return;
+
 		ht_dbg(sdata,
 		       "BA request denied - HW unavailable for %pM tid %d\n",
 		       sta->sta.addr, tid);
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c
index d737db4e07e2..cfb09e4aed4d 100644
--- a/net/mac80211/driver-ops.c
+++ b/net/mac80211/driver-ops.c
@@ -392,6 +392,9 @@ int drv_ampdu_action(struct ieee80211_local *local,
 
 	might_sleep();
 
+	if (!sdata)
+		return -EIO;
+
 	sdata = get_bss_sdata(sdata);
 	if (!check_sdata_in_driver(sdata))
 		return -EIO;
-- 
2.39.0


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

* Re: [PATCH] wifi: mac80211: Proper mark iTXQs for resumption
  2022-12-30 12:18 [PATCH] wifi: mac80211: Proper mark iTXQs for resumption Alexander Wetzel
  2022-12-30 12:18 ` [PATCH] wifi: mac80211: sdata can be NULL during AMPDU start Alexander Wetzel
@ 2023-01-10 19:33 ` Bryan O'Donoghue
  2023-01-10 19:35 ` Bryan O'Donoghue
  2 siblings, 0 replies; 4+ messages in thread
From: Bryan O'Donoghue @ 2023-01-10 19:33 UTC (permalink / raw)
  To: Alexander Wetzel, linux-wireless; +Cc: johannes

On 30/12/2022 12:18, Alexander Wetzel wrote:
> When a running wake_tx_queue() call is aborted due to a hw queue stop
> the corresponding iTXQ is not always correctly marked for resumption:
> wake_tx_push_queue() can stops the queue run without setting
> @IEEE80211_TXQ_STOP_NETIF_TX.
> 
> Without the @IEEE80211_TXQ_STOP_NETIF_TX flag __ieee80211_wake_txqs()
> will not schedule a new queue run and remaining frames in the queue get
> stuck till another frame is queued to it.
> 
> Fix the issue for all drivers - also the ones with custom wake_tx_queue
> callbacks - by moving the logic into ieee80211_tx_dequeue() and drop the
> redundant @txqs_stopped.
> 
> @IEEE80211_TXQ_STOP_NETIF_TX is also renamed to @IEEE80211_TXQ_DIRTY to
> better describe the flag.
> 
> Fixes: c850e31f79f0 ("wifi: mac80211: add internal handler for wake_tx_queue")
> Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
> ---
>   include/net/mac80211.h     |  4 ----
>   net/mac80211/debugfs_sta.c |  5 +++--
>   net/mac80211/driver-ops.h  |  2 +-
>   net/mac80211/ieee80211_i.h |  2 +-
>   net/mac80211/tx.c          | 20 +++++++++++-------
>   net/mac80211/util.c        | 42 +++-----------------------------------
>   6 files changed, 21 insertions(+), 54 deletions(-)
> 
> diff --git a/include/net/mac80211.h b/include/net/mac80211.h
> index 689da327ce2e..e3235b9c02c2 100644
> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -1832,8 +1832,6 @@ struct ieee80211_vif_cfg {
>    * @drv_priv: data area for driver use, will always be aligned to
>    *	sizeof(void \*).
>    * @txq: the multicast data TX queue
> - * @txqs_stopped: per AC flag to indicate that intermediate TXQs are stopped,
> - *	protected by fq->lock.
>    * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
>    *	&enum ieee80211_offload_flags.
>    * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled.
> @@ -1863,8 +1861,6 @@ struct ieee80211_vif {
>   	bool probe_req_reg;
>   	bool rx_mcast_action_reg;
>   
> -	bool txqs_stopped[IEEE80211_NUM_ACS];
> -
>   	struct ieee80211_vif *mbssid_tx_vif;
>   
>   	/* must be last */
> diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
> index 7a3d7893e19d..f1914bf39f0e 100644
> --- a/net/mac80211/debugfs_sta.c
> +++ b/net/mac80211/debugfs_sta.c
> @@ -167,7 +167,7 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
>   			continue;
>   		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 0x%lx(%s%s%s)\n",
> +			       "%d %d %u %u %u %u %u %u %u %u %u 0x%lx(%s%s%s%s)\n",
>   			       txqi->txq.tid,
>   			       txqi->txq.ac,
>   			       txqi->tin.backlog_bytes,
> @@ -182,7 +182,8 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
>   			       txqi->flags,
>   			       test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ? "STOP" : "RUN",
>   			       test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags) ? " AMPDU" : "",
> -			       test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags) ? " NO-AMSDU" : "");
> +			       test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags) ? " NO-AMSDU" : "",
> +			       test_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ? " DIRTY" : "");
>   	}
>   
>   	rcu_read_unlock();
> diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
> index 809bad53e15b..5d13a3dfd366 100644
> --- a/net/mac80211/driver-ops.h
> +++ b/net/mac80211/driver-ops.h
> @@ -1199,7 +1199,7 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local,
>   
>   	/* In reconfig don't transmit now, but mark for waking later */
>   	if (local->in_reconfig) {
> -		set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txq->flags);
> +		set_bit(IEEE80211_TXQ_DIRTY, &txq->flags);
>   		return;
>   	}
>   
> diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
> index 63ff0d2524b6..d16606e84e22 100644
> --- a/net/mac80211/ieee80211_i.h
> +++ b/net/mac80211/ieee80211_i.h
> @@ -838,7 +838,7 @@ enum txq_info_flags {
>   	IEEE80211_TXQ_STOP,
>   	IEEE80211_TXQ_AMPDU,
>   	IEEE80211_TXQ_NO_AMSDU,
> -	IEEE80211_TXQ_STOP_NETIF_TX,
> +	IEEE80211_TXQ_DIRTY,
>   };
>   
>   /**
> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> index 2171cd1ca807..178043f84489 100644
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -3783,6 +3783,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
>   	struct ieee80211_tx_data tx;
>   	ieee80211_tx_result r;
>   	struct ieee80211_vif *vif = txq->vif;
> +	int q = vif->hw_queue[txq->ac];
> +	bool q_stopped;
>   
>   	WARN_ON_ONCE(softirq_count() == 0);
>   
> @@ -3790,16 +3792,20 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
>   		return NULL;
>   
>   begin:
> -	spin_lock_bh(&fq->lock);
> +	spin_lock(&local->queue_stop_reason_lock);
> +	q_stopped = local->queue_stop_reasons[q];
> +	spin_unlock(&local->queue_stop_reason_lock);
>   
> -	if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ||
> -	    test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags))
> -		goto out;
> +	if (unlikely(q_stopped)) {
> +		/* mark for waking later */
> +		set_bit(IEEE80211_TXQ_DIRTY, &txqi->flags);
> +		return NULL;
> +	}
>   
> -	if (vif->txqs_stopped[txq->ac]) {
> -		set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags);
> +	spin_lock_bh(&fq->lock);
> +
> +	if (unlikely(test_bit(IEEE80211_TXQ_STOP, &txqi->flags)))
>   		goto out;
> -	}
>   
>   	/* Make sure fragments stay together. */
>   	skb = __skb_dequeue(&txqi->frags);
> diff --git a/net/mac80211/util.c b/net/mac80211/util.c
> index 6f5407038459..261ac667887f 100644
> --- a/net/mac80211/util.c
> +++ b/net/mac80211/util.c
> @@ -292,22 +292,12 @@ static void wake_tx_push_queue(struct ieee80211_local *local,
>   			       struct ieee80211_sub_if_data *sdata,
>   			       struct ieee80211_txq *queue)
>   {
> -	int q = sdata->vif.hw_queue[queue->ac];
>   	struct ieee80211_tx_control control = {
>   		.sta = queue->sta,
>   	};
>   	struct sk_buff *skb;
> -	unsigned long flags;
> -	bool q_stopped;
>   
>   	while (1) {
> -		spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
> -		q_stopped = local->queue_stop_reasons[q];
> -		spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
> -
> -		if (q_stopped)
> -			break;
> -
>   		skb = ieee80211_tx_dequeue(&local->hw, queue);
>   		if (!skb)
>   			break;
> @@ -347,8 +337,6 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
>   	local_bh_disable();
>   	spin_lock(&fq->lock);
>   
> -	sdata->vif.txqs_stopped[ac] = false;
> -
>   	if (!test_bit(SDATA_STATE_RUNNING, &sdata->state))
>   		goto out;
>   
> @@ -370,7 +358,7 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
>   			if (ac != txq->ac)
>   				continue;
>   
> -			if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX,
> +			if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY,
>   						&txqi->flags))
>   				continue;
>   
> @@ -385,7 +373,7 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
>   
>   	txqi = to_txq_info(vif->txq);
>   
> -	if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags) ||
> +	if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ||
>   	    (ps && atomic_read(&ps->num_sta_ps)) || ac != vif->txq->ac)
>   		goto out;
>   
> @@ -517,8 +505,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
>   				   bool refcounted)
>   {
>   	struct ieee80211_local *local = hw_to_local(hw);
> -	struct ieee80211_sub_if_data *sdata;
> -	int n_acs = IEEE80211_NUM_ACS;
>   
>   	trace_stop_queue(local, queue, reason);
>   
> @@ -530,29 +516,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
>   	else
>   		local->q_stop_reasons[queue][reason]++;
>   
> -	if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue]))
> -		return;
> -
> -	if (local->hw.queues < IEEE80211_NUM_ACS)
> -		n_acs = 1;
> -
> -	rcu_read_lock();
> -	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
> -		int ac;
> -
> -		if (!sdata->dev)
> -			continue;
> -
> -		for (ac = 0; ac < n_acs; ac++) {
> -			if (sdata->vif.hw_queue[ac] == queue ||
> -			    sdata->vif.cab_queue == queue) {
> -				spin_lock(&local->fq.lock);
> -				sdata->vif.txqs_stopped[ac] = true;
> -				spin_unlock(&local->fq.lock);
> -			}
> -		}
> -	}
> -	rcu_read_unlock();
> +	set_bit(reason, &local->queue_stop_reasons[queue]);
>   }
>   
>   void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,

Nice

Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

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

* Re: [PATCH] wifi: mac80211: Proper mark iTXQs for resumption
  2022-12-30 12:18 [PATCH] wifi: mac80211: Proper mark iTXQs for resumption Alexander Wetzel
  2022-12-30 12:18 ` [PATCH] wifi: mac80211: sdata can be NULL during AMPDU start Alexander Wetzel
  2023-01-10 19:33 ` [PATCH] wifi: mac80211: Proper mark iTXQs for resumption Bryan O'Donoghue
@ 2023-01-10 19:35 ` Bryan O'Donoghue
  2 siblings, 0 replies; 4+ messages in thread
From: Bryan O'Donoghue @ 2023-01-10 19:35 UTC (permalink / raw)
  To: Alexander Wetzel, linux-wireless; +Cc: johannes

On 30/12/2022 12:18, Alexander Wetzel wrote:
> When a running wake_tx_queue() call is aborted due to a hw queue stop
> the corresponding iTXQ is not always correctly marked for resumption:
> wake_tx_push_queue() can stops the queue run without setting
> @IEEE80211_TXQ_STOP_NETIF_TX.
> 
> Without the @IEEE80211_TXQ_STOP_NETIF_TX flag __ieee80211_wake_txqs()
> will not schedule a new queue run and remaining frames in the queue get
> stuck till another frame is queued to it.
> 
> Fix the issue for all drivers - also the ones with custom wake_tx_queue
> callbacks - by moving the logic into ieee80211_tx_dequeue() and drop the
> redundant @txqs_stopped.
> 
> @IEEE80211_TXQ_STOP_NETIF_TX is also renamed to @IEEE80211_TXQ_DIRTY to
> better describe the flag.
> 
> Fixes: c850e31f79f0 ("wifi: mac80211: add internal handler for wake_tx_queue")
> Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>

 From the right address this time

Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>


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

end of thread, other threads:[~2023-01-10 19:35 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-30 12:18 [PATCH] wifi: mac80211: Proper mark iTXQs for resumption Alexander Wetzel
2022-12-30 12:18 ` [PATCH] wifi: mac80211: sdata can be NULL during AMPDU start Alexander Wetzel
2023-01-10 19:33 ` [PATCH] wifi: mac80211: Proper mark iTXQs for resumption Bryan O'Donoghue
2023-01-10 19:35 ` Bryan O'Donoghue

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.