rtw89: add tx_wake notify for low ps mode
authorChin-Yen Lee <timlee@realtek.com>
Fri, 25 Feb 2022 03:08:51 +0000 (11:08 +0800)
committerKalle Valo <kvalo@kernel.org>
Wed, 9 Mar 2022 11:38:34 +0000 (13:38 +0200)
We found management frames get stuck when wifi chip
enters low ps mode. So we add one notify wake function
to trigger wifi chip into normal mode before forwarding
management frames.

Signed-off-by: Chin-Yen Lee <timlee@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220225030851.13327-3-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/mac.c
drivers/net/wireless/realtek/rtw89/mac.h
drivers/net/wireless/realtek/rtw89/reg.h

index 88f1d452e5d64c983f87a62fa266c2ad852d00d5..3adb52f3dc4579a1e44c7bc711b354b65e926cbd 100644 (file)
@@ -755,6 +755,22 @@ rtw89_core_tx_btc_spec_pkt_notify(struct rtw89_dev *rtwdev,
        return PACKET_MAX;
 }
 
+static void
+rtw89_core_tx_wake(struct rtw89_dev *rtwdev,
+                  struct rtw89_core_tx_request *tx_req)
+{
+       if (!rtwdev->fw.tx_wake)
+               return;
+
+       if (!test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags))
+               return;
+
+       if (tx_req->tx_type != RTW89_CORE_TX_TYPE_MGMT)
+               return;
+
+       rtw89_mac_notify_wake(rtwdev);
+}
+
 static void
 rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev,
                               struct rtw89_core_tx_request *tx_req)
@@ -853,6 +869,8 @@ int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
        rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true);
        rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true);
        rtw89_core_tx_update_desc_info(rtwdev, &tx_req);
