OSDN Git Service

ath10k: fix the invalid STA disconnect after wow resume
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / drivers / net / wireless / ath / ath10k / wow.c
1 /*
2  * Copyright (c) 2015 Qualcomm Atheros, Inc.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include "mac.h"
18
19 #include <net/mac80211.h>
20 #include "hif.h"
21 #include "core.h"
22 #include "debug.h"
23 #include "wmi.h"
24 #include "wmi-ops.h"
25
26 static const struct wiphy_wowlan_support ath10k_wowlan_support = {
27         .flags = WIPHY_WOWLAN_DISCONNECT |
28                 WIPHY_WOWLAN_MAGIC_PKT |
29                 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
30                 WIPHY_WOWLAN_GTK_REKEY_FAILURE,
31         .pattern_min_len = WOW_MIN_PATTERN_SIZE,
32         .pattern_max_len = WOW_MAX_PATTERN_SIZE,
33         .max_pkt_offset = WOW_MAX_PKT_OFFSET,
34 };
35
36 static int ath10k_wow_vif_cleanup(struct ath10k_vif *arvif)
37 {
38         struct ath10k *ar = arvif->ar;
39         int i, ret;
40
41         for (i = 0; i < WOW_EVENT_MAX; i++) {
42                 ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 0);
43                 if (ret) {
44                         ath10k_warn(ar, "failed to issue wow wakeup for event %s on vdev %i: %d\n",
45                                     wow_wakeup_event(i), arvif->vdev_id, ret);
46                         return ret;
47                 }
48         }
49
50         for (i = 0; i < ar->wow.max_num_patterns; i++) {
51                 ret = ath10k_wmi_wow_del_pattern(ar, arvif->vdev_id, i);
52                 if (ret) {
53                         ath10k_warn(ar, "failed to delete wow pattern %d for vdev %i: %d\n",
54                                     i, arvif->vdev_id, ret);
55                         return ret;
56                 }
57         }
58
59         return 0;
60 }
61
62 static int ath10k_wow_cleanup(struct ath10k *ar)
63 {
64         struct ath10k_vif *arvif;
65         int ret;
66
67         lockdep_assert_held(&ar->conf_mutex);
68
69         list_for_each_entry(arvif, &ar->arvifs, list) {
70                 ret = ath10k_wow_vif_cleanup(arvif);
71                 if (ret) {
72                         ath10k_warn(ar, "failed to clean wow wakeups on vdev %i: %d\n",
73                                     arvif->vdev_id, ret);
74                         return ret;
75                 }
76         }
77
78         return 0;
79 }
80
81 static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif,
82                                       struct cfg80211_wowlan *wowlan)
83 {
84         int ret, i;
85         unsigned long wow_mask = 0;
86         struct ath10k *ar = arvif->ar;
87         struct ieee80211_bss_conf *bss = &arvif->vif->bss_conf;
88         const struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
89         int pattern_id = 0;
90
91         /* Setup requested WOW features */
92         switch (arvif->vdev_type) {
93         case WMI_VDEV_TYPE_IBSS:
94                 __set_bit(WOW_BEACON_EVENT, &wow_mask);
95                  /* fall through */
96         case WMI_VDEV_TYPE_AP:
97                 __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
98                 __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
99                 __set_bit(WOW_PROBE_REQ_WPS_IE_EVENT, &wow_mask);
100                 __set_bit(WOW_AUTH_REQ_EVENT, &wow_mask);
101                 __set_bit(WOW_ASSOC_REQ_EVENT, &wow_mask);
102                 __set_bit(WOW_HTT_EVENT, &wow_mask);
103                 __set_bit(WOW_RA_MATCH_EVENT, &wow_mask);
104                 break;
105         case WMI_VDEV_TYPE_STA:
106                 if (arvif->is_up && bss->assoc) {
107                         if (wowlan->disconnect) {
108                                 __set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
109                                 __set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
110                                 __set_bit(WOW_BMISS_EVENT, &wow_mask);
111                                 __set_bit(WOW_CSA_IE_EVENT, &wow_mask);
112                         }
113
114                         if (wowlan->magic_pkt)
115                                 __set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask);
116                         if (wowlan->gtk_rekey_failure)
117                                 __set_bit(WOW_GTK_ERR_EVENT, &wow_mask);
118                 }
119                 break;
120         default:
121                 break;
122         }
123
124         for (i = 0; i < wowlan->n_patterns; i++) {
125                 u8 bitmask[WOW_MAX_PATTERN_SIZE] = {};
126                 int j;
127
128                 if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE)
129                         continue;
130
131                 /* convert bytemask to bitmask */
132                 for (j = 0; j < patterns[i].pattern_len; j++)
133                         if (patterns[i].mask[j / 8] & BIT(j % 8))
134                                 bitmask[j] = 0xff;
135
136                 ret = ath10k_wmi_wow_add_pattern(ar, arvif->vdev_id,
137                                                  pattern_id,
138                                                  patterns[i].pattern,
139                                                  bitmask,
140                                                  patterns[i].pattern_len,
141                                                  patterns[i].pkt_offset);
142                 if (ret) {
143                         ath10k_warn(ar, "failed to add pattern %i to vdev %i: %d\n",
144                                     pattern_id,
145                                     arvif->vdev_id, ret);
146                         return ret;
147                 }
148
149                 pattern_id++;
150                 __set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask);
151         }
152
153         for (i = 0; i < WOW_EVENT_MAX; i++) {
154                 if (!test_bit(i, &wow_mask))
155                         continue;
156                 ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1);
157                 if (ret) {
158                         ath10k_warn(ar, "failed to enable wakeup event %s on vdev %i: %d\n",
159                                     wow_wakeup_event(i), arvif->vdev_id, ret);
160                         return ret;
161                 }
162         }
163
164         return 0;
165 }
166
167 static int ath10k_wow_set_wakeups(struct ath10k *ar,
168                                   struct cfg80211_wowlan *wowlan)
169 {
170         struct ath10k_vif *arvif;
171         int ret;
172
173         lockdep_assert_held(&ar->conf_mutex);
174
175         list_for_each_entry(arvif, &ar->arvifs, list) {
176                 ret = ath10k_vif_wow_set_wakeups(arvif, wowlan);
177                 if (ret) {
178                         ath10k_warn(ar, "failed to set wow wakeups on vdev %i: %d\n",
179                                     arvif->vdev_id, ret);
180                         return ret;
181                 }
182         }
183
184         return 0;
185 }
186
187 static int ath10k_wow_enable(struct ath10k *ar)
188 {
189         int ret;
190
191         lockdep_assert_held(&ar->conf_mutex);
192
193         reinit_completion(&ar->target_suspend);
194
195         ret = ath10k_wmi_wow_enable(ar);
196         if (ret) {
197                 ath10k_warn(ar, "failed to issue wow enable: %d\n", ret);
198                 return ret;
199         }
200
201         ret = wait_for_completion_timeout(&ar->target_suspend, 3 * HZ);
202         if (ret == 0) {
203                 ath10k_warn(ar, "timed out while waiting for suspend completion\n");
204                 return -ETIMEDOUT;
205         }
206
207         return 0;
208 }
209
210 static int ath10k_wow_wakeup(struct ath10k *ar)
211 {
212         int ret;
213
214         lockdep_assert_held(&ar->conf_mutex);
215
216         reinit_completion(&ar->wow.wakeup_completed);
217
218         ret = ath10k_wmi_wow_host_wakeup_ind(ar);
219         if (ret) {
220                 ath10k_warn(ar, "failed to send wow wakeup indication: %d\n",
221                             ret);
222                 return ret;
223         }
224
225         ret = wait_for_completion_timeout(&ar->wow.wakeup_completed, 3 * HZ);
226         if (ret == 0) {
227                 ath10k_warn(ar, "timed out while waiting for wow wakeup completion\n");
228                 return -ETIMEDOUT;
229         }
230
231         return 0;
232 }
233
234 static int
235 ath10k_wow_fill_vdev_arp_offload_struct(struct ath10k_vif *arvif,
236                                         bool enable_offload)
237 {
238         struct in_device *in_dev;
239         struct in_ifaddr *ifa;
240         bool offload_params_found = false;
241         struct wireless_dev *wdev = ieee80211_vif_to_wdev(arvif->vif);
242         struct wmi_ns_arp_offload_req *arp = &arvif->arp_offload;
243
244         if (!enable_offload) {
245                 arp->offload_type = __cpu_to_le16(WMI_IPV4_ARP_REPLY_OFFLOAD);
246                 arp->enable_offload = __cpu_to_le16(WMI_ARP_NS_OFFLOAD_DISABLE);
247                 return 0;
248         }
249
250         if (!wdev)
251                 return -ENODEV;
252         if (!wdev->netdev)
253                 return -ENODEV;
254         in_dev = __in_dev_get_rtnl(wdev->netdev);
255         if (!in_dev)
256                 return -ENODEV;
257
258         arp->offload_type = __cpu_to_le16(WMI_IPV4_ARP_REPLY_OFFLOAD);
259         arp->enable_offload = __cpu_to_le16(WMI_ARP_NS_OFFLOAD_ENABLE);
260         for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
261                 if (!memcmp(ifa->ifa_label, wdev->netdev->name, IFNAMSIZ)) {
262                         offload_params_found = true;
263                         break;
264                 }
265         }
266
267         if (!offload_params_found)
268                 return -ENODEV;
269         memcpy(&arp->params.ipv4_addr, &ifa->ifa_local,
270                sizeof(arp->params.ipv4_addr));
271
272         return 0;
273 }
274
275 static int ath10k_wow_enable_ns_arp_offload(struct ath10k *ar, bool offload)
276 {
277         struct ath10k_vif *arvif;
278         int ret;
279
280         list_for_each_entry(arvif, &ar->arvifs, list) {
281                 if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
282                         continue;
283
284                 if (!arvif->is_up)
285                         continue;
286
287                 ret = ath10k_wow_fill_vdev_arp_offload_struct(arvif, offload);
288                 if (ret) {
289                         ath10k_err(ar, "ARP-offload config failed, vdev: %d\n",
290                                    arvif->vdev_id);
291                         return ret;
292                 }
293
294                 ret = ath10k_wmi_set_arp_ns_offload(ar, arvif);
295                 if (ret) {
296                         ath10k_err(ar, "failed to send offload cmd, vdev: %d\n",
297                                    arvif->vdev_id);
298                         return ret;
299                 }
300         }
301
302         return 0;
303 }
304
305 static int ath10k_config_wow_listen_interval(struct ath10k *ar)
306 {
307         int ret;
308         u32 param = ar->wmi.vdev_param->listen_interval;
309         u8 listen_interval = ar->hw_values->default_listen_interval;
310         struct ath10k_vif *arvif;
311
312         if (!listen_interval)
313                 return 0;
314
315         list_for_each_entry(arvif, &ar->arvifs, list) {
316                 if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
317                         continue;
318                 ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
319                                                 param, listen_interval);
320                 if (ret) {
321                         ath10k_err(ar, "failed to config LI for vdev_id: %d\n",
322                                    arvif->vdev_id);
323                         return ret;
324                 }
325         }
326
327         return 0;
328 }
329
330 void ath10k_wow_op_set_rekey_data(struct ieee80211_hw *hw,
331                                   struct ieee80211_vif *vif,
332                                   struct cfg80211_gtk_rekey_data *data)
333 {
334         struct ath10k *ar = hw->priv;
335         struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
336
337         mutex_lock(&ar->conf_mutex);
338         memcpy(&arvif->gtk_rekey_data.kek, data->kek, NL80211_KEK_LEN);
339         memcpy(&arvif->gtk_rekey_data.kck, data->kck, NL80211_KCK_LEN);
340         arvif->gtk_rekey_data.replay_ctr =
341                 cpu_to_le64(be64_to_cpup((__be64 *)data->replay_ctr));
342         arvif->gtk_rekey_data.valid = true;
343         mutex_unlock(&ar->conf_mutex);
344 }
345
346 static int ath10k_wow_config_gtk_offload(struct ath10k *ar, bool gtk_offload)
347 {
348         struct ath10k_vif *arvif;
349         struct ieee80211_bss_conf *bss;
350         struct wmi_gtk_rekey_data *rekey_data;
351         int ret;
352
353         list_for_each_entry(arvif, &ar->arvifs, list) {
354                 if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
355                         continue;
356
357                 bss = &arvif->vif->bss_conf;
358                 if (!arvif->is_up || !bss->assoc)
359                         continue;
360
361                 rekey_data = &arvif->gtk_rekey_data;
362                 if (!rekey_data->valid)
363                         continue;
364
365                 if (gtk_offload)
366                         rekey_data->enable_offload = WMI_GTK_OFFLOAD_ENABLE;
367                 else
368                         rekey_data->enable_offload = WMI_GTK_OFFLOAD_DISABLE;
369                 ret = ath10k_wmi_gtk_offload(ar, arvif);
370                 if (ret) {
371                         ath10k_err(ar, "GTK offload failed for vdev_id: %d\n",
372                                    arvif->vdev_id);
373                         return ret;
374                 }
375         }
376
377         return 0;
378 }
379
380 int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
381                           struct cfg80211_wowlan *wowlan)
382 {
383         struct ath10k *ar = hw->priv;
384         int ret;
385
386         mutex_lock(&ar->conf_mutex);
387
388         if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
389                               ar->running_fw->fw_file.fw_features))) {
390                 ret = 1;
391                 goto exit;
392         }
393
394         ret = ath10k_wow_config_gtk_offload(ar, true);
395         if (ret) {
396                 ath10k_warn(ar, "failed to enable GTK offload: %d\n", ret);
397                 goto exit;
398         }
399
400         ret = ath10k_wow_enable_ns_arp_offload(ar, true);
401         if (ret) {
402                 ath10k_warn(ar, "failed to enable ARP-NS offload: %d\n", ret);
403                 goto disable_gtk_offload;
404         }
405
406         ret =  ath10k_wow_cleanup(ar);
407         if (ret) {
408                 ath10k_warn(ar, "failed to clear wow wakeup events: %d\n",
409                             ret);
410                 goto disable_ns_arp_offload;
411         }
412
413         ret = ath10k_wow_set_wakeups(ar, wowlan);
414         if (ret) {
415                 ath10k_warn(ar, "failed to set wow wakeup events: %d\n",
416                             ret);
417                 goto cleanup;
418         }
419
420         ret = ath10k_config_wow_listen_interval(ar);
421         if (ret) {
422                 ath10k_warn(ar, "failed to config wow listen interval: %d\n",
423                             ret);
424                 goto cleanup;
425         }
426
427         ret = ath10k_wow_enable(ar);
428         if (ret) {
429                 ath10k_warn(ar, "failed to start wow: %d\n", ret);
430                 goto cleanup;
431         }
432
433         ret = ath10k_hif_suspend(ar);
434         if (ret) {
435                 ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
436                 goto wakeup;
437         }
438
439         goto exit;
440
441 wakeup:
442         ath10k_wow_wakeup(ar);
443
444 cleanup:
445         ath10k_wow_cleanup(ar);
446
447 disable_ns_arp_offload:
448         ath10k_wow_enable_ns_arp_offload(ar, false);
449
450 disable_gtk_offload:
451         ath10k_wow_config_gtk_offload(ar, false);
452 exit:
453         mutex_unlock(&ar->conf_mutex);
454         return ret ? 1 : 0;
455 }
456
457 void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled)
458 {
459         struct ath10k *ar = hw->priv;
460
461         mutex_lock(&ar->conf_mutex);
462         if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
463                      ar->running_fw->fw_file.fw_features)) {
464                 device_set_wakeup_enable(ar->dev, enabled);
465         }
466         mutex_unlock(&ar->conf_mutex);
467 }
468
469 static void ath10k_wow_op_report_wakeup_reason(struct ath10k *ar)
470 {
471         struct cfg80211_wowlan_wakeup *wakeup = &ar->wow.wakeup;
472         struct ath10k_vif *arvif;
473
474         memset(wakeup, 0, sizeof(struct cfg80211_wowlan_wakeup));
475         switch (ar->wow.wakeup_reason) {
476         case WOW_REASON_UNSPECIFIED:
477                 wakeup = NULL;
478                 break;
479         case WOW_REASON_RECV_MAGIC_PATTERN:
480                 wakeup->magic_pkt = true;
481                 break;
482         case WOW_REASON_DEAUTH_RECVD:
483         case WOW_REASON_DISASSOC_RECVD:
484         case WOW_REASON_AP_ASSOC_LOST:
485         case WOW_REASON_CSA_EVENT:
486                 wakeup->disconnect = true;
487                 break;
488         case WOW_REASON_GTK_HS_ERR:
489                 wakeup->gtk_rekey_failure = true;
490                 break;
491         }
492         ar->wow.wakeup_reason = WOW_REASON_UNSPECIFIED;
493
494         if (wakeup) {
495                 wakeup->pattern_idx = -1;
496                 list_for_each_entry(arvif, &ar->arvifs, list) {
497                         ieee80211_report_wowlan_wakeup(arvif->vif,
498                                                        wakeup, GFP_KERNEL);
499                         if (wakeup->disconnect)
500                                 ieee80211_resume_disconnect(arvif->vif);
501                 }
502         } else {
503                 list_for_each_entry(arvif, &ar->arvifs, list)
504                         ieee80211_report_wowlan_wakeup(arvif->vif,
505                                                        NULL, GFP_KERNEL);
506         }
507 }
508
509 int ath10k_wow_op_resume(struct ieee80211_hw *hw)
510 {
511         struct ath10k *ar = hw->priv;
512         int ret;
513
514         mutex_lock(&ar->conf_mutex);
515
516         if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
517                               ar->running_fw->fw_file.fw_features))) {
518                 ret = 1;
519                 goto exit;
520         }
521
522         ret = ath10k_hif_resume(ar);
523         if (ret) {
524                 ath10k_warn(ar, "failed to resume hif: %d\n", ret);
525                 goto exit;
526         }
527
528         ret = ath10k_wow_wakeup(ar);
529         if (ret) {
530                 ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret);
531                 goto exit;
532         }
533
534         ret = ath10k_wow_enable_ns_arp_offload(ar, false);
535         if (ret) {
536                 ath10k_warn(ar, "failed to disable ARP-NS offload: %d\n", ret);
537                 goto exit;
538         }
539
540         ret = ath10k_wow_config_gtk_offload(ar, false);
541         if (ret)
542                 ath10k_warn(ar, "failed to disable GTK offload: %d\n", ret);
543
544 exit:
545         if (ret) {
546                 switch (ar->state) {
547                 case ATH10K_STATE_ON:
548                         ar->state = ATH10K_STATE_RESTARTING;
549                         ret = 1;
550                         break;
551                 case ATH10K_STATE_OFF:
552                 case ATH10K_STATE_RESTARTING:
553                 case ATH10K_STATE_RESTARTED:
554                 case ATH10K_STATE_UTF:
555                 case ATH10K_STATE_WEDGED:
556                         ath10k_warn(ar, "encountered unexpected device state %d on resume, cannot recover\n",
557                                     ar->state);
558                         ret = -EIO;
559                         break;
560                 }
561         }
562
563         ath10k_wow_op_report_wakeup_reason(ar);
564         mutex_unlock(&ar->conf_mutex);
565         return ret;
566 }
567
568 int ath10k_wow_init(struct ath10k *ar)
569 {
570         if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
571                       ar->running_fw->fw_file.fw_features))
572                 return 0;
573
574         if (WARN_ON(!test_bit(WMI_SERVICE_WOW, ar->wmi.svc_map)))
575                 return -EINVAL;
576
577         ar->wow.wowlan_support = ath10k_wowlan_support;
578         ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns;
579         ar->hw->wiphy->wowlan = &ar->wow.wowlan_support;
580
581         device_set_wakeup_capable(ar->dev, true);
582
583         return 0;
584 }