Skip to content

Commit 06baab3

Browse files
committed
wifi: rtw89: enter power save mode aggressively
JIRA: https://issues.redhat.com/browse/RHEL-114889 commit 480dd4d Author: Chin-Yen Lee <timlee@realtek.com> Date: Tue Jul 1 15:38:39 2025 +0800 wifi: rtw89: enter power save mode aggressively Currently the driver allows the WiFi chip enter power save mode by checking the transmitting and receiving traffic is very low per two seconds. But it's hard for some applications to enter power save mode, like video streaming, which sends burst traffic regularly for other side to buffer and only send little traffic at most time. So adjust the criteria to enter power save while lower than 10Mbps and check it per 100ms. Thus WiFi chip could reduce power consumption under these applications. Signed-off-by: Chin-Yen Lee <timlee@realtek.com> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://patch.msgid.link/20250701073839.31905-1-pkshih@realtek.com Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
1 parent 092bce2 commit 06baab3

File tree

6 files changed

+123
-29
lines changed

6 files changed

+123
-29
lines changed

drivers/net/wireless/realtek/rtw89/core.c

Lines changed: 84 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -319,28 +319,38 @@ static const struct ieee80211_supported_band rtw89_sband_6ghz = {
319319
.n_bitrates = ARRAY_SIZE(rtw89_bitrates) - 4,
320320
};
321321

322+
static void __rtw89_traffic_stats_accu(struct rtw89_traffic_stats *stats,
323+
struct sk_buff *skb, bool tx)
324+
{
325+
if (tx) {
326+
stats->tx_cnt++;
327+
stats->tx_unicast += skb->len;
328+
} else {
329+
stats->rx_cnt++;
330+
stats->rx_unicast += skb->len;
331+
}
332+
}
333+
322334
static void rtw89_traffic_stats_accu(struct rtw89_dev *rtwdev,
323-
struct rtw89_traffic_stats *stats,
324-
struct sk_buff *skb, bool tx)
335+
struct rtw89_vif *rtwvif,
336+
struct sk_buff *skb,
337+
bool accu_dev, bool tx)
325338
{
326339
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
327340

328-
if (tx && ieee80211_is_assoc_req(hdr->frame_control))
329-
rtw89_wow_parse_akm(rtwdev, skb);
330-
331341
if (!ieee80211_is_data(hdr->frame_control))
332342
return;
333343

334344
if (is_broadcast_ether_addr(hdr->addr1) ||
335345
is_multicast_ether_addr(hdr->addr1))
336346
return;
337347

338-
if (tx) {
339-
stats->tx_cnt++;
340-
stats->tx_unicast += skb->len;
341-
} else {
342-
stats->rx_cnt++;
343-
stats->rx_unicast += skb->len;
348+
if (accu_dev)
349+
__rtw89_traffic_stats_accu(&rtwdev->stats, skb, tx);
350+
351+
if (rtwvif) {
352+
__rtw89_traffic_stats_accu(&rtwvif->stats, skb, tx);
353+
__rtw89_traffic_stats_accu(&rtwvif->stats_ps, skb, tx);
344354
}
345355
}
346356

@@ -1150,8 +1160,8 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev,
11501160
tx_req.rtwsta_link = rtwsta_link;
11511161
tx_req.desc_info.sw_mld = sw_mld;
11521162

1153-
rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true);
1154-
rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true);
1163+
rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, true, true);
1164+
rtw89_wow_parse_akm(rtwdev, skb);
11551165
rtw89_core_tx_update_desc_info(rtwdev, &tx_req);
11561166
rtw89_core_tx_wake(rtwdev, &tx_req);
11571167

@@ -2267,7 +2277,7 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
22672277
if (desc_info->data_rate < RTW89_HW_RATE_NR)
22682278
pkt_stat->rx_rate_cnt[desc_info->data_rate]++;
22692279

2270-
rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, false);
2280+
rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, false, false);
22712281

22722282
out:
22732283
rcu_read_unlock();
@@ -2280,7 +2290,7 @@ static void rtw89_core_rx_stats(struct rtw89_dev *rtwdev,
22802290
{
22812291
struct rtw89_vif_rx_stats_iter_data iter_data;
22822292

2283-
rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, false);
2293+
rtw89_traffic_stats_accu(rtwdev, NULL, skb, true, false);
22842294

22852295
iter_data.rtwdev = rtwdev;
22862296
iter_data.phy_ppdu = phy_ppdu;
@@ -3570,9 +3580,22 @@ void rtw89_roc_work(struct wiphy *wiphy, struct wiphy_work *work)
35703580
}
35713581

