public inbox for linux-wireless@vger.kernel.org
 help / color / mirror / Atom feed
From: Ping-Ke Shih <pkshih@realtek.com>
To: <linux-wireless@vger.kernel.org>
Cc: <leo.li@realtek.com>, <gary.chang@realtek.com>,
	<echuang@realtek.com>, <wenjie.tsai@realtek.com>,
	<phhuang@realtek.com>, <isaiah@realtek.com>,
	<kevin_yang@realtek.com>, <mh_chen@realtek.com>
Subject: [PATCH rtw-next 02/16] wifi: rtw89: 8852a: refine power save to lower latency
Date: Mon, 20 Apr 2026 11:40:37 +0800	[thread overview]
Message-ID: <20260420034051.17666-3-pkshih@realtek.com> (raw)
In-Reply-To: <20260420034051.17666-1-pkshih@realtek.com>

From: Po-Hao Huang <phhuang@realtek.com>

Improve user experience while using interactive applications.
Adjust power saving decisions under different scenarios.
Minimize latency for delay-sensitive connections by exiting
power-save on packet bursts and maintain active until a period
of inactivity is reached. For connections that are not that
sensitive to delays, keep the current aggressive power save logic.

Signed-off-by: Po-Hao Huang <phhuang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/core.c | 87 +++++++++++++++++++++--
 drivers/net/wireless/realtek/rtw89/core.h |  9 +++
 2 files changed, 89 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 70feab97dccb..c9c4ec1d93af 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -341,10 +341,26 @@ static const struct rtw89_hw_rate_def {
 	},
 };
 
+static void rtw89_core_tx_skb_proto_stats(struct rtw89_traffic_stats *stats,
+					  struct sk_buff *skb)
+{
+	switch (ip_hdr(skb)->protocol) {
+	case IPPROTO_TCP:
+		stats->tcp++;
+		break;
+	case IPPROTO_UDP:
+		stats->udp++;
+		break;
+	default:
+		break;
+	}
+}
+
 static void __rtw89_traffic_stats_accu(struct rtw89_traffic_stats *stats,
 				       struct sk_buff *skb, bool tx)
 {
 	if (tx) {
+		rtw89_core_tx_skb_proto_stats(stats, skb);
 		stats->tx_cnt++;
 		stats->tx_unicast += skb->len;
 	} else {
@@ -2902,6 +2918,23 @@ static void rtw89_core_bcn_track_reset(struct rtw89_dev *rtwdev)
 	memset(&rtwdev->bcn_track, 0, sizeof(rtwdev->bcn_track));
 }
 
+static bool rtw89_core_proto_stats_can_lps(struct rtw89_dev *rtwdev,
+					   struct rtw89_vif *rtwvif,
+					   enum rtw89_tfc_interval interval)
+{
+	if (rtwdev->chip->chip_id != RTL8852A)
+		return true;
+
+	if (rtwvif->burst_active)
+		return false;
+
+	if (interval == RTW89_TFC_INTERVAL_100MS &&
+	    hweight8(rtwvif->stats_ps.active_histogram) < 3)
+		return false;
+
+	return true;
+}
+
 static void rtw89_vif_rx_bcn_stat(struct rtw89_dev *rtwdev, struct sk_buff *skb)
 {
 #define RTW89_APPEND_TSF_2GHZ 384
@@ -4540,9 +4573,42 @@ static enum rtw89_tfc_lv rtw89_get_traffic_level(struct rtw89_dev *rtwdev,
 	return RTW89_TFC_ULTRA_LOW;
 }
 
+static void rtw89_calc_vif_active_histogram(struct rtw89_dev *rtwdev,
+					    struct rtw89_traffic_stats *stats,
+					    enum rtw89_tfc_interval interval)
+{
+	struct rtw89_vif *rtwvif;
+
+	stats->udp_ratio = stats->tx_cnt ?
+			   DIV_ROUND_DOWN_ULL(stats->udp * 100, stats->tx_cnt) : 0;
+	stats->active_histogram <<= 1;
+
+	switch (interval) {
+	case RTW89_TFC_INTERVAL_2SEC:
+		rtwvif = container_of(stats, struct rtw89_vif, stats);
+
+		if (stats->tcp >= RTW89_TCP_TH && stats->tx_cnt >= stats->rx_cnt)
+			stats->active_histogram |= BIT(0);
+
+		if (stats->active_histogram & RTW89_RECENT_ACTIVE_HIST)
+			rtwvif->burst_active = true;
+		else
+			rtwvif->burst_active = false;
+
+		break;
+	case RTW89_TFC_INTERVAL_100MS:
+		if (stats->udp_ratio >= RTW89_UDP_RATIO_TH)
+			stats->active_histogram |= BIT(0);
+		break;
+	}
+
+	stats->tcp = 0;
+	stats->udp = 0;
+}
+
 static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev,
 				     struct rtw89_traffic_stats *stats,
-				     enum rtw89_tfc_interval interval)
+				     enum rtw89_tfc_interval interval, bool by_vif)
 {
 	enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv;
 	enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv;
@@ -4564,6 +4630,9 @@ static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev,
 	stats->rx_avg_len = stats->rx_cnt ?
 			    DIV_ROUND_DOWN_ULL(stats->rx_unicast, stats->rx_cnt) : 0;
 
+	if (by_vif)
+		rtw89_calc_vif_active_histogram(rtwdev, stats, interval);
+
 	stats->tx_unicast = 0;
 	stats->rx_unicast = 0;
 	stats->tx_cnt = 0;
@@ -4585,11 +4654,11 @@ static bool rtw89_traffic_stats_track(struct rtw89_dev *rtwdev)
 	bool tfc_changed;
 
 	tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats,
-					       RTW89_TFC_INTERVAL_2SEC);
+					       RTW89_TFC_INTERVAL_2SEC, false);
 
 	rtw89_for_each_rtwvif(rtwdev, rtwvif) {
 		rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats,
-					 RTW89_TFC_INTERVAL_2SEC);
+					 RTW89_TFC_INTERVAL_2SEC, true);
 
 		rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
 			rtw89_fw_h2c_tp_offload(rtwdev, rtwvif_link);
