Skip to content

Commit

Permalink
rtw89: add tx_wake notify for low ps mode
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Chin-Yen Lee authored and Kalle Valo committed Mar 9, 2022
1 parent 8959077 commit 7bfd05f
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 9 deletions.
19 changes: 19 additions & 0 deletions drivers/net/wireless/realtek/rtw89/core.c
Expand Up @@ -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)
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/realtek/rtw89/core.h
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;

Expand Down
4 changes: 4 additions & 0 deletions drivers/net/wireless/realtek/rtw89/fw.c
Expand Up @@ -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)
Expand Down
34 changes: 25 additions & 9 deletions drivers/net/wireless/realtek/rtw89/mac.c
Expand Up @@ -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,
Expand Down Expand Up @@ -993,14 +1001,22 @@ 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)
rtw89_err(rtwdev, "firmware failed to ack for %s ps mode\n",
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
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/realtek/rtw89/mac.h
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/realtek/rtw89/reg.h
Expand Up @@ -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)
Expand Down

0 comments on commit 7bfd05f

Please sign in to comment.