From nobody Tue Nov 26 02:39:29 2024 Received: from e2i340.smtp2go.com (e2i340.smtp2go.com [103.2.141.84]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 45F33194C96 for ; Tue, 22 Oct 2024 09:15:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.2.141.84 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729588555; cv=none; b=DiRaDVcfRM8aINGNGZwn4sY+XZ3N5B4QlShVAmMnj7jcaNzBRY3SifiD1uf3hPeCiO44EsmjTqhPaFEOxWveBGsSYRMsCQDNmy+mhCa0fHAJfkmKuAV+dO7zU2wzIFxk0MdJ3dVGRvnfqAkESDIun9BBEZVFPvAFC9oncY+fE2o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729588555; c=relaxed/simple; bh=7eFcQEIvBRhl18swlptD4ddj7Zc4ehZzReoGa/gH0zA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=gGbSMIdwcf7kfMgdnTkPxmpi9u3+pTHZ9pfc4E6ftrfSF85kV+NhogLM+uzllixhqhaDI9EzuR5ItGp5V04209knw44uMGDlzQECyhmRacZR+zqAoMH8OuiCM6TbQwEY2lZizQduEGR2ZrUaznWXnpv2r1YkwEo7rOxVCTZnglk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=triplefau.lt; spf=pass smtp.mailfrom=em510616.triplefau.lt; dkim=fail (0-bit key) header.d=smtpservice.net header.i=@smtpservice.net header.b=3IEzWBcP reason="unknown key version"; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b=lRkHk3X7; arc=none smtp.client-ip=103.2.141.84 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=triplefau.lt Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=em510616.triplefau.lt Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="unknown key version" (0-bit key) header.d=smtpservice.net header.i=@smtpservice.net header.b="3IEzWBcP"; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b="lRkHk3X7" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=smtpservice.net; s=maxzs0.a1-4.dyn; x=1729589453; h=Feedback-ID: X-Smtpcorp-Track:Message-Id:Date:Subject:To:From:Reply-To:Sender: List-Unsubscribe:List-Unsubscribe-Post; bh=YfS8lecAdepFQaM/ZpxsCooHN0CCYe5nh7n3SVBoO7Q=; b=3IEzWBcPCrP2IGoQNkDphsgX6C JEiDkof/7N8/366ltm4GOmcL5JSs9POu2MeOkBzRD+BfgrG0L6GeVcMH6GkZoFKYOHbI85ajD5yMn PJF2/ZQFSIro2XvOP+ud4EeKSDhdABi4z4uqDzH80KpKxevEgW1ONuZ+LqdslQqAsj5FWyQjRfUhR eoMgZhBhWnXKgIQnEs/jLGBT8Sct0Oudo4IG8faj7UZbovfYt6iDI41gN0r2m4x0SgQyKmhIFtgig Xf1W0kVk2tGzXBfTueBA3ZzpIS5MMEPOgZTT1JV7hCHpXGgxnihxi4lZ7d5xw0NUPW2/U88UIo4G3 sDW+QqLg==; DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=triplefau.lt; i=@triplefau.lt; q=dns/txt; s=s510616; t=1729588553; h=from : subject : to : message-id : date; bh=YfS8lecAdepFQaM/ZpxsCooHN0CCYe5nh7n3SVBoO7Q=; b=lRkHk3X718zwUh3NtBtme2CGc/jmf38ccw+rLroW9o5aaqU0su0xpcOB6sZlkeH34GDxx QUITgFNWC3HmeAJyDz3K8bL/BulkdyWG32OGPVhZZGgtl1rTwDp4X55V/QNZwixVRxJ+A6I P0PiPg86O/TUn+Y3hLzxe/3dqog0JLR2o4SB5nIDv07qC0xPnFL9xkop3w2qNO4haS6o55X 3h2924IRFLokFIxzRdWoSQVWum31HFkQjw869WBp7c5giOJUoPeT3XIfYQz9T4n7W8cyVtm zC87+nd/0mq4ytl7MMOF428+mgjvf7SOcklmtYzLIjh/CDDCy7HSFjiT4QWw== Received: from [10.172.233.58] (helo=SmtpCorp) by smtpcorp.com with esmtpsa (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.94.2-S2G) (envelope-from ) id 1t3Ayq-TRk3tB-2w; Tue, 22 Oct 2024 09:15:08 +0000 Received: from [10.12.239.196] (helo=localhost) by smtpcorp.com with esmtpsa (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.97.1-S2G) (envelope-from ) id 1t3Ayp-FnQW0hPkkwx-nGXk; Tue, 22 Oct 2024 09:15:07 +0000 From: Remi Pommarel To: ath10k@lists.infradead.org, linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Kalle Valo , Jeff Johnson , Cedric Veilleux , Vasanthakumar Thiagarajan , Remi Pommarel Subject: [PATCH v2 1/2] wifi: ath10k: Implement ieee80211 flush_sta callback Date: Tue, 22 Oct 2024 11:14:57 +0200 Message-Id: X-Mailer: git-send-email 2.40.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Smtpcorp-Track: zKufZaB8Cfqc.Lq8Z4DGP_HOr.Tu3UhgWw7To Feedback-ID: 510616m:510616apGKSTK:510616s5MvkDfj2Z X-Report-Abuse: Please forward a copy of this message, including all headers, to Content-Type: text/plain; charset="utf-8" When a STA reassociates, mac80211's _sta_info_move_state() waits for all pending frame to be flushed before removing the key (so that no frame get sent unencrypted after key removable [0]). When a driver does not implement the flush_sta callback, ieee80211_flush_queues() is called instead which effectively stops the whole queue until it is completely drained. The ath10k driver configure all STAs of one vdev to share the same queue. So when flushing one STA this is the whole vdev queue that is blocked until completely drained causing Tx to other STA to also stall this whole time. One easy way to reproduce the issue is to connect two STAs (STA0 and STA1) to an ath10k AP. While Generating a bunch of traffic from AP to STA0 (e.g. fping -l -p 20 ) disconnect STA0 from AP without clean disassociation (e.g. remove power, reboot -f). Then as soon as STA0 is effectively disconnected from AP (either after inactivity timeout or forced with iw dev AP station del STA0), its queues get flushed using ieee80211_flush_queues(). This causes STA1 to suffer a connectivity stall for about 5 seconds (see ATH10K_FLUSH_TIMEOUT_HZ). Implement a flush_sta callback in ath10k to wait only for a specific STA pending frames to be drained (without stopping the whole HW queue) to fix that. [0]: commit 0b75a1b1e42e ("wifi: mac80211: flush queues on STA removal") Reported-by: Cedric Veilleux Closes: https://lore.kernel.org/all/CA+Xfe4FjUmzM5mvPxGbpJsF3SvSdE5_wgxvgFJ= 0bsdrKODVXCQ@mail.gmail.com/ Signed-off-by: Remi Pommarel --- drivers/net/wireless/ath/ath10k/core.h | 2 ++ drivers/net/wireless/ath/ath10k/htt.h | 4 +++ drivers/net/wireless/ath/ath10k/htt_tx.c | 31 ++++++++++++++++++ drivers/net/wireless/ath/ath10k/mac.c | 40 +++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/txrx.c | 9 ++++-- 5 files changed, 82 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/= ath/ath10k/core.h index 446dca74f06a..4ec2faa055c0 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -558,6 +558,8 @@ struct ath10k_sta { u8 rate_ctrl[ATH10K_TID_MAX]; u32 rate_code[ATH10K_TID_MAX]; int rtscts[ATH10K_TID_MAX]; + wait_queue_head_t empty_tx_wq; + atomic_t num_fw_queued; }; =20 #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/a= th/ath10k/htt.h index 603f6de62b0a..d150f9330941 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -2452,6 +2452,10 @@ int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt= ); void ath10k_htt_tx_mgmt_dec_pending(struct ath10k_htt *htt); int ath10k_htt_tx_mgmt_inc_pending(struct ath10k_htt *htt, bool is_mgmt, bool is_presp); +void ath10k_htt_tx_sta_inc_pending(struct ath10k_htt *htt, + struct ieee80211_sta *sta); +void ath10k_htt_tx_sta_dec_pending(struct ath10k_htt *htt, + struct ieee80211_sta *sta); =20 int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *sk= b); void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id); diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireles= s/ath/ath10k/htt_tx.c index 9725feecefd6..211752bd0f65 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -195,6 +195,37 @@ void ath10k_htt_tx_mgmt_dec_pending(struct ath10k_htt = *htt) htt->num_pending_mgmt_tx--; } =20 +void ath10k_htt_tx_sta_inc_pending(struct ath10k_htt *htt, + struct ieee80211_sta *sta) +{ + struct ath10k_sta *arsta; + + if (!sta) + return; + + arsta =3D (struct ath10k_sta *)sta->drv_priv; + + atomic_inc(&arsta->num_fw_queued); +} + +void ath10k_htt_tx_sta_dec_pending(struct ath10k_htt *htt, + struct ieee80211_sta *sta) +{ + struct ath10k_sta *arsta; + int v; + + if (!sta) + return; + + arsta =3D (struct ath10k_sta *)sta->drv_priv; + + v =3D atomic_dec_if_positive(&arsta->num_fw_queued); + if (v < 0) + WARN_ON_ONCE(1); + if (v =3D=3D 0) + wake_up(&arsta->empty_tx_wq); +} + int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *sk= b) { struct ath10k *ar =3D htt->ar; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/a= th/ath10k/mac.c index 646e1737d4c4..86386a0af14d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4423,6 +4423,8 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, spin_unlock_bh(&ar->htt.tx_lock); } =20 + ath10k_htt_tx_sta_inc_pending(&ar->htt, sta); + ret =3D ath10k_mac_tx(ar, vif, txmode, txpath, skb, false); if (unlikely(ret)) { ath10k_warn(ar, "failed to push frame: %d\n", ret); @@ -4432,6 +4434,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, if (is_mgmt) ath10k_htt_tx_mgmt_dec_pending(htt); spin_unlock_bh(&ar->htt.tx_lock); + ath10k_htt_tx_sta_dec_pending(&ar->htt, sta); =20 return ret; } @@ -7474,7 +7477,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, arsta->peer_ps_state =3D WMI_PEER_PS_STATE_DISABLED; INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk); INIT_WORK(&arsta->tid_config_wk, ath10k_sta_tid_cfg_wk); - + init_waitqueue_head(&arsta->empty_tx_wq); for (i =3D 0; i < ARRAY_SIZE(sta->txq); i++) ath10k_mac_txq_init(sta->txq[i]); } @@ -8098,6 +8101,40 @@ static void ath10k_flush(struct ieee80211_hw *hw, st= ruct ieee80211_vif *vif, mutex_unlock(&ar->conf_mutex); } =20 +static void ath10k_flush_sta(struct ieee80211_hw *hw, struct ieee80211_vif= *vif, + struct ieee80211_sta *sta) +{ + struct ath10k_sta *arsta =3D (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar =3D hw->priv; + bool skip; + long time_left; + + /* TODO do we need drop implemented here ? */ + + mutex_lock(&ar->conf_mutex); + + if (ar->state =3D=3D ATH10K_STATE_WEDGED) + goto out; + + time_left =3D wait_event_timeout(arsta->empty_tx_wq, ({ + bool empty; + + empty =3D atomic_read(&arsta->num_fw_queued) =3D=3D 0; + + skip =3D (ar->state =3D=3D ATH10K_STATE_WEDGED) || + test_bit(ATH10K_FLAG_CRASH_FLUSH, + &ar->dev_flags); + + (empty || skip); + }), ATH10K_FLUSH_TIMEOUT_HZ); + + if (time_left =3D=3D 0 || skip) + ath10k_warn(ar, "failed to flush sta txq (sta %pM skip %i ar-state %i): = %ld\n", + sta->addr, skip, ar->state, time_left); +out: + mutex_unlock(&ar->conf_mutex); +} + /* TODO: Implement this function properly * For now it is needed to reply to Probe Requests in IBSS mode. * Probably we need this information from FW. @@ -9444,6 +9481,7 @@ static const struct ieee80211_ops ath10k_ops =3D { .set_rts_threshold =3D ath10k_set_rts_threshold, .set_frag_threshold =3D ath10k_mac_op_set_frag_threshold, .flush =3D ath10k_flush, + .flush_sta =3D ath10k_flush_sta, .tx_last_beacon =3D ath10k_tx_last_beacon, .set_antenna =3D ath10k_set_antenna, .get_antenna =3D ath10k_get_antenna, diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/= ath/ath10k/txrx.c index da3bc35e41aa..5b6750ef7d19 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -86,9 +86,12 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, spin_unlock_bh(&htt->tx_lock); =20 rcu_read_lock(); - if (txq && txq->sta && skb_cb->airtime_est) - ieee80211_sta_register_airtime(txq->sta, txq->tid, - skb_cb->airtime_est, 0); + if (txq && txq->sta) { + if (skb_cb->airtime_est) + ieee80211_sta_register_airtime(txq->sta, txq->tid, + skb_cb->airtime_est, 0); + ath10k_htt_tx_sta_dec_pending(htt, txq->sta); + } rcu_read_unlock(); =20 if (ar->bus_param.dev_type !=3D ATH10K_DEV_TYPE_HL) --=20 2.40.0 From nobody Tue Nov 26 02:39:29 2024 Received: from e2i340.smtp2go.com (e2i340.smtp2go.com [103.2.141.84]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5E7A7197A98 for ; Tue, 22 Oct 2024 09:15:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.2.141.84 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729588556; cv=none; b=Js1yByfi+BvHPSp36kzEUTmLpGIMc4CAb+Kig9bvziRmoYl+BTT27OT8vbBxmgjXZoPkE6VQV/miJZaKNvOewvCSlxpmqpPUZJTVAY7RfAEOCoeBAqOsD9DJSq/bpeG02d1myFr8n9lwWFGoTceq/O8zsf3R4faixgQ/HpAprig= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729588556; c=relaxed/simple; bh=VYIVhCRh5GjScxbLeNOWyTpyb6JIDR4fDNkJRf/9+Ps=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=NO4H7iLRKwLJaIhBuSrE2Zr2RKV5SfdM5Hhcy5O8lx1F2JT1ObUcjpHfaq7LGKEbSd3dNrl/Cyagk44Yis7rjI2hcKksQD9RugND+wKJVKH7S8BoLVRl0+EKLmLAyZMo9WTHZacbDp84C8PP3gXDKcBIZVR5PRCIWjKu18vf/ks= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=triplefau.lt; spf=pass smtp.mailfrom=em510616.triplefau.lt; dkim=fail (0-bit key) header.d=smtpservice.net header.i=@smtpservice.net header.b=cTzUlkos reason="unknown key version"; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b=WrVElH1w; arc=none smtp.client-ip=103.2.141.84 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=triplefau.lt Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=em510616.triplefau.lt Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="unknown key version" (0-bit key) header.d=smtpservice.net header.i=@smtpservice.net header.b="cTzUlkos"; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b="WrVElH1w" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=smtpservice.net; s=maxzs0.a1-4.dyn; x=1729589453; h=Feedback-ID: X-Smtpcorp-Track:Message-Id:Date:Subject:To:From:Reply-To:Sender: List-Unsubscribe:List-Unsubscribe-Post; bh=0PwoQaqLU7KtlIp8sVmkq4RKFJmWa6ysnkPeV/6n0ao=; b=cTzUlkosWkZmb7ellU0v3z0E8u fkm22LLwRm8wuAp7ureQX+/Ih1BRL69oLrxTA3CEeusVlEPnWLQk1RKBj2H62rY2DfM5M8XSljIHB ZmYDG/0LG/QJFYkyh7qQHa6xeCH5qKdkzyzdTquPo0AsEHZiUlaC73dLYZge44miDOHXTI5NEwzxO 0u+E+fIhj7kKf+2YW74GkJd+ohcJdja1HfsArFr8au1GBPyQnuNNyPD+ueIonW61uF6JWv8SN8lxq L+vYc8f2nxoLt+bJ+lYy1uFiXUL/sjx29DrGEZb0q67zsfVwfkvZV1HsCdfgTu4stH6guCbKkGeTq ne78KJ/A==; DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=triplefau.lt; i=@triplefau.lt; q=dns/txt; s=s510616; t=1729588553; h=from : subject : to : message-id : date; bh=0PwoQaqLU7KtlIp8sVmkq4RKFJmWa6ysnkPeV/6n0ao=; b=WrVElH1wwSWsg+wrx/rMhwLvNz4/JMjlUWjGrAbuWcg9ElxcjPa5wkU9qFd2fu69WYWtA 620uRAK+wbcUa/sHaDkSphMxhqhnMV1uiDrERVjYa3GoRU3CuuIzjV/nyLH2U4wNEBZhjJ0 BrCSgHe+BIDv+Kohu3GYDrbS6lZGLC0q+GV0iMfIilzrlkMq/YFwq9m02o+K79r4umY2juU TZI8mbnh+kIVi9mY7xWEajXDP5E7UwMzlcLCzLCWaX2eEsmTJe39BL2FuTJWIdZLQjCqFFN hLqTAmlxi2BeLEePKg90jKL5GDfoFP6Fp21SwgefK1Yf4b27rz5oJ4s9GF8Q== Received: from [10.176.58.103] (helo=SmtpCorp) by smtpcorp.com with esmtpsa (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.94.2-S2G) (envelope-from ) id 1t3Ayq-TRk3uj-Gq; Tue, 22 Oct 2024 09:15:08 +0000 Received: from [10.12.239.196] (helo=localhost) by smtpcorp.com with esmtpsa (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.97.1-S2G) (envelope-from ) id 1t3Ayq-4o5NDgruWkf-oq6z; Tue, 22 Oct 2024 09:15:08 +0000 From: Remi Pommarel To: ath10k@lists.infradead.org, linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Kalle Valo , Jeff Johnson , Cedric Veilleux , Vasanthakumar Thiagarajan , Remi Pommarel Subject: [PATCH v2 2/2] wifi: ath10k: Flush only requested txq in ath10k_flush() Date: Tue, 22 Oct 2024 11:14:58 +0200 Message-Id: <0f55986ebe34f2b5aa4ccbcb0bed445324099fbd.1729586267.git.repk@triplefau.lt> X-Mailer: git-send-email 2.40.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Smtpcorp-Track: NDmkXlzHlPYg.C94vL_6lkESk.kQGNAA4Z0V7 Feedback-ID: 510616m:510616apGKSTK:510616s6ZVVxhofP X-Report-Abuse: Please forward a copy of this message, including all headers, to Content-Type: text/plain; charset="utf-8" The ieee80211 flush callback can be called to flush only part of all hw queues. The ath10k's flush callback implementation (i.e. ath10k_flush()) was waiting for all pending frames of all queues to be flushed ignoring the queue parameter. Because only the queues to be flushed are stopped by mac80211, skb can still be queued to other queues meanwhile. Thus ath10k_flush() could fail (and wait 5sec holding ar->conf lock) even if the requested queues are flushed correctly. A way to reproduce the issue is to use two different APs because each vdev has its own hw queue in ath10k. Connect STA0 to AP0 and STA1 to AP1. Then generate traffic from AP0 to STA0 and kill STA0 without clean disassociation frame (e.g. unplug power cable, reboot -f, ...). Now if we were to flush AP1's queue, ath10k_flush() would fail (and effectively block 5 seconds with ar->conf or even wiphy's lock held) with the following warning: ath10k_pci 0000:01:00.0: failed to flush transmit queue (skip 0 ar-state 2= ): 0 Wait only for pending frames of the requested queues to be flushed in ath10k_flush() to avoid that long blocking. Reported-by: Cedric Veilleux Closes: https://lore.kernel.org/all/CA+Xfe4FjUmzM5mvPxGbpJsF3SvSdE5_wgxvgFJ= 0bsdrKODVXCQ@mail.gmail.com/ Signed-off-by: Remi Pommarel --- drivers/net/wireless/ath/ath10k/htt.h | 7 +++-- drivers/net/wireless/ath/ath10k/htt_tx.c | 18 ++++++++++--- drivers/net/wireless/ath/ath10k/mac.c | 33 +++++++++++++++++------- drivers/net/wireless/ath/ath10k/txrx.c | 2 +- 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/a= th/ath10k/htt.h index d150f9330941..ca8bf3b6766d 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1870,6 +1870,7 @@ struct ath10k_htt { spinlock_t tx_lock; int max_num_pending_tx; int num_pending_tx; + int num_pending_per_queue[IEEE80211_MAX_QUEUES]; int num_pending_mgmt_tx; struct idr pending_tx; wait_queue_head_t empty_tx_wq; @@ -2447,8 +2448,10 @@ void ath10k_htt_tx_txq_update(struct ieee80211_hw *h= w, void ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw, struct ieee80211_txq *txq); void ath10k_htt_tx_txq_sync(struct ath10k *ar); -void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt); -int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt); +void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, + struct ieee80211_txq *txq); +int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt, + struct ieee80211_txq *txq); void ath10k_htt_tx_mgmt_dec_pending(struct ath10k_htt *htt); int ath10k_htt_tx_mgmt_inc_pending(struct ath10k_htt *htt, bool is_mgmt, bool is_presp); diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireles= s/ath/ath10k/htt_tx.c index 211752bd0f65..ef5a992e8cce 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -140,19 +140,26 @@ void ath10k_htt_tx_txq_update(struct ieee80211_hw *hw, spin_unlock_bh(&ar->htt.tx_lock); } =20 -void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt) +void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, + struct ieee80211_txq *txq) { + int qnr =3D -1; + lockdep_assert_held(&htt->tx_lock); =20 htt->num_pending_tx--; if (htt->num_pending_tx =3D=3D htt->max_num_pending_tx - 1) ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL); =20 - if (htt->num_pending_tx =3D=3D 0) + if (txq) + qnr =3D --htt->num_pending_per_queue[txq->vif->hw_queue[txq->ac]]; + + if (htt->num_pending_tx =3D=3D 0 || qnr =3D=3D 0) wake_up(&htt->empty_tx_wq); } =20 -int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt) +int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt, + struct ieee80211_txq *txq) { lockdep_assert_held(&htt->tx_lock); =20 @@ -163,6 +170,11 @@ int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt) if (htt->num_pending_tx =3D=3D htt->max_num_pending_tx) ath10k_mac_tx_lock(htt->ar, ATH10K_TX_PAUSE_Q_FULL); =20 + if (!txq) + return 0; + + htt->num_pending_per_queue[txq->vif->hw_queue[txq->ac]]++; + return 0; } =20 diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/a= th/ath10k/mac.c index 86386a0af14d..e78b112df339 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4385,7 +4385,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, u16 airtime; =20 spin_lock_bh(&ar->htt.tx_lock); - ret =3D ath10k_htt_tx_inc_pending(htt); + ret =3D ath10k_htt_tx_inc_pending(htt, txq); spin_unlock_bh(&ar->htt.tx_lock); =20 if (ret) @@ -4394,7 +4394,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, skb =3D ieee80211_tx_dequeue_ni(hw, txq); if (!skb) { spin_lock_bh(&ar->htt.tx_lock); - ath10k_htt_tx_dec_pending(htt); + ath10k_htt_tx_dec_pending(htt, txq); spin_unlock_bh(&ar->htt.tx_lock); =20 return -ENOENT; @@ -4416,7 +4416,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, ret =3D ath10k_htt_tx_mgmt_inc_pending(htt, is_mgmt, is_presp); =20 if (ret) { - ath10k_htt_tx_dec_pending(htt); + ath10k_htt_tx_dec_pending(htt, txq); spin_unlock_bh(&ar->htt.tx_lock); return ret; } @@ -4430,7 +4430,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, ath10k_warn(ar, "failed to push frame: %d\n", ret); =20 spin_lock_bh(&ar->htt.tx_lock); - ath10k_htt_tx_dec_pending(htt); + ath10k_htt_tx_dec_pending(htt, txq); if (is_mgmt) ath10k_htt_tx_mgmt_dec_pending(htt); spin_unlock_bh(&ar->htt.tx_lock); @@ -4693,7 +4693,7 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw, is_presp =3D ieee80211_is_probe_resp(hdr->frame_control); } =20 - ret =3D ath10k_htt_tx_inc_pending(htt); + ret =3D ath10k_htt_tx_inc_pending(htt, txq); if (ret) { ath10k_warn(ar, "failed to increase tx pending count: %d, dropping\n", ret); @@ -4706,7 +4706,7 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw, if (ret) { ath10k_dbg(ar, ATH10K_DBG_MAC, "failed to increase tx mgmt pending coun= t: %d, dropping\n", ret); - ath10k_htt_tx_dec_pending(htt); + ath10k_htt_tx_dec_pending(htt, txq); spin_unlock_bh(&ar->htt.tx_lock); ieee80211_free_txskb(ar->hw, skb); return; @@ -4719,7 +4719,7 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw, ath10k_warn(ar, "failed to transmit frame: %d\n", ret); if (is_htt) { spin_lock_bh(&ar->htt.tx_lock); - ath10k_htt_tx_dec_pending(htt); + ath10k_htt_tx_dec_pending(htt, txq); if (is_mgmt) ath10k_htt_tx_mgmt_dec_pending(htt); spin_unlock_bh(&ar->htt.tx_lock); @@ -8045,10 +8045,12 @@ static int ath10k_mac_op_set_frag_threshold(struct = ieee80211_hw *hw, u32 value) return -EOPNOTSUPP; } =20 -void ath10k_mac_wait_tx_complete(struct ath10k *ar) +static void _ath10k_mac_wait_tx_complete(struct ath10k *ar, + unsigned long queues) { bool skip; long time_left; + unsigned int q; =20 /* mac80211 doesn't care if we really xmit queued frames or not * we'll collect those frames either way if we stop/delete vdevs @@ -8061,7 +8063,11 @@ void ath10k_mac_wait_tx_complete(struct ath10k *ar) bool empty; =20 spin_lock_bh(&ar->htt.tx_lock); - empty =3D (ar->htt.num_pending_tx =3D=3D 0); + for_each_set_bit(q, &queues, ar->hw->queues) { + empty =3D (ar->htt.num_pending_per_queue[q] =3D=3D 0); + if (!empty) + break; + } spin_unlock_bh(&ar->htt.tx_lock); =20 skip =3D (ar->state =3D=3D ATH10K_STATE_WEDGED) || @@ -8076,6 +8082,13 @@ void ath10k_mac_wait_tx_complete(struct ath10k *ar) skip, ar->state, time_left); } =20 +void ath10k_mac_wait_tx_complete(struct ath10k *ar) +{ + unsigned int queues =3D GENMASK(ar->hw->queues - 1, 0); + + _ath10k_mac_wait_tx_complete(ar, queues); +} + static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vi= f, u32 queues, bool drop) { @@ -8097,7 +8110,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, str= uct ieee80211_vif *vif, } =20 mutex_lock(&ar->conf_mutex); - ath10k_mac_wait_tx_complete(ar); + _ath10k_mac_wait_tx_complete(ar, queues); mutex_unlock(&ar->conf_mutex); } =20 diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/= ath/ath10k/txrx.c index 5b6750ef7d19..b848962fc8fb 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -82,7 +82,7 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, =20 flags =3D skb_cb->flags; ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); - ath10k_htt_tx_dec_pending(htt); + ath10k_htt_tx_dec_pending(htt, txq); spin_unlock_bh(&htt->tx_lock); =20 rcu_read_lock(); --=20 2.40.0