35723582
static enum rtw89_tfc_lv rtw89_get_traffic_level(struct rtw89_dev *rtwdev,
3573-
u32 throughput, u64 cnt)
3583+
u32 throughput, u64 cnt,
3584+
enum rtw89_tfc_interval interval)
35743585
{
3575-
if (cnt < 100)
3586+
u64 cnt_level;
3587+
3588+
switch (interval) {
3589+
default:
3590+
case RTW89_TFC_INTERVAL_100MS:
3591+
cnt_level = 5;
3592+
break;
3593+
case RTW89_TFC_INTERVAL_2SEC:
3594+
cnt_level = 100;
3595+
break;
3596+
}
3597+
3598+
if (cnt < cnt_level)
35763599
return RTW89_TFC_IDLE;
35773600
if (throughput > 50)
35783601
return RTW89_TFC_HIGH;
@@ -3584,23 +3607,24 @@ static enum rtw89_tfc_lv rtw89_get_traffic_level(struct rtw89_dev *rtwdev,
35843607
}
35853608

35863609
static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev,
3587-
struct rtw89_traffic_stats *stats)
3610+
struct rtw89_traffic_stats *stats,
3611+
enum rtw89_tfc_interval interval)
35883612
{
35893613
enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv;
35903614
enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv;
35913615

3592-
stats->tx_throughput_raw = (u32)(stats->tx_unicast >> RTW89_TP_SHIFT);
3593-
stats->rx_throughput_raw = (u32)(stats->rx_unicast >> RTW89_TP_SHIFT);
3616+
stats->tx_throughput_raw = rtw89_bytes_to_mbps(stats->tx_unicast, interval);
3617+
stats->rx_throughput_raw = rtw89_bytes_to_mbps(stats->rx_unicast, interval);
35943618

35953619
ewma_tp_add(&stats->tx_ewma_tp, stats->tx_throughput_raw);
35963620
ewma_tp_add(&stats->rx_ewma_tp, stats->rx_throughput_raw);
35973621

35983622
stats->tx_throughput = ewma_tp_read(&stats->tx_ewma_tp);
35993623
stats->rx_throughput = ewma_tp_read(&stats->rx_ewma_tp);
36003624
stats->tx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->tx_throughput,
3601-
stats->tx_cnt);
3625+
stats->tx_cnt, interval);
36023626
stats->rx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->rx_throughput,
3603-
stats->rx_cnt);
3627+
stats->rx_cnt, interval);
36043628
stats->tx_avg_len = stats->tx_cnt ?
36053629
DIV_ROUND_DOWN_ULL(stats->tx_unicast, stats->tx_cnt) : 0;
36063630
stats->rx_avg_len = stats->rx_cnt ?
@@ -3626,10 +3650,12 @@ static bool rtw89_traffic_stats_track(struct rtw89_dev *rtwdev)
36263650
unsigned int link_id;
36273651
bool tfc_changed;
36283652

3629-
tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats);
3653+
tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats,
3654+
RTW89_TFC_INTERVAL_2SEC);
36303655

36313656
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
3632-
rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats);
3657+
rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats,
3658+
RTW89_TFC_INTERVAL_2SEC);
36333659

36343660
rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
36353661
rtw89_fw_h2c_tp_offload(rtwdev, rtwvif_link);
@@ -3649,8 +3675,8 @@ static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev)
36493675
if (rtwvif->offchan)
36503676
continue;
36513677

3652-
if (rtwvif->stats.tx_tfc_lv != RTW89_TFC_IDLE ||
3653-
rtwvif->stats.rx_tfc_lv != RTW89_TFC_IDLE)
3678+
if (rtwvif->stats_ps.tx_tfc_lv >= RTW89_TFC_MID ||
3679+
rtwvif->stats_ps.rx_tfc_lv >= RTW89_TFC_MID)
36543680
continue;
36553681

36563682
vif = rtwvif_to_vif(rtwvif);
@@ -3789,6 +3815,34 @@ static void rtw89_core_mlo_track(struct rtw89_dev *rtwdev)
37893815
}
37903816
}
37913817

