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 { 119 lockdep_assert_held(&rtwdev->mutex); 120 121 if (test_and_set_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags)) 122 return; 123 124 __rtw89_enter_lps(rtwdev, rtwvif->mac_id); 125 __rtw89_enter_ps_mode(rtwdev, rtwvif); 126 } 127 128 static void rtw89_leave_lps_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 129 { 130 if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION && 131 rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) 132 return; 133 134 __rtw89_leave_lps(rtwdev, rtwvif->mac_id); 135 } 136 137 void rtw89_leave_lps(struct rtw89_dev *rtwdev) 138 { 139 struct rtw89_vif *rtwvif; 140 141 lockdep_assert_held(&rtwdev->mutex); 142 143 if (!test_and_clear_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags)) 144 return; 145 146 __rtw89_leave_ps_mode(rtwdev); 147 148 rtw89_for_each_rtwvif(rtwdev, rtwvif) 149 rtw89_leave_lps_vif(rtwdev, rtwvif); 150 } 151 152 void rtw89_enter_ips(struct rtw89_dev *rtwdev) 153 { 154 struct rtw89_vif *rtwvif; 155 156 set_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags); 157 158 rtw89_for_each_rtwvif(rtwdev, rtwvif) 159 rtw89_mac_vif_deinit(rtwdev, rtwvif); 160 161 rtw89_core_stop(rtwdev); 162 } 163 164 void rtw89_leave_ips(struct rtw89_dev *rtwdev) 165 { 166 struct rtw89_vif *rtwvif; 167 int ret; 168 169 ret = rtw89_core_start(rtwdev); 170 if (ret) 171 rtw89_err(rtwdev, "failed to leave idle state\n"); 172 173 rtw89_set_channel(rtwdev); 174 175 rtw89_for_each_rtwvif(rtwdev, rtwvif) 176 rtw89_mac_vif_init(rtwdev, rtwvif); 177 178 clear_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags); 179 } 180 181 void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl) 182 { 183 if (btc_ctrl) 184 rtw89_leave_lps(rtwdev); 185 } 186 187 static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, 188 enum rtw89_p2pps_action act) 189 { 190 if (act == RTW89_P2P_ACT_UPDATE || act == RTW89_P2P_ACT_REMOVE) 191 return; 192 193 if (act == RTW89_P2P_ACT_INIT) 194 rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, true); 195 else if (act == RTW89_P2P_ACT_TERMINATE) 196 rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, false); 197 } 198 199 static void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev, 200 struct ieee80211_vif *vif) 201 { 202 struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 203 enum rtw89_p2pps_action act; 204 u8 noa_id; 205 206 if (rtwvif->last_noa_nr == 0) 207 return; 208 209 for (noa_id = 0; noa_id < rtwvif->last_noa_nr; noa_id++) { 210 if (noa_id == rtwvif->last_noa_nr - 1) 211 act = RTW89_P2P_ACT_TERMINATE; 212 else 213 act = RTW89_P2P_ACT_REMOVE; 214 rtw89_tsf32_toggle(rtwdev, rtwvif, act); 215 rtw89_fw_h2c_p2p_act(rtwdev, vif, NULL, act, noa_id); 216 } 217 } 218 219 static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev, 220 struct ieee80211_vif *vif) 221 { 222 struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 223 struct ieee80211_p2p_noa_desc *desc; 224 enum rtw89_p2pps_action act; 225 u8 noa_id; 226 227 for (noa_id = 0; noa_id < RTW89_P2P_MAX_NOA_NUM; noa_id++) { 228 desc = &vif->bss_conf.p2p_noa_attr.desc[noa_id]; 229 if (!desc->count || !desc->duration) 230 break; 231 232 if (noa_id == 0) 233 act = RTW89_P2P_ACT_INIT; 234 else 235 act = RTW89_P2P_ACT_UPDATE; 236 rtw89_tsf32_toggle(rtwdev, rtwvif, act); 237 rtw89_fw_h2c_p2p_act(rtwdev, vif, desc, act, noa_id); 238 } 239 rtwvif->last_noa_nr = noa_id; 240 } 241 242 void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) 243 { 244 rtw89_p2p_disable_all_noa(rtwdev, vif); 245 rtw89_p2p_update_noa(rtwdev, vif); 246 } 247