1dd4f32aeSBjoern A. Zeeb // SPDX-License-Identifier: BSD-3-Clause-Clear
2dd4f32aeSBjoern A. Zeeb /*
3dd4f32aeSBjoern A. Zeeb * Copyright (c) 2020 The Linux Foundation. All rights reserved.
4*28348caeSBjoern A. Zeeb * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
5dd4f32aeSBjoern A. Zeeb */
6dd4f32aeSBjoern A. Zeeb
7dd4f32aeSBjoern A. Zeeb #include <linux/delay.h>
8dd4f32aeSBjoern A. Zeeb
9dd4f32aeSBjoern A. Zeeb #include "mac.h"
10*28348caeSBjoern A. Zeeb
11*28348caeSBjoern A. Zeeb #include <net/mac80211.h>
12dd4f32aeSBjoern A. Zeeb #include "core.h"
13dd4f32aeSBjoern A. Zeeb #include "hif.h"
14dd4f32aeSBjoern A. Zeeb #include "debug.h"
15dd4f32aeSBjoern A. Zeeb #include "wmi.h"
16dd4f32aeSBjoern A. Zeeb #include "wow.h"
17*28348caeSBjoern A. Zeeb #include "dp_rx.h"
18*28348caeSBjoern A. Zeeb
19*28348caeSBjoern A. Zeeb static const struct wiphy_wowlan_support ath11k_wowlan_support = {
20*28348caeSBjoern A. Zeeb .flags = WIPHY_WOWLAN_DISCONNECT |
21*28348caeSBjoern A. Zeeb WIPHY_WOWLAN_MAGIC_PKT |
22*28348caeSBjoern A. Zeeb WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
23*28348caeSBjoern A. Zeeb WIPHY_WOWLAN_GTK_REKEY_FAILURE,
24*28348caeSBjoern A. Zeeb .pattern_min_len = WOW_MIN_PATTERN_SIZE,
25*28348caeSBjoern A. Zeeb .pattern_max_len = WOW_MAX_PATTERN_SIZE,
26*28348caeSBjoern A. Zeeb .max_pkt_offset = WOW_MAX_PKT_OFFSET,
27*28348caeSBjoern A. Zeeb };
28dd4f32aeSBjoern A. Zeeb
ath11k_wow_enable(struct ath11k_base * ab)29dd4f32aeSBjoern A. Zeeb int ath11k_wow_enable(struct ath11k_base *ab)
30dd4f32aeSBjoern A. Zeeb {
31dd4f32aeSBjoern A. Zeeb struct ath11k *ar = ath11k_ab_to_ar(ab, 0);
32dd4f32aeSBjoern A. Zeeb int i, ret;
33dd4f32aeSBjoern A. Zeeb
34dd4f32aeSBjoern A. Zeeb clear_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags);
35dd4f32aeSBjoern A. Zeeb
36dd4f32aeSBjoern A. Zeeb for (i = 0; i < ATH11K_WOW_RETRY_NUM; i++) {
37dd4f32aeSBjoern A. Zeeb reinit_completion(&ab->htc_suspend);
38dd4f32aeSBjoern A. Zeeb
39dd4f32aeSBjoern A. Zeeb ret = ath11k_wmi_wow_enable(ar);
40dd4f32aeSBjoern A. Zeeb if (ret) {
41dd4f32aeSBjoern A. Zeeb ath11k_warn(ab, "failed to issue wow enable: %d\n", ret);
42dd4f32aeSBjoern A. Zeeb return ret;
43dd4f32aeSBjoern A. Zeeb }
44dd4f32aeSBjoern A. Zeeb
45dd4f32aeSBjoern A. Zeeb ret = wait_for_completion_timeout(&ab->htc_suspend, 3 * HZ);
46dd4f32aeSBjoern A. Zeeb if (ret == 0) {
47dd4f32aeSBjoern A. Zeeb ath11k_warn(ab,
48dd4f32aeSBjoern A. Zeeb "timed out while waiting for htc suspend completion\n");
49dd4f32aeSBjoern A. Zeeb return -ETIMEDOUT;
50dd4f32aeSBjoern A. Zeeb }
51dd4f32aeSBjoern A. Zeeb
52dd4f32aeSBjoern A. Zeeb if (test_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags))
53dd4f32aeSBjoern A. Zeeb /* success, suspend complete received */
54dd4f32aeSBjoern A. Zeeb return 0;
55dd4f32aeSBjoern A. Zeeb
56dd4f32aeSBjoern A. Zeeb ath11k_warn(ab, "htc suspend not complete, retrying (try %d)\n",
57dd4f32aeSBjoern A. Zeeb i);
58dd4f32aeSBjoern A. Zeeb msleep(ATH11K_WOW_RETRY_WAIT_MS);
59dd4f32aeSBjoern A. Zeeb }
60dd4f32aeSBjoern A. Zeeb
61dd4f32aeSBjoern A. Zeeb ath11k_warn(ab, "htc suspend not complete, failing after %d tries\n", i);
62dd4f32aeSBjoern A. Zeeb
63dd4f32aeSBjoern A. Zeeb return -ETIMEDOUT;
64dd4f32aeSBjoern A. Zeeb }
65dd4f32aeSBjoern A. Zeeb
ath11k_wow_wakeup(struct ath11k_base * ab)66dd4f32aeSBjoern A. Zeeb int ath11k_wow_wakeup(struct ath11k_base *ab)
67dd4f32aeSBjoern A. Zeeb {
68dd4f32aeSBjoern A. Zeeb struct ath11k *ar = ath11k_ab_to_ar(ab, 0);
69dd4f32aeSBjoern A. Zeeb int ret;
70dd4f32aeSBjoern A. Zeeb
71*28348caeSBjoern A. Zeeb /* In the case of WCN6750, WoW wakeup is done
72*28348caeSBjoern A. Zeeb * by sending SMP2P power save exit message
73*28348caeSBjoern A. Zeeb * to the target processor.
74*28348caeSBjoern A. Zeeb */
75*28348caeSBjoern A. Zeeb if (ab->hw_params.smp2p_wow_exit)
76*28348caeSBjoern A. Zeeb return 0;
77*28348caeSBjoern A. Zeeb
78dd4f32aeSBjoern A. Zeeb reinit_completion(&ab->wow.wakeup_completed);
79dd4f32aeSBjoern A. Zeeb
80dd4f32aeSBjoern A. Zeeb ret = ath11k_wmi_wow_host_wakeup_ind(ar);
81dd4f32aeSBjoern A. Zeeb if (ret) {
82dd4f32aeSBjoern A. Zeeb ath11k_warn(ab, "failed to send wow wakeup indication: %d\n",
83dd4f32aeSBjoern A. Zeeb ret);
84dd4f32aeSBjoern A. Zeeb return ret;
85dd4f32aeSBjoern A. Zeeb }
86dd4f32aeSBjoern A. Zeeb
87dd4f32aeSBjoern A. Zeeb ret = wait_for_completion_timeout(&ab->wow.wakeup_completed, 3 * HZ);
88dd4f32aeSBjoern A. Zeeb if (ret == 0) {
89dd4f32aeSBjoern A. Zeeb ath11k_warn(ab, "timed out while waiting for wow wakeup completion\n");
90dd4f32aeSBjoern A. Zeeb return -ETIMEDOUT;
91dd4f32aeSBjoern A. Zeeb }
92dd4f32aeSBjoern A. Zeeb
93dd4f32aeSBjoern A. Zeeb return 0;
94dd4f32aeSBjoern A. Zeeb }
95*28348caeSBjoern A. Zeeb
ath11k_wow_vif_cleanup(struct ath11k_vif * arvif)96*28348caeSBjoern A. Zeeb static int ath11k_wow_vif_cleanup(struct ath11k_vif *arvif)
97*28348caeSBjoern A. Zeeb {
98*28348caeSBjoern A. Zeeb struct ath11k *ar = arvif->ar;
99*28348caeSBjoern A. Zeeb int i, ret;
100*28348caeSBjoern A. Zeeb
101*28348caeSBjoern A. Zeeb for (i = 0; i < WOW_EVENT_MAX; i++) {
102*28348caeSBjoern A. Zeeb ret = ath11k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 0);
103*28348caeSBjoern A. Zeeb if (ret) {
104*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to issue wow wakeup for event %s on vdev %i: %d\n",
105*28348caeSBjoern A. Zeeb wow_wakeup_event(i), arvif->vdev_id, ret);
106*28348caeSBjoern A. Zeeb return ret;
107*28348caeSBjoern A. Zeeb }
108*28348caeSBjoern A. Zeeb }
109*28348caeSBjoern A. Zeeb
110*28348caeSBjoern A. Zeeb for (i = 0; i < ar->wow.max_num_patterns; i++) {
111*28348caeSBjoern A. Zeeb ret = ath11k_wmi_wow_del_pattern(ar, arvif->vdev_id, i);
112*28348caeSBjoern A. Zeeb if (ret) {
113*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to delete wow pattern %d for vdev %i: %d\n",
114*28348caeSBjoern A. Zeeb i, arvif->vdev_id, ret);
115*28348caeSBjoern A. Zeeb return ret;
116*28348caeSBjoern A. Zeeb }
117*28348caeSBjoern A. Zeeb }
118*28348caeSBjoern A. Zeeb
119*28348caeSBjoern A. Zeeb return 0;
120*28348caeSBjoern A. Zeeb }
121*28348caeSBjoern A. Zeeb
ath11k_wow_cleanup(struct ath11k * ar)122*28348caeSBjoern A. Zeeb static int ath11k_wow_cleanup(struct ath11k *ar)
123*28348caeSBjoern A. Zeeb {
124*28348caeSBjoern A. Zeeb struct ath11k_vif *arvif;
125*28348caeSBjoern A. Zeeb int ret;
126*28348caeSBjoern A. Zeeb
127*28348caeSBjoern A. Zeeb lockdep_assert_held(&ar->conf_mutex);
128*28348caeSBjoern A. Zeeb
129*28348caeSBjoern A. Zeeb list_for_each_entry(arvif, &ar->arvifs, list) {
130*28348caeSBjoern A. Zeeb ret = ath11k_wow_vif_cleanup(arvif);
131*28348caeSBjoern A. Zeeb if (ret) {
132*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to clean wow wakeups on vdev %i: %d\n",
133*28348caeSBjoern A. Zeeb arvif->vdev_id, ret);
134*28348caeSBjoern A. Zeeb return ret;
135*28348caeSBjoern A. Zeeb }
136*28348caeSBjoern A. Zeeb }
137*28348caeSBjoern A. Zeeb
138*28348caeSBjoern A. Zeeb return 0;
139*28348caeSBjoern A. Zeeb }
140*28348caeSBjoern A. Zeeb
141*28348caeSBjoern A. Zeeb /* Convert a 802.3 format to a 802.11 format.
142*28348caeSBjoern A. Zeeb * +------------+-----------+--------+----------------+
143*28348caeSBjoern A. Zeeb * 802.3: |dest mac(6B)|src mac(6B)|type(2B)| body... |
144*28348caeSBjoern A. Zeeb * +------------+-----------+--------+----------------+
145*28348caeSBjoern A. Zeeb * |__ |_______ |____________ |________
146*28348caeSBjoern A. Zeeb * | | | |
147*28348caeSBjoern A. Zeeb * +--+------------+----+-----------+---------------+-----------+
148*28348caeSBjoern A. Zeeb * 802.11: |4B|dest mac(6B)| 6B |src mac(6B)| 8B |type(2B)| body... |
149*28348caeSBjoern A. Zeeb * +--+------------+----+-----------+---------------+-----------+
150*28348caeSBjoern A. Zeeb */
ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern * new,const struct cfg80211_pkt_pattern * old)151*28348caeSBjoern A. Zeeb static void ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new,
152*28348caeSBjoern A. Zeeb const struct cfg80211_pkt_pattern *old)
153*28348caeSBjoern A. Zeeb {
154*28348caeSBjoern A. Zeeb u8 hdr_8023_pattern[ETH_HLEN] = {};
155*28348caeSBjoern A. Zeeb u8 hdr_8023_bit_mask[ETH_HLEN] = {};
156*28348caeSBjoern A. Zeeb u8 hdr_80211_pattern[WOW_HDR_LEN] = {};
157*28348caeSBjoern A. Zeeb u8 hdr_80211_bit_mask[WOW_HDR_LEN] = {};
158*28348caeSBjoern A. Zeeb
159*28348caeSBjoern A. Zeeb int total_len = old->pkt_offset + old->pattern_len;
160*28348caeSBjoern A. Zeeb int hdr_80211_end_offset;
161*28348caeSBjoern A. Zeeb
162*28348caeSBjoern A. Zeeb struct ieee80211_hdr_3addr *new_hdr_pattern =
163*28348caeSBjoern A. Zeeb (struct ieee80211_hdr_3addr *)hdr_80211_pattern;
164*28348caeSBjoern A. Zeeb struct ieee80211_hdr_3addr *new_hdr_mask =
165*28348caeSBjoern A. Zeeb (struct ieee80211_hdr_3addr *)hdr_80211_bit_mask;
166*28348caeSBjoern A. Zeeb struct ethhdr *old_hdr_pattern = (struct ethhdr *)hdr_8023_pattern;
167*28348caeSBjoern A. Zeeb struct ethhdr *old_hdr_mask = (struct ethhdr *)hdr_8023_bit_mask;
168*28348caeSBjoern A. Zeeb int hdr_len = sizeof(*new_hdr_pattern);
169*28348caeSBjoern A. Zeeb
170*28348caeSBjoern A. Zeeb struct rfc1042_hdr *new_rfc_pattern =
171*28348caeSBjoern A. Zeeb (struct rfc1042_hdr *)(hdr_80211_pattern + hdr_len);
172*28348caeSBjoern A. Zeeb struct rfc1042_hdr *new_rfc_mask =
173*28348caeSBjoern A. Zeeb (struct rfc1042_hdr *)(hdr_80211_bit_mask + hdr_len);
174*28348caeSBjoern A. Zeeb int rfc_len = sizeof(*new_rfc_pattern);
175*28348caeSBjoern A. Zeeb
176*28348caeSBjoern A. Zeeb memcpy(hdr_8023_pattern + old->pkt_offset,
177*28348caeSBjoern A. Zeeb old->pattern, ETH_HLEN - old->pkt_offset);
178*28348caeSBjoern A. Zeeb memcpy(hdr_8023_bit_mask + old->pkt_offset,
179*28348caeSBjoern A. Zeeb old->mask, ETH_HLEN - old->pkt_offset);
180*28348caeSBjoern A. Zeeb
181*28348caeSBjoern A. Zeeb /* Copy destination address */
182*28348caeSBjoern A. Zeeb memcpy(new_hdr_pattern->addr1, old_hdr_pattern->h_dest, ETH_ALEN);
183*28348caeSBjoern A. Zeeb memcpy(new_hdr_mask->addr1, old_hdr_mask->h_dest, ETH_ALEN);
184*28348caeSBjoern A. Zeeb
185*28348caeSBjoern A. Zeeb /* Copy source address */
186*28348caeSBjoern A. Zeeb memcpy(new_hdr_pattern->addr3, old_hdr_pattern->h_source, ETH_ALEN);
187*28348caeSBjoern A. Zeeb memcpy(new_hdr_mask->addr3, old_hdr_mask->h_source, ETH_ALEN);
188*28348caeSBjoern A. Zeeb
189*28348caeSBjoern A. Zeeb /* Copy logic link type */
190*28348caeSBjoern A. Zeeb memcpy(&new_rfc_pattern->snap_type,
191*28348caeSBjoern A. Zeeb &old_hdr_pattern->h_proto,
192*28348caeSBjoern A. Zeeb sizeof(old_hdr_pattern->h_proto));
193*28348caeSBjoern A. Zeeb memcpy(&new_rfc_mask->snap_type,
194*28348caeSBjoern A. Zeeb &old_hdr_mask->h_proto,
195*28348caeSBjoern A. Zeeb sizeof(old_hdr_mask->h_proto));
196*28348caeSBjoern A. Zeeb
197*28348caeSBjoern A. Zeeb /* Compute new pkt_offset */
198*28348caeSBjoern A. Zeeb if (old->pkt_offset < ETH_ALEN)
199*28348caeSBjoern A. Zeeb new->pkt_offset = old->pkt_offset +
200*28348caeSBjoern A. Zeeb offsetof(struct ieee80211_hdr_3addr, addr1);
201*28348caeSBjoern A. Zeeb else if (old->pkt_offset < offsetof(struct ethhdr, h_proto))
202*28348caeSBjoern A. Zeeb new->pkt_offset = old->pkt_offset +
203*28348caeSBjoern A. Zeeb offsetof(struct ieee80211_hdr_3addr, addr3) -
204*28348caeSBjoern A. Zeeb offsetof(struct ethhdr, h_source);
205*28348caeSBjoern A. Zeeb else
206*28348caeSBjoern A. Zeeb new->pkt_offset = old->pkt_offset + hdr_len + rfc_len - ETH_HLEN;
207*28348caeSBjoern A. Zeeb
208*28348caeSBjoern A. Zeeb /* Compute new hdr end offset */
209*28348caeSBjoern A. Zeeb if (total_len > ETH_HLEN)
210*28348caeSBjoern A. Zeeb hdr_80211_end_offset = hdr_len + rfc_len;
211*28348caeSBjoern A. Zeeb else if (total_len > offsetof(struct ethhdr, h_proto))
212*28348caeSBjoern A. Zeeb hdr_80211_end_offset = hdr_len + rfc_len + total_len - ETH_HLEN;
213*28348caeSBjoern A. Zeeb else if (total_len > ETH_ALEN)
214*28348caeSBjoern A. Zeeb hdr_80211_end_offset = total_len - ETH_ALEN +
215*28348caeSBjoern A. Zeeb offsetof(struct ieee80211_hdr_3addr, addr3);
216*28348caeSBjoern A. Zeeb else
217*28348caeSBjoern A. Zeeb hdr_80211_end_offset = total_len +
218*28348caeSBjoern A. Zeeb offsetof(struct ieee80211_hdr_3addr, addr1);
219*28348caeSBjoern A. Zeeb
220*28348caeSBjoern A. Zeeb new->pattern_len = hdr_80211_end_offset - new->pkt_offset;
221*28348caeSBjoern A. Zeeb
222*28348caeSBjoern A. Zeeb memcpy((u8 *)new->pattern,
223*28348caeSBjoern A. Zeeb hdr_80211_pattern + new->pkt_offset,
224*28348caeSBjoern A. Zeeb new->pattern_len);
225*28348caeSBjoern A. Zeeb memcpy((u8 *)new->mask,
226*28348caeSBjoern A. Zeeb hdr_80211_bit_mask + new->pkt_offset,
227*28348caeSBjoern A. Zeeb new->pattern_len);
228*28348caeSBjoern A. Zeeb
229*28348caeSBjoern A. Zeeb if (total_len > ETH_HLEN) {
230*28348caeSBjoern A. Zeeb /* Copy frame body */
231*28348caeSBjoern A. Zeeb memcpy((u8 *)new->pattern + new->pattern_len,
232*28348caeSBjoern A. Zeeb (void *)old->pattern + ETH_HLEN - old->pkt_offset,
233*28348caeSBjoern A. Zeeb total_len - ETH_HLEN);
234*28348caeSBjoern A. Zeeb memcpy((u8 *)new->mask + new->pattern_len,
235*28348caeSBjoern A. Zeeb (void *)old->mask + ETH_HLEN - old->pkt_offset,
236*28348caeSBjoern A. Zeeb total_len - ETH_HLEN);
237*28348caeSBjoern A. Zeeb
238*28348caeSBjoern A. Zeeb new->pattern_len += total_len - ETH_HLEN;
239*28348caeSBjoern A. Zeeb }
240*28348caeSBjoern A. Zeeb }
241*28348caeSBjoern A. Zeeb
ath11k_wmi_pno_check_and_convert(struct ath11k * ar,u32 vdev_id,struct cfg80211_sched_scan_request * nd_config,struct wmi_pno_scan_req * pno)242*28348caeSBjoern A. Zeeb static int ath11k_wmi_pno_check_and_convert(struct ath11k *ar, u32 vdev_id,
243*28348caeSBjoern A. Zeeb struct cfg80211_sched_scan_request *nd_config,
244*28348caeSBjoern A. Zeeb struct wmi_pno_scan_req *pno)
245*28348caeSBjoern A. Zeeb {
246*28348caeSBjoern A. Zeeb int i, j;
247*28348caeSBjoern A. Zeeb u8 ssid_len;
248*28348caeSBjoern A. Zeeb
249*28348caeSBjoern A. Zeeb pno->enable = 1;
250*28348caeSBjoern A. Zeeb pno->vdev_id = vdev_id;
251*28348caeSBjoern A. Zeeb pno->uc_networks_count = nd_config->n_match_sets;
252*28348caeSBjoern A. Zeeb
253*28348caeSBjoern A. Zeeb if (!pno->uc_networks_count ||
254*28348caeSBjoern A. Zeeb pno->uc_networks_count > WMI_PNO_MAX_SUPP_NETWORKS)
255*28348caeSBjoern A. Zeeb return -EINVAL;
256*28348caeSBjoern A. Zeeb
257*28348caeSBjoern A. Zeeb if (nd_config->n_channels > WMI_PNO_MAX_NETW_CHANNELS_EX)
258*28348caeSBjoern A. Zeeb return -EINVAL;
259*28348caeSBjoern A. Zeeb
260*28348caeSBjoern A. Zeeb /* Filling per profile params */
261*28348caeSBjoern A. Zeeb for (i = 0; i < pno->uc_networks_count; i++) {
262*28348caeSBjoern A. Zeeb ssid_len = nd_config->match_sets[i].ssid.ssid_len;
263*28348caeSBjoern A. Zeeb
264*28348caeSBjoern A. Zeeb if (ssid_len == 0 || ssid_len > 32)
265*28348caeSBjoern A. Zeeb return -EINVAL;
266*28348caeSBjoern A. Zeeb
267*28348caeSBjoern A. Zeeb pno->a_networks[i].ssid.ssid_len = ssid_len;
268*28348caeSBjoern A. Zeeb
269*28348caeSBjoern A. Zeeb memcpy(pno->a_networks[i].ssid.ssid,
270*28348caeSBjoern A. Zeeb nd_config->match_sets[i].ssid.ssid,
271*28348caeSBjoern A. Zeeb nd_config->match_sets[i].ssid.ssid_len);
272*28348caeSBjoern A. Zeeb pno->a_networks[i].authentication = 0;
273*28348caeSBjoern A. Zeeb pno->a_networks[i].encryption = 0;
274*28348caeSBjoern A. Zeeb pno->a_networks[i].bcast_nw_type = 0;
275*28348caeSBjoern A. Zeeb
276*28348caeSBjoern A. Zeeb /* Copying list of valid channel into request */
277*28348caeSBjoern A. Zeeb pno->a_networks[i].channel_count = nd_config->n_channels;
278*28348caeSBjoern A. Zeeb pno->a_networks[i].rssi_threshold = nd_config->match_sets[i].rssi_thold;
279*28348caeSBjoern A. Zeeb
280*28348caeSBjoern A. Zeeb for (j = 0; j < nd_config->n_channels; j++) {
281*28348caeSBjoern A. Zeeb pno->a_networks[i].channels[j] =
282*28348caeSBjoern A. Zeeb nd_config->channels[j]->center_freq;
283*28348caeSBjoern A. Zeeb }
284*28348caeSBjoern A. Zeeb }
285*28348caeSBjoern A. Zeeb
286*28348caeSBjoern A. Zeeb /* set scan to passive if no SSIDs are specified in the request */
287*28348caeSBjoern A. Zeeb if (nd_config->n_ssids == 0)
288*28348caeSBjoern A. Zeeb pno->do_passive_scan = true;
289*28348caeSBjoern A. Zeeb else
290*28348caeSBjoern A. Zeeb pno->do_passive_scan = false;
291*28348caeSBjoern A. Zeeb
292*28348caeSBjoern A. Zeeb for (i = 0; i < nd_config->n_ssids; i++) {
293*28348caeSBjoern A. Zeeb j = 0;
294*28348caeSBjoern A. Zeeb while (j < pno->uc_networks_count) {
295*28348caeSBjoern A. Zeeb if (pno->a_networks[j].ssid.ssid_len ==
296*28348caeSBjoern A. Zeeb nd_config->ssids[i].ssid_len &&
297*28348caeSBjoern A. Zeeb (memcmp(pno->a_networks[j].ssid.ssid,
298*28348caeSBjoern A. Zeeb nd_config->ssids[i].ssid,
299*28348caeSBjoern A. Zeeb pno->a_networks[j].ssid.ssid_len) == 0)) {
300*28348caeSBjoern A. Zeeb pno->a_networks[j].bcast_nw_type = BCAST_HIDDEN;
301*28348caeSBjoern A. Zeeb break;
302*28348caeSBjoern A. Zeeb }
303*28348caeSBjoern A. Zeeb j++;
304*28348caeSBjoern A. Zeeb }
305*28348caeSBjoern A. Zeeb }
306*28348caeSBjoern A. Zeeb
307*28348caeSBjoern A. Zeeb if (nd_config->n_scan_plans == 2) {
308*28348caeSBjoern A. Zeeb pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;
309*28348caeSBjoern A. Zeeb pno->fast_scan_max_cycles = nd_config->scan_plans[0].iterations;
310*28348caeSBjoern A. Zeeb pno->slow_scan_period =
311*28348caeSBjoern A. Zeeb nd_config->scan_plans[1].interval * MSEC_PER_SEC;
312*28348caeSBjoern A. Zeeb } else if (nd_config->n_scan_plans == 1) {
313*28348caeSBjoern A. Zeeb pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;
314*28348caeSBjoern A. Zeeb pno->fast_scan_max_cycles = 1;
315*28348caeSBjoern A. Zeeb pno->slow_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;
316*28348caeSBjoern A. Zeeb } else {
317*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "Invalid number of scan plans %d !!",
318*28348caeSBjoern A. Zeeb nd_config->n_scan_plans);
319*28348caeSBjoern A. Zeeb }
320*28348caeSBjoern A. Zeeb
321*28348caeSBjoern A. Zeeb if (nd_config->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
322*28348caeSBjoern A. Zeeb /* enable mac randomization */
323*28348caeSBjoern A. Zeeb pno->enable_pno_scan_randomization = 1;
324*28348caeSBjoern A. Zeeb memcpy(pno->mac_addr, nd_config->mac_addr, ETH_ALEN);
325*28348caeSBjoern A. Zeeb memcpy(pno->mac_addr_mask, nd_config->mac_addr_mask, ETH_ALEN);
326*28348caeSBjoern A. Zeeb }
327*28348caeSBjoern A. Zeeb
328*28348caeSBjoern A. Zeeb pno->delay_start_time = nd_config->delay;
329*28348caeSBjoern A. Zeeb
330*28348caeSBjoern A. Zeeb /* Current FW does not support min-max range for dwell time */
331*28348caeSBjoern A. Zeeb pno->active_max_time = WMI_ACTIVE_MAX_CHANNEL_TIME;
332*28348caeSBjoern A. Zeeb pno->passive_max_time = WMI_PASSIVE_MAX_CHANNEL_TIME;
333*28348caeSBjoern A. Zeeb
334*28348caeSBjoern A. Zeeb return 0;
335*28348caeSBjoern A. Zeeb }
336*28348caeSBjoern A. Zeeb
ath11k_vif_wow_set_wakeups(struct ath11k_vif * arvif,struct cfg80211_wowlan * wowlan)337*28348caeSBjoern A. Zeeb static int ath11k_vif_wow_set_wakeups(struct ath11k_vif *arvif,
338*28348caeSBjoern A. Zeeb struct cfg80211_wowlan *wowlan)
339*28348caeSBjoern A. Zeeb {
340*28348caeSBjoern A. Zeeb int ret, i;
341*28348caeSBjoern A. Zeeb unsigned long wow_mask = 0;
342*28348caeSBjoern A. Zeeb struct ath11k *ar = arvif->ar;
343*28348caeSBjoern A. Zeeb const struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
344*28348caeSBjoern A. Zeeb int pattern_id = 0;
345*28348caeSBjoern A. Zeeb
346*28348caeSBjoern A. Zeeb /* Setup requested WOW features */
347*28348caeSBjoern A. Zeeb switch (arvif->vdev_type) {
348*28348caeSBjoern A. Zeeb case WMI_VDEV_TYPE_IBSS:
349*28348caeSBjoern A. Zeeb __set_bit(WOW_BEACON_EVENT, &wow_mask);
350*28348caeSBjoern A. Zeeb fallthrough;
351*28348caeSBjoern A. Zeeb case WMI_VDEV_TYPE_AP:
352*28348caeSBjoern A. Zeeb __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
353*28348caeSBjoern A. Zeeb __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
354*28348caeSBjoern A. Zeeb __set_bit(WOW_PROBE_REQ_WPS_IE_EVENT, &wow_mask);
355*28348caeSBjoern A. Zeeb __set_bit(WOW_AUTH_REQ_EVENT, &wow_mask);
356*28348caeSBjoern A. Zeeb __set_bit(WOW_ASSOC_REQ_EVENT, &wow_mask);
357*28348caeSBjoern A. Zeeb __set_bit(WOW_HTT_EVENT, &wow_mask);
358*28348caeSBjoern A. Zeeb __set_bit(WOW_RA_MATCH_EVENT, &wow_mask);
359*28348caeSBjoern A. Zeeb break;
360*28348caeSBjoern A. Zeeb case WMI_VDEV_TYPE_STA:
361*28348caeSBjoern A. Zeeb if (wowlan->disconnect) {
362*28348caeSBjoern A. Zeeb __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
363*28348caeSBjoern A. Zeeb __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
364*28348caeSBjoern A. Zeeb __set_bit(WOW_BMISS_EVENT, &wow_mask);
365*28348caeSBjoern A. Zeeb __set_bit(WOW_CSA_IE_EVENT, &wow_mask);
366*28348caeSBjoern A. Zeeb }
367*28348caeSBjoern A. Zeeb
368*28348caeSBjoern A. Zeeb if (wowlan->magic_pkt)
369*28348caeSBjoern A. Zeeb __set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask);
370*28348caeSBjoern A. Zeeb
371*28348caeSBjoern A. Zeeb if (wowlan->nd_config) {
372*28348caeSBjoern A. Zeeb struct wmi_pno_scan_req *pno;
373*28348caeSBjoern A. Zeeb int ret;
374*28348caeSBjoern A. Zeeb
375*28348caeSBjoern A. Zeeb pno = kzalloc(sizeof(*pno), GFP_KERNEL);
376*28348caeSBjoern A. Zeeb if (!pno)
377*28348caeSBjoern A. Zeeb return -ENOMEM;
378*28348caeSBjoern A. Zeeb
379*28348caeSBjoern A. Zeeb ar->nlo_enabled = true;
380*28348caeSBjoern A. Zeeb
381*28348caeSBjoern A. Zeeb ret = ath11k_wmi_pno_check_and_convert(ar, arvif->vdev_id,
382*28348caeSBjoern A. Zeeb wowlan->nd_config, pno);
383*28348caeSBjoern A. Zeeb if (!ret) {
384*28348caeSBjoern A. Zeeb ath11k_wmi_wow_config_pno(ar, arvif->vdev_id, pno);
385*28348caeSBjoern A. Zeeb __set_bit(WOW_NLO_DETECTED_EVENT, &wow_mask);
386*28348caeSBjoern A. Zeeb }
387*28348caeSBjoern A. Zeeb
388*28348caeSBjoern A. Zeeb kfree(pno);
389*28348caeSBjoern A. Zeeb }
390*28348caeSBjoern A. Zeeb break;
391*28348caeSBjoern A. Zeeb default:
392*28348caeSBjoern A. Zeeb break;
393*28348caeSBjoern A. Zeeb }
394*28348caeSBjoern A. Zeeb
395*28348caeSBjoern A. Zeeb for (i = 0; i < wowlan->n_patterns; i++) {
396*28348caeSBjoern A. Zeeb u8 bitmask[WOW_MAX_PATTERN_SIZE] = {};
397*28348caeSBjoern A. Zeeb u8 ath_pattern[WOW_MAX_PATTERN_SIZE] = {};
398*28348caeSBjoern A. Zeeb u8 ath_bitmask[WOW_MAX_PATTERN_SIZE] = {};
399*28348caeSBjoern A. Zeeb struct cfg80211_pkt_pattern new_pattern = {};
400*28348caeSBjoern A. Zeeb struct cfg80211_pkt_pattern old_pattern = patterns[i];
401*28348caeSBjoern A. Zeeb int j;
402*28348caeSBjoern A. Zeeb
403*28348caeSBjoern A. Zeeb new_pattern.pattern = ath_pattern;
404*28348caeSBjoern A. Zeeb new_pattern.mask = ath_bitmask;
405*28348caeSBjoern A. Zeeb if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE)
406*28348caeSBjoern A. Zeeb continue;
407*28348caeSBjoern A. Zeeb /* convert bytemask to bitmask */
408*28348caeSBjoern A. Zeeb for (j = 0; j < patterns[i].pattern_len; j++)
409*28348caeSBjoern A. Zeeb if (patterns[i].mask[j / 8] & BIT(j % 8))
410*28348caeSBjoern A. Zeeb bitmask[j] = 0xff;
411*28348caeSBjoern A. Zeeb old_pattern.mask = bitmask;
412*28348caeSBjoern A. Zeeb
413*28348caeSBjoern A. Zeeb if (ar->wmi->wmi_ab->wlan_resource_config.rx_decap_mode ==
414*28348caeSBjoern A. Zeeb ATH11K_HW_TXRX_NATIVE_WIFI) {
415*28348caeSBjoern A. Zeeb if (patterns[i].pkt_offset < ETH_HLEN) {
416*28348caeSBjoern A. Zeeb u8 pattern_ext[WOW_MAX_PATTERN_SIZE] = {};
417*28348caeSBjoern A. Zeeb
418*28348caeSBjoern A. Zeeb memcpy(pattern_ext, old_pattern.pattern,
419*28348caeSBjoern A. Zeeb old_pattern.pattern_len);
420*28348caeSBjoern A. Zeeb old_pattern.pattern = pattern_ext;
421*28348caeSBjoern A. Zeeb ath11k_wow_convert_8023_to_80211(&new_pattern,
422*28348caeSBjoern A. Zeeb &old_pattern);
423*28348caeSBjoern A. Zeeb } else {
424*28348caeSBjoern A. Zeeb new_pattern = old_pattern;
425*28348caeSBjoern A. Zeeb new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN;
426*28348caeSBjoern A. Zeeb }
427*28348caeSBjoern A. Zeeb }
428*28348caeSBjoern A. Zeeb
429*28348caeSBjoern A. Zeeb if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE))
430*28348caeSBjoern A. Zeeb return -EINVAL;
431*28348caeSBjoern A. Zeeb
432*28348caeSBjoern A. Zeeb ret = ath11k_wmi_wow_add_pattern(ar, arvif->vdev_id,
433*28348caeSBjoern A. Zeeb pattern_id,
434*28348caeSBjoern A. Zeeb new_pattern.pattern,
435*28348caeSBjoern A. Zeeb new_pattern.mask,
436*28348caeSBjoern A. Zeeb new_pattern.pattern_len,
437*28348caeSBjoern A. Zeeb new_pattern.pkt_offset);
438*28348caeSBjoern A. Zeeb if (ret) {
439*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to add pattern %i to vdev %i: %d\n",
440*28348caeSBjoern A. Zeeb pattern_id,
441*28348caeSBjoern A. Zeeb arvif->vdev_id, ret);
442*28348caeSBjoern A. Zeeb return ret;
443*28348caeSBjoern A. Zeeb }
444*28348caeSBjoern A. Zeeb
445*28348caeSBjoern A. Zeeb pattern_id++;
446*28348caeSBjoern A. Zeeb __set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask);
447*28348caeSBjoern A. Zeeb }
448*28348caeSBjoern A. Zeeb
449*28348caeSBjoern A. Zeeb for (i = 0; i < WOW_EVENT_MAX; i++) {
450*28348caeSBjoern A. Zeeb if (!test_bit(i, &wow_mask))
451*28348caeSBjoern A. Zeeb continue;
452*28348caeSBjoern A. Zeeb ret = ath11k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1);
453*28348caeSBjoern A. Zeeb if (ret) {
454*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to enable wakeup event %s on vdev %i: %d\n",
455*28348caeSBjoern A. Zeeb wow_wakeup_event(i), arvif->vdev_id, ret);
456*28348caeSBjoern A. Zeeb return ret;
457*28348caeSBjoern A. Zeeb }
458*28348caeSBjoern A. Zeeb }
459*28348caeSBjoern A. Zeeb
460*28348caeSBjoern A. Zeeb return 0;
461*28348caeSBjoern A. Zeeb }
462*28348caeSBjoern A. Zeeb
ath11k_wow_set_wakeups(struct ath11k * ar,struct cfg80211_wowlan * wowlan)463*28348caeSBjoern A. Zeeb static int ath11k_wow_set_wakeups(struct ath11k *ar,
464*28348caeSBjoern A. Zeeb struct cfg80211_wowlan *wowlan)
465*28348caeSBjoern A. Zeeb {
466*28348caeSBjoern A. Zeeb struct ath11k_vif *arvif;
467*28348caeSBjoern A. Zeeb int ret;
468*28348caeSBjoern A. Zeeb
469*28348caeSBjoern A. Zeeb lockdep_assert_held(&ar->conf_mutex);
470*28348caeSBjoern A. Zeeb
471*28348caeSBjoern A. Zeeb list_for_each_entry(arvif, &ar->arvifs, list) {
472*28348caeSBjoern A. Zeeb ret = ath11k_vif_wow_set_wakeups(arvif, wowlan);
473*28348caeSBjoern A. Zeeb if (ret) {
474*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to set wow wakeups on vdev %i: %d\n",
475*28348caeSBjoern A. Zeeb arvif->vdev_id, ret);
476*28348caeSBjoern A. Zeeb return ret;
477*28348caeSBjoern A. Zeeb }
478*28348caeSBjoern A. Zeeb }
479*28348caeSBjoern A. Zeeb
480*28348caeSBjoern A. Zeeb return 0;
481*28348caeSBjoern A. Zeeb }
482*28348caeSBjoern A. Zeeb
ath11k_vif_wow_clean_nlo(struct ath11k_vif * arvif)483*28348caeSBjoern A. Zeeb static int ath11k_vif_wow_clean_nlo(struct ath11k_vif *arvif)
484*28348caeSBjoern A. Zeeb {
485*28348caeSBjoern A. Zeeb int ret = 0;
486*28348caeSBjoern A. Zeeb struct ath11k *ar = arvif->ar;
487*28348caeSBjoern A. Zeeb
488*28348caeSBjoern A. Zeeb switch (arvif->vdev_type) {
489*28348caeSBjoern A. Zeeb case WMI_VDEV_TYPE_STA:
490*28348caeSBjoern A. Zeeb if (ar->nlo_enabled) {
491*28348caeSBjoern A. Zeeb struct wmi_pno_scan_req *pno;
492*28348caeSBjoern A. Zeeb
493*28348caeSBjoern A. Zeeb pno = kzalloc(sizeof(*pno), GFP_KERNEL);
494*28348caeSBjoern A. Zeeb if (!pno)
495*28348caeSBjoern A. Zeeb return -ENOMEM;
496*28348caeSBjoern A. Zeeb
497*28348caeSBjoern A. Zeeb pno->enable = 0;
498*28348caeSBjoern A. Zeeb ar->nlo_enabled = false;
499*28348caeSBjoern A. Zeeb ret = ath11k_wmi_wow_config_pno(ar, arvif->vdev_id, pno);
500*28348caeSBjoern A. Zeeb kfree(pno);
501*28348caeSBjoern A. Zeeb }
502*28348caeSBjoern A. Zeeb break;
503*28348caeSBjoern A. Zeeb default:
504*28348caeSBjoern A. Zeeb break;
505*28348caeSBjoern A. Zeeb }
506*28348caeSBjoern A. Zeeb return ret;
507*28348caeSBjoern A. Zeeb }
508*28348caeSBjoern A. Zeeb
ath11k_wow_nlo_cleanup(struct ath11k * ar)509*28348caeSBjoern A. Zeeb static int ath11k_wow_nlo_cleanup(struct ath11k *ar)
510*28348caeSBjoern A. Zeeb {
511*28348caeSBjoern A. Zeeb struct ath11k_vif *arvif;
512*28348caeSBjoern A. Zeeb int ret;
513*28348caeSBjoern A. Zeeb
514*28348caeSBjoern A. Zeeb lockdep_assert_held(&ar->conf_mutex);
515*28348caeSBjoern A. Zeeb
516*28348caeSBjoern A. Zeeb list_for_each_entry(arvif, &ar->arvifs, list) {
517*28348caeSBjoern A. Zeeb ret = ath11k_vif_wow_clean_nlo(arvif);
518*28348caeSBjoern A. Zeeb if (ret) {
519*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to clean nlo settings on vdev %i: %d\n",
520*28348caeSBjoern A. Zeeb arvif->vdev_id, ret);
521*28348caeSBjoern A. Zeeb return ret;
522*28348caeSBjoern A. Zeeb }
523*28348caeSBjoern A. Zeeb }
524*28348caeSBjoern A. Zeeb
525*28348caeSBjoern A. Zeeb return 0;
526*28348caeSBjoern A. Zeeb }
527*28348caeSBjoern A. Zeeb
ath11k_wow_set_hw_filter(struct ath11k * ar)528*28348caeSBjoern A. Zeeb static int ath11k_wow_set_hw_filter(struct ath11k *ar)
529*28348caeSBjoern A. Zeeb {
530*28348caeSBjoern A. Zeeb struct ath11k_vif *arvif;
531*28348caeSBjoern A. Zeeb u32 bitmap;
532*28348caeSBjoern A. Zeeb int ret;
533*28348caeSBjoern A. Zeeb
534*28348caeSBjoern A. Zeeb lockdep_assert_held(&ar->conf_mutex);
535*28348caeSBjoern A. Zeeb
536*28348caeSBjoern A. Zeeb list_for_each_entry(arvif, &ar->arvifs, list) {
537*28348caeSBjoern A. Zeeb bitmap = WMI_HW_DATA_FILTER_DROP_NON_ICMPV6_MC |
538*28348caeSBjoern A. Zeeb WMI_HW_DATA_FILTER_DROP_NON_ARP_BC;
539*28348caeSBjoern A. Zeeb ret = ath11k_wmi_hw_data_filter_cmd(ar, arvif->vdev_id,
540*28348caeSBjoern A. Zeeb bitmap,
541*28348caeSBjoern A. Zeeb true);
542*28348caeSBjoern A. Zeeb if (ret) {
543*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to set hw data filter on vdev %i: %d\n",
544*28348caeSBjoern A. Zeeb arvif->vdev_id, ret);
545*28348caeSBjoern A. Zeeb return ret;
546*28348caeSBjoern A. Zeeb }
547*28348caeSBjoern A. Zeeb }
548*28348caeSBjoern A. Zeeb
549*28348caeSBjoern A. Zeeb return 0;
550*28348caeSBjoern A. Zeeb }
551*28348caeSBjoern A. Zeeb
ath11k_wow_clear_hw_filter(struct ath11k * ar)552*28348caeSBjoern A. Zeeb static int ath11k_wow_clear_hw_filter(struct ath11k *ar)
553*28348caeSBjoern A. Zeeb {
554*28348caeSBjoern A. Zeeb struct ath11k_vif *arvif;
555*28348caeSBjoern A. Zeeb int ret;
556*28348caeSBjoern A. Zeeb
557*28348caeSBjoern A. Zeeb lockdep_assert_held(&ar->conf_mutex);
558*28348caeSBjoern A. Zeeb
559*28348caeSBjoern A. Zeeb list_for_each_entry(arvif, &ar->arvifs, list) {
560*28348caeSBjoern A. Zeeb ret = ath11k_wmi_hw_data_filter_cmd(ar, arvif->vdev_id, 0, false);
561*28348caeSBjoern A. Zeeb
562*28348caeSBjoern A. Zeeb if (ret) {
563*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to clear hw data filter on vdev %i: %d\n",
564*28348caeSBjoern A. Zeeb arvif->vdev_id, ret);
565*28348caeSBjoern A. Zeeb return ret;
566*28348caeSBjoern A. Zeeb }
567*28348caeSBjoern A. Zeeb }
568*28348caeSBjoern A. Zeeb
569*28348caeSBjoern A. Zeeb return 0;
570*28348caeSBjoern A. Zeeb }
571*28348caeSBjoern A. Zeeb
ath11k_wow_arp_ns_offload(struct ath11k * ar,bool enable)572*28348caeSBjoern A. Zeeb static int ath11k_wow_arp_ns_offload(struct ath11k *ar, bool enable)
573*28348caeSBjoern A. Zeeb {
574*28348caeSBjoern A. Zeeb struct ath11k_vif *arvif;
575*28348caeSBjoern A. Zeeb int ret;
576*28348caeSBjoern A. Zeeb
577*28348caeSBjoern A. Zeeb lockdep_assert_held(&ar->conf_mutex);
578*28348caeSBjoern A. Zeeb
579*28348caeSBjoern A. Zeeb list_for_each_entry(arvif, &ar->arvifs, list) {
580*28348caeSBjoern A. Zeeb if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
581*28348caeSBjoern A. Zeeb continue;
582*28348caeSBjoern A. Zeeb
583*28348caeSBjoern A. Zeeb ret = ath11k_wmi_arp_ns_offload(ar, arvif, enable);
584*28348caeSBjoern A. Zeeb
585*28348caeSBjoern A. Zeeb if (ret) {
586*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to set arp ns offload vdev %i: enable %d, ret %d\n",
587*28348caeSBjoern A. Zeeb arvif->vdev_id, enable, ret);
588*28348caeSBjoern A. Zeeb return ret;
589*28348caeSBjoern A. Zeeb }
590*28348caeSBjoern A. Zeeb }
591*28348caeSBjoern A. Zeeb
592*28348caeSBjoern A. Zeeb return 0;
593*28348caeSBjoern A. Zeeb }
594*28348caeSBjoern A. Zeeb
ath11k_gtk_rekey_offload(struct ath11k * ar,bool enable)595*28348caeSBjoern A. Zeeb static int ath11k_gtk_rekey_offload(struct ath11k *ar, bool enable)
596*28348caeSBjoern A. Zeeb {
597*28348caeSBjoern A. Zeeb struct ath11k_vif *arvif;
598*28348caeSBjoern A. Zeeb int ret;
599*28348caeSBjoern A. Zeeb
600*28348caeSBjoern A. Zeeb lockdep_assert_held(&ar->conf_mutex);
601*28348caeSBjoern A. Zeeb
602*28348caeSBjoern A. Zeeb list_for_each_entry(arvif, &ar->arvifs, list) {
603*28348caeSBjoern A. Zeeb if (arvif->vdev_type != WMI_VDEV_TYPE_STA ||
604*28348caeSBjoern A. Zeeb !arvif->is_up ||
605*28348caeSBjoern A. Zeeb !arvif->rekey_data.enable_offload)
606*28348caeSBjoern A. Zeeb continue;
607*28348caeSBjoern A. Zeeb
608*28348caeSBjoern A. Zeeb /* get rekey info before disable rekey offload */
609*28348caeSBjoern A. Zeeb if (!enable) {
610*28348caeSBjoern A. Zeeb ret = ath11k_wmi_gtk_rekey_getinfo(ar, arvif);
611*28348caeSBjoern A. Zeeb if (ret) {
612*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to request rekey info vdev %i, ret %d\n",
613*28348caeSBjoern A. Zeeb arvif->vdev_id, ret);
614*28348caeSBjoern A. Zeeb return ret;
615*28348caeSBjoern A. Zeeb }
616*28348caeSBjoern A. Zeeb }
617*28348caeSBjoern A. Zeeb
618*28348caeSBjoern A. Zeeb ret = ath11k_wmi_gtk_rekey_offload(ar, arvif, enable);
619*28348caeSBjoern A. Zeeb
620*28348caeSBjoern A. Zeeb if (ret) {
621*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to offload gtk reky vdev %i: enable %d, ret %d\n",
622*28348caeSBjoern A. Zeeb arvif->vdev_id, enable, ret);
623*28348caeSBjoern A. Zeeb return ret;
624*28348caeSBjoern A. Zeeb }
625*28348caeSBjoern A. Zeeb }
626*28348caeSBjoern A. Zeeb
627*28348caeSBjoern A. Zeeb return 0;
628*28348caeSBjoern A. Zeeb }
629*28348caeSBjoern A. Zeeb
ath11k_wow_protocol_offload(struct ath11k * ar,bool enable)630*28348caeSBjoern A. Zeeb static int ath11k_wow_protocol_offload(struct ath11k *ar, bool enable)
631*28348caeSBjoern A. Zeeb {
632*28348caeSBjoern A. Zeeb int ret;
633*28348caeSBjoern A. Zeeb
634*28348caeSBjoern A. Zeeb ret = ath11k_wow_arp_ns_offload(ar, enable);
635*28348caeSBjoern A. Zeeb if (ret) {
636*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to offload ARP and NS %d %d\n",
637*28348caeSBjoern A. Zeeb enable, ret);
638*28348caeSBjoern A. Zeeb return ret;
639*28348caeSBjoern A. Zeeb }
640*28348caeSBjoern A. Zeeb
641*28348caeSBjoern A. Zeeb ret = ath11k_gtk_rekey_offload(ar, enable);
642*28348caeSBjoern A. Zeeb if (ret) {
643*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to offload gtk rekey %d %d\n",
644*28348caeSBjoern A. Zeeb enable, ret);
645*28348caeSBjoern A. Zeeb return ret;
646*28348caeSBjoern A. Zeeb }
647*28348caeSBjoern A. Zeeb
648*28348caeSBjoern A. Zeeb return 0;
649*28348caeSBjoern A. Zeeb }
650*28348caeSBjoern A. Zeeb
ath11k_wow_set_keepalive(struct ath11k * ar,enum wmi_sta_keepalive_method method,u32 interval)651*28348caeSBjoern A. Zeeb static int ath11k_wow_set_keepalive(struct ath11k *ar,
652*28348caeSBjoern A. Zeeb enum wmi_sta_keepalive_method method,
653*28348caeSBjoern A. Zeeb u32 interval)
654*28348caeSBjoern A. Zeeb {
655*28348caeSBjoern A. Zeeb struct ath11k_vif *arvif;
656*28348caeSBjoern A. Zeeb int ret;
657*28348caeSBjoern A. Zeeb
658*28348caeSBjoern A. Zeeb lockdep_assert_held(&ar->conf_mutex);
659*28348caeSBjoern A. Zeeb
660*28348caeSBjoern A. Zeeb list_for_each_entry(arvif, &ar->arvifs, list) {
661*28348caeSBjoern A. Zeeb ret = ath11k_mac_vif_set_keepalive(arvif, method, interval);
662*28348caeSBjoern A. Zeeb if (ret)
663*28348caeSBjoern A. Zeeb return ret;
664*28348caeSBjoern A. Zeeb }
665*28348caeSBjoern A. Zeeb
666*28348caeSBjoern A. Zeeb return 0;
667*28348caeSBjoern A. Zeeb }
668*28348caeSBjoern A. Zeeb
ath11k_wow_op_suspend(struct ieee80211_hw * hw,struct cfg80211_wowlan * wowlan)669*28348caeSBjoern A. Zeeb int ath11k_wow_op_suspend(struct ieee80211_hw *hw,
670*28348caeSBjoern A. Zeeb struct cfg80211_wowlan *wowlan)
671*28348caeSBjoern A. Zeeb {
672*28348caeSBjoern A. Zeeb struct ath11k *ar = hw->priv;
673*28348caeSBjoern A. Zeeb int ret;
674*28348caeSBjoern A. Zeeb
675*28348caeSBjoern A. Zeeb ret = ath11k_mac_wait_tx_complete(ar);
676*28348caeSBjoern A. Zeeb if (ret) {
677*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to wait tx complete: %d\n", ret);
678*28348caeSBjoern A. Zeeb return ret;
679*28348caeSBjoern A. Zeeb }
680*28348caeSBjoern A. Zeeb
681*28348caeSBjoern A. Zeeb mutex_lock(&ar->conf_mutex);
682*28348caeSBjoern A. Zeeb
683*28348caeSBjoern A. Zeeb ret = ath11k_dp_rx_pktlog_stop(ar->ab, true);
684*28348caeSBjoern A. Zeeb if (ret) {
685*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab,
686*28348caeSBjoern A. Zeeb "failed to stop dp rx (and timer) pktlog during wow suspend: %d\n",
687*28348caeSBjoern A. Zeeb ret);
688*28348caeSBjoern A. Zeeb goto exit;
689*28348caeSBjoern A. Zeeb }
690*28348caeSBjoern A. Zeeb
691*28348caeSBjoern A. Zeeb ret = ath11k_wow_cleanup(ar);
692*28348caeSBjoern A. Zeeb if (ret) {
693*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to clear wow wakeup events: %d\n",
694*28348caeSBjoern A. Zeeb ret);
695*28348caeSBjoern A. Zeeb goto exit;
696*28348caeSBjoern A. Zeeb }
697*28348caeSBjoern A. Zeeb
698*28348caeSBjoern A. Zeeb ret = ath11k_wow_set_wakeups(ar, wowlan);
699*28348caeSBjoern A. Zeeb if (ret) {
700*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to set wow wakeup events: %d\n",
701*28348caeSBjoern A. Zeeb ret);
702*28348caeSBjoern A. Zeeb goto cleanup;
703*28348caeSBjoern A. Zeeb }
704*28348caeSBjoern A. Zeeb
705*28348caeSBjoern A. Zeeb ret = ath11k_wow_protocol_offload(ar, true);
706*28348caeSBjoern A. Zeeb if (ret) {
707*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to set wow protocol offload events: %d\n",
708*28348caeSBjoern A. Zeeb ret);
709*28348caeSBjoern A. Zeeb goto cleanup;
710*28348caeSBjoern A. Zeeb }
711*28348caeSBjoern A. Zeeb
712*28348caeSBjoern A. Zeeb ret = ath11k_wow_set_hw_filter(ar);
713*28348caeSBjoern A. Zeeb if (ret) {
714*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to set hw filter: %d\n",
715*28348caeSBjoern A. Zeeb ret);
716*28348caeSBjoern A. Zeeb goto cleanup;
717*28348caeSBjoern A. Zeeb }
718*28348caeSBjoern A. Zeeb
719*28348caeSBjoern A. Zeeb ret = ath11k_wow_set_keepalive(ar,
720*28348caeSBjoern A. Zeeb WMI_STA_KEEPALIVE_METHOD_NULL_FRAME,
721*28348caeSBjoern A. Zeeb WMI_STA_KEEPALIVE_INTERVAL_DEFAULT);
722*28348caeSBjoern A. Zeeb if (ret) {
723*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to enable wow keepalive: %d\n", ret);
724*28348caeSBjoern A. Zeeb goto cleanup;
725*28348caeSBjoern A. Zeeb }
726*28348caeSBjoern A. Zeeb
727*28348caeSBjoern A. Zeeb ret = ath11k_wow_enable(ar->ab);
728*28348caeSBjoern A. Zeeb if (ret) {
729*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to start wow: %d\n", ret);
730*28348caeSBjoern A. Zeeb goto cleanup;
731*28348caeSBjoern A. Zeeb }
732*28348caeSBjoern A. Zeeb
733*28348caeSBjoern A. Zeeb ret = ath11k_dp_rx_pktlog_stop(ar->ab, false);
734*28348caeSBjoern A. Zeeb if (ret) {
735*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab,
736*28348caeSBjoern A. Zeeb "failed to stop dp rx pktlog during wow suspend: %d\n",
737*28348caeSBjoern A. Zeeb ret);
738*28348caeSBjoern A. Zeeb goto cleanup;
739*28348caeSBjoern A. Zeeb }
740*28348caeSBjoern A. Zeeb
741*28348caeSBjoern A. Zeeb ath11k_ce_stop_shadow_timers(ar->ab);
742*28348caeSBjoern A. Zeeb ath11k_dp_stop_shadow_timers(ar->ab);
743*28348caeSBjoern A. Zeeb
744*28348caeSBjoern A. Zeeb ath11k_hif_irq_disable(ar->ab);
745*28348caeSBjoern A. Zeeb ath11k_hif_ce_irq_disable(ar->ab);
746*28348caeSBjoern A. Zeeb
747*28348caeSBjoern A. Zeeb ret = ath11k_hif_suspend(ar->ab);
748*28348caeSBjoern A. Zeeb if (ret) {
749*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to suspend hif: %d\n", ret);
750*28348caeSBjoern A. Zeeb goto wakeup;
751*28348caeSBjoern A. Zeeb }
752*28348caeSBjoern A. Zeeb
753*28348caeSBjoern A. Zeeb goto exit;
754*28348caeSBjoern A. Zeeb
755*28348caeSBjoern A. Zeeb wakeup:
756*28348caeSBjoern A. Zeeb ath11k_wow_wakeup(ar->ab);
757*28348caeSBjoern A. Zeeb
758*28348caeSBjoern A. Zeeb cleanup:
759*28348caeSBjoern A. Zeeb ath11k_wow_cleanup(ar);
760*28348caeSBjoern A. Zeeb
761*28348caeSBjoern A. Zeeb exit:
762*28348caeSBjoern A. Zeeb mutex_unlock(&ar->conf_mutex);
763*28348caeSBjoern A. Zeeb return ret ? 1 : 0;
764*28348caeSBjoern A. Zeeb }
765*28348caeSBjoern A. Zeeb
ath11k_wow_op_set_wakeup(struct ieee80211_hw * hw,bool enabled)766*28348caeSBjoern A. Zeeb void ath11k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled)
767*28348caeSBjoern A. Zeeb {
768*28348caeSBjoern A. Zeeb struct ath11k *ar = hw->priv;
769*28348caeSBjoern A. Zeeb
770*28348caeSBjoern A. Zeeb mutex_lock(&ar->conf_mutex);
771*28348caeSBjoern A. Zeeb device_set_wakeup_enable(ar->ab->dev, enabled);
772*28348caeSBjoern A. Zeeb mutex_unlock(&ar->conf_mutex);
773*28348caeSBjoern A. Zeeb }
774*28348caeSBjoern A. Zeeb
ath11k_wow_op_resume(struct ieee80211_hw * hw)775*28348caeSBjoern A. Zeeb int ath11k_wow_op_resume(struct ieee80211_hw *hw)
776*28348caeSBjoern A. Zeeb {
777*28348caeSBjoern A. Zeeb struct ath11k *ar = hw->priv;
778*28348caeSBjoern A. Zeeb int ret;
779*28348caeSBjoern A. Zeeb
780*28348caeSBjoern A. Zeeb mutex_lock(&ar->conf_mutex);
781*28348caeSBjoern A. Zeeb
782*28348caeSBjoern A. Zeeb ret = ath11k_hif_resume(ar->ab);
783*28348caeSBjoern A. Zeeb if (ret) {
784*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to resume hif: %d\n", ret);
785*28348caeSBjoern A. Zeeb goto exit;
786*28348caeSBjoern A. Zeeb }
787*28348caeSBjoern A. Zeeb
788*28348caeSBjoern A. Zeeb ath11k_hif_ce_irq_enable(ar->ab);
789*28348caeSBjoern A. Zeeb ath11k_hif_irq_enable(ar->ab);
790*28348caeSBjoern A. Zeeb
791*28348caeSBjoern A. Zeeb ret = ath11k_dp_rx_pktlog_start(ar->ab);
792*28348caeSBjoern A. Zeeb if (ret) {
793*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to start rx pktlog from wow: %d\n", ret);
794*28348caeSBjoern A. Zeeb goto exit;
795*28348caeSBjoern A. Zeeb }
796*28348caeSBjoern A. Zeeb
797*28348caeSBjoern A. Zeeb ret = ath11k_wow_wakeup(ar->ab);
798*28348caeSBjoern A. Zeeb if (ret) {
799*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to wakeup from wow: %d\n", ret);
800*28348caeSBjoern A. Zeeb goto exit;
801*28348caeSBjoern A. Zeeb }
802*28348caeSBjoern A. Zeeb
803*28348caeSBjoern A. Zeeb ret = ath11k_wow_nlo_cleanup(ar);
804*28348caeSBjoern A. Zeeb if (ret) {
805*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to cleanup nlo: %d\n", ret);
806*28348caeSBjoern A. Zeeb goto exit;
807*28348caeSBjoern A. Zeeb }
808*28348caeSBjoern A. Zeeb
809*28348caeSBjoern A. Zeeb ret = ath11k_wow_clear_hw_filter(ar);
810*28348caeSBjoern A. Zeeb if (ret) {
811*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to clear hw filter: %d\n", ret);
812*28348caeSBjoern A. Zeeb goto exit;
813*28348caeSBjoern A. Zeeb }
814*28348caeSBjoern A. Zeeb
815*28348caeSBjoern A. Zeeb ret = ath11k_wow_protocol_offload(ar, false);
816*28348caeSBjoern A. Zeeb if (ret) {
817*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to clear wow protocol offload events: %d\n",
818*28348caeSBjoern A. Zeeb ret);
819*28348caeSBjoern A. Zeeb goto exit;
820*28348caeSBjoern A. Zeeb }
821*28348caeSBjoern A. Zeeb
822*28348caeSBjoern A. Zeeb ret = ath11k_wow_set_keepalive(ar,
823*28348caeSBjoern A. Zeeb WMI_STA_KEEPALIVE_METHOD_NULL_FRAME,
824*28348caeSBjoern A. Zeeb WMI_STA_KEEPALIVE_INTERVAL_DISABLE);
825*28348caeSBjoern A. Zeeb if (ret) {
826*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "failed to disable wow keepalive: %d\n", ret);
827*28348caeSBjoern A. Zeeb goto exit;
828*28348caeSBjoern A. Zeeb }
829*28348caeSBjoern A. Zeeb
830*28348caeSBjoern A. Zeeb exit:
831*28348caeSBjoern A. Zeeb if (ret) {
832*28348caeSBjoern A. Zeeb switch (ar->state) {
833*28348caeSBjoern A. Zeeb case ATH11K_STATE_ON:
834*28348caeSBjoern A. Zeeb ar->state = ATH11K_STATE_RESTARTING;
835*28348caeSBjoern A. Zeeb ret = 1;
836*28348caeSBjoern A. Zeeb break;
837*28348caeSBjoern A. Zeeb case ATH11K_STATE_OFF:
838*28348caeSBjoern A. Zeeb case ATH11K_STATE_RESTARTING:
839*28348caeSBjoern A. Zeeb case ATH11K_STATE_RESTARTED:
840*28348caeSBjoern A. Zeeb case ATH11K_STATE_WEDGED:
841*28348caeSBjoern A. Zeeb case ATH11K_STATE_FTM:
842*28348caeSBjoern A. Zeeb ath11k_warn(ar->ab, "encountered unexpected device state %d on resume, cannot recover\n",
843*28348caeSBjoern A. Zeeb ar->state);
844*28348caeSBjoern A. Zeeb ret = -EIO;
845*28348caeSBjoern A. Zeeb break;
846*28348caeSBjoern A. Zeeb }
847*28348caeSBjoern A. Zeeb }
848*28348caeSBjoern A. Zeeb
849*28348caeSBjoern A. Zeeb mutex_unlock(&ar->conf_mutex);
850*28348caeSBjoern A. Zeeb return ret;
851*28348caeSBjoern A. Zeeb }
852*28348caeSBjoern A. Zeeb
ath11k_wow_init(struct ath11k * ar)853*28348caeSBjoern A. Zeeb int ath11k_wow_init(struct ath11k *ar)
854*28348caeSBjoern A. Zeeb {
855*28348caeSBjoern A. Zeeb if (!test_bit(WMI_TLV_SERVICE_WOW, ar->wmi->wmi_ab->svc_map))
856*28348caeSBjoern A. Zeeb return 0;
857*28348caeSBjoern A. Zeeb
858*28348caeSBjoern A. Zeeb ar->wow.wowlan_support = ath11k_wowlan_support;
859*28348caeSBjoern A. Zeeb
860*28348caeSBjoern A. Zeeb if (ar->wmi->wmi_ab->wlan_resource_config.rx_decap_mode ==
861*28348caeSBjoern A. Zeeb ATH11K_HW_TXRX_NATIVE_WIFI) {
862*28348caeSBjoern A. Zeeb ar->wow.wowlan_support.pattern_max_len -= WOW_MAX_REDUCE;
863*28348caeSBjoern A. Zeeb ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE;
864*28348caeSBjoern A. Zeeb }
865*28348caeSBjoern A. Zeeb
866*28348caeSBjoern A. Zeeb if (test_bit(WMI_TLV_SERVICE_NLO, ar->wmi->wmi_ab->svc_map)) {
867*28348caeSBjoern A. Zeeb ar->wow.wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
868*28348caeSBjoern A. Zeeb ar->wow.wowlan_support.max_nd_match_sets = WMI_PNO_MAX_SUPP_NETWORKS;
869*28348caeSBjoern A. Zeeb }
870*28348caeSBjoern A. Zeeb
871*28348caeSBjoern A. Zeeb ar->wow.max_num_patterns = ATH11K_WOW_PATTERNS;
872*28348caeSBjoern A. Zeeb ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns;
873*28348caeSBjoern A. Zeeb ar->hw->wiphy->wowlan = &ar->wow.wowlan_support;
874*28348caeSBjoern A. Zeeb
875*28348caeSBjoern A. Zeeb device_set_wakeup_capable(ar->ab->dev, true);
876*28348caeSBjoern A. Zeeb
877*28348caeSBjoern A. Zeeb return 0;
878*28348caeSBjoern A. Zeeb }
879