3818+
static void rtw89_track_ps_work(struct wiphy *wiphy, struct wiphy_work *work)
3819+
{
3820+
struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
3821+
track_ps_work.work);
3822+
struct rtw89_vif *rtwvif;
3823+
3824+
lockdep_assert_wiphy(wiphy);
3825+
3826+
if (test_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags))
3827+
return;
3828+
3829+
if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags))
3830+
return;
3831+
3832+
wiphy_delayed_work_queue(wiphy, &rtwdev->track_ps_work,
3833+
RTW89_TRACK_PS_WORK_PERIOD);
3834+
3835+
rtw89_for_each_rtwvif(rtwdev, rtwvif)
3836+
rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats_ps,
3837+
RTW89_TFC_INTERVAL_100MS);
3838+
3839+
if (rtwdev->scanning)
3840+
return;
3841+
3842+
if (rtwdev->lps_enabled && !rtwdev->btc.lps)
3843+
rtw89_enter_lps_track(rtwdev);
3844+
}
3845+
37923846
static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work)
37933847
{
37943848
struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
@@ -4875,6 +4929,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev)
48754929

48764930
wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->track_work,
48774931
RTW89_TRACK_WORK_PERIOD);
4932+
wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->track_ps_work,
4933+
RTW89_TRACK_PS_WORK_PERIOD);
48784934

48794935
set_bit(RTW89_FLAG_RUNNING, rtwdev->flags);
48804936

@@ -4909,6 +4965,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev)
49094965
wiphy_work_cancel(wiphy, &btc->icmp_notify_work);
49104966
cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work);
49114967
wiphy_delayed_work_cancel(wiphy, &rtwdev->track_work);
4968+
wiphy_delayed_work_cancel(wiphy, &rtwdev->track_ps_work);
49124969
wiphy_delayed_work_cancel(wiphy, &rtwdev->chanctx_work);
49134970
wiphy_delayed_work_cancel(wiphy, &rtwdev->coex_act1_work);
49144971
wiphy_delayed_work_cancel(wiphy, &rtwdev->coex_bt_devinfo_work);
@@ -5136,6 +5193,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
51365193
INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work);
51375194
INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work);
51385195
wiphy_delayed_work_init(&rtwdev->track_work, rtw89_track_work);
5196+
wiphy_delayed_work_init(&rtwdev->track_ps_work, rtw89_track_ps_work);
51395197
wiphy_delayed_work_init(&rtwdev->chanctx_work, rtw89_chanctx_work);
51405198
wiphy_delayed_work_init(&rtwdev->coex_act1_work, rtw89_coex_act1_work);
51415199
wiphy_delayed_work_init(&rtwdev->coex_bt_devinfo_work, rtw89_coex_bt_devinfo_work);

drivers/net/wireless/realtek/rtw89/core.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ extern const struct ieee80211_ops rtw89_ops;
4040
#define BYPASS_CR_DATA 0xbabecafe
4141

4242
#define RTW89_TRACK_WORK_PERIOD round_jiffies_relative(HZ * 2)
43+
#define RTW89_TRACK_PS_WORK_PERIOD msecs_to_jiffies(100)
4344
#define RTW89_FORBID_BA_TIMER round_jiffies_relative(HZ * 4)
4445
#define CFO_TRACK_MAX_USER 64
4546
#define MAX_RSSI 110
@@ -1392,6 +1393,11 @@ struct rtw89_btc_wl_smap {
13921393
u32 emlsr: 1;
13931394
};
13941395

