xref: /linux/drivers/net/wireless/realtek/rtw89/ps.c (revision db10cb9b)
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