]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
wifi: rtw89: wow: implement PS mode for net-detect
authorChin-Yen Lee <timlee@realtek.com>
Mon, 5 Aug 2024 09:00:25 +0000 (17:00 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Fri, 9 Aug 2024 00:39:05 +0000 (08:39 +0800)
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
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/fw.h
drivers/net/wireless/realtek/rtw89/wow.c
drivers/net/wireless/realtek/rtw89/wow.h

index 4c0a1aed6efdb02af13f010be8c6ef984d90162a..e545d2a7fb49d4d205e0dc259b2616a772d1cfe8 100644 (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);
 
index 0b0c5b5c6bb9b314b6f4573c5ec27e41a3ddabb9..1bbdf0613ca4eaade5898da1a2b97997947e5b02 100644 (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,
index 9882064ef68d336b65a5f83bd9aecf9734ebb74e..fa7fd657105127e8f9cdf168d65efdc6e23e72b5 100644 (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) {
index 0d90add0e88d998a3d7209f32d05c60c1f23740d..5eff3084119b320dac6d758b4402ccafb135bb05 100644 (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);