2 * Copyright (c) 2015-2017 Qualcomm Atheros, Inc.
3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <net/mac80211.h>
27 static const struct wiphy_wowlan_support ath10k_wowlan_support
= {
28 .flags
= WIPHY_WOWLAN_DISCONNECT
|
29 WIPHY_WOWLAN_MAGIC_PKT
,
30 .pattern_min_len
= WOW_MIN_PATTERN_SIZE
,
31 .pattern_max_len
= WOW_MAX_PATTERN_SIZE
,
32 .max_pkt_offset
= WOW_MAX_PKT_OFFSET
,
35 static int ath10k_wow_vif_cleanup(struct ath10k_vif
*arvif
)
37 struct ath10k
*ar
= arvif
->ar
;
40 for (i
= 0; i
< WOW_EVENT_MAX
; i
++) {
41 ret
= ath10k_wmi_wow_add_wakeup_event(ar
, arvif
->vdev_id
, i
, 0);
43 ath10k_warn(ar
, "failed to issue wow wakeup for event %s on vdev %i: %d\n",
44 wow_wakeup_event(i
), arvif
->vdev_id
, ret
);
49 for (i
= 0; i
< ar
->wow
.max_num_patterns
; i
++) {
50 ret
= ath10k_wmi_wow_del_pattern(ar
, arvif
->vdev_id
, i
);
52 ath10k_warn(ar
, "failed to delete wow pattern %d for vdev %i: %d\n",
53 i
, arvif
->vdev_id
, ret
);
61 static int ath10k_wow_cleanup(struct ath10k
*ar
)
63 struct ath10k_vif
*arvif
;
66 lockdep_assert_held(&ar
->conf_mutex
);
68 list_for_each_entry(arvif
, &ar
->arvifs
, list
) {
69 ret
= ath10k_wow_vif_cleanup(arvif
);
71 ath10k_warn(ar
, "failed to clean wow wakeups on vdev %i: %d\n",
81 * Convert a 802.3 format to a 802.11 format.
82 * +------------+-----------+--------+----------------+
83 * 802.3: |dest mac(6B)|src mac(6B)|type(2B)| body... |
84 * +------------+-----------+--------+----------------+
85 * |__ |_______ |____________ |________
87 * +--+------------+----+-----------+---------------+-----------+
88 * 802.11: |4B|dest mac(6B)| 6B |src mac(6B)| 8B |type(2B)| body... |
89 * +--+------------+----+-----------+---------------+-----------+
91 static void ath10k_wow_convert_8023_to_80211
92 (struct cfg80211_pkt_pattern
*new,
93 const struct cfg80211_pkt_pattern
*old
)
95 u8 hdr_8023_pattern
[ETH_HLEN
] = {};
96 u8 hdr_8023_bit_mask
[ETH_HLEN
] = {};
97 u8 hdr_80211_pattern
[WOW_HDR_LEN
] = {};
98 u8 hdr_80211_bit_mask
[WOW_HDR_LEN
] = {};
100 int total_len
= old
->pkt_offset
+ old
->pattern_len
;
101 int hdr_80211_end_offset
;
103 struct ieee80211_hdr_3addr
*new_hdr_pattern
=
104 (struct ieee80211_hdr_3addr
*)hdr_80211_pattern
;
105 struct ieee80211_hdr_3addr
*new_hdr_mask
=
106 (struct ieee80211_hdr_3addr
*)hdr_80211_bit_mask
;
107 struct ethhdr
*old_hdr_pattern
= (struct ethhdr
*)hdr_8023_pattern
;
108 struct ethhdr
*old_hdr_mask
= (struct ethhdr
*)hdr_8023_bit_mask
;
109 int hdr_len
= sizeof(*new_hdr_pattern
);
111 struct rfc1042_hdr
*new_rfc_pattern
=
112 (struct rfc1042_hdr
*)(hdr_80211_pattern
+ hdr_len
);
113 struct rfc1042_hdr
*new_rfc_mask
=
114 (struct rfc1042_hdr
*)(hdr_80211_bit_mask
+ hdr_len
);
115 int rfc_len
= sizeof(*new_rfc_pattern
);
117 memcpy(hdr_8023_pattern
+ old
->pkt_offset
,
118 old
->pattern
, ETH_HLEN
- old
->pkt_offset
);
119 memcpy(hdr_8023_bit_mask
+ old
->pkt_offset
,
120 old
->mask
, ETH_HLEN
- old
->pkt_offset
);
122 /* Copy destination address */
123 memcpy(new_hdr_pattern
->addr1
, old_hdr_pattern
->h_dest
, ETH_ALEN
);
124 memcpy(new_hdr_mask
->addr1
, old_hdr_mask
->h_dest
, ETH_ALEN
);
126 /* Copy source address */
127 memcpy(new_hdr_pattern
->addr3
, old_hdr_pattern
->h_source
, ETH_ALEN
);
128 memcpy(new_hdr_mask
->addr3
, old_hdr_mask
->h_source
, ETH_ALEN
);
130 /* Copy logic link type */
131 memcpy(&new_rfc_pattern
->snap_type
,
132 &old_hdr_pattern
->h_proto
,
133 sizeof(old_hdr_pattern
->h_proto
));
134 memcpy(&new_rfc_mask
->snap_type
,
135 &old_hdr_mask
->h_proto
,
136 sizeof(old_hdr_mask
->h_proto
));
138 /* Caculate new pkt_offset */
139 if (old
->pkt_offset
< ETH_ALEN
)
140 new->pkt_offset
= old
->pkt_offset
+
141 offsetof(struct ieee80211_hdr_3addr
, addr1
);
142 else if (old
->pkt_offset
< offsetof(struct ethhdr
, h_proto
))
143 new->pkt_offset
= old
->pkt_offset
+
144 offsetof(struct ieee80211_hdr_3addr
, addr3
) -
145 offsetof(struct ethhdr
, h_source
);
147 new->pkt_offset
= old
->pkt_offset
+ hdr_len
+ rfc_len
- ETH_HLEN
;
149 /* Caculate new hdr end offset */
150 if (total_len
> ETH_HLEN
)
151 hdr_80211_end_offset
= hdr_len
+ rfc_len
;
152 else if (total_len
> offsetof(struct ethhdr
, h_proto
))
153 hdr_80211_end_offset
= hdr_len
+ rfc_len
+ total_len
- ETH_HLEN
;
154 else if (total_len
> ETH_ALEN
)
155 hdr_80211_end_offset
= total_len
- ETH_ALEN
+
156 offsetof(struct ieee80211_hdr_3addr
, addr3
);
158 hdr_80211_end_offset
= total_len
+
159 offsetof(struct ieee80211_hdr_3addr
, addr1
);
161 new->pattern_len
= hdr_80211_end_offset
- new->pkt_offset
;
163 memcpy((u8
*)new->pattern
,
164 hdr_80211_pattern
+ new->pkt_offset
,
166 memcpy((u8
*)new->mask
,
167 hdr_80211_bit_mask
+ new->pkt_offset
,
170 if (total_len
> ETH_HLEN
) {
171 /* Copy frame body */
172 memcpy((u8
*)new->pattern
+ new->pattern_len
,
173 (void *)old
->pattern
+ ETH_HLEN
- old
->pkt_offset
,
174 total_len
- ETH_HLEN
);
175 memcpy((u8
*)new->mask
+ new->pattern_len
,
176 (void *)old
->mask
+ ETH_HLEN
- old
->pkt_offset
,
177 total_len
- ETH_HLEN
);
179 new->pattern_len
+= total_len
- ETH_HLEN
;
183 static int ath10k_wmi_pno_check(struct ath10k
*ar
, u32 vdev_id
,
184 struct cfg80211_sched_scan_request
*nd_config
,
185 struct wmi_pno_scan_req
*pno
)
191 pno
->vdev_id
= vdev_id
;
192 pno
->uc_networks_count
= nd_config
->n_match_sets
;
194 if (!pno
->uc_networks_count
||
195 pno
->uc_networks_count
> WMI_PNO_MAX_SUPP_NETWORKS
)
198 if (nd_config
->n_channels
> WMI_PNO_MAX_NETW_CHANNELS_EX
)
201 /* Filling per profile params */
202 for (i
= 0; i
< pno
->uc_networks_count
; i
++) {
203 ssid_len
= nd_config
->match_sets
[i
].ssid
.ssid_len
;
205 if (ssid_len
== 0 || ssid_len
> 32)
208 pno
->a_networks
[i
].ssid
.ssid_len
= __cpu_to_le32(ssid_len
);
210 memcpy(pno
->a_networks
[i
].ssid
.ssid
,
211 nd_config
->match_sets
[i
].ssid
.ssid
,
212 nd_config
->match_sets
[i
].ssid
.ssid_len
);
213 pno
->a_networks
[i
].authentication
= 0;
214 pno
->a_networks
[i
].encryption
= 0;
215 pno
->a_networks
[i
].bcast_nw_type
= 0;
217 /*Copying list of valid channel into request */
218 pno
->a_networks
[i
].channel_count
= nd_config
->n_channels
;
219 pno
->a_networks
[i
].rssi_threshold
= nd_config
->match_sets
[i
].rssi_thold
;
221 for (j
= 0; j
< nd_config
->n_channels
; j
++) {
222 pno
->a_networks
[i
].channels
[j
] =
223 nd_config
->channels
[j
]->center_freq
;
227 /* set scan to passive if no SSIDs are specified in the request */
228 if (nd_config
->n_ssids
== 0)
229 pno
->do_passive_scan
= true;
231 pno
->do_passive_scan
= false;
233 for (i
= 0; i
< nd_config
->n_ssids
; i
++) {
235 while (j
< pno
->uc_networks_count
) {
236 if (__le32_to_cpu(pno
->a_networks
[j
].ssid
.ssid_len
) ==
237 nd_config
->ssids
[i
].ssid_len
&&
238 (memcmp(pno
->a_networks
[j
].ssid
.ssid
,
239 nd_config
->ssids
[i
].ssid
,
240 __le32_to_cpu(pno
->a_networks
[j
].ssid
.ssid_len
)) == 0)) {
241 pno
->a_networks
[j
].bcast_nw_type
= BCAST_HIDDEN
;
248 if (nd_config
->n_scan_plans
== 2) {
249 pno
->fast_scan_period
= nd_config
->scan_plans
[0].interval
* MSEC_PER_SEC
;
250 pno
->fast_scan_max_cycles
= nd_config
->scan_plans
[0].iterations
;
251 pno
->slow_scan_period
=
252 nd_config
->scan_plans
[1].interval
* MSEC_PER_SEC
;
253 } else if (nd_config
->n_scan_plans
== 1) {
254 pno
->fast_scan_period
= nd_config
->scan_plans
[0].interval
* MSEC_PER_SEC
;
255 pno
->fast_scan_max_cycles
= 1;
256 pno
->slow_scan_period
= nd_config
->scan_plans
[0].interval
* MSEC_PER_SEC
;
258 ath10k_warn(ar
, "Invalid number of scan plans %d !!",
259 nd_config
->n_scan_plans
);
262 if (nd_config
->flags
& NL80211_SCAN_FLAG_RANDOM_ADDR
) {
263 /* enable mac randomization */
264 pno
->enable_pno_scan_randomization
= 1;
265 memcpy(pno
->mac_addr
, nd_config
->mac_addr
, ETH_ALEN
);
266 memcpy(pno
->mac_addr_mask
, nd_config
->mac_addr_mask
, ETH_ALEN
);
269 pno
->delay_start_time
= nd_config
->delay
;
271 /* Current FW does not support min-max range for dwell time */
272 pno
->active_max_time
= WMI_ACTIVE_MAX_CHANNEL_TIME
;
273 pno
->passive_max_time
= WMI_PASSIVE_MAX_CHANNEL_TIME
;
277 static int ath10k_vif_wow_set_wakeups(struct ath10k_vif
*arvif
,
278 struct cfg80211_wowlan
*wowlan
)
281 unsigned long wow_mask
= 0;
282 struct ath10k
*ar
= arvif
->ar
;
283 const struct cfg80211_pkt_pattern
*patterns
= wowlan
->patterns
;
286 /* Setup requested WOW features */
287 switch (arvif
->vdev_type
) {
288 case WMI_VDEV_TYPE_IBSS
:
289 __set_bit(WOW_BEACON_EVENT
, &wow_mask
);
291 case WMI_VDEV_TYPE_AP
:
292 __set_bit(WOW_DEAUTH_RECVD_EVENT
, &wow_mask
);
293 __set_bit(WOW_DISASSOC_RECVD_EVENT
, &wow_mask
);
294 __set_bit(WOW_PROBE_REQ_WPS_IE_EVENT
, &wow_mask
);
295 __set_bit(WOW_AUTH_REQ_EVENT
, &wow_mask
);
296 __set_bit(WOW_ASSOC_REQ_EVENT
, &wow_mask
);
297 __set_bit(WOW_HTT_EVENT
, &wow_mask
);
298 __set_bit(WOW_RA_MATCH_EVENT
, &wow_mask
);
300 case WMI_VDEV_TYPE_STA
:
301 if (wowlan
->disconnect
) {
302 __set_bit(WOW_DEAUTH_RECVD_EVENT
, &wow_mask
);
303 __set_bit(WOW_DISASSOC_RECVD_EVENT
, &wow_mask
);
304 __set_bit(WOW_BMISS_EVENT
, &wow_mask
);
305 __set_bit(WOW_CSA_IE_EVENT
, &wow_mask
);
308 if (wowlan
->magic_pkt
)
309 __set_bit(WOW_MAGIC_PKT_RECVD_EVENT
, &wow_mask
);
311 if (wowlan
->nd_config
) {
312 struct wmi_pno_scan_req
*pno
;
315 pno
= kzalloc(sizeof(*pno
), GFP_KERNEL
);
319 ar
->nlo_enabled
= true;
321 ret
= ath10k_wmi_pno_check(ar
, arvif
->vdev_id
,
322 wowlan
->nd_config
, pno
);
324 ath10k_wmi_wow_config_pno(ar
, arvif
->vdev_id
, pno
);
325 __set_bit(WOW_NLO_DETECTED_EVENT
, &wow_mask
);
335 for (i
= 0; i
< wowlan
->n_patterns
; i
++) {
336 u8 bitmask
[WOW_MAX_PATTERN_SIZE
] = {};
337 u8 ath_pattern
[WOW_MAX_PATTERN_SIZE
] = {};
338 u8 ath_bitmask
[WOW_MAX_PATTERN_SIZE
] = {};
339 struct cfg80211_pkt_pattern new_pattern
= {};
340 struct cfg80211_pkt_pattern old_pattern
= patterns
[i
];
343 new_pattern
.pattern
= ath_pattern
;
344 new_pattern
.mask
= ath_bitmask
;
345 if (patterns
[i
].pattern_len
> WOW_MAX_PATTERN_SIZE
)
347 /* convert bytemask to bitmask */
348 for (j
= 0; j
< patterns
[i
].pattern_len
; j
++)
349 if (patterns
[i
].mask
[j
/ 8] & BIT(j
% 8))
351 old_pattern
.mask
= bitmask
;
352 new_pattern
= old_pattern
;
354 if (ar
->wmi
.rx_decap_mode
== ATH10K_HW_TXRX_NATIVE_WIFI
) {
355 if (patterns
[i
].pkt_offset
< ETH_HLEN
)
356 ath10k_wow_convert_8023_to_80211(&new_pattern
,
359 new_pattern
.pkt_offset
+= WOW_HDR_LEN
- ETH_HLEN
;
362 if (WARN_ON(new_pattern
.pattern_len
> WOW_MAX_PATTERN_SIZE
))
365 ret
= ath10k_wmi_wow_add_pattern(ar
, arvif
->vdev_id
,
369 new_pattern
.pattern_len
,
370 new_pattern
.pkt_offset
);
372 ath10k_warn(ar
, "failed to add pattern %i to vdev %i: %d\n",
374 arvif
->vdev_id
, ret
);
379 __set_bit(WOW_PATTERN_MATCH_EVENT
, &wow_mask
);
382 for (i
= 0; i
< WOW_EVENT_MAX
; i
++) {
383 if (!test_bit(i
, &wow_mask
))
385 ret
= ath10k_wmi_wow_add_wakeup_event(ar
, arvif
->vdev_id
, i
, 1);
387 ath10k_warn(ar
, "failed to enable wakeup event %s on vdev %i: %d\n",
388 wow_wakeup_event(i
), arvif
->vdev_id
, ret
);
396 static int ath10k_wow_set_wakeups(struct ath10k
*ar
,
397 struct cfg80211_wowlan
*wowlan
)
399 struct ath10k_vif
*arvif
;
402 lockdep_assert_held(&ar
->conf_mutex
);
404 list_for_each_entry(arvif
, &ar
->arvifs
, list
) {
405 ret
= ath10k_vif_wow_set_wakeups(arvif
, wowlan
);
407 ath10k_warn(ar
, "failed to set wow wakeups on vdev %i: %d\n",
408 arvif
->vdev_id
, ret
);
416 static int ath10k_vif_wow_clean_nlo(struct ath10k_vif
*arvif
)
419 struct ath10k
*ar
= arvif
->ar
;
421 switch (arvif
->vdev_type
) {
422 case WMI_VDEV_TYPE_STA
:
423 if (ar
->nlo_enabled
) {
424 struct wmi_pno_scan_req
*pno
;
426 pno
= kzalloc(sizeof(*pno
), GFP_KERNEL
);
431 ar
->nlo_enabled
= false;
432 ret
= ath10k_wmi_wow_config_pno(ar
, arvif
->vdev_id
, pno
);
442 static int ath10k_wow_nlo_cleanup(struct ath10k
*ar
)
444 struct ath10k_vif
*arvif
;
447 lockdep_assert_held(&ar
->conf_mutex
);
449 list_for_each_entry(arvif
, &ar
->arvifs
, list
) {
450 ret
= ath10k_vif_wow_clean_nlo(arvif
);
452 ath10k_warn(ar
, "failed to clean nlo settings on vdev %i: %d\n",
453 arvif
->vdev_id
, ret
);
461 static int ath10k_wow_enable(struct ath10k
*ar
)
465 lockdep_assert_held(&ar
->conf_mutex
);
467 reinit_completion(&ar
->target_suspend
);
469 ret
= ath10k_wmi_wow_enable(ar
);
471 ath10k_warn(ar
, "failed to issue wow enable: %d\n", ret
);
475 ret
= wait_for_completion_timeout(&ar
->target_suspend
, 3 * HZ
);
477 ath10k_warn(ar
, "timed out while waiting for suspend completion\n");
484 static int ath10k_wow_wakeup(struct ath10k
*ar
)
488 lockdep_assert_held(&ar
->conf_mutex
);
490 reinit_completion(&ar
->wow
.wakeup_completed
);
492 ret
= ath10k_wmi_wow_host_wakeup_ind(ar
);
494 ath10k_warn(ar
, "failed to send wow wakeup indication: %d\n",
499 ret
= wait_for_completion_timeout(&ar
->wow
.wakeup_completed
, 3 * HZ
);
501 ath10k_warn(ar
, "timed out while waiting for wow wakeup completion\n");
508 int ath10k_wow_op_suspend(struct ieee80211_hw
*hw
,
509 struct cfg80211_wowlan
*wowlan
)
511 struct ath10k
*ar
= hw
->priv
;
514 mutex_lock(&ar
->conf_mutex
);
516 if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT
,
517 ar
->running_fw
->fw_file
.fw_features
))) {
522 ret
= ath10k_wow_cleanup(ar
);
524 ath10k_warn(ar
, "failed to clear wow wakeup events: %d\n",
529 ret
= ath10k_wow_set_wakeups(ar
, wowlan
);
531 ath10k_warn(ar
, "failed to set wow wakeup events: %d\n",
536 ath10k_mac_wait_tx_complete(ar
);
538 ret
= ath10k_wow_enable(ar
);
540 ath10k_warn(ar
, "failed to start wow: %d\n", ret
);
544 ret
= ath10k_hif_suspend(ar
);
546 ath10k_warn(ar
, "failed to suspend hif: %d\n", ret
);
553 ath10k_wow_wakeup(ar
);
556 ath10k_wow_cleanup(ar
);
559 mutex_unlock(&ar
->conf_mutex
);
563 void ath10k_wow_op_set_wakeup(struct ieee80211_hw
*hw
, bool enabled
)
565 struct ath10k
*ar
= hw
->priv
;
567 mutex_lock(&ar
->conf_mutex
);
568 if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT
,
569 ar
->running_fw
->fw_file
.fw_features
)) {
570 device_set_wakeup_enable(ar
->dev
, enabled
);
572 mutex_unlock(&ar
->conf_mutex
);
575 int ath10k_wow_op_resume(struct ieee80211_hw
*hw
)
577 struct ath10k
*ar
= hw
->priv
;
580 mutex_lock(&ar
->conf_mutex
);
582 if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT
,
583 ar
->running_fw
->fw_file
.fw_features
))) {
588 ret
= ath10k_hif_resume(ar
);
590 ath10k_warn(ar
, "failed to resume hif: %d\n", ret
);
594 ret
= ath10k_wow_wakeup(ar
);
596 ath10k_warn(ar
, "failed to wakeup from wow: %d\n", ret
);
598 ret
= ath10k_wow_nlo_cleanup(ar
);
600 ath10k_warn(ar
, "failed to cleanup nlo: %d\n", ret
);
605 case ATH10K_STATE_ON
:
606 ar
->state
= ATH10K_STATE_RESTARTING
;
609 case ATH10K_STATE_OFF
:
610 case ATH10K_STATE_RESTARTING
:
611 case ATH10K_STATE_RESTARTED
:
612 case ATH10K_STATE_UTF
:
613 case ATH10K_STATE_WEDGED
:
614 ath10k_warn(ar
, "encountered unexpected device state %d on resume, cannot recover\n",
621 mutex_unlock(&ar
->conf_mutex
);
625 int ath10k_wow_init(struct ath10k
*ar
)
627 if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT
,
628 ar
->running_fw
->fw_file
.fw_features
))
631 if (WARN_ON(!test_bit(WMI_SERVICE_WOW
, ar
->wmi
.svc_map
)))
634 ar
->wow
.wowlan_support
= ath10k_wowlan_support
;
636 if (ar
->wmi
.rx_decap_mode
== ATH10K_HW_TXRX_NATIVE_WIFI
) {
637 ar
->wow
.wowlan_support
.pattern_max_len
-= WOW_MAX_REDUCE
;
638 ar
->wow
.wowlan_support
.max_pkt_offset
-= WOW_MAX_REDUCE
;
641 if (test_bit(WMI_SERVICE_NLO
, ar
->wmi
.svc_map
)) {
642 ar
->wow
.wowlan_support
.flags
|= WIPHY_WOWLAN_NET_DETECT
;
643 ar
->wow
.wowlan_support
.max_nd_match_sets
= WMI_PNO_MAX_SUPP_NETWORKS
;
646 ar
->wow
.wowlan_support
.n_patterns
= ar
->wow
.max_num_patterns
;
647 ar
->hw
->wiphy
->wowlan
= &ar
->wow
.wowlan_support
;
649 device_set_wakeup_capable(ar
->dev
, true);