wifi: rtw88: fix not entering PS mode after AP stops
authorPo-Hao Huang <phhuang@realtek.com>
Fri, 16 Jun 2023 12:55:40 +0000 (20:55 +0800)
committerKalle Valo <kvalo@kernel.org>
Wed, 21 Jun 2023 09:41:46 +0000 (12:41 +0300)
Without this patch, firmware only track beacons for port 0 and since
we will always start AP on port 0, this results in misbehavior of
power saving mode on other ports after AP stops.

The "default port" H2C command is used to notify which port should
firmware track. Update the correct settings to firmware so power
saving mode can work properly.

Signed-off-by: Po-Hao Huang <phhuang@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/20230616125540.36877-7-pkshih@realtek.com
drivers/net/wireless/realtek/rtw88/fw.c
drivers/net/wireless/realtek/rtw88/fw.h
drivers/net/wireless/realtek/rtw88/mac80211.c
drivers/net/wireless/realtek/rtw88/main.c
drivers/net/wireless/realtek/rtw88/main.h

index 5e329bb95bb897b8d8880f8177a40cda1ff59edc..567bbedd8ee09ba468b85b2404d27d9156756b99 100644 (file)
@@ -519,6 +519,23 @@ void rtw_fw_query_bt_info(struct rtw_dev *rtwdev)
        rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
 }
 
+void rtw_fw_default_port(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif)
+{
+       struct rtw_h2c_register h2c = {};
+
+       if (rtwvif->net_type != RTW_NET_MGD_LINKED)
+               return;
+
+       /* Leave LPS before default port H2C so FW timer is correct */
+       rtw_leave_lps(rtwdev);
+
+       h2c.w0 = u32_encode_bits(H2C_CMD_DEFAULT_PORT, RTW_H2C_W0_CMDID) |
+                u32_encode_bits(rtwvif->port, RTW_H2C_DEFAULT_PORT_W0_PORTID) |
+                u32_encode_bits(rtwvif->mac_id, RTW_H2C_DEFAULT_PORT_W0_MACID);
+
+       rtw_fw_send_h2c_command_register(rtwdev, &h2c);
+}
+
 void rtw_fw_wl_ch_info(struct rtw_dev *rtwdev, u8 link, u8 ch, u8 bw)
 {
        u8 h2c_pkt[H2C_PKT_SIZE] = {0};
index 11a77d86cd144d86a42ae90bd8ccb55f97d4fba4..43ccdf9965ac46ea8dca247389a402c883958154 100644 (file)
@@ -86,6 +86,12 @@ struct rtw_h2c_register {
        u32 w1;
 } __packed;
 
+#define RTW_H2C_W0_CMDID               GENMASK(7, 0)
+
+/* H2C_CMD_DEFAULT_PORT command */
+#define RTW_H2C_DEFAULT_PORT_W0_PORTID GENMASK(15, 8)
+#define RTW_H2C_DEFAULT_PORT_W0_MACID  GENMASK(23, 16)
+
 struct rtw_h2c_cmd {
        __le32 msg;
        __le32 msg_ext;
@@ -535,6 +541,7 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
 #define H2C_CMD_MEDIA_STATUS_RPT       0x01
 #define H2C_CMD_SET_PWR_MODE           0x20
 #define H2C_CMD_LPS_PG_INFO            0x2b
+#define H2C_CMD_DEFAULT_PORT           0x2c
 #define H2C_CMD_RA_INFO                        0x40
 #define H2C_CMD_RSSI_MONITOR           0x42
 #define H2C_CMD_BCN_FILTER_OFFLOAD_P0  0x56
@@ -806,6 +813,7 @@ void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
 void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb);
 void rtw_fw_send_general_info(struct rtw_dev *rtwdev);
 void rtw_fw_send_phydm_info(struct rtw_dev *rtwdev);
+void rtw_fw_default_port(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif);
 
 void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para);
 void rtw_fw_inform_rfk_status(struct rtw_dev *rtwdev, bool start);
index aacea2098df85ae8f7d6b5ccfd2a10366cafbede..a99b53d4426763dd719beeef43235fd6dd072184 100644 (file)
@@ -382,6 +382,7 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
 
                        rtw_fw_download_rsvd_page(rtwdev);
                        rtw_send_rsvd_page_h2c(rtwdev);
+                       rtw_fw_default_port(rtwdev, rtwvif);
                        rtw_coex_media_status_notify(rtwdev, vif->cfg.assoc);
                        if (rtw_bf_support)
                                rtw_bf_assoc(rtwdev, vif, conf);
index d55b041a6bb93ecbb3103fadfbc7f3b1e0b75a10..c853e2f2d448f12f7147accbe0e0eb47722ecf44 100644 (file)
@@ -334,12 +334,15 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta,
                struct ieee80211_vif *vif)
 {
        struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
+       struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
        int i;
 
        si->mac_id = rtw_acquire_macid(rtwdev);
        if (si->mac_id >= RTW_MAX_MAC_ID_NUM)
                return -ENOSPC;
 
+       if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc == 0)
+               rtwvif->mac_id = si->mac_id;
        si->rtwdev = rtwdev;
        si->sta = sta;
        si->vif = vif;
@@ -2340,6 +2343,9 @@ static void rtw_port_switch_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
        rtw_dbg(rtwdev, RTW_DBG_STATE, "AP port switch from %d -> %d\n",
                rtwvif_ap->port, rtwvif_target->port);
 
+       /* Leave LPS so the value swapped are not in PS mode */
+       rtw_leave_lps(rtwdev);
+
        reg1 = &rtwvif_ap->conf->net_type;
        reg2 = &rtwvif_target->conf->net_type;
        rtw_swap_reg_mask(rtwdev, reg1, reg2);
@@ -2358,6 +2364,8 @@ static void rtw_port_switch_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 
        swap(rtwvif_target->port, rtwvif_ap->port);
        swap(rtwvif_target->conf, rtwvif_ap->conf);
+
+       rtw_fw_default_port(rtwdev, rtwvif_target);
 }
 
 void rtw_core_port_switch(struct rtw_dev *rtwdev, struct ieee80211_vif *vif)
index 9e841f6991a9a4d0d984fe5892282bd8d473ade4..f9dd2ab941c8fbb4de72d33ab481d8956862433a 100644 (file)
@@ -803,6 +803,7 @@ struct rtw_bf_info {
 struct rtw_vif {
        enum rtw_net_type net_type;
        u16 aid;
+       u8 mac_id; /* for STA mode only */
        u8 mac_addr[ETH_ALEN];
        u8 bssid[ETH_ALEN];
        u8 port;