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
next prev 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