xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/wow.c (revision ba9177fcef21fa98406e73c472b5ac2eb4ec5f31)
1 // SPDX-License-Identifier: BSD-3-Clause-Clear
2 /*
3  * Copyright (c) 2020 The Linux Foundation. All rights reserved.
4  */
5 
6 #include <linux/delay.h>
7 
8 #include "mac.h"
9 
10 #include <net/mac80211.h>
11 #include "core.h"
12 #include "hif.h"
13 #include "debug.h"
14 #include "wmi.h"
15 #include "wow.h"
16 
17 static const struct wiphy_wowlan_support ath11k_wowlan_support = {
18 	.flags = WIPHY_WOWLAN_DISCONNECT |
19 		 WIPHY_WOWLAN_MAGIC_PKT,
20 	.pattern_min_len = WOW_MIN_PATTERN_SIZE,
21 	.pattern_max_len = WOW_MAX_PATTERN_SIZE,
22 	.max_pkt_offset = WOW_MAX_PKT_OFFSET,
23 };
24 
25 int ath11k_wow_enable(struct ath11k_base *ab)
26 {
27 	struct ath11k *ar = ath11k_ab_to_ar(ab, 0);
28 	int i, ret;
29 
30 	clear_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags);
31 
32 	for (i = 0; i < ATH11K_WOW_RETRY_NUM; i++) {
33 		reinit_completion(&ab->htc_suspend);
34 
35 		ret = ath11k_wmi_wow_enable(ar);
36 		if (ret) {
37 			ath11k_warn(ab, "failed to issue wow enable: %d\n", ret);
38 			return ret;
39 		}
40 
41 		ret = wait_for_completion_timeout(&ab->htc_suspend, 3 * HZ);
42 		if (ret == 0) {
43 			ath11k_warn(ab,
44 				    "timed out while waiting for htc suspend completion\n");
45 			return -ETIMEDOUT;
46 		}
47 
48 		if (test_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags))
49 			/* success, suspend complete received */
50 			return 0;
51 
52 		ath11k_warn(ab, "htc suspend not complete, retrying (try %d)\n",
53 			    i);
54 		msleep(ATH11K_WOW_RETRY_WAIT_MS);
55 	}
56 
57 	ath11k_warn(ab, "htc suspend not complete, failing after %d tries\n", i);
58 
59 	return -ETIMEDOUT;
60 }
61 
62 int ath11k_wow_wakeup(struct ath11k_base *ab)
63 {
64 	struct ath11k *ar = ath11k_ab_to_ar(ab, 0);
65 	int ret;
66 
67 	reinit_completion(&ab->wow.wakeup_completed);
68 
69 	ret = ath11k_wmi_wow_host_wakeup_ind(ar);
70 	if (ret) {
71 		ath11k_warn(ab, "failed to send wow wakeup indication: %d\n",
72 			    ret);
73 		return ret;
74 	}
75 
76 	ret = wait_for_completion_timeout(&ab->wow.wakeup_completed, 3 * HZ);
77 	if (ret == 0) {
78 		ath11k_warn(ab, "timed out while waiting for wow wakeup completion\n");
79 		return -ETIMEDOUT;
80 	}
81 
82 	return 0;
83 }
84 
85 static int ath11k_wow_vif_cleanup(struct ath11k_vif *arvif)
86 {
87 	struct ath11k *ar = arvif->ar;
88 	int i, ret;
89 
90 	for (i = 0; i < WOW_EVENT_MAX; i++) {
91 		ret = ath11k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 0);
92 		if (ret) {
93 			ath11k_warn(ar->ab, "failed to issue wow wakeup for event %s on vdev %i: %d\n",
94 				    wow_wakeup_event(i), arvif->vdev_id, ret);
95 			return ret;
96 		}
97 	}
98 
99 	for (i = 0; i < ar->wow.max_num_patterns; i++) {
100 		ret = ath11k_wmi_wow_del_pattern(ar, arvif->vdev_id, i);
101 		if (ret) {
102 			ath11k_warn(ar->ab, "failed to delete wow pattern %d for vdev %i: %d\n",
103 				    i, arvif->vdev_id, ret);
104 			return ret;
105 		}
106 	}
107 
108 	return 0;
109 }
110 
111 static int ath11k_wow_cleanup(struct ath11k *ar)
112 {
113 	struct ath11k_vif *arvif;
114 	int ret;
115 
116 	lockdep_assert_held(&ar->conf_mutex);
117 
118 	list_for_each_entry(arvif, &ar->arvifs, list) {
119 		ret = ath11k_wow_vif_cleanup(arvif);
120 		if (ret) {
121 			ath11k_warn(ar->ab, "failed to clean wow wakeups on vdev %i: %d\n",
122 				    arvif->vdev_id, ret);
123 			return ret;
124 		}
125 	}
126 
127 	return 0;
128 }
129 
130 /* Convert a 802.3 format to a 802.11 format.
131  *         +------------+-----------+--------+----------------+
132  * 802.3:  |dest mac(6B)|src mac(6B)|type(2B)|     body...    |
133  *         +------------+-----------+--------+----------------+
134  *                |__         |_______    |____________  |________
135  *                   |                |                |          |
136  *         +--+------------+----+-----------+---------------+-----------+
137  * 802.11: |4B|dest mac(6B)| 6B |src mac(6B)|  8B  |type(2B)|  body...  |
138  *         +--+------------+----+-----------+---------------+-----------+
139  */
140 static void ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new,
141 					     const struct cfg80211_pkt_pattern *old)
142 {
143 	u8 hdr_8023_pattern[ETH_HLEN] = {};
144 	u8 hdr_8023_bit_mask[ETH_HLEN] = {};
145 	u8 hdr_80211_pattern[WOW_HDR_LEN] = {};
146 	u8 hdr_80211_bit_mask[WOW_HDR_LEN] = {};
147 
148 	int total_len = old->pkt_offset + old->pattern_len;
149 	int hdr_80211_end_offset;
150 
151 	struct ieee80211_hdr_3addr *new_hdr_pattern =
152 		(struct ieee80211_hdr_3addr *)hdr_80211_pattern;
153 	struct ieee80211_hdr_3addr *new_hdr_mask =
154 		(struct ieee80211_hdr_3addr *)hdr_80211_bit_mask;
155 	struct ethhdr *old_hdr_pattern = (struct ethhdr *)hdr_8023_pattern;
156 	struct ethhdr *old_hdr_mask = (struct ethhdr *)hdr_8023_bit_mask;
157 	int hdr_len = sizeof(*new_hdr_pattern);
158 
159 	struct rfc1042_hdr *new_rfc_pattern =
160 		(struct rfc1042_hdr *)(hdr_80211_pattern + hdr_len);
161 	struct rfc1042_hdr *new_rfc_mask =
162 		(struct rfc1042_hdr *)(hdr_80211_bit_mask + hdr_len);
163 	int rfc_len = sizeof(*new_rfc_pattern);
164 
165 	memcpy(hdr_8023_pattern + old->pkt_offset,
166 	       old->pattern, ETH_HLEN - old->pkt_offset);
167 	memcpy(hdr_8023_bit_mask + old->pkt_offset,
168 	       old->mask, ETH_HLEN - old->pkt_offset);
169 
170 	/* Copy destination address */
171 	memcpy(new_hdr_pattern->addr1, old_hdr_pattern->h_dest, ETH_ALEN);
172 	memcpy(new_hdr_mask->addr1, old_hdr_mask->h_dest, ETH_ALEN);
173 
174 	/* Copy source address */
175 	memcpy(new_hdr_pattern->addr3, old_hdr_pattern->h_source, ETH_ALEN);
176 	memcpy(new_hdr_mask->addr3, old_hdr_mask->h_source, ETH_ALEN);
177 
178 	/* Copy logic link type */
179 	memcpy(&new_rfc_pattern->snap_type,
180 	       &old_hdr_pattern->h_proto,
181 	       sizeof(old_hdr_pattern->h_proto));
182 	memcpy(&new_rfc_mask->snap_type,
183 	       &old_hdr_mask->h_proto,
184 	       sizeof(old_hdr_mask->h_proto));
185 
186 	/* Compute new pkt_offset */
187 	if (old->pkt_offset < ETH_ALEN)
188 		new->pkt_offset = old->pkt_offset +
189 			offsetof(struct ieee80211_hdr_3addr, addr1);
190 	else if (old->pkt_offset < offsetof(struct ethhdr, h_proto))
191 		new->pkt_offset = old->pkt_offset +
192 			offsetof(struct ieee80211_hdr_3addr, addr3) -
193 			offsetof(struct ethhdr, h_source);
194 	else
195 		new->pkt_offset = old->pkt_offset + hdr_len + rfc_len - ETH_HLEN;
196 
197 	/* Compute new hdr end offset */
198 	if (total_len > ETH_HLEN)
199 		hdr_80211_end_offset = hdr_len + rfc_len;
200 	else if (total_len > offsetof(struct ethhdr, h_proto))
201 		hdr_80211_end_offset = hdr_len + rfc_len + total_len - ETH_HLEN;
202 	else if (total_len > ETH_ALEN)
203 		hdr_80211_end_offset = total_len - ETH_ALEN +
204 			offsetof(struct ieee80211_hdr_3addr, addr3);
205 	else
206 		hdr_80211_end_offset = total_len +
207 			offsetof(struct ieee80211_hdr_3addr, addr1);
208 
209 	new->pattern_len = hdr_80211_end_offset - new->pkt_offset;
210 
211 	memcpy((u8 *)new->pattern,
212 	       hdr_80211_pattern + new->pkt_offset,
213 	       new->pattern_len);
214 	memcpy((u8 *)new->mask,
215 	       hdr_80211_bit_mask + new->pkt_offset,
216 	       new->pattern_len);
217 
218 	if (total_len > ETH_HLEN) {
219 		/* Copy frame body */
220 		memcpy((u8 *)new->pattern + new->pattern_len,
221 		       (void *)old->pattern + ETH_HLEN - old->pkt_offset,
222 		       total_len - ETH_HLEN);
223 		memcpy((u8 *)new->mask + new->pattern_len,
224 		       (void *)old->mask + ETH_HLEN - old->pkt_offset,
225 		       total_len - ETH_HLEN);
226 
227 		new->pattern_len += total_len - ETH_HLEN;
228 	}
229 }
230 
231 static int ath11k_vif_wow_set_wakeups(struct ath11k_vif *arvif,
232 				      struct cfg80211_wowlan *wowlan)
233 {
234 	int ret, i;
235 	unsigned long wow_mask = 0;
236 	struct ath11k *ar = arvif->ar;
237 	const struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
238 	int pattern_id = 0;
239 
240 	/* Setup requested WOW features */
241 	switch (arvif->vdev_type) {
242 	case WMI_VDEV_TYPE_IBSS:
243 		__set_bit(WOW_BEACON_EVENT, &wow_mask);
244 		fallthrough;
245 	case WMI_VDEV_TYPE_AP:
246 		__set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
247 		__set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
248 		__set_bit(WOW_PROBE_REQ_WPS_IE_EVENT, &wow_mask);
249 		__set_bit(WOW_AUTH_REQ_EVENT, &wow_mask);
250 		__set_bit(WOW_ASSOC_REQ_EVENT, &wow_mask);
251 		__set_bit(WOW_HTT_EVENT, &wow_mask);
252 		__set_bit(WOW_RA_MATCH_EVENT, &wow_mask);
253 		break;
254 	case WMI_VDEV_TYPE_STA:
255 		if (wowlan->disconnect) {
256 			__set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
257 			__set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
258 			__set_bit(WOW_BMISS_EVENT, &wow_mask);
259 			__set_bit(WOW_CSA_IE_EVENT, &wow_mask);
260 		}
261 
262 		if (wowlan->magic_pkt)
263 			__set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask);
264 		break;
265 	default:
266 		break;
267 	}
268 
269 	for (i = 0; i < wowlan->n_patterns; i++) {
270 		u8 bitmask[WOW_MAX_PATTERN_SIZE] = {};
271 		u8 ath_pattern[WOW_MAX_PATTERN_SIZE] = {};
272 		u8 ath_bitmask[WOW_MAX_PATTERN_SIZE] = {};
273 		struct cfg80211_pkt_pattern new_pattern = {};
274 		struct cfg80211_pkt_pattern old_pattern = patterns[i];
275 		int j;
276 
277 		new_pattern.pattern = ath_pattern;
278 		new_pattern.mask = ath_bitmask;
279 		if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE)
280 			continue;
281 		/* convert bytemask to bitmask */
282 		for (j = 0; j < patterns[i].pattern_len; j++)
283 			if (patterns[i].mask[j / 8] & BIT(j % 8))
284 				bitmask[j] = 0xff;
285 		old_pattern.mask = bitmask;
286 
287 		if (ar->wmi->wmi_ab->wlan_resource_config.rx_decap_mode ==
288 		    ATH11K_HW_TXRX_NATIVE_WIFI) {
289 			if (patterns[i].pkt_offset < ETH_HLEN) {
290 				u8 pattern_ext[WOW_MAX_PATTERN_SIZE] = {};
291 
292 				memcpy(pattern_ext, old_pattern.pattern,
293 				       old_pattern.pattern_len);
294 				old_pattern.pattern = pattern_ext;
295 				ath11k_wow_convert_8023_to_80211(&new_pattern,
296 								 &old_pattern);
297 			} else {
298 				new_pattern = old_pattern;
299 				new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN;
300 			}
301 		}
302 
303 		if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE))
304 			return -EINVAL;
305 
306 		ret = ath11k_wmi_wow_add_pattern(ar, arvif->vdev_id,
307 						 pattern_id,
308 						 new_pattern.pattern,
309 						 new_pattern.mask,
310 						 new_pattern.pattern_len,
311 						 new_pattern.pkt_offset);
312 		if (ret) {
313 			ath11k_warn(ar->ab, "failed to add pattern %i to vdev %i: %d\n",
314 				    pattern_id,
315 				    arvif->vdev_id, ret);
316 			return ret;
317 		}
318 
319 		pattern_id++;
320 		__set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask);
321 	}
322 
323 	for (i = 0; i < WOW_EVENT_MAX; i++) {
324 		if (!test_bit(i, &wow_mask))
325 			continue;
326 		ret = ath11k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1);
327 		if (ret) {
328 			ath11k_warn(ar->ab, "failed to enable wakeup event %s on vdev %i: %d\n",
329 				    wow_wakeup_event(i), arvif->vdev_id, ret);
330 			return ret;
331 		}
332 	}
333 
334 	return 0;
335 }
336 
337 static int ath11k_wow_set_wakeups(struct ath11k *ar,
338 				  struct cfg80211_wowlan *wowlan)
339 {
340 	struct ath11k_vif *arvif;
341 	int ret;
342 
343 	lockdep_assert_held(&ar->conf_mutex);
344 
345 	list_for_each_entry(arvif, &ar->arvifs, list) {
346 		ret = ath11k_vif_wow_set_wakeups(arvif, wowlan);
347 		if (ret) {
348 			ath11k_warn(ar->ab, "failed to set wow wakeups on vdev %i: %d\n",
349 				    arvif->vdev_id, ret);
350 			return ret;
351 		}
352 	}
353 
354 	return 0;
355 }
356 
357 int ath11k_wow_op_suspend(struct ieee80211_hw *hw,
358 			  struct cfg80211_wowlan *wowlan)
359 {
360 	struct ath11k *ar = hw->priv;
361 	int ret;
362 
363 	mutex_lock(&ar->conf_mutex);
364 
365 	ret =  ath11k_wow_cleanup(ar);
366 	if (ret) {
367 		ath11k_warn(ar->ab, "failed to clear wow wakeup events: %d\n",
368 			    ret);
369 		goto exit;
370 	}
371 
372 	ret = ath11k_wow_set_wakeups(ar, wowlan);
373 	if (ret) {
374 		ath11k_warn(ar->ab, "failed to set wow wakeup events: %d\n",
375 			    ret);
376 		goto cleanup;
377 	}
378 
379 	ret = ath11k_mac_wait_tx_complete(ar);
380 	if (ret) {
381 		ath11k_warn(ar->ab, "failed to wait tx complete: %d\n", ret);
382 		goto cleanup;
383 	}
384 
385 	ret = ath11k_wow_enable(ar->ab);
386 	if (ret) {
387 		ath11k_warn(ar->ab, "failed to start wow: %d\n", ret);
388 		goto cleanup;
389 	}
390 
391 	ath11k_ce_stop_shadow_timers(ar->ab);
392 	ath11k_dp_stop_shadow_timers(ar->ab);
393 
394 	ath11k_hif_irq_disable(ar->ab);
395 	ath11k_hif_ce_irq_disable(ar->ab);
396 
397 	ret = ath11k_hif_suspend(ar->ab);
398 	if (ret) {
399 		ath11k_warn(ar->ab, "failed to suspend hif: %d\n", ret);
400 		goto wakeup;
401 	}
402 
403 	goto exit;
404 
405 wakeup:
406 	ath11k_wow_wakeup(ar->ab);
407 
408 cleanup:
409 	ath11k_wow_cleanup(ar);
410 
411 exit:
412 	mutex_unlock(&ar->conf_mutex);
413 	return ret ? 1 : 0;
414 }
415 
416 void ath11k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled)
417 {
418 	struct ath11k *ar = hw->priv;
419 
420 	mutex_lock(&ar->conf_mutex);
421 	device_set_wakeup_enable(ar->ab->dev, enabled);
422 	mutex_unlock(&ar->conf_mutex);
423 }
424 
425 int ath11k_wow_op_resume(struct ieee80211_hw *hw)
426 {
427 	struct ath11k *ar = hw->priv;
428 	int ret;
429 
430 	mutex_lock(&ar->conf_mutex);
431 
432 	ret = ath11k_hif_resume(ar->ab);
433 	if (ret) {
434 		ath11k_warn(ar->ab, "failed to resume hif: %d\n", ret);
435 		goto exit;
436 	}
437 
438 	ath11k_hif_ce_irq_enable(ar->ab);
439 	ath11k_hif_irq_enable(ar->ab);
440 
441 	ret = ath11k_wow_wakeup(ar->ab);
442 	if (ret)
443 		ath11k_warn(ar->ab, "failed to wakeup from wow: %d\n", ret);
444 
445 exit:
446 	if (ret) {
447 		switch (ar->state) {
448 		case ATH11K_STATE_ON:
449 			ar->state = ATH11K_STATE_RESTARTING;
450 			ret = 1;
451 			break;
452 		case ATH11K_STATE_OFF:
453 		case ATH11K_STATE_RESTARTING:
454 		case ATH11K_STATE_RESTARTED:
455 		case ATH11K_STATE_WEDGED:
456 			ath11k_warn(ar->ab, "encountered unexpected device state %d on resume, cannot recover\n",
457 				    ar->state);
458 			ret = -EIO;
459 			break;
460 		}
461 	}
462 
463 	mutex_unlock(&ar->conf_mutex);
464 	return ret;
465 }
466 
467 int ath11k_wow_init(struct ath11k *ar)
468 {
469 	if (WARN_ON(!test_bit(WMI_TLV_SERVICE_WOW, ar->wmi->wmi_ab->svc_map)))
470 		return -EINVAL;
471 
472 	ar->wow.wowlan_support = ath11k_wowlan_support;
473 
474 	if (ar->wmi->wmi_ab->wlan_resource_config.rx_decap_mode ==
475 	    ATH11K_HW_TXRX_NATIVE_WIFI) {
476 		ar->wow.wowlan_support.pattern_max_len -= WOW_MAX_REDUCE;
477 		ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE;
478 	}
479 
480 	ar->wow.max_num_patterns = ATH11K_WOW_PATTERNS;
481 	ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns;
482 	ar->hw->wiphy->wowlan = &ar->wow.wowlan_support;
483 
484 	device_set_wakeup_capable(ar->ab->dev, true);
485 
486 	return 0;
487 }
488