xref: /linux/drivers/net/wireless/realtek/rtw89/wow.c (revision 335bbdf01d25517ae832ac1807fd8323c1f4f3b9)
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 	const struct rtw89_chip_info *chip = rtwdev->chip;
492 	bool include_bb = !!chip->bbmcu_nr;
493 	struct ieee80211_sta *wow_sta;
494 	struct rtw89_sta *rtwsta = NULL;
495 	bool is_conn = true;
496 	int ret;
497 
498 	rtw89_hci_disable_intr(rtwdev);
499 
500 	wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid);
501 	if (wow_sta)
502 		rtwsta = (struct rtw89_sta *)wow_sta->drv_priv;
503 	else
504 		is_conn = false;
505 
506 	ret = rtw89_fw_download(rtwdev, fw_type, include_bb);
507 	if (ret) {
508 		rtw89_warn(rtwdev, "download fw failed\n");
509 		return ret;
510 	}
511 
512 	rtw89_phy_init_rf_reg(rtwdev, true);
513 
514 	ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta,
515 					 RTW89_ROLE_FW_RESTORE);
516 	if (ret) {
517 		rtw89_warn(rtwdev, "failed to send h2c role maintain\n");
518 		return ret;
519 	}
520 
521 	ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, wow_vif, wow_sta);
522 	if (ret) {
523 		rtw89_warn(rtwdev, "failed to send h2c assoc cmac tbl\n");
524 		return ret;
525 	}
526 
527 	if (!is_conn)
528 		rtw89_cam_reset_keys(rtwdev);
529 
530 	ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, !is_conn);
531 	if (ret) {
532 		rtw89_warn(rtwdev, "failed to send h2c join info\n");
533 		return ret;
534 	}
535 
536 	ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
537 	if (ret) {
538 		rtw89_warn(rtwdev, "failed to send h2c cam\n");
539 		return ret;
540 	}
541 
542 	if (is_conn) {
543 		ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id);
544 		if (ret) {
545 			rtw89_warn(rtwdev, "failed to send h2c general packet\n");
546 			return ret;
547 		}
548 		rtw89_phy_ra_assoc(rtwdev, wow_sta);
549 		rtw89_phy_set_bss_color(rtwdev, wow_vif);
550 		rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, wow_vif);
551 	}
552 
553 	rtw89_mac_hw_mgnt_sec(rtwdev, wow);
554 	rtw89_hci_enable_intr(rtwdev);
555 
556 	return 0;
557 }
558 
559 static int rtw89_wow_enable_trx_pre(struct rtw89_dev *rtwdev)
560 {
561 	int ret;
562 
563 	rtw89_hci_ctrl_txdma_ch(rtwdev, false);
564 	rtw89_hci_ctrl_txdma_fw_ch(rtwdev, true);
565 
566 	rtw89_mac_ptk_drop_by_band_and_wait(rtwdev, RTW89_MAC_0);
567 
568 	ret = rtw89_hci_poll_txdma_ch(rtwdev);
569 	if (ret) {
570 		rtw89_err(rtwdev, "txdma ch busy\n");
571 		return ret;
572 	}
573 	rtw89_wow_set_rx_filter(rtwdev, true);
574 
575 	ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false);
576 	if (ret) {
577 		rtw89_err(rtwdev, "cfg ppdu status\n");
578 		return ret;
579 	}
580 
581 	return 0;
582 }
583 
584 static int rtw89_wow_enable_trx_post(struct rtw89_dev *rtwdev)
585 {
586 	int ret;
587 
588 	rtw89_hci_disable_intr(rtwdev);
589 	rtw89_hci_ctrl_trxhci(rtwdev, false);
590 
591 	ret = rtw89_hci_poll_txdma_ch(rtwdev);
592 	if (ret) {
593 		rtw89_err(rtwdev, "failed to poll txdma ch idle pcie\n");
594 		return ret;
595 	}
596 
597 	ret = rtw89_wow_config_mac(rtwdev, true);
598 	if (ret) {
599 		rtw89_err(rtwdev, "failed to config mac\n");
600 		return ret;
601 	}
602 
603 	rtw89_wow_set_rx_filter(rtwdev, false);
604 	rtw89_hci_reset(rtwdev);
605 
606 	return 0;
607 }
608 
609 static int rtw89_wow_disable_trx_pre(struct rtw89_dev *rtwdev)
610 {
611 	int ret;
612 
613 	rtw89_hci_clr_idx_all(rtwdev);
614 
615 	ret = rtw89_hci_rst_bdram(rtwdev);
616 	if (ret) {
617 		rtw89_warn(rtwdev, "reset bdram busy\n");
618 		return ret;
619 	}
620 
621 	rtw89_hci_ctrl_trxhci(rtwdev, true);
622 	rtw89_hci_ctrl_txdma_ch(rtwdev, true);
623 
624 	ret = rtw89_wow_config_mac(rtwdev, false);
625 	if (ret) {
626 		rtw89_err(rtwdev, "failed to config mac\n");
627 		return ret;
628 	}
629 	rtw89_hci_enable_intr(rtwdev);
630 
631 	return 0;
632 }
633 
634 static int rtw89_wow_disable_trx_post(struct rtw89_dev *rtwdev)
635 {
636 	int ret;
637 
638 	ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true);
639 	if (ret)
640 		rtw89_err(rtwdev, "cfg ppdu status\n");
641 
642 	return ret;
643 }
644 
645 static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev)
646 {
647 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
648 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv;
649 	int ret;
650 
651 	rtw89_wow_pattern_write(rtwdev);
652 
653 	ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, true);
654 	if (ret) {
655 		rtw89_err(rtwdev, "wow: failed to enable keep alive\n");
656 		return ret;
657 	}
658 
659 	ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, true);
660 	if (ret) {
661 		rtw89_err(rtwdev, "wow: failed to enable disconnect detect\n");
662 		goto out;
663 	}
664 
665 	ret = rtw89_wow_cfg_wake(rtwdev, true);
666 	if (ret) {
667 		rtw89_err(rtwdev, "wow: failed to config wake\n");
668 		goto out;
669 	}
670 
671 	ret = rtw89_wow_check_fw_status(rtwdev, true);
672 	if (ret) {
673 		rtw89_err(rtwdev, "wow: failed to check enable fw ready\n");
674 		goto out;
675 	}
676 
677 out:
678 	return ret;
679 }
680 
681 static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev)
682 {
683 	struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
684 	struct rtw89_vif *rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv;
685 	int ret;
686 
687 	rtw89_wow_pattern_clear(rtwdev);
688 
689 	ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, false);
690 	if (ret) {
691 		rtw89_err(rtwdev, "wow: failed to disable keep alive\n");
692 		goto out;
693 	}
694 
695 	ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, false);
696 	if (ret) {
697 		rtw89_err(rtwdev, "wow: failed to disable disconnect detect\n");
698 		goto out;
699 	}
700 
701 	ret = rtw89_wow_cfg_wake(rtwdev, false);
702 	if (ret) {
703 		rtw89_err(rtwdev, "wow: failed to disable config wake\n");
704 		goto out;
705 	}
706 
707 	rtw89_fw_release_general_pkt_list(rtwdev, true);
708 
709 	ret = rtw89_wow_check_fw_status(rtwdev, false);
710 	if (ret) {
711 		rtw89_err(rtwdev, "wow: failed to check disable fw ready\n");
712 		goto out;
713 	}
714 
715 out:
716 	return ret;
717 }
718 
719 static int rtw89_wow_enable(struct rtw89_dev *rtwdev)
720 {
721 	int ret;
722 
723 	set_bit(RTW89_FLAG_WOWLAN, rtwdev->flags);
724 
725 	ret = rtw89_wow_enable_trx_pre(rtwdev);
726 	if (ret) {
727 		rtw89_err(rtwdev, "wow: failed to enable trx_pre\n");
728 		goto out;
729 	}
730 
731 	rtw89_fw_release_general_pkt_list(rtwdev, true);
732 
733 	ret = rtw89_wow_swap_fw(rtwdev, true);
734 	if (ret) {
735 		rtw89_err(rtwdev, "wow: failed to swap to wow fw\n");
736 		goto out;
737 	}
738 
739 	ret = rtw89_wow_fw_start(rtwdev);
740 	if (ret) {
741 		rtw89_err(rtwdev, "wow: failed to let wow fw start\n");
742 		goto out;
743 	}
744 
745 	rtw89_wow_enter_lps(rtwdev);
746 
747 	ret = rtw89_wow_enable_trx_post(rtwdev);
748 	if (ret) {
749 		rtw89_err(rtwdev, "wow: failed to enable trx_post\n");
750 		goto out;
751 	}
752 
753 	return 0;
754 
755 out:
756 	clear_bit(RTW89_FLAG_WOWLAN, rtwdev->flags);
757 	return ret;
758 }
759 
760 static int rtw89_wow_disable(struct rtw89_dev *rtwdev)
761 {
762 	int ret;
763 
764 	ret = rtw89_wow_disable_trx_pre(rtwdev);
765 	if (ret) {
766 		rtw89_err(rtwdev, "wow: failed to disable trx_pre\n");
767 		goto out;
768 	}
769 
770 	rtw89_wow_leave_lps(rtwdev);
771 
772 	ret = rtw89_wow_fw_stop(rtwdev);
773 	if (ret) {
774 		rtw89_err(rtwdev, "wow: failed to swap to normal fw\n");
775 		goto out;
776 	}
777 
778 	ret = rtw89_wow_swap_fw(rtwdev, false);
779 	if (ret) {
780 		rtw89_err(rtwdev, "wow: failed to disable trx_post\n");
781 		goto out;
782 	}
783 
784 	ret = rtw89_wow_disable_trx_post(rtwdev);
785 	if (ret) {
786 		rtw89_err(rtwdev, "wow: failed to disable trx_pre\n");
787 		goto out;
788 	}
789 
790 out:
791 	clear_bit(RTW89_FLAG_WOWLAN, rtwdev->flags);
792 	return ret;
793 }
794 
795 int rtw89_wow_resume(struct rtw89_dev *rtwdev)
796 {
797 	int ret;
798 
799 	if (!test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) {
800 		rtw89_err(rtwdev, "wow is not enabled\n");
801 		ret = -EPERM;
802 		goto out;
803 	}
804 
805 	if (!rtw89_mac_get_power_state(rtwdev)) {
806 		rtw89_err(rtwdev, "chip is no power when resume\n");
807 		ret = -EPERM;
808 		goto out;
809 	}
810 
811 	rtw89_wow_leave_deep_ps(rtwdev);
812 
813 	rtw89_wow_show_wakeup_reason(rtwdev);
814 
815 	ret = rtw89_wow_disable(rtwdev);
816 	if (ret)
817 		rtw89_err(rtwdev, "failed to disable wow\n");
818 
819 out:
820 	rtw89_wow_clear_wakeups(rtwdev);
821 	return ret;
822 }
823 
824 int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan)
825 {
826 	int ret;
827 
828 	ret = rtw89_wow_set_wakeups(rtwdev, wowlan);
829 	if (ret) {
830 		rtw89_err(rtwdev, "failed to set wakeup event\n");
831 		return ret;
832 	}
833 
834 	rtw89_wow_leave_lps(rtwdev);
835 
836 	ret = rtw89_wow_enable(rtwdev);
837 	if (ret) {
838 		rtw89_err(rtwdev, "failed to enable wow\n");
839 		return ret;
840 	}
841 
842 	rtw89_wow_enter_deep_ps(rtwdev);
843 
844 	return 0;
845 }
846