@@ -4598,7 +4667,8 @@ static bool rtw89_traffic_stats_track(struct rtw89_dev *rtwdev)
 	return tfc_changed;
 }
 
-static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev)
+static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev,
+				  enum rtw89_tfc_interval interval)
 {
 	struct ieee80211_vif *vif;
 	struct rtw89_vif *rtwvif;
@@ -4622,6 +4692,9 @@ static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev)
 		if (!rtw89_core_bcn_track_can_lps(rtwdev))
 			continue;
 
+		if (!rtw89_core_proto_stats_can_lps(rtwdev, rtwvif, interval))
+			continue;
+
 		rtw89_enter_lps(rtwdev, rtwvif, true);
 	}
 }
@@ -4771,13 +4844,13 @@ static void rtw89_track_ps_work(struct wiphy *wiphy, struct wiphy_work *work)
 
 	rtw89_for_each_rtwvif(rtwdev, rtwvif)
 		rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats_ps,
-					 RTW89_TFC_INTERVAL_100MS);
+					 RTW89_TFC_INTERVAL_100MS, true);
 
 	if (rtwdev->scanning)
 		return;
 
 	if (rtwdev->lps_enabled && !rtwdev->btc.lps)
-		rtw89_enter_lps_track(rtwdev);
+		rtw89_enter_lps_track(rtwdev, RTW89_TFC_INTERVAL_100MS);
 }
 
 static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work)
@@ -4825,7 +4898,7 @@ static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work)
 	rtw89_core_mlo_track(rtwdev);
 
 	if (rtwdev->lps_enabled && !rtwdev->btc.lps)
-		rtw89_enter_lps_track(rtwdev);
+		rtw89_enter_lps_track(rtwdev, RTW89_TFC_INTERVAL_2SEC);
 }
 
 void rtw89_core_dm_disable_cfg(struct rtw89_dev *rtwdev, u32 new)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index fd29dbbb120d..bbcac7cc207c 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -1477,6 +1477,10 @@ enum rtw89_tfc_lv {
 
 DECLARE_EWMA(tp, 10, 2);
 
+#define RTW89_TCP_TH 40
+#define RTW89_UDP_RATIO_TH 70
+#define RTW89_RECENT_ACTIVE_HIST GENMASK(4, 0)
+
 struct rtw89_traffic_stats {
 	/* units in bytes */
 	u64 tx_unicast;
@@ -1504,6 +1508,10 @@ struct rtw89_traffic_stats {
 
 	u16 tx_rate;
 	u16 rx_rate;
+
+	/* used by rtwvif only */
+	u64 tcp, udp, udp_ratio;
+	u8 active_histogram;
 };
 
 struct rtw89_btc_chdef {
@@ -6354,6 +6362,7 @@ struct rtw89_vif {
 
 	struct rtw89_roc roc;
 	bool offchan;
+	bool burst_active;
 
 	enum rtw89_mlo_mode mlo_mode;
 	struct rtw89_vif_ml_trans ml_trans;
-- 
2.25.1


  parent reply	other threads:[~2026-04-20  3:41 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-20  3:40 [PATCH rtw-next 00/16] wifi: rtw89: add USB IO offload and some refactors Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 01/16] wifi: rtw89: 8922d: fix typo rx_freq_frome_ie Ping-Ke Shih
2026-04-20  3:40 ` Ping-Ke Shih [this message]
2026-04-20  3:40 ` [PATCH rtw-next 03/16] wifi: rtw89: debug: disable hw_scan for latency-sensitive scenarios Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 04/16] wifi: rtw89: debug: disable inactive power save to reduce bus overhead Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 05/16] wifi: rtw89: phy: support static PD level setting Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 06/16] wifi: rtw89: Correct data type for scan index to avoid infinite loop Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 07/16] wifi: rtw89: 8852bt: configure support_noise field explicitly Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 08/16] wifi: rtw89: add IO offload support via firmware Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 09/16] wifi: rtw89: offload DMAC and CMAC init IO to firmware Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 10/16] wifi: rtw89: use firmware offload for PHY and RF batch register writes Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 11/16] wifi: rtw89: 8832cu: Add ID 2c7c:8206 for RTL8832CU Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 12/16] wifi: rtw89: use struct to fill C2H recv ack Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 13/16] wifi: rtw89: check scan C2H event recv ack instead of C2H event done ack Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 14/16] wifi: rtw89: suspend DIG when remain-on-channel Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 15/16] wifi: rtw89: chan: introduce new helper to get entity current configuration Ping-Ke Shih
2026-04-20  3:40 ` [PATCH rtw-next 16/16] wifi: rtw89: 8922d: update RF calibration flow for MLD Ping-Ke Shih

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260420034051.17666-3-pkshih@realtek.com \
    --to=pkshih@realtek.com \
    --cc=echuang@realtek.com \
    --cc=gary.chang@realtek.com \
    --cc=isaiah@realtek.com \
    --cc=kevin_yang@realtek.com \
    --cc=leo.li@realtek.com \
    --cc=linux-wireless@vger.kernel.org \
    --cc=mh_chen@realtek.com \
    --cc=phhuang@realtek.com \
    --cc=wenjie.tsai@realtek.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox