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
rtw89_wow_leave_deep_ps(struct rtw89_dev * rtwdev)15 static void rtw89_wow_leave_deep_ps(struct rtw89_dev *rtwdev)
16 {
17 __rtw89_leave_ps_mode(rtwdev);
18 }
19
rtw89_wow_enter_deep_ps(struct rtw89_dev * rtwdev)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
rtw89_wow_enter_lps(struct rtw89_dev * rtwdev)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
rtw89_wow_leave_lps(struct rtw89_dev * rtwdev)36 static void rtw89_wow_leave_lps(struct rtw89_dev *rtwdev)
37 {
38 rtw89_leave_lps(rtwdev);
39 }
40
rtw89_wow_config_mac(struct rtw89_dev * rtwdev,bool enable_wow)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
rtw89_wow_set_rx_filter(struct rtw89_dev * rtwdev,bool enable)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
rtw89_wow_show_wakeup_reason(struct rtw89_dev * rtwdev)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
rtw89_wow_vif_iter(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif)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
__rtw89_cal_crc16(u8 data,u16 crc)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
rtw89_calc_crc(u8 * pdata,int length)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
rtw89_wow_pattern_get_type(struct rtw89_vif * rtwvif,struct rtw89_wow_cam_info * rtw_pattern,const u8 * pattern,u8 da_mask)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
rtw89_wow_pattern_generate(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif,const struct cfg80211_pkt_pattern * pkt_pattern,struct rtw89_wow_cam_info * rtw_pattern)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
rtw89_wow_parse_patterns(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif,struct cfg80211_wowlan * wowlan)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
rtw89_wow_pattern_clear_cam(struct rtw89_dev * rtwdev)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
rtw89_wow_pattern_write(struct rtw89_dev * rtwdev)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
rtw89_wow_pattern_clear(struct rtw89_dev * rtwdev)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
rtw89_wow_clear_wakeups(struct rtw89_dev * rtwdev)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
rtw89_wow_set_wakeups(struct rtw89_dev * rtwdev,struct cfg80211_wowlan * wowlan)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
rtw89_wow_cfg_wake(struct rtw89_dev * rtwdev,bool wow)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
rtw89_wow_check_fw_status(struct rtw89_dev * rtwdev,bool wow_enable)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
rtw89_wow_swap_fw(struct rtw89_dev * rtwdev,bool wow)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
rtw89_wow_enable_trx_pre(struct rtw89_dev * rtwdev)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
rtw89_wow_enable_trx_post(struct rtw89_dev * rtwdev)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
rtw89_wow_disable_trx_pre(struct rtw89_dev * rtwdev)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
rtw89_wow_disable_trx_post(struct rtw89_dev * rtwdev)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
rtw89_wow_fw_start(struct rtw89_dev * rtwdev)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
rtw89_wow_fw_stop(struct rtw89_dev * rtwdev)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
rtw89_wow_enable(struct rtw89_dev * rtwdev)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
rtw89_wow_disable(struct rtw89_dev * rtwdev)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
rtw89_wow_resume(struct rtw89_dev * rtwdev)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
rtw89_wow_suspend(struct rtw89_dev * rtwdev,struct cfg80211_wowlan * wowlan)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