wifi: rtw89: wow: implement PS mode for net-detect

When net-detect is enabled, WoWLAN firmware will periodically
scan until beacon or probe response of configured networks are
received. To reduce power consumption, the FW-IPS mode is
implemented to keep WiFi chip in idle mode between each scan.
The FW-IPS is controlled by WoWLAN firmware to turn of some critical
electrical components, and is different from the original IPS mode
which most electrical components are turned off.

Signed-off-by: Chin-Yen Lee <timlee@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20240805090028.27768-3-pkshih@realtek.com
This commit is contained in:
Chin-Yen Lee 2024-08-05 17:00:25 +08:00 committed by Ping-Ke Shih
parent 45ae0e8cf8
commit 0f683c2cf6
4 changed files with 89 additions and 7 deletions

View File

@ -6856,7 +6856,43 @@ hdr:
goto fail;
}
return 0;
fail:
dev_kfree_skb_any(skb);
return ret;
}
int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
bool enable)
{
struct rtw89_h2c_fwips *h2c;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
int ret;
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw ips\n");
return -ENOMEM;
}
skb_put(skb, len);
h2c = (struct rtw89_h2c_fwips *)skb->data;
h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_FW_IPS_W0_MACID) |
le32_encode_bits(enable, RTW89_H2C_FW_IPS_W0_ENABLE);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC,
H2C_CL_MAC_PS,
H2C_FUNC_IPS_CFG, 0, 1,
len);
ret = rtw89_h2c_tx(rtwdev, skb, false);
if (ret) {
rtw89_err(rtwdev, "failed to send h2c\n");
goto fail;
}
return 0;
fail:
dev_kfree_skb_any(skb);

View File

@ -2748,6 +2748,13 @@ struct rtw89_h2c_scanofld_be {
#define RTW89_H2C_SCANOFLD_BE_W9_SIZE_MACC GENMASK(15, 8)
#define RTW89_H2C_SCANOFLD_BE_W9_SIZE_OP GENMASK(23, 16)
struct rtw89_h2c_fwips {
__le32 w0;
} __packed;
#define RTW89_H2C_FW_IPS_W0_MACID GENMASK(7, 0)
#define RTW89_H2C_FW_IPS_W0_ENABLE BIT(8)
static inline void RTW89_SET_FWCMD_P2P_MACID(void *cmd, u32 val)
{
le32p_replace_bits((__le32 *)cmd, val, GENMASK(7, 0));
@ -3965,6 +3972,7 @@ enum rtw89_wow_h2c_func {
#define H2C_CL_MAC_PS 0x2
#define H2C_FUNC_MAC_LPS_PARM 0x0
#define H2C_FUNC_P2P_ACT 0x1
#define H2C_FUNC_IPS_CFG 0x3
/* CLASS 3 - FW download */
#define H2C_CL_MAC_FWDL 0x3
@ -4446,6 +4454,8 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev,
struct rtw89_lps_parm *lps_param);
int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif);
int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
bool enable);
struct sk_buff *rtw89_fw_h2c_alloc_skb_with_hdr(struct rtw89_dev *rtwdev, u32 len);
struct sk_buff *rtw89_fw_h2c_alloc_skb_no_hdr(struct rtw89_dev *rtwdev, u32 len);
int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev,

View File

@ -687,17 +687,30 @@ static void rtw89_wow_enter_deep_ps(struct rtw89_dev *rtwdev)
__rtw89_enter_ps_mode(rtwdev, rtwvif);
}
static void rtw89_wow_enter_lps(struct rtw89_dev *rtwdev)
static void rtw89_wow_enter_ps(struct rtw89_dev *rtwdev)
{
struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
rtw89_enter_lps(rtwdev, rtwvif, false);
if (rtw89_wow_mgd_linked(rtwdev))
rtw89_enter_lps(rtwdev, rtwvif, false);
else if (rtw89_wow_no_link(rtwdev))
rtw89_fw_h2c_fwips(rtwdev, rtwvif, true);
}
static void rtw89_wow_leave_lps(struct rtw89_dev *rtwdev)
static void rtw89_wow_leave_ps(struct rtw89_dev *rtwdev, bool enable_wow)
{
rtw89_leave_lps(rtwdev);
struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
if (rtw89_wow_mgd_linked(rtwdev)) {
rtw89_leave_lps(rtwdev);
} else if (rtw89_wow_no_link(rtwdev)) {
if (enable_wow)
rtw89_leave_ips(rtwdev);
else
rtw89_fw_h2c_fwips(rtwdev, rtwvif, false);
}
}
static int rtw89_wow_config_mac(struct rtw89_dev *rtwdev, bool enable_wow)
@ -1430,7 +1443,7 @@ static int rtw89_wow_enable(struct rtw89_dev *rtwdev)
goto out;
}
rtw89_wow_enter_lps(rtwdev);
rtw89_wow_enter_ps(rtwdev);
ret = rtw89_wow_enable_trx_post(rtwdev);
if (ret) {
@ -1455,7 +1468,7 @@ static int rtw89_wow_disable(struct rtw89_dev *rtwdev)
goto out;
}
rtw89_wow_leave_lps(rtwdev);
rtw89_wow_leave_ps(rtwdev, false);
ret = rtw89_wow_fw_stop(rtwdev);
if (ret) {
@ -1480,6 +1493,12 @@ out:
return ret;
}
static void rtw89_wow_restore_ps(struct rtw89_dev *rtwdev)
{
if (rtw89_wow_no_link(rtwdev))
rtw89_enter_ips(rtwdev);
}
int rtw89_wow_resume(struct rtw89_dev *rtwdev)
{
int ret;
@ -1504,6 +1523,7 @@ int rtw89_wow_resume(struct rtw89_dev *rtwdev)
if (ret)
rtw89_err(rtwdev, "failed to disable wow\n");
rtw89_wow_restore_ps(rtwdev);
out:
rtw89_wow_clear_wakeups(rtwdev);
return ret;
@ -1519,7 +1539,7 @@ int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan)
return ret;
}
rtw89_wow_leave_lps(rtwdev);
rtw89_wow_leave_ps(rtwdev, true);
ret = rtw89_wow_enable(rtwdev);
if (ret) {

View File

@ -95,6 +95,22 @@ static inline int rtw89_wow_get_sec_hdr_len(struct rtw89_dev *rtwdev)
}
#ifdef CONFIG_PM
static inline bool rtw89_wow_mgd_linked(struct rtw89_dev *rtwdev)
{
struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
return rtwvif->net_type == RTW89_NET_TYPE_INFRA;
}
static inline bool rtw89_wow_no_link(struct rtw89_dev *rtwdev)
{
struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
return rtwvif->net_type == RTW89_NET_TYPE_NO_LINK;
}
int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan);
int rtw89_wow_resume(struct rtw89_dev *rtwdev);
void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb);