aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/d3.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-01-24 08:25:36 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-01 05:27:15 -0500
commit8ca151b568b67a7b72dcfc6ee6ea7c107ddd795c (patch)
treedac0236038f3791140e9f864c5db2be873c568f0 /drivers/net/wireless/iwlwifi/mvm/d3.c
parentb1e1adfa7d30cd0e8ad9a5c6a89e8c45ebe084f4 (diff)
iwlwifi: add the MVM driver
Newer firmware revisions have a completely new firmware API. This is the new driver for this new API. I've listed the people who directly contributed code, but many others from various teams have contributed in other ways. Cc: Alexander Bondar <alexander.bondar@intel.com> Cc: Amit Beka <amit.beka@intel.com> Cc: Amnon Paz <amnonx.paz@intel.com> Cc: Assaf Krauss <assaf.krauss@intel.com> Cc: David Spinadel <david.spinadel@intel.com> Cc: Dor Shaish <dor.shaish@intel.com> Cc: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Cc: Eytan Lifshitz <eytan.lifshitz@intel.com> Cc: Ilan Peer <ilan.peer@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/d3.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c841
1 files changed, 841 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
new file mode 100644
index 000000000000..9a95c374990d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -0,0 +1,841 @@
1/******************************************************************************
2 *
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * GPL LICENSE SUMMARY
7 *
8 * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
22 * USA
23 *
24 * The full GNU General Public License is included in this distribution
25 * in the file called LICENSE.GPL.
26 *
27 * Contact Information:
28 * Intel Linux Wireless <ilw@linux.intel.com>
29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30 *
31 * BSD LICENSE
32 *
33 * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 *
40 * * Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * * Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in
44 * the documentation and/or other materials provided with the
45 * distribution.
46 * * Neither the name Intel Corporation nor the names of its
47 * contributors may be used to endorse or promote products derived
48 * from this software without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
54 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
56 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 *
62 *****************************************************************************/
63
64#include <net/cfg80211.h>
65#include <net/ipv6.h>
66#include "iwl-modparams.h"
67#include "fw-api.h"
68#include "mvm.h"
69
70void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw,
71 struct ieee80211_vif *vif,
72 struct cfg80211_gtk_rekey_data *data)
73{
74 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
75 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
76
77 if (iwlwifi_mod_params.sw_crypto)
78 return;
79
80 mutex_lock(&mvm->mutex);
81
82 memcpy(mvmvif->rekey_data.kek, data->kek, NL80211_KEK_LEN);
83 memcpy(mvmvif->rekey_data.kck, data->kck, NL80211_KCK_LEN);
84 mvmvif->rekey_data.replay_ctr =
85 cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
86 mvmvif->rekey_data.valid = true;
87
88 mutex_unlock(&mvm->mutex);
89}
90
91#if IS_ENABLED(CONFIG_IPV6)
92void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
93 struct ieee80211_vif *vif,
94 struct inet6_dev *idev)
95{
96 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
97 struct inet6_ifaddr *ifa;
98 int idx = 0;
99
100 read_lock(&idev->lock);
101 list_for_each_entry(ifa, &idev->addr_list, if_list) {
102 mvmvif->target_ipv6_addrs[idx] = ifa->addr;
103 idx++;
104 if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS)
105 break;
106 }
107 read_unlock(&idev->lock);
108
109 mvmvif->num_target_ipv6_addrs = idx;
110}
111#endif
112
113void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
114 struct ieee80211_vif *vif, int idx)
115{
116 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
117
118 mvmvif->tx_key_idx = idx;
119}
120
121static void iwl_mvm_convert_p1k(u16 *p1k, __le16 *out)
122{
123 int i;
124
125 for (i = 0; i < IWL_P1K_SIZE; i++)
126 out[i] = cpu_to_le16(p1k[i]);
127}
128
129struct wowlan_key_data {
130 struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
131 struct iwl_wowlan_tkip_params_cmd *tkip;
132 bool error, use_rsc_tsc, use_tkip;
133 int gtk_key_idx;
134};
135
136static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
137 struct ieee80211_vif *vif,
138 struct ieee80211_sta *sta,
139 struct ieee80211_key_conf *key,
140 void *_data)
141{
142 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
143 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
144 struct wowlan_key_data *data = _data;
145 struct aes_sc *aes_sc, *aes_tx_sc = NULL;
146 struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
147 struct iwl_p1k_cache *rx_p1ks;
148 u8 *rx_mic_key;
149 struct ieee80211_key_seq seq;
150 u32 cur_rx_iv32 = 0;
151 u16 p1k[IWL_P1K_SIZE];
152 int ret, i;
153
154 mutex_lock(&mvm->mutex);
155
156 switch (key->cipher) {
157 case WLAN_CIPHER_SUITE_WEP40:
158 case WLAN_CIPHER_SUITE_WEP104: { /* hack it for now */
159 struct {
160 struct iwl_mvm_wep_key_cmd wep_key_cmd;
161 struct iwl_mvm_wep_key wep_key;
162 } __packed wkc = {
163 .wep_key_cmd.mac_id_n_color =
164 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
165 mvmvif->color)),
166 .wep_key_cmd.num_keys = 1,
167 /* firmware sets STA_KEY_FLG_WEP_13BYTES */
168 .wep_key_cmd.decryption_type = STA_KEY_FLG_WEP,
169 .wep_key.key_index = key->keyidx,
170 .wep_key.key_size = key->keylen,
171 };
172
173 /*
174 * This will fail -- the key functions don't set support
175 * pairwise WEP keys. However, that's better than silently
176 * failing WoWLAN. Or maybe not?
177 */
178 if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
179 break;
180
181 memcpy(&wkc.wep_key.key[3], key->key, key->keylen);
182 if (key->keyidx == mvmvif->tx_key_idx) {
183 /* TX key must be at offset 0 */
184 wkc.wep_key.key_offset = 0;
185 } else {
186 /* others start at 1 */
187 data->gtk_key_idx++;
188 wkc.wep_key.key_offset = data->gtk_key_idx;
189 }
190
191 ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC,
192 sizeof(wkc), &wkc);
193 data->error = ret != 0;
194
195 /* don't upload key again */
196 goto out_unlock;
197 }
198 default:
199 data->error = true;
200 goto out_unlock;
201 case WLAN_CIPHER_SUITE_AES_CMAC:
202 /*
203 * Ignore CMAC keys -- the WoWLAN firmware doesn't support them
204 * but we also shouldn't abort suspend due to that. It does have
205 * support for the IGTK key renewal, but doesn't really use the
206 * IGTK for anything. This means we could spuriously wake up or
207 * be deauthenticated, but that was considered acceptable.
208 */
209 goto out_unlock;
210 case WLAN_CIPHER_SUITE_TKIP:
211 if (sta) {
212 tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
213 tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
214
215 rx_p1ks = data->tkip->rx_uni;
216
217 ieee80211_get_key_tx_seq(key, &seq);
218 tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
219 tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
220
221 ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
222 iwl_mvm_convert_p1k(p1k, data->tkip->tx.p1k);
223
224 memcpy(data->tkip->mic_keys.tx,
225 &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
226 IWL_MIC_KEY_SIZE);
227
228 rx_mic_key = data->tkip->mic_keys.rx_unicast;
229 } else {
230 tkip_sc =
231 data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
232 rx_p1ks = data->tkip->rx_multi;
233 rx_mic_key = data->tkip->mic_keys.rx_mcast;
234 }
235
236 /*
237 * For non-QoS this relies on the fact that both the uCode and
238 * mac80211 use TID 0 (as they need to to avoid replay attacks)
239 * for checking the IV in the frames.
240 */
241 for (i = 0; i < IWL_NUM_RSC; i++) {
242 ieee80211_get_key_rx_seq(key, i, &seq);
243 tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
244 tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
245 /* wrapping isn't allowed, AP must rekey */
246 if (seq.tkip.iv32 > cur_rx_iv32)
247 cur_rx_iv32 = seq.tkip.iv32;
248 }
249
250 ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid,
251 cur_rx_iv32, p1k);
252 iwl_mvm_convert_p1k(p1k, rx_p1ks[0].p1k);
253 ieee80211_get_tkip_rx_p1k(key, vif->bss_conf.bssid,
254 cur_rx_iv32 + 1, p1k);
255 iwl_mvm_convert_p1k(p1k, rx_p1ks[1].p1k);
256
257 memcpy(rx_mic_key,
258 &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
259 IWL_MIC_KEY_SIZE);
260
261 data->use_tkip = true;
262 data->use_rsc_tsc = true;
263 break;
264 case WLAN_CIPHER_SUITE_CCMP:
265 if (sta) {
266 u8 *pn = seq.ccmp.pn;
267
268 aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
269 aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
270
271 ieee80211_get_key_tx_seq(key, &seq);
272 aes_tx_sc->pn = cpu_to_le64((u64)pn[5] |
273 ((u64)pn[4] << 8) |
274 ((u64)pn[3] << 16) |
275 ((u64)pn[2] << 24) |
276 ((u64)pn[1] << 32) |
277 ((u64)pn[0] << 40));
278 } else {
279 aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
280 }
281
282 /*
283 * For non-QoS this relies on the fact that both the uCode and
284 * mac80211 use TID 0 for checking the IV in the frames.
285 */
286 for (i = 0; i < IWL_NUM_RSC; i++) {
287 u8 *pn = seq.ccmp.pn;
288
289 ieee80211_get_key_rx_seq(key, i, &seq);
290 aes_sc->pn = cpu_to_le64((u64)pn[5] |
291 ((u64)pn[4] << 8) |
292 ((u64)pn[3] << 16) |
293 ((u64)pn[2] << 24) |
294 ((u64)pn[1] << 32) |
295 ((u64)pn[0] << 40));
296 }
297 data->use_rsc_tsc = true;
298 break;
299 }
300
301 /*
302 * The D3 firmware hardcodes the key offset 0 as the key it uses
303 * to transmit packets to the AP, i.e. the PTK.
304 */
305 if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
306 key->hw_key_idx = 0;
307 } else {
308 data->gtk_key_idx++;
309 key->hw_key_idx = data->gtk_key_idx;
310 }
311
312 ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true);
313 data->error = ret != 0;
314out_unlock:
315 mutex_unlock(&mvm->mutex);
316}
317
318static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,
319 struct cfg80211_wowlan *wowlan)
320{
321 struct iwl_wowlan_patterns_cmd *pattern_cmd;
322 struct iwl_host_cmd cmd = {
323 .id = WOWLAN_PATTERNS,
324 .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
325 .flags = CMD_SYNC,
326 };
327 int i, err;
328
329 if (!wowlan->n_patterns)
330 return 0;
331
332 cmd.len[0] = sizeof(*pattern_cmd) +
333 wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern);
334
335 pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
336 if (!pattern_cmd)
337 return -ENOMEM;
338
339 pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
340
341 for (i = 0; i < wowlan->n_patterns; i++) {
342 int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
343
344 memcpy(&pattern_cmd->patterns[i].mask,
345 wowlan->patterns[i].mask, mask_len);
346 memcpy(&pattern_cmd->patterns[i].pattern,
347 wowlan->patterns[i].pattern,
348 wowlan->patterns[i].pattern_len);
349 pattern_cmd->patterns[i].mask_size = mask_len;
350 pattern_cmd->patterns[i].pattern_size =
351 wowlan->patterns[i].pattern_len;
352 }
353
354 cmd.data[0] = pattern_cmd;
355 err = iwl_mvm_send_cmd(mvm, &cmd);
356 kfree(pattern_cmd);
357 return err;
358}
359
360static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
361 struct ieee80211_vif *vif)
362{
363 struct iwl_proto_offload_cmd cmd = {};
364#if IS_ENABLED(CONFIG_IPV6)
365 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
366 int i;
367
368 if (mvmvif->num_target_ipv6_addrs) {
369 cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_NS);
370 memcpy(cmd.ndp_mac_addr, vif->addr, ETH_ALEN);
371 }
372
373 BUILD_BUG_ON(sizeof(cmd.target_ipv6_addr[i]) !=
374 sizeof(mvmvif->target_ipv6_addrs[i]));
375
376 for (i = 0; i < mvmvif->num_target_ipv6_addrs; i++)
377 memcpy(cmd.target_ipv6_addr[i],
378 &mvmvif->target_ipv6_addrs[i],
379 sizeof(cmd.target_ipv6_addr[i]));
380#endif
381
382 if (vif->bss_conf.arp_addr_cnt) {
383 cmd.enabled |= cpu_to_le32(IWL_D3_PROTO_OFFLOAD_ARP);
384 cmd.host_ipv4_addr = vif->bss_conf.arp_addr_list[0];
385 memcpy(cmd.arp_mac_addr, vif->addr, ETH_ALEN);
386 }
387
388 if (!cmd.enabled)
389 return 0;
390
391 return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC,
392 sizeof(cmd), &cmd);
393}
394
395struct iwl_d3_iter_data {
396 struct iwl_mvm *mvm;
397 struct ieee80211_vif *vif;
398 bool error;
399};
400
401static void iwl_mvm_d3_iface_iterator(void *_data, u8 *mac,
402 struct ieee80211_vif *vif)
403{
404 struct iwl_d3_iter_data *data = _data;
405 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
406
407 if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
408 return;
409
410 if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
411 return;
412
413 if (data->vif) {
414 IWL_ERR(data->mvm, "More than one managed interface active!\n");
415 data->error = true;
416 return;
417 }
418
419 data->vif = vif;
420}
421
422static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
423 struct ieee80211_sta *ap_sta)
424{
425 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
426 struct ieee80211_chanctx_conf *ctx;
427 u8 chains_static, chains_dynamic;
428 struct cfg80211_chan_def chandef;
429 int ret, i;
430 struct iwl_binding_cmd binding_cmd = {};
431 struct iwl_time_quota_cmd quota_cmd = {};
432 u32 status;
433
434 /* add back the PHY */
435 if (WARN_ON(!mvmvif->phy_ctxt))
436 return -EINVAL;
437
438 rcu_read_lock();
439 ctx = rcu_dereference(vif->chanctx_conf);
440 if (WARN_ON(!ctx)) {
441 rcu_read_unlock();
442 return -EINVAL;
443 }
444 chandef = ctx->def;
445 chains_static = ctx->rx_chains_static;
446 chains_dynamic = ctx->rx_chains_dynamic;
447 rcu_read_unlock();
448
449 ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt, &chandef,
450 chains_static, chains_dynamic);
451 if (ret)
452 return ret;
453
454 /* add back the MAC */
455 mvmvif->uploaded = false;
456
457 if (WARN_ON(!vif->bss_conf.assoc))
458 return -EINVAL;
459 /* hack */
460 vif->bss_conf.assoc = false;
461 ret = iwl_mvm_mac_ctxt_add(mvm, vif);
462 vif->bss_conf.assoc = true;
463 if (ret)
464 return ret;
465
466 /* add back binding - XXX refactor? */
467 binding_cmd.id_and_color =
468 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
469 mvmvif->phy_ctxt->color));
470 binding_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
471 binding_cmd.phy =
472 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
473 mvmvif->phy_ctxt->color));
474 binding_cmd.macs[0] = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
475 mvmvif->color));
476 for (i = 1; i < MAX_MACS_IN_BINDING; i++)
477 binding_cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID);
478
479 status = 0;
480 ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,
481 sizeof(binding_cmd), &binding_cmd,
482 &status);
483 if (ret) {
484 IWL_ERR(mvm, "Failed to add binding: %d\n", ret);
485 return ret;
486 }
487
488 if (status) {
489 IWL_ERR(mvm, "Binding command failed: %u\n", status);
490 return -EIO;
491 }
492
493 ret = iwl_mvm_sta_add_to_fw(mvm, ap_sta);
494 if (ret)
495 return ret;
496 rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta);
497
498 ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
499 if (ret)
500 return ret;
501
502 /* and some quota */
503 quota_cmd.quotas[0].id_and_color =
504 cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->phy_ctxt->id,
505 mvmvif->phy_ctxt->color));
506 quota_cmd.quotas[0].quota = cpu_to_le32(100);
507 quota_cmd.quotas[0].max_duration = cpu_to_le32(1000);
508
509 for (i = 1; i < MAX_BINDINGS; i++)
510 quota_cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID);
511
512 ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC,
513 sizeof(quota_cmd), &quota_cmd);
514 if (ret)
515 IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
516
517 return 0;
518}
519
520int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
521{
522 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
523 struct iwl_d3_iter_data suspend_iter_data = {
524 .mvm = mvm,
525 };
526 struct ieee80211_vif *vif;
527 struct iwl_mvm_vif *mvmvif;
528 struct ieee80211_sta *ap_sta;
529 struct iwl_mvm_sta *mvm_ap_sta;
530 struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
531 struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
532 struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
533 struct iwl_d3_manager_config d3_cfg_cmd = {};
534 struct wowlan_key_data key_data = {
535 .use_rsc_tsc = false,
536 .tkip = &tkip_cmd,
537 .use_tkip = false,
538 };
539 int ret, i;
540 u16 seq;
541 u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT;
542
543 if (WARN_ON(!wowlan))
544 return -EINVAL;
545
546 key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
547 if (!key_data.rsc_tsc)
548 return -ENOMEM;
549
550 mutex_lock(&mvm->mutex);
551
552 old_aux_sta_id = mvm->aux_sta.sta_id;
553
554 /* see if there's only a single BSS vif and it's associated */
555 ieee80211_iterate_active_interfaces_atomic(
556 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
557 iwl_mvm_d3_iface_iterator, &suspend_iter_data);
558
559 if (suspend_iter_data.error || !suspend_iter_data.vif) {
560 ret = 1;
561 goto out_noreset;
562 }
563
564 vif = suspend_iter_data.vif;
565 mvmvif = iwl_mvm_vif_from_mac80211(vif);
566
567 ap_sta = rcu_dereference_protected(
568 mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
569 lockdep_is_held(&mvm->mutex));
570 if (IS_ERR_OR_NULL(ap_sta)) {
571 ret = -EINVAL;
572 goto out_noreset;
573 }
574
575 mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
576
577 /*
578 * The D3 firmware still hardcodes the AP station ID for the
579 * BSS we're associated with as 0. Store the real STA ID here
580 * and assign 0. When we leave this function, we'll restore
581 * the original value for the resume code.
582 */
583 old_ap_sta_id = mvm_ap_sta->sta_id;
584 mvm_ap_sta->sta_id = 0;
585 mvmvif->ap_sta_id = 0;
586
587 /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */
588
589 wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported;
590
591 /*
592 * We know the last used seqno, and the uCode expects to know that
593 * one, it will increment before TX.
594 */
595 seq = mvm_ap_sta->last_seq_ctl & IEEE80211_SCTL_SEQ;
596 wowlan_config_cmd.non_qos_seq = cpu_to_le16(seq);
597
598 /*
599 * For QoS counters, we store the one to use next, so subtract 0x10
600 * since the uCode will add 0x10 *before* using the value while we
601 * increment after using the value (i.e. store the next value to use).
602 */
603 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
604 seq = mvm_ap_sta->tid_data[i].seq_number;
605 seq -= 0x10;
606 wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq);
607 }
608
609 if (wowlan->disconnect)
610 wowlan_config_cmd.wakeup_filter |=
611 cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS |
612 IWL_WOWLAN_WAKEUP_LINK_CHANGE);
613 if (wowlan->magic_pkt)
614 wowlan_config_cmd.wakeup_filter |=
615 cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET);
616 if (wowlan->gtk_rekey_failure)
617 wowlan_config_cmd.wakeup_filter |=
618 cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
619 if (wowlan->eap_identity_req)
620 wowlan_config_cmd.wakeup_filter |=
621 cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ);
622 if (wowlan->four_way_handshake)
623 wowlan_config_cmd.wakeup_filter |=
624 cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
625 if (wowlan->n_patterns)
626 wowlan_config_cmd.wakeup_filter |=
627 cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);
628
629 if (wowlan->rfkill_release)
630 d3_cfg_cmd.wakeup_flags |=
631 cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
632
633 iwl_mvm_cancel_scan(mvm);
634
635 iwl_trans_stop_device(mvm->trans);
636
637 /*
638 * Set the HW restart bit -- this is mostly true as we're
639 * going to load new firmware and reprogram that, though
640 * the reprogramming is going to be manual to avoid adding
641 * all the MACs that aren't support.
642 * We don't have to clear up everything though because the
643 * reprogramming is manual. When we resume, we'll actually
644 * go through a proper restart sequence again to switch
645 * back to the runtime firmware image.
646 */
647 set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
648
649 /* We reprogram keys and shouldn't allocate new key indices */
650 memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
651
652 /*
653 * The D3 firmware still hardcodes the AP station ID for the
654 * BSS we're associated with as 0. As a result, we have to move
655 * the auxiliary station to ID 1 so the ID 0 remains free for
656 * the AP station for later.
657 * We set the sta_id to 1 here, and reset it to its previous
658 * value (that we stored above) later.
659 */
660 mvm->aux_sta.sta_id = 1;
661
662 ret = iwl_mvm_load_d3_fw(mvm);
663 if (ret)
664 goto out;
665
666 ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
667 if (ret)
668 goto out;
669
670 if (!iwlwifi_mod_params.sw_crypto) {
671 /*
672 * This needs to be unlocked due to lock ordering
673 * constraints. Since we're in the suspend path
674 * that isn't really a problem though.
675 */
676 mutex_unlock(&mvm->mutex);
677 ieee80211_iter_keys(mvm->hw, vif,
678 iwl_mvm_wowlan_program_keys,
679 &key_data);
680 mutex_lock(&mvm->mutex);
681 if (key_data.error) {
682 ret = -EIO;
683 goto out;
684 }
685
686 if (key_data.use_rsc_tsc) {
687 struct iwl_host_cmd rsc_tsc_cmd = {
688 .id = WOWLAN_TSC_RSC_PARAM,
689 .flags = CMD_SYNC,
690 .data[0] = key_data.rsc_tsc,
691 .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
692 .len[0] = sizeof(*key_data.rsc_tsc),
693 };
694
695 ret = iwl_mvm_send_cmd(mvm, &rsc_tsc_cmd);
696 if (ret)
697 goto out;
698 }
699
700 if (key_data.use_tkip) {
701 ret = iwl_mvm_send_cmd_pdu(mvm,
702 WOWLAN_TKIP_PARAM,
703 CMD_SYNC, sizeof(tkip_cmd),
704 &tkip_cmd);
705 if (ret)
706 goto out;
707 }
708
709 if (mvmvif->rekey_data.valid) {
710 memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
711 memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck,
712 NL80211_KCK_LEN);
713 kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
714 memcpy(kek_kck_cmd.kek, mvmvif->rekey_data.kek,
715 NL80211_KEK_LEN);
716 kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
717 kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr;
718
719 ret = iwl_mvm_send_cmd_pdu(mvm,
720 WOWLAN_KEK_KCK_MATERIAL,
721 CMD_SYNC,
722 sizeof(kek_kck_cmd),
723 &kek_kck_cmd);
724 if (ret)
725 goto out;
726 }
727 }
728
729 ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION,
730 CMD_SYNC, sizeof(wowlan_config_cmd),
731 &wowlan_config_cmd);
732 if (ret)
733 goto out;
734
735 ret = iwl_mvm_send_patterns(mvm, wowlan);
736 if (ret)
737 goto out;
738
739 ret = iwl_mvm_send_proto_offload(mvm, vif);
740 if (ret)
741 goto out;
742
743 /* must be last -- this switches firmware state */
744 ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC,
745 sizeof(d3_cfg_cmd), &d3_cfg_cmd);
746 if (ret)
747 goto out;
748
749 clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
750
751 iwl_trans_d3_suspend(mvm->trans);
752 out:
753 mvm->aux_sta.sta_id = old_aux_sta_id;
754 mvm_ap_sta->sta_id = old_ap_sta_id;
755 mvmvif->ap_sta_id = old_ap_sta_id;
756 out_noreset:
757 kfree(key_data.rsc_tsc);
758 if (ret < 0)
759 ieee80211_restart_hw(mvm->hw);
760
761 mutex_unlock(&mvm->mutex);
762
763 return ret;
764}
765
766int iwl_mvm_resume(struct ieee80211_hw *hw)
767{
768 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
769 struct iwl_d3_iter_data resume_iter_data = {
770 .mvm = mvm,
771 };
772 struct ieee80211_vif *vif = NULL;
773 u32 base;
774 int ret;
775 enum iwl_d3_status d3_status;
776 struct error_table_start {
777 /* cf. struct iwl_error_event_table */
778 u32 valid;
779 u32 error_id;
780 } err_info;
781
782 mutex_lock(&mvm->mutex);
783
784 /* get the BSS vif pointer again */
785 ieee80211_iterate_active_interfaces_atomic(
786 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
787 iwl_mvm_d3_iface_iterator, &resume_iter_data);
788
789 if (WARN_ON(resume_iter_data.error || !resume_iter_data.vif))
790 goto out_unlock;
791
792 vif = resume_iter_data.vif;
793
794 ret = iwl_trans_d3_resume(mvm->trans, &d3_status);
795 if (ret)
796 goto out_unlock;
797
798 if (d3_status != IWL_D3_STATUS_ALIVE) {
799 IWL_INFO(mvm, "Device was reset during suspend\n");
800 goto out_unlock;
801 }
802
803 base = mvm->error_event_table;
804
805 iwl_trans_read_mem_bytes(mvm->trans, base,
806 &err_info, sizeof(err_info));
807
808 if (err_info.valid) {
809 IWL_INFO(mvm, "error table is valid (%d)\n",
810 err_info.valid);
811 if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN)
812 IWL_ERR(mvm, "this was due to RF-kill\n");
813 goto out_unlock;
814 }
815
816 /* TODO: get status and whatever else ... */
817 ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_GET_STATUSES, CMD_SYNC, 0, NULL);
818 if (ret)
819 IWL_ERR(mvm, "failed to query status (%d)\n", ret);
820
821 ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL);
822 if (ret)
823 IWL_ERR(mvm, "failed to query offloads (%d)\n", ret);
824
825 out_unlock:
826 mutex_unlock(&mvm->mutex);
827
828 if (vif)
829 ieee80211_resume_disconnect(vif);
830
831 /* return 1 to reconfigure the device */
832 set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
833 return 1;
834}
835
836void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled)
837{
838 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
839
840 device_set_wakeup_enable(mvm->trans->dev, enabled);
841}