1396+
enum rtw89_tfc_interval {
1397+
RTW89_TFC_INTERVAL_100MS,
1398+
RTW89_TFC_INTERVAL_2SEC,
1399+
};
1400+
13951401
enum rtw89_tfc_lv {
13961402
RTW89_TFC_IDLE,
13971403
RTW89_TFC_ULTRA_LOW,
@@ -1400,7 +1406,6 @@ enum rtw89_tfc_lv {
14001406
RTW89_TFC_HIGH,
14011407
};
14021408

1403-
#define RTW89_TP_SHIFT 18 /* bytes/2s --> Mbps */
14041409
DECLARE_EWMA(tp, 10, 2);
14051410

14061411
struct rtw89_traffic_stats {
@@ -5943,6 +5948,7 @@ struct rtw89_dev {
59435948
} bbs[RTW89_PHY_NUM];
59445949

59455950
struct wiphy_delayed_work track_work;
5951+
struct wiphy_delayed_work track_ps_work;
59465952
struct wiphy_delayed_work chanctx_work;
59475953
struct wiphy_delayed_work coex_act1_work;
59485954
struct wiphy_delayed_work coex_bt_devinfo_work;
@@ -5993,6 +5999,7 @@ struct rtw89_vif {
59935999
__be32 ip_addr;
59946000

59956001
struct rtw89_traffic_stats stats;
6002+
struct rtw89_traffic_stats stats_ps;
59966003
u32 tdls_peer;
59976004

59986005
struct ieee80211_scan_ies *scan_ies;
@@ -7305,6 +7312,17 @@ static inline bool rtw89_is_rtl885xb(struct rtw89_dev *rtwdev)
73057312
return false;
73067313
}
73077314

7315+
static inline u32 rtw89_bytes_to_mbps(u64 bytes, enum rtw89_tfc_interval interval)
7316+
{
7317+
switch (interval) {
7318+
default:
7319+
case RTW89_TFC_INTERVAL_2SEC:
7320+
return bytes >> 18; /* bytes/2s --> Mbps */;
7321+
case RTW89_TFC_INTERVAL_100MS:
7322+
return (bytes * 10) >> 17; /* bytes/100ms --> Mbps */
7323+
}
7324+
}
7325+
73087326
int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
73097327
struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel);
73107328
int rtw89_h2c_tx(struct rtw89_dev *rtwdev,

drivers/net/wireless/realtek/rtw89/mac80211.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,7 @@ static int rtw89_ops_suspend(struct ieee80211_hw *hw,
17721772

17731773
set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags);
17741774
wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->track_work);
1775+
wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->track_ps_work);
17751776

17761777
ret = rtw89_wow_suspend(rtwdev, wowlan);
17771778
if (ret) {
@@ -1797,6 +1798,8 @@ static int rtw89_ops_resume(struct ieee80211_hw *hw)
17971798
clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags);
17981799
wiphy_delayed_work_queue(hw->wiphy, &rtwdev->track_work,
17991800
RTW89_TRACK_WORK_PERIOD);
1801+
wiphy_delayed_work_queue(hw->wiphy, &rtwdev->track_ps_work,
1802+
RTW89_TRACK_PS_WORK_PERIOD);
18001803

18011804
return ret ? 1 : 0;
18021805
}

drivers/net/wireless/realtek/rtw89/ser.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt)
492492
case SER_EV_STATE_IN:
493493
wiphy_lock(wiphy);
494494
wiphy_delayed_work_cancel(wiphy, &rtwdev->track_work);
495+
wiphy_delayed_work_cancel(wiphy, &rtwdev->track_ps_work);
495496
wiphy_unlock(wiphy);
496497
drv_stop_tx(ser);
497498

@@ -525,6 +526,8 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt)
525526
drv_resume_tx(ser);
526527
wiphy_delayed_work_queue(wiphy, &rtwdev->track_work,
527528
RTW89_TRACK_WORK_PERIOD);
529+
wiphy_delayed_work_queue(wiphy, &rtwdev->track_ps_work,
530+
RTW89_TRACK_PS_WORK_PERIOD);
528531
break;
529532

530533
default:

drivers/net/wireless/realtek/rtw89/wow.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#include "util.h"
1313
#include "wow.h"
1414

15-
void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb)
15+
void __rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb)
1616
{
1717
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
1818
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;

drivers/net/wireless/realtek/rtw89/wow.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,21 @@ static inline bool rtw_wow_has_mgd_features(struct rtw89_dev *rtwdev)
116116
return !bitmap_empty(rtw_wow->flags, RTW89_WOW_FLAG_NUM);
117117
}
118118

119+
void __rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb);
120+
121+
static inline
122+
void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb)
123+
{
124+
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
125+
126+
if (likely(!ieee80211_is_assoc_req(hdr->frame_control)))
127+
return;
128+
129+
__rtw89_wow_parse_akm(rtwdev, skb);
130+
}
131+
119132
int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan);
120133
int rtw89_wow_resume(struct rtw89_dev *rtwdev);
121-
void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb);
122134
#else
123135
static inline
124136
void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb)

0 commit comments

Comments
 (0)