1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* Copyright(c) 2019-2020 Realtek Corporation 3 */ 4 5 #include "coex.h" 6 #include "core.h" 7 #include "debug.h" 8 #include "fw.h" 9 #include "mac.h" 10 #include "ps.h" 11 #include "reg.h" 12 #include "util.h" 13 14 static int rtw89_fw_leave_lps_check(struct rtw89_dev *rtwdev, u8 macid) 15 { 16 u32 pwr_en_bit = 0xE; 17 u32 chk_msk = pwr_en_bit << (4 * macid); 18 u32 polling; 19 int ret; 20 21 ret = read_poll_timeout_atomic(rtw89_read32_mask, polling, !polling, 22 1000, 50000, false, rtwdev, 23 R_AX_PPWRBIT_SETTING, chk_msk); 24 if (ret) { 25 rtw89_info(rtwdev, "rtw89: failed to leave lps state\n"); 26 return -EBUSY; 27 } 28 29 return 0; 30 } 31 32 static void rtw89_ps_power_mode_change_with_hci(struct rtw89_dev *rtwdev, 33 bool enter) 34 { 35 ieee80211_stop_queues(rtwdev->hw); 36 rtwdev->hci.paused = true; 37 flush_work(&rtwdev->txq_work); 38 ieee80211_wake_queues(rtwdev->hw); 39 40 rtw89_hci_pause(rtwdev, true); 41 rtw89_mac_power_mode_change(rtwdev, enter); 42 rtw89_hci_switch_mode(rtwdev, enter); 43 rtw89_hci_pause(rtwdev, false); 44 45 rtwdev->hci.paused = false; 46 47 if (!enter) { 48 local_bh_disable(); 49 napi_schedule(&rtwdev->napi); 50 local_bh_enable(); 51 } 52 } 53 54 static void rtw89_ps_power_mode_change(struct rtw89_dev *rtwdev, bool enter) 55 { 56 if (rtwdev->chip->low_power_hci_modes & BIT(rtwdev->ps_mode)) 57 rtw89_ps_power_mode_change_with_hci(rtwdev, enter); 58 else 59 rtw89_mac_power_mode_change(rtwdev, enter); 60 } 61 62 void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 63 { 64 if (rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) 65 return; 66 67 if (!rtwdev->ps_mode) 68 return; 69 70 if (test_and_set_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags)) 71 return; 72 73 rtw89_ps_power_mode_change(rtwdev, true); 74 } 75 76 void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev) 77 { 78 if (!rtwdev->ps_mode) 79 return; 80 81 if (test_and_clear_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags)) 82 rtw89_ps_power_mode_change(rtwdev, false); 83 } 84 85 static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, u8 mac_id) 86 { 87 struct rtw89_lps_parm lps_param = { 88 .macid = mac_id, 89 .psmode = RTW89_MAC_AX_PS_MODE_LEGACY, 90 .lastrpwm = RTW89_LAST_RPWM_PS, 91 }; 92 93 rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_FW_CTRL); 94 rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); 95 } 96 97 static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, u8 mac_id) 98 { 99 struct rtw89_lps_parm lps_param = { 100 .macid = mac_id, 101 .psmode = RTW89_MAC_AX_PS_MODE_ACTIVE, 102 .lastrpwm = RTW89_LAST_RPWM_ACTIVE, 103 }; 104 105 rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); 106 rtw89_fw_leave_lps_check(rtwdev, 0); 107 rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON); 108 } 109 110 void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev) 111 { 112 lockdep_assert_held(&rtwdev->mutex); 113 114 __rtw89_leave_ps_mode(rtwdev); 115 } 116 117 void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, 118 bool ps_mode) 119 { 120 lockdep_assert_held(&rtwdev->mutex); 121 122 if (test_and_set_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags)) 123 return; 124 125 __rtw89_enter_lps(rtwdev, rtwvif->mac_id); 126 if (ps_mode) 127 __rtw89_enter_ps_mode(rtwdev, rtwvif); 128 } 129 130 static void rtw89_leave_lps_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 131 { 132 if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION && 133 rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) 134 return; 135 136 __rtw89_leave_lps(rtwdev, rtwvif->mac_id); 137 } 138 139 void rtw89_leave_lps(struct rtw89_dev *rtwdev) 140 { 141 struct rtw89_vif *rtwvif; 142 143 lockdep_assert_held(&rtwdev->mutex); 144 145 if (!test_and_clear_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags)) 146 return; 147 148 __rtw89_leave_ps_mode(rtwdev); 149 150 rtw89_for_each_rtwvif(rtwdev, rtwvif) 151 rtw89_leave_lps_vif(rtwdev, rtwvif); 152 } 153 154 void rtw89_enter_ips(struct rtw89_dev *rtwdev) 155 { 156 struct rtw89_vif *rtwvif; 157 158 set_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags); 159 160 if (!test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) 161 return; 162 163 rtw89_for_each_rtwvif(rtwdev, rtwvif) 164 rtw89_mac_vif_deinit(rtwdev, rtwvif); 165 166 rtw89_core_stop(rtwdev); 167 } 168 169 void rtw89_leave_ips(struct rtw89_dev *rtwdev) 170 { 171 struct rtw89_vif *rtwvif; 172 int ret; 173 174 if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) 175 return; 176 177 ret = rtw89_core_start(rtwdev); 178 if (ret) 179 rtw89_err(rtwdev, "failed to leave idle state\n"); 180 181 rtw89_set_channel(rtwdev); 182 183 rtw89_for_each_rtwvif(rtwdev, rtwvif) 184 rtw89_mac_vif_init(rtwdev, rtwvif); 185 186 clear_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags); 187 } 188 189 void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl) 190 { 191 if (btc_ctrl) 192 rtw89_leave_lps(rtwdev); 193 } 194 195 static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, 196 enum rtw89_p2pps_action act) 197 { 198 if (act == RTW89_P2P_ACT_UPDATE || act == RTW89_P2P_ACT_REMOVE) 199 return; 200 201 if (act == RTW89_P2P_ACT_INIT) 202 rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, true); 203 else if (act == RTW89_P2P_ACT_TERMINATE) 204 rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, false); 205 } 206 207 static void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev, 208 struct ieee80211_vif *vif) 209 { 210 struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 211 enum rtw89_p2pps_action act; 212 u8 noa_id; 213 214 if (rtwvif->last_noa_nr == 0) 215 return; 216 217 for (noa_id = 0; noa_id < rtwvif->last_noa_nr; noa_id++) { 218 if (noa_id == rtwvif->last_noa_nr - 1) 219 act = RTW89_P2P_ACT_TERMINATE; 220 else 221 act = RTW89_P2P_ACT_REMOVE; 222 rtw89_tsf32_toggle(rtwdev, rtwvif, act); 223 rtw89_fw_h2c_p2p_act(rtwdev, vif, NULL, act, noa_id); 224 } 225 } 226 227 static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev, 228 struct ieee80211_vif *vif) 229 { 230 struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 231 struct ieee80211_p2p_noa_desc *desc; 232 enum rtw89_p2pps_action act; 233 u8 noa_id; 234 235 for (noa_id = 0; noa_id < RTW89_P2P_MAX_NOA_NUM; noa_id++) { 236 desc = &vif->bss_conf.p2p_noa_attr.desc[noa_id]; 237 if (!desc->count || !desc->duration) 238 break; 239 240 if (noa_id == 0) 241 act = RTW89_P2P_ACT_INIT; 242 else 243 act = RTW89_P2P_ACT_UPDATE; 244 rtw89_tsf32_toggle(rtwdev, rtwvif, act); 245 rtw89_fw_h2c_p2p_act(rtwdev, vif, desc, act, noa_id); 246 } 247 rtwvif->last_noa_nr = noa_id; 248 } 249 250 void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) 251 { 252 rtw89_p2p_disable_all_noa(rtwdev, vif); 253 rtw89_p2p_update_noa(rtwdev, vif); 254 } 255 256 void rtw89_recalc_lps(struct rtw89_dev *rtwdev) 257 { 258 struct ieee80211_vif *vif, *found_vif = NULL; 259 struct rtw89_vif *rtwvif; 260 int count = 0; 261 262 rtw89_for_each_rtwvif(rtwdev, rtwvif) { 263 vif = rtwvif_to_vif(rtwvif); 264 265 if (vif->type != NL80211_IFTYPE_STATION) { 266 count = 0; 267 break; 268 } 269 270 count++; 271 found_vif = vif; 272 } 273 274 if (count == 1 && found_vif->cfg.ps) { 275 rtwdev->lps_enabled = true; 276 } else { 277 rtw89_leave_lps(rtwdev); 278 rtwdev->lps_enabled = false; 279 } 280 } 281