xref: /linux/drivers/net/wireless/realtek/rtw89/wow.c (revision 561add0da6d3d07c9bccb0832fb6ed5619167d26)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright(c) 2019-2022  Realtek Corporation
3  */
4 #include "cam.h"
5 #include "core.h"
6 #include "debug.h"
7 #include "fw.h"
8 #include "mac.h"
9 #include "phy.h"
10 #include "ps.h"
11 #include "reg.h"
12 #include "util.h"
13 #include "wow.h"
14 
15 static void rtw89_wow_leave_deep_ps(struct rtw89_dev *rtwdev)
16 {
17 	__rtw89_leave_ps_mode(rtwdev);
18 }
19 
20 static void rtw89_wow_enter_deep_ps(struct rtw89_dev *rtwdev)
21 {
22 	struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
23 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
24 
25 	__rtw89_enter_ps_mode(rtwdev, rtwvif);
26 }
27 
28 static void rtw89_wow_enter_lps(struct rtw89_dev *rtwdev)
29 {
30 	struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
31 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
32 
33 	rtw89_enter_lps(rtwdev, rtwvif, false);
34 }
35 
36 static void rtw89_wow_leave_lps(struct rtw89_dev *rtwdev)
37 {
38 	rtw89_leave_lps(rtwdev);
39 }
40 
41 static int rtw89_wow_config_mac(struct rtw89_dev *rtwdev, bool enable_wow)
42 {
43 	const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
44 	int ret;
45 
46 	if (enable_wow) {
47 		ret = rtw89_mac_resize_ple_rx_quota(rtwdev, true);
48 		if (ret) {
49 			rtw89_err(rtwdev, "[ERR]patch rx qta %d\n", ret);
50 			return ret;
51 		}
52 		rtw89_write32_set(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP);
53 		rtw89_write32_clr(rtwdev, mac->rx_fltr, B_AX_SNIFFER_MODE);
54 		rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false);
55 		rtw89_write32(rtwdev, R_AX_ACTION_FWD0, 0);
56 		rtw89_write32(rtwdev, R_AX_ACTION_FWD1, 0);
57 		rtw89_write32(rtwdev, R_AX_TF_FWD, 0);
58 		rtw89_write32(rtwdev, R_AX_HW_RPT_FWD, 0);
59 	} else {
60 		ret = rtw89_mac_resize_ple_rx_quota(rtwdev, false);
61 		if (ret) {
62 			rtw89_err(rtwdev, "[ERR]patch rx qta %d\n", ret);
63 			return ret;
64 		}
65 		rtw89_write32_clr(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP);
66 		rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true);
67 		rtw89_write32(rtwdev, R_AX_ACTION_FWD0, TRXCFG_MPDU_PROC_ACT_FRWD);
68 		rtw89_write32(rtwdev, R_AX_TF_FWD, TRXCFG_MPDU_PROC_TF_FRWD);
69 	}
70 
71 	return 0;
72 }
73 
74 static void rtw89_wow_set_rx_filter(struct rtw89_dev *rtwdev, bool enable)
75 {
76 	enum rtw89_mac_fwd_target fwd_target = enable ?
77 					       RTW89_FWD_DONT_CARE :
78 					       RTW89_FWD_TO_HOST;
79 
80 	rtw89_mac_typ_fltr_opt(rtwdev, RTW89_MGNT, fwd_target, RTW89_MAC_0);
81 	rtw89_mac_typ_fltr_opt(rtwdev, RTW89_CTRL, fwd_target, RTW89_MAC_0);
82 	rtw89_mac_typ_fltr_opt(rtwdev, RTW89_DATA, fwd_target, RTW89_MAC_0);
83 }
84 
85 static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev)
86 {
87 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
88 	struct cfg80211_wowlan_nd_info nd_info;
89 	struct cfg80211_wowlan_wakeup wakeup = {
90 		.pattern_idx = -1,
91 	};
92 	u32 wow_reason_reg;
93 	u8 reason;
94 
95 	if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B)
96 		wow_reason_reg = R_AX_C2HREG_DATA3 + 3;
97 	else
98 		wow_reason_reg = R_AX_C2HREG_DATA3_V1 + 3;
99 
100 	reason = rtw89_read8(rtwdev, wow_reason_reg);
101 
102 	switch (reason) {
103 	case RTW89_WOW_RSN_RX_DEAUTH:
104 		wakeup.disconnect = true;
105 		rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx deauth\n");
106 		break;
107 	case RTW89_WOW_RSN_DISCONNECT:
108 		wakeup.disconnect = true;
109 		rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: AP is off\n");
110 		break;
111 	case RTW89_WOW_RSN_RX_MAGIC_PKT:
112 		wakeup.magic_pkt = true;
113 		rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx magic packet\n");
114 		break;
115 	case RTW89_WOW_RSN_RX_GTK_REKEY:
116 		wakeup.gtk_rekey_failure = true;
117 		rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx gtk rekey\n");
118 		break;
119 	case RTW89_WOW_RSN_RX_PATTERN_MATCH:
120 		/* Current firmware and driver don't report pattern index
121 		 * Use pattern_idx to 0 defaultly.
122 		 */
123 		wakeup.pattern_idx = 0;
124 		rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx pattern match packet\n");
125 		break;
126 	case RTW89_WOW_RSN_RX_NLO:
127 		/* Current firmware and driver don't report ssid index.
128 		 * Use 0 for n_matches based on its comment.
129 		 */
130 		nd_info.n_matches = 0;
131 		wakeup.net_detect = &nd_info;
132 		rtw89_debug(rtwdev, RTW89_DBG_WOW, "Rx NLO\n");
133 		break;
134 	default:
135 		rtw89_warn(rtwdev, "Unknown wakeup reason %x\n", reason);
136 		ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, NULL,
137 					       GFP_KERNEL);
138 		return;
139 	}
140 
141 	ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, &wakeup,
142 				       GFP_KERNEL);
143 }
144 
145 static void rtw89_wow_vif_iter(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
146 {
147 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
148 	struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
149 
150 	/* Current wowlan function support setting of only one STATION vif.
151 	 * So when one suitable vif is found, stop the iteration.
152 	 */
153 	if (rtw_wow->wow_vif || vif->type != NL80211_IFTYPE_STATION)
154 		return;
155 
156 	switch (rtwvif->net_type) {
157 	case RTW89_NET_TYPE_INFRA:
158 		rtw_wow->wow_vif = vif;
159 		break;
160 	case RTW89_NET_TYPE_NO_LINK:
161 	default:
162 		break;
163 	}
164 }
165 
166 static u16 __rtw89_cal_crc16(u8 data, u16 crc)
167 {
168 	u8 shift_in, data_bit;
169 	u8 crc_bit4, crc_bit11, crc_bit15;
170 	u16 crc_result;
171 	int index;
172 
173 	for (index = 0; index < 8; index++) {
174 		crc_bit15 = crc & BIT(15) ? 1 : 0;
175 		data_bit = data & BIT(index) ? 1 : 0;
176 		shift_in = crc_bit15 ^ data_bit;
177 
178 		crc_result = crc << 1;
179 
180 		if (shift_in == 0)
181 			crc_result &= ~BIT(0);
182 		else
183 			crc_result |= BIT(0);
184 
185 		crc_bit11 = (crc & BIT(11) ? 1 : 0) ^ shift_in;
186 
187 		if (crc_bit11 == 0)
188 			crc_result &= ~BIT(12);
189 		else
190 			crc_result |= BIT(12);
191 
192 		crc_bit4 = (crc & BIT(4) ? 1 : 0) ^ shift_in;
193 
194 		if (crc_bit4 == 0)
195 			crc_result &= ~BIT(5);
196 		else
197 			crc_result |= BIT(5);
198 
199 		crc = crc_result;
200 	}
201 	return crc;
202 }
203 
204 static u16 rtw89_calc_crc(u8 *pdata, int length)
205 {
206 	u16 crc = 0xffff;
207 	int i;
208 
209 	for (i = 0; i < length; i++)
210 		crc = __rtw89_cal_crc16(pdata[i], crc);
211 
212 	/* get 1' complement */
213 	return ~crc;
214 }
215 
216 static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif,
217 				      struct rtw89_wow_cam_info *rtw_pattern,
218 				      const u8 *pattern, u8 da_mask)
219 {
220 	u8 da[ETH_ALEN];
221 
222 	ether_addr_copy_mask(da, pattern, da_mask);
223 
224 	/* Each pattern is divided into different kinds by DA address
225 	 *  a. DA is broadcast address: set bc = 0;
226 	 *  b. DA is multicast address: set mc = 0
227 	 *  c. DA is unicast address same as dev's mac address: set uc = 0
228 	 *  d. DA is unmasked. Also called wildcard type: set uc = bc = mc = 0
229 	 *  e. Others is invalid type.
230 	 */
231 
232 	if (is_broadcast_ether_addr(da))
233 		rtw_pattern->bc = true;
234 	else if (is_multicast_ether_addr(da))
235 		rtw_pattern->mc = true;
236 	else if (ether_addr_equal(da, rtwvif->mac_addr) &&
237 		 da_mask == GENMASK(5, 0))
238 		rtw_pattern->uc = true;
239 	else if (!da_mask) /*da_mask == 0 mean wildcard*/
240 		return 0;
241 	else
242 		return -EPERM;
243 
244 	return 0;
245 }
246 
247 static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev,
248 				      struct rtw89_vif *rtwvif,
249 				      const struct cfg80211_pkt_pattern *pkt_pattern,
250 				      struct rtw89_wow_cam_info *rtw_pattern)
251 {
252 	u8 mask_hw[RTW89_MAX_PATTERN_MASK_SIZE * 4] = {0};
253 	u8 content[RTW89_MAX_PATTERN_SIZE] = {0};
254 	const u8 *mask;
255 	const u8 *pattern;
256 	u8 mask_len;
257 	u16 count;
258 	u32 len;
259 	int i, ret;
260 
261 	pattern = pkt_pattern->pattern;
262 	len = pkt_pattern->pattern_len;
263 	mask = pkt_pattern->mask;
264 	mask_len = DIV_ROUND_UP(len, 8);
265 	memset(rtw_pattern, 0, sizeof(*rtw_pattern));
266 
267 	ret = rtw89_wow_pattern_get_type(rtwvif, rtw_pattern, pattern,
268 					 mask[0] & GENMASK(5, 0));
269 	if (ret)
270 		return ret;
271 
272 	/* translate mask from os to mask for hw
273 	 * pattern from OS uses 'ethenet frame', like this:
274 	 * |    6   |    6   |   2  |     20    |  Variable  |  4  |
275 	 * |--------+--------+------+-----------+------------+-----|
276 	 * |    802.3 Mac Header    | IP Header | TCP Packet | FCS |
277 	 * |   DA   |   SA   | Type |
278 	 *
279 	 * BUT, packet catched by our HW is in '802.11 frame', begin from LLC
280 	 * |     24 or 30      |    6   |   2  |     20    |  Variable  |  4  |
281 	 * |-------------------+--------+------+-----------+------------+-----|
282 	 * | 802.11 MAC Header |       LLC     | IP Header | TCP Packet | FCS |
283 	 *		       | Others | Tpye |
284 	 *
285 	 * Therefore, we need translate mask_from_OS to mask_to_hw.
286 	 * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0,
287 	 * because new mask[0~5] means 'SA', but our HW packet begins from LLC,
288 	 * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match.
289 	 */
290 
291 	/* Shift 6 bits */
292 	for (i = 0; i < mask_len - 1; i++) {
293 		mask_hw[i] = u8_get_bits(mask[i], GENMASK(7, 6)) |
294 			     u8_get_bits(mask[i + 1], GENMASK(5, 0)) << 2;
295 	}
296 	mask_hw[i] = u8_get_bits(mask[i], GENMASK(7, 6));
297 
298 	/* Set bit 0-5 to zero */
299 	mask_hw[0] &= ~GENMASK(5, 0);
300 
301 	memcpy(rtw_pattern->mask, mask_hw, sizeof(rtw_pattern->mask));
302 
303 	/* To get the wake up pattern from the mask.
304 	 * We do not count first 12 bits which means
305 	 * DA[6] and SA[6] in the pattern to match HW design.
306 	 */
307 	count = 0;
308 	for (i = 12; i < len; i++) {
309 		if ((mask[i / 8] >> (i % 8)) & 0x01) {
310 			content[count] = pattern[i];
311 			count++;
312 		}
313 	}
314 
315 	rtw_pattern->crc = rtw89_calc_crc(content, count);
316 
317 	return 0;
318 }
319 
320 static int rtw89_wow_parse_patterns(struct rtw89_dev *rtwdev,
321 				    struct rtw89_vif *rtwvif,
322 				    struct cfg80211_wowlan *wowlan)
323 {
324 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
325 	struct rtw89_wow_cam_info *rtw_pattern = rtw_wow->patterns;
326 	int i;
327 	int ret;
328 
329 	if (!wowlan->n_patterns || !wowlan->patterns)
330 		return 0;
331 
332 	for (i = 0; i < wowlan->n_patterns; i++) {
333 		rtw_pattern = &rtw_wow->patterns[i];
334 		ret = rtw89_wow_pattern_generate(rtwdev, rtwvif,
335 						 &wowlan->patterns[i],
336 						 rtw_pattern);
337 		if (ret) {
338 			rtw89_err(rtwdev, "failed to generate pattern(%d)\n", i);
339 			rtw_wow->pattern_cnt = 0;
340 			return ret;
341 		}
342 
343 		rtw_pattern->r_w = true;
344 		rtw_pattern->idx = i;
345 		rtw_pattern->negative_pattern_match = false;
346 		rtw_pattern->skip_mac_hdr = true;
347 		rtw_pattern->valid = true;
348 	}
349 	rtw_wow->pattern_cnt = wowlan->n_patterns;
350 
351 	return 0;
352 }
353 
354 static void rtw89_wow_pattern_clear_cam(struct rtw89_dev *rtwdev)
355 {
356 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
357 	struct rtw89_wow_cam_info *rtw_pattern = rtw_wow->patterns;
358 	int i = 0;
359 
360 	for (i = 0; i < rtw_wow->pattern_cnt; i++) {
361 		rtw_pattern = &rtw_wow->patterns[i];
362 		rtw_pattern->valid = false;
363 		rtw89_fw_wow_cam_update(rtwdev, rtw_pattern);
364 	}
365 }
366 
367 static void rtw89_wow_pattern_write(struct rtw89_dev *rtwdev)
368 {
369 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
370 	struct rtw89_wow_cam_info *rtw_pattern = rtw_wow->patterns;
371 	int i;
372 
373 	for (i = 0; i < rtw_wow->pattern_cnt; i++)
374 		rtw89_fw_wow_cam_update(rtwdev, rtw_pattern + i);
375 }
376 
377 static void rtw89_wow_pattern_clear(struct rtw89_dev *rtwdev)
378 {
379 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
380 
381 	rtw89_wow_pattern_clear_cam(rtwdev);
382 
383 	rtw_wow->pattern_cnt = 0;
384 	memset(rtw_wow->patterns, 0, sizeof(rtw_wow->patterns));
385 }
386 
387 static void rtw89_wow_clear_wakeups(struct rtw89_dev *rtwdev)
388 {
389 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
390 
391 	rtw_wow->wow_vif = NULL;
392 	rtw89_core_release_all_bits_map(rtw_wow->flags, RTW89_WOW_FLAG_NUM);
393 	rtw_wow->pattern_cnt = 0;
394 }
395 
396 static int rtw89_wow_set_wakeups(struct rtw89_dev *rtwdev,
397 				 struct cfg80211_wowlan *wowlan)
398 {
399 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
400 	struct rtw89_vif *rtwvif;
401 
402 	if (wowlan->disconnect)
403 		set_bit(RTW89_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags);
404 	if (wowlan->magic_pkt)
405 		set_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags);
406 
407 	rtw89_for_each_rtwvif(rtwdev, rtwvif)
408 		rtw89_wow_vif_iter(rtwdev, rtwvif);
409 
410 	if (!rtw_wow->wow_vif)
411 		return -EPERM;
412 
413 	rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv;
414 	return rtw89_wow_parse_patterns(rtwdev, rtwvif, wowlan);
415 }
416 
417 static int rtw89_wow_cfg_wake(struct rtw89_dev *rtwdev, bool wow)
418 {
419 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
420 	struct ieee80211_vif *wow_vif = rtw_wow->wow_vif;
421 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
422 	struct ieee80211_sta *wow_sta;
423 	struct rtw89_sta *rtwsta = NULL;
424 	int ret;
425 
426 	wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid);
427 	if (wow_sta)
428 		rtwsta = (struct rtw89_sta *)wow_sta->drv_priv;
429 
430 	if (wow) {
431 		if (rtw_wow->pattern_cnt)
432 			rtwvif->wowlan_pattern = true;
433 		if (test_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags))
434 			rtwvif->wowlan_magic = true;
435 	} else {
436 		rtwvif->wowlan_pattern = false;
437 		rtwvif->wowlan_magic = false;
438 	}
439 
440 	ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif, wow);
441 	if (ret) {
442 		rtw89_err(rtwdev, "failed to fw wow wakeup ctrl\n");
443 		return ret;
444 	}
445 
446 	if (wow) {
447 		ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta);
448 		if (ret) {
449 			rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n",
450 				  ret);
451 			return ret;
452 		}
453 	}
454 
455 	ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
456 	if (ret) {
457 		rtw89_warn(rtwdev, "failed to send h2c cam\n");
458 		return ret;
459 	}
460 
461 	ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif, wow);
462 	if (ret) {
463 		rtw89_err(rtwdev, "failed to fw wow global\n");
464 		return ret;
465 	}
466 
467 	return 0;
468 }
469 
470 static int rtw89_wow_check_fw_status(struct rtw89_dev *rtwdev, bool wow_enable)
471 {
472 	u8 polling;
473 	int ret;
474 
475 	ret = read_poll_timeout_atomic(rtw89_read8_mask, polling,
476 				       wow_enable == !!polling,
477 				       50, 50000, false, rtwdev,
478 				       R_AX_WOW_CTRL, B_AX_WOW_WOWEN);
479 	if (ret)
480 		rtw89_err(rtwdev, "failed to check wow status %s\n",
481 			  wow_enable ? "enabled" : "disabled");
482 	return ret;
483 }
484 
485 static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow)
486 {
487 	enum rtw89_fw_type fw_type = wow ? RTW89_FW_WOWLAN : RTW89_FW_NORMAL;
488 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
489 	struct ieee80211_vif *wow_vif = rtw_wow->wow_vif;
490 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
491 	struct ieee80211_sta *wow_sta;
492 	struct rtw89_sta *rtwsta = NULL;
493 	bool is_conn = true;
494 	int ret;
495 
496 	rtw89_hci_disable_intr(rtwdev);
497 
498 	wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid);
499 	if (wow_sta)
500 		rtwsta = (struct rtw89_sta *)wow_sta->drv_priv;
501 	else
502 		is_conn = false;
503 
504 	ret = rtw89_fw_download(rtwdev, fw_type);
505 	if (ret) {
506 		rtw89_warn(rtwdev, "download fw failed\n");
507 		return ret;
508 	}
509 
510 	rtw89_phy_init_rf_reg(rtwdev, true);
511 
512 	ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta,
513 					 RTW89_ROLE_FW_RESTORE);
514 	if (ret) {
515 		rtw89_warn(rtwdev, "failed to send h2c role maintain\n");
516 		return ret;
517 	}
518 
519 	ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, wow_vif, wow_sta);
520 	if (ret) {
521 		rtw89_warn(rtwdev, "failed to send h2c assoc cmac tbl\n");
522 		return ret;
523 	}
524 
525 	if (!is_conn)
526 		rtw89_cam_reset_keys(rtwdev);
527 
528 	ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, !is_conn);
529 	if (ret) {
530 		rtw89_warn(rtwdev, "failed to send h2c join info\n");
531 		return ret;
532 	}
533 
534 	ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
535 	if (ret) {
536 		rtw89_warn(rtwdev, "failed to send h2c cam\n");
537 		return ret;
538 	}
539 
540 	if (is_conn) {
541 		ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id);
542 		if (ret) {
543 			rtw89_warn(rtwdev, "failed to send h2c general packet\n");
544 			return ret;
545 		}
546 		rtw89_phy_ra_assoc(rtwdev, wow_sta);
547 		rtw89_phy_set_bss_color(rtwdev, wow_vif);
548 		rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, wow_vif);
549 	}
550 
551 	rtw89_mac_hw_mgnt_sec(rtwdev, wow);
552 	rtw89_hci_enable_intr(rtwdev);
553 
554 	return 0;
555 }
556 
557 static int rtw89_wow_enable_trx_pre(struct rtw89_dev *rtwdev)
558 {
559 	int ret;
560 
561 	rtw89_hci_ctrl_txdma_ch(rtwdev, false);
562 	rtw89_hci_ctrl_txdma_fw_ch(rtwdev, true);
563 
564 	rtw89_mac_ptk_drop_by_band_and_wait(rtwdev, RTW89_MAC_0);
565 
566 	ret = rtw89_hci_poll_txdma_ch(rtwdev);
567 	if (ret) {
568 		rtw89_err(rtwdev, "txdma ch busy\n");
569 		return ret;
570 	}
571 	rtw89_wow_set_rx_filter(rtwdev, true);
572 
573 	ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false);
574 	if (ret) {
575 		rtw89_err(rtwdev, "cfg ppdu status\n");
576 		return ret;
577 	}
578 
579 	return 0;
580 }
581 
582 static int rtw89_wow_enable_trx_post(struct rtw89_dev *rtwdev)
583 {
584 	int ret;
585 
586 	rtw89_hci_disable_intr(rtwdev);
587 	rtw89_hci_ctrl_trxhci(rtwdev, false);
588 
589 	ret = rtw89_hci_poll_txdma_ch(rtwdev);
590 	if (ret) {
591 		rtw89_err(rtwdev, "failed to poll txdma ch idle pcie\n");
592 		return ret;
593 	}
594 
595 	ret = rtw89_wow_config_mac(rtwdev, true);
596 	if (ret) {
597 		rtw89_err(rtwdev, "failed to config mac\n");
598 		return ret;
599 	}
600 
601 	rtw89_wow_set_rx_filter(rtwdev, false);
602 	rtw89_hci_reset(rtwdev);
603 
604 	return 0;
605 }
606 
607 static int rtw89_wow_disable_trx_pre(struct rtw89_dev *rtwdev)
608 {
609 	int ret;
610 
611 	rtw89_hci_clr_idx_all(rtwdev);
612 
613 	ret = rtw89_hci_rst_bdram(rtwdev);
614 	if (ret) {
615 		rtw89_warn(rtwdev, "reset bdram busy\n");
616 		return ret;
617 	}
618 
619 	rtw89_hci_ctrl_trxhci(rtwdev, true);
620 	rtw89_hci_ctrl_txdma_ch(rtwdev, true);
621 
622 	ret = rtw89_wow_config_mac(rtwdev, false);
623 	if (ret) {
624 		rtw89_err(rtwdev, "failed to config mac\n");
625 		return ret;
626 	}
627 	rtw89_hci_enable_intr(rtwdev);
628 
629 	return 0;
630 }
631 
632 static int rtw89_wow_disable_trx_post(struct rtw89_dev *rtwdev)
633 {
634 	int ret;
635 
636 	ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true);
637 	if (ret)
638 		rtw89_err(rtwdev, "cfg ppdu status\n");
639 
640 	return ret;
641 }
642 
643 static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev)
644 {
645 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
646 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv;
647 	int ret;
648 
649 	rtw89_wow_pattern_write(rtwdev);
650 
651 	ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, true);
652 	if (ret) {
653 		rtw89_err(rtwdev, "wow: failed to enable keep alive\n");
654 		return ret;
655 	}
656 
657 	ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, true);
658 	if (ret) {
659 		rtw89_err(rtwdev, "wow: failed to enable disconnect detect\n");
660 		goto out;
661 	}
662 
663 	ret = rtw89_wow_cfg_wake(rtwdev, true);
664 	if (ret) {
665 		rtw89_err(rtwdev, "wow: failed to config wake\n");
666 		goto out;
667 	}
668 
669 	ret = rtw89_wow_check_fw_status(rtwdev, true);
670 	if (ret) {
671 		rtw89_err(rtwdev, "wow: failed to check enable fw ready\n");
672 		goto out;
673 	}
674 
675 out:
676 	return ret;
677 }
678 
679 static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev)
680 {
681 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
682 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv;
683 	int ret;
684 
685 	rtw89_wow_pattern_clear(rtwdev);
686 
687 	ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, false);
688 	if (ret) {
689 		rtw89_err(rtwdev, "wow: failed to disable keep alive\n");
690 		goto out;
691 	}
692 
693 	ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, false);
694 	if (ret) {
695 		rtw89_err(rtwdev, "wow: failed to disable disconnect detect\n");
696 		goto out;
697 	}
698 
699 	ret = rtw89_wow_cfg_wake(rtwdev, false);
700 	if (ret) {
701 		rtw89_err(rtwdev, "wow: failed to disable config wake\n");
702 		goto out;
703 	}
704 
705 	rtw89_fw_release_general_pkt_list(rtwdev, true);
706 
707 	ret = rtw89_wow_check_fw_status(rtwdev, false);
708 	if (ret) {
709 		rtw89_err(rtwdev, "wow: failed to check disable fw ready\n");
710 		goto out;
711 	}
712 
713 out:
714 	return ret;
715 }
716 
717 static int rtw89_wow_enable(struct rtw89_dev *rtwdev)
718 {
719 	int ret;
720 
721 	set_bit(RTW89_FLAG_WOWLAN, rtwdev->flags);
722 
723 	ret = rtw89_wow_enable_trx_pre(rtwdev);
724 	if (ret) {
725 		rtw89_err(rtwdev, "wow: failed to enable trx_pre\n");
726 		goto out;
727 	}
728 
729 	rtw89_fw_release_general_pkt_list(rtwdev, true);
730 
731 	ret = rtw89_wow_swap_fw(rtwdev, true);
732 	if (ret) {
733 		rtw89_err(rtwdev, "wow: failed to swap to wow fw\n");
734 		goto out;
735 	}
736 
737 	ret = rtw89_wow_fw_start(rtwdev);
738 	if (ret) {
739 		rtw89_err(rtwdev, "wow: failed to let wow fw start\n");
740 		goto out;
741 	}
742 
743 	rtw89_wow_enter_lps(rtwdev);
744 
745 	ret = rtw89_wow_enable_trx_post(rtwdev);
746 	if (ret) {
747 		rtw89_err(rtwdev, "wow: failed to enable trx_post\n");
748 		goto out;
749 	}
750 
751 	return 0;
752 
753 out:
754 	clear_bit(RTW89_FLAG_WOWLAN, rtwdev->flags);
755 	return ret;
756 }
757 
758 static int rtw89_wow_disable(struct rtw89_dev *rtwdev)
759 {
760 	int ret;
761 
762 	ret = rtw89_wow_disable_trx_pre(rtwdev);
763 	if (ret) {
764 		rtw89_err(rtwdev, "wow: failed to disable trx_pre\n");
765 		goto out;
766 	}
767 
768 	rtw89_wow_leave_lps(rtwdev);
769 
770 	ret = rtw89_wow_fw_stop(rtwdev);
771 	if (ret) {
772 		rtw89_err(rtwdev, "wow: failed to swap to normal fw\n");
773 		goto out;
774 	}
775 
776 	ret = rtw89_wow_swap_fw(rtwdev, false);
777 	if (ret) {
778 		rtw89_err(rtwdev, "wow: failed to disable trx_post\n");
779 		goto out;
780 	}
781 
782 	ret = rtw89_wow_disable_trx_post(rtwdev);
783 	if (ret) {
784 		rtw89_err(rtwdev, "wow: failed to disable trx_pre\n");
785 		goto out;
786 	}
787 
788 out:
789 	clear_bit(RTW89_FLAG_WOWLAN, rtwdev->flags);
790 	return ret;
791 }
792 
793 int rtw89_wow_resume(struct rtw89_dev *rtwdev)
794 {
795 	int ret;
796 
797 	if (!test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) {
798 		rtw89_err(rtwdev, "wow is not enabled\n");
799 		ret = -EPERM;
800 		goto out;
801 	}
802 
803 	if (!rtw89_mac_get_power_state(rtwdev)) {
804 		rtw89_err(rtwdev, "chip is no power when resume\n");
805 		ret = -EPERM;
806 		goto out;
807 	}
808 
809 	rtw89_wow_leave_deep_ps(rtwdev);
810 
811 	rtw89_wow_show_wakeup_reason(rtwdev);
812 
813 	ret = rtw89_wow_disable(rtwdev);
814 	if (ret)
815 		rtw89_err(rtwdev, "failed to disable wow\n");
816 
817 out:
818 	rtw89_wow_clear_wakeups(rtwdev);
819 	return ret;
820 }
821 
822 int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan)
823 {
824 	int ret;
825 
826 	ret = rtw89_wow_set_wakeups(rtwdev, wowlan);
827 	if (ret) {
828 		rtw89_err(rtwdev, "failed to set wakeup event\n");
829 		return ret;
830 	}
831 
832 	rtw89_wow_leave_lps(rtwdev);
833 
834 	ret = rtw89_wow_enable(rtwdev);
835 	if (ret) {
836 		rtw89_err(rtwdev, "failed to enable wow\n");
837 		return ret;
838 	}
839 
840 	rtw89_wow_enter_deep_ps(rtwdev);
841 
842 	return 0;
843 }
844