+       rtw89_core_tx_wake(rtwdev, &tx_req);
+
        ret = rtw89_hci_tx_write(rtwdev, &tx_req);
        if (ret) {
                rtw89_err(rtwdev, "failed to transmit skb to HCI\n");
@@ -2618,6 +2636,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
        INIT_DELAYED_WORK(&rtwdev->cfo_track_work, rtw89_phy_cfo_track_work);
        rtwdev->txq_wq = alloc_workqueue("rtw89_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0);
        spin_lock_init(&rtwdev->ba_lock);
+       spin_lock_init(&rtwdev->rpwm_lock);
        mutex_init(&rtwdev->mutex);
        mutex_init(&rtwdev->rf_mutex);
        rtwdev->total_sta_assoc = 0;
index d4c6d3140e2266bcf3bbc5f244d625a80ab0915f..d203e4c5727d2a4e267e64aadf3602dc418a456a 100644 (file)
@@ -2376,6 +2376,7 @@ struct rtw89_fw_info {
        bool fw_log_enable;
        bool old_ht_ra_format;
        bool scan_offload;
+       bool tx_wake;
 };
 
 struct rtw89_cam_info {
@@ -2877,6 +2878,8 @@ struct rtw89_dev {
        /* txqs to setup ba session */
        struct list_head ba_list;
        struct work_struct ba_work;
+       /* used to protect rpwm */
+       spinlock_t rpwm_lock;
 
        struct rtw89_cam_info cam_info;
 
index b610f676dab25944a2aaa671f0f784469a1a08a3..97224483f6188b89e28c8824eeba5e30a3dee65e 100644 (file)
@@ -205,6 +205,10 @@ static void rtw89_fw_recognize_features(struct rtw89_dev *rtwdev)
        if (chip->chip_id == RTL8852A &&
            RTW89_FW_SUIT_VER_CODE(fw_suit) >= RTW89_FW_VER_CODE(0, 13, 35, 0))
                rtwdev->fw.scan_offload = true;
+
+       if (chip->chip_id == RTL8852A &&
+           RTW89_FW_SUIT_VER_CODE(fw_suit) >= RTW89_FW_VER_CODE(0, 13, 35, 0))
+               rtwdev->fw.tx_wake = true;
 }
 
 int rtw89_fw_recognize(struct rtw89_dev *rtwdev)
index 5e140290fe04ad2443a4ea7060fd47bc49ec63a8..9a91b408cd28e68c80b2f9ff177c27ee057a377d 100644 (file)
@@ -917,23 +917,31 @@ rtw89_mac_get_req_pwr_state(struct rtw89_dev *rtwdev)
 }
 
 static void rtw89_mac_send_rpwm(struct rtw89_dev *rtwdev,
-                               enum rtw89_rpwm_req_pwr_state req_pwr_state)
+                               enum rtw89_rpwm_req_pwr_state req_pwr_state,
+                               bool notify_wake)
 {
        u16 request;
 
+       spin_lock_bh(&rtwdev->rpwm_lock);
+
        request = rtw89_read16(rtwdev, R_AX_RPWM);
        request ^= request | PS_RPWM_TOGGLE;
-
-       rtwdev->mac.rpwm_seq_num = (rtwdev->mac.rpwm_seq_num + 1) &
-                                  RPWM_SEQ_NUM_MAX;
-       request |= FIELD_PREP(PS_RPWM_SEQ_NUM, rtwdev->mac.rpwm_seq_num);
-
        request |= req_pwr_state;
 
-       if (req_pwr_state < RTW89_MAC_RPWM_REQ_PWR_STATE_CLK_GATED)
-               request |= PS_RPWM_ACK;
+       if (notify_wake) {
+               request |= PS_RPWM_NOTIFY_WAKE;
+       } else {
+               rtwdev->mac.rpwm_seq_num = (rtwdev->mac.rpwm_seq_num + 1) &
+                                           RPWM_SEQ_NUM_MAX;
+               request |= FIELD_PREP(PS_RPWM_SEQ_NUM,
+                                     rtwdev->mac.rpwm_seq_num);
 
+               if (req_pwr_state < RTW89_MAC_RPWM_REQ_PWR_STATE_CLK_GATED)
+                       request |= PS_RPWM_ACK;
+       }
        rtw89_write16(rtwdev, rtwdev->hci.rpwm_addr, request);
+
+       spin_unlock_bh(&rtwdev->rpwm_lock);
 }
 
 static int rtw89_mac_check_cpwm_state(struct rtw89_dev *rtwdev,
@@ -993,7 +1001,7 @@ void rtw89_mac_power_mode_change(struct rtw89_dev *rtwdev, bool enter)
        else
                state = RTW89_MAC_RPWM_REQ_PWR_STATE_ACTIVE;
 
-       rtw89_mac_send_rpwm(rtwdev, state);
+       rtw89_mac_send_rpwm(rtwdev, state, false);
        ret = read_poll_timeout_atomic(rtw89_mac_check_cpwm_state, ret, !ret,
                                       1000, 15000, false, rtwdev, state);
        if (ret)
@@ -1001,6 +1009,14 @@ void rtw89_mac_power_mode_change(struct rtw89_dev *rtwdev, bool enter)
                          enter ? "entering" : "leaving");
 }
 
+void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev)
+{
+       enum rtw89_rpwm_req_pwr_state state;
+
+       state = rtw89_mac_get_req_pwr_state(rtwdev);
+       rtw89_mac_send_rpwm(rtwdev, state, true);
+}
+
 static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on)
 {
 #define PWR_ACT 1
index 9ea84349e593cefffe5449ca74aa302122b55b31..5c7a9d784265a6d3b4e699106bf21f8a2506cf06 100644 (file)
@@ -799,6 +799,7 @@ bool rtw89_mac_get_txpwr_cr(struct rtw89_dev *rtwdev,
                            enum rtw89_phy_idx phy_idx,
                            u32 reg_base, u32 *cr);
 void rtw89_mac_power_mode_change(struct rtw89_dev *rtwdev, bool enter);
+void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev);
 void rtw89_mac_bf_assoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta);
 void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
index b39e531df2d7af00053ffbb2fe4a8b73fea65018..62dca0888d88ddc46e3d3fc5fa761ad56d0f68c1 100644 (file)
 #define PS_RPWM_TOGGLE BIT(15)
 #define PS_RPWM_ACK BIT(14)
 #define PS_RPWM_SEQ_NUM GENMASK(13, 12)
+#define PS_RPWM_NOTIFY_WAKE BIT(8)
 #define PS_RPWM_STATE 0x7
 #define RPWM_SEQ_NUM_MAX 3
 #define PS_CPWM_SEQ_NUM GENMASK(13, 12)