From patchwork Fri Nov 22 16:48:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Remi Pommarel X-Patchwork-Id: 845184 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 23F4360890 for ; Fri, 22 Nov 2024 16:49:44 +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=1732294187; cv=none; b=ejQI4ziwGDY71gUHA4qIF3Aw8lJX1sWcjYiWRmH4/aL6go8BOOzLl8FrCvR7w8yUTO/2I/opBoTqP1G6BsF3KERW83HXt6CNUZR+BAi/owcLf/kkMDZuKwn1MubhTEyrVigzYigOlr4HWqfUY+vEjJCthEEKI6uZIN22yVwwHB8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732294187; c=relaxed/simple; bh=xBp48a7NJAmuRhfuvTg1UfVngg6KTk5DZh5riLJL8NU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=bTLpeMr41sNajH4ZRkvDSk/os0c9u1fJx5lf6naHHuiJs296d+6aJ/AuW9Bls3OaXz66tX1wZ54lHYM+qfgHcxz0OFMTLVwOqrqVKuSmaN9QJjMnwrri6RniHJYcpz5Z15ivatVFuanv00sQC6sa3zh90LfIUplIyq4A9E6iFCE= 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=qweMUWO5 reason="unknown key version"; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b=MbXp5m8s; 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="qweMUWO5"; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b="MbXp5m8s" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=smtpservice.net; s=maxzs0.a1-4.dyn; x=1732295085; h=Feedback-ID: X-Smtpcorp-Track:Message-Id:Date:Subject:To:From:Reply-To:Sender: List-Unsubscribe:List-Unsubscribe-Post; bh=H6t+0VQi/hPriWRBUTFUcC2YjAKrLFxImgas1F5cAQM=; b=qweMUWO5gigpcdmfN163S9rlz0 ufJvT9eXfsXm7B2E1egKKBeQQxIVRbsr/XORvuAuouu8OUJtNeZCBJ8dDUd3VdEEDGZqCGacD9Jt2 6CKSwuNXaHyz+KzCn2fREhk2aZN5btzLlz1eIqDqht7HS2ZJnAVrLF4KDNSmQEMAU0+guuEoseV9t 9U0TPSW4jFeMFqBVCQGb1Lrx6WEnoGjM2w69ucjpO0WiSO1rorxggA3/8SvOvimiwlrMeX5bpid0A EtPn1aQz6Us1E2cqqeTgKeqr3ZCmv5RsKt8wnNr9Gx6W0ddX01U4VmSMfFxLKQucNMRj/RwTo4jb1 Ixeny+XQ==; DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=triplefau.lt; i=@triplefau.lt; q=dns/txt; s=s510616; t=1732294185; h=from : subject : to : message-id : date; bh=H6t+0VQi/hPriWRBUTFUcC2YjAKrLFxImgas1F5cAQM=; b=MbXp5m8soxoClg7HdjjPF4d+6/p6bJgIw/1s6+DMmkQV1l13KBvjimVxK3JOy5RT/89fX PTyIX6c9fH1yFrrIwmXERg+Corj3J57/cQk2InhNVrWiWu2Q72gse6K5mr4ZE3Dq66R3xEx N6jB/ak3J+LHdeZR/MkfT+2fzrGoTKqqlHPYYBOtkPXHduuBO9Muwjvgu/3eLSki5Ldv9Gi poGrHGcg2qrLgD77/KxPMC1KkNC3RIu71eHCr4YP0kmzTf621O9CsbcZBtYdTcuU0schEc4 4xVqgXJWH2kmrvVLHI/KrzbNQ9XEtRF24C5uQPxkzeB31AvOtI03dpD8B6iw== 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 1tEWqT-TRjyMk-Jd; Fri, 22 Nov 2024 16:49:25 +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 1tEWqT-4o5NDgrusvn-pkjQ; Fri, 22 Nov 2024 16:49:25 +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: [RESEND PATCH v3 1/2] wifi: ath10k: Implement ieee80211 flush_sta callback Date: Fri, 22 Nov 2024 17:48:01 +0100 Message-Id: <17d26d6a3e80ff03939ee7935fdc07f979b61a4f.1732293922.git.repk@triplefau.lt> X-Mailer: git-send-email 2.40.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Smtpcorp-Track: ZOeNrQmZkgHL.xerYKmMykMlO.Po71RQJqitq Feedback-ID: 510616m:510616apGKSTK:510616sqVrJeNwUF X-Report-Abuse: Please forward a copy of this message, including all headers, to 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_wgxvgFJ0bsdrKODVXCQ@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; }; #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/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); int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb); 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/wireless/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--; } +void ath10k_htt_tx_sta_inc_pending(struct ath10k_htt *htt, + struct ieee80211_sta *sta) +{ + struct ath10k_sta *arsta; + + if (!sta) + return; + + arsta = (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 = (struct ath10k_sta *)sta->drv_priv; + + v = atomic_dec_if_positive(&arsta->num_fw_queued); + if (v < 0) + WARN_ON_ONCE(1); + if (v == 0) + wake_up(&arsta->empty_tx_wq); +} + int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb) { struct ath10k *ar = htt->ar; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c61b95a928da..8b8d4f24e5fb 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); } + ath10k_htt_tx_sta_inc_pending(&ar->htt, sta); + ret = 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); return ret; } @@ -7481,7 +7484,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, arsta->peer_ps_state = 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 = 0; i < ARRAY_SIZE(sta->txq); i++) ath10k_mac_txq_init(sta->txq[i]); } @@ -8112,6 +8115,40 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_unlock(&ar->conf_mutex); } +static void ath10k_flush_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = hw->priv; + bool skip; + long time_left; + + /* TODO do we need drop implemented here ? */ + + mutex_lock(&ar->conf_mutex); + + if (ar->state == ATH10K_STATE_WEDGED) + goto out; + + time_left = wait_event_timeout(arsta->empty_tx_wq, ({ + bool empty; + + empty = atomic_read(&arsta->num_fw_queued) == 0; + + skip = (ar->state == ATH10K_STATE_WEDGED) || + test_bit(ATH10K_FLAG_CRASH_FLUSH, + &ar->dev_flags); + + (empty || skip); + }), ATH10K_FLUSH_TIMEOUT_HZ); + + if (time_left == 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. @@ -9459,6 +9496,7 @@ static const struct ieee80211_ops ath10k_ops = { .set_rts_threshold = ath10k_set_rts_threshold, .set_frag_threshold = ath10k_mac_op_set_frag_threshold, .flush = ath10k_flush, + .flush_sta = ath10k_flush_sta, .tx_last_beacon = ath10k_tx_last_beacon, .set_antenna = ath10k_set_antenna, .get_antenna = 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); 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(); if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL)