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