From 7bfd05ff4e805d017940e889b7a91014c7b6f9e6 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Fri, 25 Feb 2022 11:08:51 +0800 Subject: [PATCH] rtw89: add tx_wake notify for low ps mode 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 Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220225030851.13327-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 19 +++++++++++++ drivers/net/wireless/realtek/rtw89/core.h | 3 ++ drivers/net/wireless/realtek/rtw89/fw.c | 4 +++ drivers/net/wireless/realtek/rtw89/mac.c | 34 +++++++++++++++++------ drivers/net/wireless/realtek/rtw89/mac.h | 1 + drivers/net/wireless/realtek/rtw89/reg.h | 1 + 6 files changed, 53 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 88f1d452e5d64c..3adb52f3dc4579 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -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; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index d4c6d3140e2266..d203e4c5727d2a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -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; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index b610f676dab259..97224483f6188b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -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) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 5e140290fe04ad..9a91b408cd28e6 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -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 diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 9ea84349e593ce..5c7a9d784265a6 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -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, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index b39e531df2d7af..62dca0888d88dd 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -112,6 +112,7 @@ #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)