summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/realtek/rtw88/ps.c
diff options
context:
space:
mode:
authorChin-Yen Lee <timlee@realtek.com>2020-10-30 16:48:25 +0800
committerKalle Valo <kvalo@codeaurora.org>2020-11-07 17:51:04 +0200
commitf31e039fab38fb29104ef35c6c7d29e66a37adea (patch)
treea072b6f4b096c3b74809540d2731b0e093dd7cfd /drivers/net/wireless/realtek/rtw88/ps.c
parenta95949606828e1c9d91e5b05171b39ff147ced58 (diff)
rtw88: add C2H response for checking firmware leave lps
Originally driver checks if firmware has left lps via reading the setting of REG_TCR register. But this way may fail when firmware is frequently changing power state. Therefore, firmware provides a safer option for driver. When firmware leaves lps successfully, it sends a C2H response to inform driver. Signed-off-by: Chin-Yen Lee <timlee@realtek.com> Signed-off-by: Tzu-En Huang <tehuang@realtek.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Link: https://lore.kernel.org/r/20201030084826.9034-4-tehuang@realtek.com
Diffstat (limited to 'drivers/net/wireless/realtek/rtw88/ps.c')
-rw-r--r--drivers/net/wireless/realtek/rtw88/ps.c52
1 files changed, 47 insertions, 5 deletions
diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c
index 8ed243628dcb..233b3df264b3 100644
--- a/drivers/net/wireless/realtek/rtw88/ps.c
+++ b/drivers/net/wireless/realtek/rtw88/ps.c
@@ -109,7 +109,7 @@ static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev)
rtw_hci_deep_ps(rtwdev, false);
}
-static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev)
+static int __rtw_fw_leave_lps_check_reg(struct rtw_dev *rtwdev)
{
int i;
@@ -127,12 +127,53 @@ static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev)
*/
for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) {
if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0)
- return;
+ return 0;
msleep(20);
}
- rtw_write32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN, 0);
- rtw_warn(rtwdev, "firmware failed to restore hardware setting\n");
+ return -EBUSY;
+}
+
+static int __rtw_fw_leave_lps_check_c2h(struct rtw_dev *rtwdev)
+{
+ if (wait_for_completion_timeout(&rtwdev->lps_leave_check,
+ LEAVE_LPS_TIMEOUT))
+ return 0;
+ return -EBUSY;
+}
+
+static void rtw_fw_leave_lps_check(struct rtw_dev *rtwdev)
+{
+ bool ret = false;
+ struct rtw_fw_state *fw;
+
+ if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
+ fw = &rtwdev->wow_fw;
+ else
+ fw = &rtwdev->fw;
+
+ if (fw->feature & FW_FEATURE_LPS_C2H)
+ ret = __rtw_fw_leave_lps_check_c2h(rtwdev);
+ else
+ ret = __rtw_fw_leave_lps_check_reg(rtwdev);
+
+ if (ret) {
+ rtw_write32_clr(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN);
+ rtw_warn(rtwdev, "firmware failed to leave lps state\n");
+ }
+}
+
+static void rtw_fw_leave_lps_check_prepare(struct rtw_dev *rtwdev)
+{
+ struct rtw_fw_state *fw;
+
+ if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
+ fw = &rtwdev->wow_fw;
+ else
+ fw = &rtwdev->fw;
+
+ if (fw->feature & FW_FEATURE_LPS_C2H)
+ reinit_completion(&rtwdev->lps_leave_check);
}
static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
@@ -145,8 +186,9 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
conf->smart_ps = 0;
rtw_hci_link_ps(rtwdev, false);
+ rtw_fw_leave_lps_check_prepare(rtwdev);
rtw_fw_set_pwr_mode(rtwdev);
- rtw_fw_leave_lps_state_check(rtwdev);
+ rtw_fw_leave_lps_check(rtwdev);
clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);