]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
rtw88: check firmware leave lps successfully
authorChin-Yen Lee <timlee@realtek.com>
Wed, 2 Oct 2019 06:35:18 +0000 (14:35 +0800)
committerKalle Valo <kvalo@codeaurora.org>
Fri, 4 Oct 2019 13:44:54 +0000 (16:44 +0300)
Driver needs to wait for firmware to restore hardware setting
to active mode after leaving lps.

After getting H2C from driver for leaving lps, firmware will
issue null packet without PS bit to inform AP driver is active,
and then restore REG_TCR Register if AP has receiced null packet.

But the transmission of null packet may cost much more time
in noisy environment. If driver does not wait for firmware,
null packet with PS bit could be sent due to incorrect REG_TCR setting.
And AP will be confused.

In our test, 100ms is enough for firmware to send null packet
to AP. If REG_TCR Register is still wrong after 100ms, we will
modify it directly, force the PS bit to be cleared

Signed-off-by: Chin-Yen Lee <timlee@realtek.com>
Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/realtek/rtw88/ps.c
drivers/net/wireless/realtek/rtw88/ps.h
drivers/net/wireless/realtek/rtw88/reg.h

index 83db6cf6a219ca8c3eaa8aa8a9a7e24de945c462..bf149956b04e70dbc9d7f866ff839c27df591be6 100644 (file)
@@ -9,6 +9,7 @@
 #include "mac.h"
 #include "coex.h"
 #include "debug.h"
+#include "reg.h"
 
 static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
 {
@@ -118,6 +119,32 @@ 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)
+{
+       int i;
+
+       /* Driver needs to wait for firmware to leave LPS state
+        * successfully. Firmware will send null packet to inform AP,
+        * and see if AP sends an ACK back, then firmware will restore
+        * the REG_TCR register.
+        *
+        * If driver does not wait for firmware, null packet with
+        * PS bit could be sent due to incorrect REG_TCR setting.
+        *
+        * In our test, 100ms should be enough for firmware to finish
+        * the flow. If REG_TCR Register is still incorrect after 100ms,
+        * just modify it directly, and throw a warn message.
+        */
+       for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) {
+               if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0)
+                       return;
+               msleep(20);
+       }
+
+       rtw_write32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN, 0);
+       rtw_warn(rtwdev, "firmware failed to restore hardware setting\n");
+}
+
 static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
 {
        struct rtw_lps_conf *conf = &rtwdev->lps_conf;
@@ -128,6 +155,8 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
        conf->smart_ps = 0;
 
        rtw_fw_set_pwr_mode(rtwdev);
+       rtw_fw_leave_lps_state_check(rtwdev);
+
        clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
 
        rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE);
index 18f687cfe211348e541907b27d516afa4aeb1920..25925eedbad4b2870d1b526300cb4e15da5df344 100644 (file)
@@ -11,6 +11,8 @@
 #define POWER_MODE_PG          BIT(4)
 #define POWER_MODE_LCLK                BIT(0)
 
+#define LEAVE_LPS_TRY_CNT      5
+
 int rtw_enter_ips(struct rtw_dev *rtwdev);
 int rtw_leave_ips(struct rtw_dev *rtwdev);
 
index fe793e270d22f245629cdc9107f44478981dd550..60014077de7740d7ba36018a3f1381de6ead6d2e 100644 (file)
 #define BIT_TSFT_SEL_TIMER0    (BIT(4) | BIT(5) | BIT(6))
 
 #define REG_TCR                        0x0604
+#define BIT_PWRMGT_HWDATA_EN   BIT(7)
 #define REG_RCR                        0x0608
 #define BIT_APP_FCS            BIT(31)
 #define BIT_APP_MIC            BIT(30)