blob: 5c044eac1eed17b938515fb514d3022d97690642 [file] [log] [blame]
Johannes Berg8ca151b2013-01-24 14:25:36 +01001/******************************************************************************
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 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +02008 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
Johannes Berg8b4139d2014-07-24 14:05:26 +02009 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
Sara Sharonf92659a2016-02-03 15:04:49 +020010 * Copyright(c) 2016 Intel Deutschland GmbH
Johannes Berg8ca151b2013-01-24 14:25:36 +010011 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of version 2 of the GNU General Public License as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
24 * USA
25 *
26 * The full GNU General Public License is included in this distribution
Emmanuel Grumbach410dc5a2013-02-18 09:22:28 +020027 * in the file called COPYING.
Johannes Berg8ca151b2013-01-24 14:25:36 +010028 *
29 * Contact Information:
Emmanuel Grumbachcb2f8272015-11-17 15:39:56 +020030 * Intel Linux Wireless <linuxwifi@intel.com>
Johannes Berg8ca151b2013-01-24 14:25:36 +010031 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
32 *
33 * BSD LICENSE
34 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +020035 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
Johannes Berg8b4139d2014-07-24 14:05:26 +020036 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
Johannes Berg8ca151b2013-01-24 14:25:36 +010037 * All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 *
43 * * Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * * Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in
47 * the documentation and/or other materials provided with the
48 * distribution.
49 * * Neither the name Intel Corporation nor the names of its
50 * contributors may be used to endorse or promote products derived
51 * from this software without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
54 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
55 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
56 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
57 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
58 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
59 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
60 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
61 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
62 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
63 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 *
65 *****************************************************************************/
66#include <linux/kernel.h>
67#include <linux/slab.h>
68#include <linux/skbuff.h>
69#include <linux/netdevice.h>
70#include <linux/etherdevice.h>
Johannes Bergf0c26462013-01-22 20:41:58 +010071#include <linux/ip.h>
Eliad Peller2ee8f022014-01-13 19:07:09 +020072#include <linux/if_arp.h>
Golan Ben-Ami2f89a5d2015-10-27 19:17:14 +020073#include <linux/time.h>
Johannes Berg8ca151b2013-01-24 14:25:36 +010074#include <net/mac80211.h>
Emmanuel Grumbach7b1dd042014-02-04 15:32:43 +020075#include <net/ieee80211_radiotap.h>
Johannes Bergf0c26462013-01-22 20:41:58 +010076#include <net/tcp.h>
Johannes Berg8ca151b2013-01-24 14:25:36 +010077
78#include "iwl-op-mode.h"
79#include "iwl-io.h"
80#include "mvm.h"
81#include "sta.h"
82#include "time-event.h"
83#include "iwl-eeprom-parse.h"
Johannes Berg8ca151b2013-01-24 14:25:36 +010084#include "iwl-phy-db.h"
David Spinadel507cadf2013-07-31 18:07:21 +030085#include "testmode.h"
Emmanuel Grumbach655e6d62014-06-25 14:08:58 +030086#include "iwl-fw-error-dump.h"
87#include "iwl-prph.h"
Arik Nemtsov88931cc2014-03-05 12:26:15 +020088#include "iwl-nvm-parse.h"
Golan Ben-Ami2f89a5d2015-10-27 19:17:14 +020089#include "fw-dbg.h"
Johannes Berg8ca151b2013-01-24 14:25:36 +010090
91static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
92 {
93 .max = 1,
Ilan Peer8eb38712013-06-01 20:17:18 +030094 .types = BIT(NL80211_IFTYPE_STATION),
Johannes Berg8ca151b2013-01-24 14:25:36 +010095 },
Johannes Berg3c15a0f2013-05-31 10:17:19 +020096 {
97 .max = 1,
Ilan Peer8eb38712013-06-01 20:17:18 +030098 .types = BIT(NL80211_IFTYPE_AP) |
99 BIT(NL80211_IFTYPE_P2P_CLIENT) |
Johannes Berg3c15a0f2013-05-31 10:17:19 +0200100 BIT(NL80211_IFTYPE_P2P_GO),
101 },
102 {
103 .max = 1,
104 .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
105 },
Johannes Berg8ca151b2013-01-24 14:25:36 +0100106};
107
108static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {
109 {
Emmanuel Grumbach2624a5c2014-12-16 13:02:03 +0200110 .num_different_channels = 2,
Johannes Berg8ca151b2013-01-24 14:25:36 +0100111 .max_interfaces = 3,
112 .limits = iwl_mvm_limits,
113 .n_limits = ARRAY_SIZE(iwl_mvm_limits),
114 },
115};
116
Johannes Bergf0c26462013-01-22 20:41:58 +0100117#ifdef CONFIG_PM_SLEEP
118static const struct nl80211_wowlan_tcp_data_token_feature
119iwl_mvm_wowlan_tcp_token_feature = {
120 .min_len = 0,
121 .max_len = 255,
122 .bufsize = IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS,
123};
124
125static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = {
126 .tok = &iwl_mvm_wowlan_tcp_token_feature,
127 .data_payload_max = IWL_WOWLAN_TCP_MAX_PACKET_LEN -
128 sizeof(struct ethhdr) -
129 sizeof(struct iphdr) -
130 sizeof(struct tcphdr),
131 .data_interval_max = 65535, /* __le16 in API */
132 .wake_payload_max = IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN -
133 sizeof(struct ethhdr) -
134 sizeof(struct iphdr) -
135 sizeof(struct tcphdr),
136 .seq = true,
137};
138#endif
139
Eliad Peller77736922014-01-14 12:35:49 +0200140#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
Eliad Peller2ee8f022014-01-13 19:07:09 +0200141/*
142 * Use the reserved field to indicate magic values.
143 * these values will only be used internally by the driver,
144 * and won't make it to the fw (reserved will be 0).
145 * BC_FILTER_MAGIC_IP - configure the val of this attribute to
146 * be the vif's ip address. in case there is not a single
147 * ip address (0, or more than 1), this attribute will
148 * be skipped.
149 * BC_FILTER_MAGIC_MAC - set the val of this attribute to
150 * the LSB bytes of the vif's mac address
151 */
152enum {
153 BC_FILTER_MAGIC_NONE = 0,
154 BC_FILTER_MAGIC_IP,
155 BC_FILTER_MAGIC_MAC,
156};
157
Eliad Peller77736922014-01-14 12:35:49 +0200158static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = {
159 {
160 /* arp */
161 .discard = 0,
162 .frame_type = BCAST_FILTER_FRAME_TYPE_ALL,
163 .attrs = {
164 {
165 /* frame type - arp, hw type - ethernet */
166 .offset_type =
167 BCAST_FILTER_OFFSET_PAYLOAD_START,
168 .offset = sizeof(rfc1042_header),
169 .val = cpu_to_be32(0x08060001),
170 .mask = cpu_to_be32(0xffffffff),
171 },
Eliad Peller2ee8f022014-01-13 19:07:09 +0200172 {
173 /* arp dest ip */
174 .offset_type =
175 BCAST_FILTER_OFFSET_PAYLOAD_START,
176 .offset = sizeof(rfc1042_header) + 2 +
177 sizeof(struct arphdr) +
178 ETH_ALEN + sizeof(__be32) +
179 ETH_ALEN,
180 .mask = cpu_to_be32(0xffffffff),
181 /* mark it as special field */
182 .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_IP),
183 },
184 },
185 },
186 {
187 /* dhcp offer bcast */
188 .discard = 0,
189 .frame_type = BCAST_FILTER_FRAME_TYPE_IPV4,
190 .attrs = {
191 {
192 /* udp dest port - 68 (bootp client)*/
193 .offset_type = BCAST_FILTER_OFFSET_IP_END,
194 .offset = offsetof(struct udphdr, dest),
195 .val = cpu_to_be32(0x00440000),
196 .mask = cpu_to_be32(0xffff0000),
197 },
198 {
199 /* dhcp - lsb bytes of client hw address */
200 .offset_type = BCAST_FILTER_OFFSET_IP_END,
201 .offset = 38,
202 .mask = cpu_to_be32(0xffffffff),
203 /* mark it as special field */
204 .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_MAC),
205 },
Eliad Peller77736922014-01-14 12:35:49 +0200206 },
207 },
208 /* last filter must be empty */
209 {},
210};
211#endif
212
Eliad Peller7498cf42014-01-16 17:10:44 +0200213void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
214{
Eliad Peller7bb426e2014-02-24 12:54:37 +0200215 if (!iwl_mvm_is_d0i3_supported(mvm))
Eliad Peller7498cf42014-01-16 17:10:44 +0200216 return;
217
218 IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type);
Eliad Peller576eeee2014-07-01 18:38:38 +0300219 spin_lock_bh(&mvm->refs_lock);
220 mvm->refs[ref_type]++;
221 spin_unlock_bh(&mvm->refs_lock);
Eliad Peller7498cf42014-01-16 17:10:44 +0200222 iwl_trans_ref(mvm->trans);
223}
224
225void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
226{
Eliad Peller7bb426e2014-02-24 12:54:37 +0200227 if (!iwl_mvm_is_d0i3_supported(mvm))
Eliad Peller7498cf42014-01-16 17:10:44 +0200228 return;
229
230 IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type);
Eliad Peller576eeee2014-07-01 18:38:38 +0300231 spin_lock_bh(&mvm->refs_lock);
Sara Sharon16c45822016-04-04 19:30:05 +0300232 if (WARN_ON(!mvm->refs[ref_type])) {
233 spin_unlock_bh(&mvm->refs_lock);
234 return;
235 }
236 mvm->refs[ref_type]--;
Eliad Peller576eeee2014-07-01 18:38:38 +0300237 spin_unlock_bh(&mvm->refs_lock);
Eliad Peller7498cf42014-01-16 17:10:44 +0200238 iwl_trans_unref(mvm->trans);
239}
240
Eliad Peller576eeee2014-07-01 18:38:38 +0300241static void iwl_mvm_unref_all_except(struct iwl_mvm *mvm,
242 enum iwl_mvm_ref_type except_ref)
Eliad Peller7498cf42014-01-16 17:10:44 +0200243{
Eliad Peller576eeee2014-07-01 18:38:38 +0300244 int i, j;
Eliad Peller7498cf42014-01-16 17:10:44 +0200245
Eliad Peller7bb426e2014-02-24 12:54:37 +0200246 if (!iwl_mvm_is_d0i3_supported(mvm))
Eliad Peller7498cf42014-01-16 17:10:44 +0200247 return;
248
Eliad Peller576eeee2014-07-01 18:38:38 +0300249 spin_lock_bh(&mvm->refs_lock);
250 for (i = 0; i < IWL_MVM_REF_COUNT; i++) {
251 if (except_ref == i || !mvm->refs[i])
Eliad Peller7498cf42014-01-16 17:10:44 +0200252 continue;
253
Eliad Peller576eeee2014-07-01 18:38:38 +0300254 IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d (%d)\n",
255 i, mvm->refs[i]);
256 for (j = 0; j < mvm->refs[i]; j++)
257 iwl_trans_unref(mvm->trans);
258 mvm->refs[i] = 0;
Eliad Peller7498cf42014-01-16 17:10:44 +0200259 }
Eliad Peller576eeee2014-07-01 18:38:38 +0300260 spin_unlock_bh(&mvm->refs_lock);
Eliad Peller7498cf42014-01-16 17:10:44 +0200261}
262
Eliad Pellerf4cf8682014-11-04 16:57:06 +0200263bool iwl_mvm_ref_taken(struct iwl_mvm *mvm)
264{
265 int i;
266 bool taken = false;
267
268 if (!iwl_mvm_is_d0i3_supported(mvm))
269 return true;
270
271 spin_lock_bh(&mvm->refs_lock);
272 for (i = 0; i < IWL_MVM_REF_COUNT; i++) {
273 if (mvm->refs[i]) {
274 taken = true;
275 break;
276 }
277 }
278 spin_unlock_bh(&mvm->refs_lock);
279
280 return taken;
281}
282
Eliad Peller576eeee2014-07-01 18:38:38 +0300283int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
Gregory Greenmand40fc482014-06-25 14:08:50 +0200284{
285 iwl_mvm_ref(mvm, ref_type);
286
287 if (!wait_event_timeout(mvm->d0i3_exit_waitq,
288 !test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status),
289 HZ)) {
290 WARN_ON_ONCE(1);
291 iwl_mvm_unref(mvm, ref_type);
292 return -EIO;
293 }
294
295 return 0;
296}
297
Ilan Peerfe0f2de2013-03-21 10:23:52 +0200298static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)
299{
300 int i;
301
302 memset(mvm->phy_ctxts, 0, sizeof(mvm->phy_ctxts));
303 for (i = 0; i < NUM_PHY_CTX; i++) {
304 mvm->phy_ctxts[i].id = i;
305 mvm->phy_ctxts[i].ref = 0;
306 }
307}
308
Arik Nemtsov88931cc2014-03-05 12:26:15 +0200309struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200310 const char *alpha2,
Jonathan Doron47c8b152014-11-27 16:55:25 +0200311 enum iwl_mcc_source src_id,
312 bool *changed)
Arik Nemtsov88931cc2014-03-05 12:26:15 +0200313{
314 struct ieee80211_regdomain *regd = NULL;
315 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
316 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
317 struct iwl_mcc_update_resp *resp;
318
319 IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2);
320
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200321 lockdep_assert_held(&mvm->mutex);
Arik Nemtsov88931cc2014-03-05 12:26:15 +0200322
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200323 resp = iwl_mvm_update_mcc(mvm, alpha2, src_id);
Arik Nemtsov88931cc2014-03-05 12:26:15 +0200324 if (IS_ERR_OR_NULL(resp)) {
325 IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n",
Nicholas Krauseb8c474d2015-05-23 20:53:21 -0400326 PTR_ERR_OR_ZERO(resp));
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200327 goto out;
Arik Nemtsov88931cc2014-03-05 12:26:15 +0200328 }
329
Jonathan Doron47c8b152014-11-27 16:55:25 +0200330 if (changed)
331 *changed = (resp->status == MCC_RESP_NEW_CHAN_PROFILE);
332
Arik Nemtsov162ee3c2014-06-10 11:25:35 +0300333 regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg,
Arik Nemtsov88931cc2014-03-05 12:26:15 +0200334 __le32_to_cpu(resp->n_channels),
335 resp->channels,
336 __le16_to_cpu(resp->mcc));
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200337 /* Store the return source id */
338 src_id = resp->source_id;
Arik Nemtsov88931cc2014-03-05 12:26:15 +0200339 kfree(resp);
340 if (IS_ERR_OR_NULL(regd)) {
341 IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n",
Nicholas Krauseb8c474d2015-05-23 20:53:21 -0400342 PTR_ERR_OR_ZERO(regd));
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200343 goto out;
Arik Nemtsov88931cc2014-03-05 12:26:15 +0200344 }
345
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200346 IWL_DEBUG_LAR(mvm, "setting alpha2 from FW to %s (0x%x, 0x%x) src=%d\n",
347 regd->alpha2, regd->alpha2[0], regd->alpha2[1], src_id);
Arik Nemtsov88931cc2014-03-05 12:26:15 +0200348 mvm->lar_regdom_set = true;
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200349 mvm->mcc_src = src_id;
Arik Nemtsov88931cc2014-03-05 12:26:15 +0200350
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200351out:
Arik Nemtsov88931cc2014-03-05 12:26:15 +0200352 return regd;
353}
354
Jonathan Doron47c8b152014-11-27 16:55:25 +0200355void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm)
356{
357 bool changed;
358 struct ieee80211_regdomain *regd;
359
360 if (!iwl_mvm_is_lar_supported(mvm))
361 return;
362
363 regd = iwl_mvm_get_current_regdomain(mvm, &changed);
364 if (!IS_ERR_OR_NULL(regd)) {
365 /* only update the regulatory core if changed */
366 if (changed)
367 regulatory_set_wiphy_regd(mvm->hw->wiphy, regd);
368
369 kfree(regd);
370 }
371}
372
373struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm,
374 bool *changed)
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200375{
376 return iwl_mvm_get_regdomain(mvm->hw->wiphy, "ZZ",
377 iwl_mvm_is_wifi_mcc_supported(mvm) ?
378 MCC_SOURCE_GET_CURRENT :
Jonathan Doron47c8b152014-11-27 16:55:25 +0200379 MCC_SOURCE_OLD_FW, changed);
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200380}
381
382int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm)
383{
384 enum iwl_mcc_source used_src;
385 struct ieee80211_regdomain *regd;
Arik Nemtsovb6e160a2015-03-23 14:32:53 +0200386 int ret;
387 bool changed;
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200388 const struct ieee80211_regdomain *r =
389 rtnl_dereference(mvm->hw->wiphy->regd);
390
391 if (!r)
Arik Nemtsovb6e160a2015-03-23 14:32:53 +0200392 return -ENOENT;
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200393
394 /* save the last source in case we overwrite it below */
395 used_src = mvm->mcc_src;
396 if (iwl_mvm_is_wifi_mcc_supported(mvm)) {
397 /* Notify the firmware we support wifi location updates */
Jonathan Doron47c8b152014-11-27 16:55:25 +0200398 regd = iwl_mvm_get_current_regdomain(mvm, NULL);
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200399 if (!IS_ERR_OR_NULL(regd))
400 kfree(regd);
401 }
402
403 /* Now set our last stored MCC and source */
Arik Nemtsovb6e160a2015-03-23 14:32:53 +0200404 regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src,
405 &changed);
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200406 if (IS_ERR_OR_NULL(regd))
407 return -EIO;
408
Arik Nemtsovb6e160a2015-03-23 14:32:53 +0200409 /* update cfg80211 if the regdomain was changed */
410 if (changed)
411 ret = regulatory_set_wiphy_regd_sync_rtnl(mvm->hw->wiphy, regd);
412 else
413 ret = 0;
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200414
Arik Nemtsovb6e160a2015-03-23 14:32:53 +0200415 kfree(regd);
416 return ret;
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200417}
418
Johannes Berg8ca151b2013-01-24 14:25:36 +0100419int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
420{
421 struct ieee80211_hw *hw = mvm->hw;
Ilan Peer831e85f2013-02-07 17:09:09 +0200422 int num_mac, ret, i;
Johannes Berg5f4c02e2015-05-20 16:51:28 +0200423 static const u32 mvm_ciphers[] = {
424 WLAN_CIPHER_SUITE_WEP40,
425 WLAN_CIPHER_SUITE_WEP104,
426 WLAN_CIPHER_SUITE_TKIP,
427 WLAN_CIPHER_SUITE_CCMP,
428 };
Johannes Berg8ca151b2013-01-24 14:25:36 +0100429
430 /* Tell mac80211 our characteristics */
Johannes Berg30686bf2015-06-02 21:39:54 +0200431 ieee80211_hw_set(hw, SIGNAL_DBM);
432 ieee80211_hw_set(hw, SPECTRUM_MGMT);
433 ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
434 ieee80211_hw_set(hw, QUEUE_CONTROL);
435 ieee80211_hw_set(hw, WANT_MONITOR_VIF);
436 ieee80211_hw_set(hw, SUPPORTS_PS);
437 ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
438 ieee80211_hw_set(hw, AMPDU_AGGREGATION);
439 ieee80211_hw_set(hw, TIMING_BEACON_ONLY);
440 ieee80211_hw_set(hw, CONNECTION_MONITOR);
441 ieee80211_hw_set(hw, CHANCTX_STA_CSA);
442 ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
443 ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
Johannes Berg909ddf02015-09-21 14:09:17 +0200444 ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
Johannes Berg30433d32015-09-24 18:14:55 +0200445 ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
Sara Sharonb915c102016-03-23 16:32:02 +0200446 if (iwl_mvm_has_new_rx_api(mvm))
447 ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
Johannes Berg8ca151b2013-01-24 14:25:36 +0100448
Johannes Berg80938ab2016-03-30 11:05:16 +0200449 if (mvm->trans->num_rx_queues > 1)
450 ieee80211_hw_set(hw, USES_RSS);
451
Johannes Berg2d7cf542015-04-17 16:39:12 +0200452 if (mvm->trans->max_skb_frags)
453 hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG;
454
Liad Kaufmancf961e12015-08-13 19:16:08 +0300455 if (!iwl_mvm_is_dqa_supported(mvm))
456 hw->queues = mvm->first_agg_queue;
457 else
458 hw->queues = IEEE80211_MAX_QUEUES;
Ilan Peer398e8c62013-03-13 15:20:35 +0200459 hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
Emmanuel Grumbach7b1dd042014-02-04 15:32:43 +0200460 hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC |
461 IEEE80211_RADIOTAP_MCS_HAVE_STBC;
Eyal Shapira339b3082014-11-18 16:43:55 +0200462 hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC |
463 IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100464 hw->rate_control_algorithm = "iwl-mvm-rs";
Johannes Berg848955c2014-11-11 12:48:42 +0100465 hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
466 hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100467
Ayala Beker2a53d162016-04-07 16:21:57 +0300468 BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 4);
Johannes Berg5f4c02e2015-05-20 16:51:28 +0200469 memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers));
470 hw->wiphy->n_cipher_suites = ARRAY_SIZE(mvm_ciphers);
471 hw->wiphy->cipher_suites = mvm->ciphers;
472
Ayala Beker2a53d162016-04-07 16:21:57 +0300473 if (iwl_mvm_has_new_rx_api(mvm)) {
474 mvm->ciphers[hw->wiphy->n_cipher_suites] =
475 WLAN_CIPHER_SUITE_GCMP;
476 hw->wiphy->n_cipher_suites++;
477 mvm->ciphers[hw->wiphy->n_cipher_suites] =
478 WLAN_CIPHER_SUITE_GCMP_256;
479 hw->wiphy->n_cipher_suites++;
480 }
481
Johannes Berg8ca151b2013-01-24 14:25:36 +0100482 /*
483 * Enable 11w if advertised by firmware and software crypto
484 * is not enabled (as the firmware will interpret some mgmt
485 * packets, so enabling it with software crypto isn't safe)
486 */
487 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP &&
Johannes Berg5f4c02e2015-05-20 16:51:28 +0200488 !iwlwifi_mod_params.sw_crypto) {
Johannes Berg30686bf2015-06-02 21:39:54 +0200489 ieee80211_hw_set(hw, MFP_CAPABLE);
Johannes Berg5f4c02e2015-05-20 16:51:28 +0200490 mvm->ciphers[hw->wiphy->n_cipher_suites] =
491 WLAN_CIPHER_SUITE_AES_CMAC;
492 hw->wiphy->n_cipher_suites++;
493 }
494
495 /* currently FW API supports only one optional cipher scheme */
496 if (mvm->fw->cs[0].cipher) {
497 mvm->hw->n_cipher_schemes = 1;
498 mvm->hw->cipher_schemes = &mvm->fw->cs[0];
499 mvm->ciphers[hw->wiphy->n_cipher_suites] =
500 mvm->fw->cs[0].cipher;
501 hw->wiphy->n_cipher_suites++;
502 }
Johannes Berg8ca151b2013-01-24 14:25:36 +0100503
Johannes Berg30686bf2015-06-02 21:39:54 +0200504 ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
Luciano Coelho1f940382015-02-10 13:03:38 +0200505 hw->wiphy->features |=
506 NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
Johannes Berg3db93422015-05-06 14:56:51 +0200507 NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |
508 NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
David Spinadelfb98be52014-05-04 12:51:10 +0300509
Johannes Berg8ca151b2013-01-24 14:25:36 +0100510 hw->sta_data_size = sizeof(struct iwl_mvm_sta);
511 hw->vif_data_size = sizeof(struct iwl_mvm_vif);
Ilan Peerfe0f2de2013-03-21 10:23:52 +0200512 hw->chanctx_data_size = sizeof(u16);
Johannes Berg8ca151b2013-01-24 14:25:36 +0100513
514 hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Johannes Berg3c15a0f2013-05-31 10:17:19 +0200515 BIT(NL80211_IFTYPE_P2P_CLIENT) |
516 BIT(NL80211_IFTYPE_AP) |
517 BIT(NL80211_IFTYPE_P2P_GO) |
Emmanuel Grumbachc13b1722014-03-27 19:12:12 +0200518 BIT(NL80211_IFTYPE_P2P_DEVICE) |
519 BIT(NL80211_IFTYPE_ADHOC);
Johannes Berg5023d962013-07-31 14:07:43 +0200520
Luis R. Rodrigueza2f73b62013-11-11 22:15:29 +0100521 hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200522 hw->wiphy->regulatory_flags |= REGULATORY_ENABLE_RELAX_NO_IR;
523 if (iwl_mvm_is_lar_supported(mvm))
524 hw->wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
525 else
526 hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
527 REGULATORY_DISABLE_BEACON_HINTS;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100528
Johannes Berg3e56ead2013-02-15 22:23:18 +0100529 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD)
530 hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
531
Emmanuel Grumbach94bbed72014-11-24 08:53:33 +0200532 hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +0200533
Johannes Berg8ca151b2013-01-24 14:25:36 +0100534 hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;
535 hw->wiphy->n_iface_combinations =
536 ARRAY_SIZE(iwl_mvm_iface_combinations);
537
Ilan Peerc451e6d2013-02-20 08:41:54 +0200538 hw->wiphy->max_remain_on_channel_duration = 10000;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100539 hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
Emmanuel Grumbachf1a68542014-12-16 12:31:13 +0200540 /* we can compensate an offset of up to 3 channels = 15 MHz */
541 hw->wiphy->max_adj_channel_rssi_comp = 3 * 5;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100542
543 /* Extract MAC address */
544 memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN);
545 hw->wiphy->addresses = mvm->addresses;
546 hw->wiphy->n_addresses = 1;
Ilan Peer831e85f2013-02-07 17:09:09 +0200547
548 /* Extract additional MAC addresses if available */
549 num_mac = (mvm->nvm_data->n_hw_addrs > 1) ?
550 min(IWL_MVM_MAX_ADDRESSES, mvm->nvm_data->n_hw_addrs) : 1;
551
552 for (i = 1; i < num_mac; i++) {
553 memcpy(mvm->addresses[i].addr, mvm->addresses[i-1].addr,
Johannes Berg8ca151b2013-01-24 14:25:36 +0100554 ETH_ALEN);
Ilan Peer831e85f2013-02-07 17:09:09 +0200555 mvm->addresses[i].addr[5]++;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100556 hw->wiphy->n_addresses++;
557 }
558
Ilan Peerfe0f2de2013-03-21 10:23:52 +0200559 iwl_mvm_reset_phy_ctxts(mvm);
560
Luciano Coelho999d2562015-03-27 10:28:26 +0300561 hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm);
David Spinadel20f1a5d2013-08-21 09:14:27 +0300562
Johannes Berg8ca151b2013-01-24 14:25:36 +0100563 hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
564
Luciano Coelhoc7d42482015-05-07 16:00:26 +0300565 BUILD_BUG_ON(IWL_MVM_SCAN_STOPPING_MASK & IWL_MVM_SCAN_MASK);
Luciano Coelho507e4cd2015-03-19 22:58:33 +0200566 BUILD_BUG_ON(IWL_MVM_MAX_UMAC_SCANS > HWEIGHT32(IWL_MVM_SCAN_MASK) ||
567 IWL_MVM_MAX_LMAC_SCANS > HWEIGHT32(IWL_MVM_SCAN_MASK));
568
Johannes Berg859d9142015-06-01 17:11:11 +0200569 if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN))
Luciano Coelho507e4cd2015-03-19 22:58:33 +0200570 mvm->max_scans = IWL_MVM_MAX_UMAC_SCANS;
571 else
572 mvm->max_scans = IWL_MVM_MAX_LMAC_SCANS;
573
Johannes Berg57fbcce2016-04-12 15:56:15 +0200574 if (mvm->nvm_data->bands[NL80211_BAND_2GHZ].n_channels)
575 hw->wiphy->bands[NL80211_BAND_2GHZ] =
576 &mvm->nvm_data->bands[NL80211_BAND_2GHZ];
577 if (mvm->nvm_data->bands[NL80211_BAND_5GHZ].n_channels) {
578 hw->wiphy->bands[NL80211_BAND_5GHZ] =
579 &mvm->nvm_data->bands[NL80211_BAND_5GHZ];
Johannes Berg8ca151b2013-01-24 14:25:36 +0100580
Johannes Berg859d9142015-06-01 17:11:11 +0200581 if (fw_has_capa(&mvm->fw->ucode_capa,
582 IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
583 fw_has_api(&mvm->fw->ucode_capa,
584 IWL_UCODE_TLV_API_LQ_SS_PARAMS))
Johannes Berg57fbcce2016-04-12 15:56:15 +0200585 hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.cap |=
Eyal Shapira3d44eeb2015-01-16 22:37:04 +0200586 IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
587 }
588
Johannes Berg8ca151b2013-01-24 14:25:36 +0100589 hw->wiphy->hw_version = mvm->trans->hw_id;
590
Alexander Bondarade50652013-04-03 16:28:47 +0300591 if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)
Johannes Berg8ca151b2013-01-24 14:25:36 +0100592 hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
593 else
594 hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
595
Emmanuel Grumbach9954b372015-03-16 14:49:55 +0200596 hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
597 hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
598 hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
599 /* we create the 802.11 header and zero length SSID IE. */
600 hw->wiphy->max_sched_scan_ie_len =
601 SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
Avraham Sterncd55cce2015-08-19 12:46:12 +0300602 hw->wiphy->max_sched_scan_plans = IWL_MAX_SCHED_SCAN_PLANS;
603 hw->wiphy->max_sched_scan_plan_interval = U16_MAX;
604
605 /*
606 * the firmware uses u8 for num of iterations, but 0xff is saved for
607 * infinite loop, so the maximum number of iterations is actually 254.
608 */
609 hw->wiphy->max_sched_scan_plan_iterations = 254;
David Spinadel35a000b2013-08-28 09:29:43 +0300610
Johannes Berg8ca151b2013-01-24 14:25:36 +0100611 hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
Johannes Bergab480032014-06-04 10:13:50 +0200612 NL80211_FEATURE_LOW_PRIORITY_SCAN |
Eliad Peller0d8614b2014-09-10 14:07:36 +0300613 NL80211_FEATURE_P2P_GO_OPPPS |
614 NL80211_FEATURE_DYNAMIC_SMPS |
Emmanuel Grumbach9b5452f2014-10-07 10:38:53 +0300615 NL80211_FEATURE_STATIC_SMPS |
616 NL80211_FEATURE_SUPPORTS_WMM_ADMISSION;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100617
Johannes Berg859d9142015-06-01 17:11:11 +0200618 if (fw_has_capa(&mvm->fw->ucode_capa,
619 IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT))
Andrei Otcheretianskif1daa002014-07-01 12:54:25 +0300620 hw->wiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION;
Johannes Berg859d9142015-06-01 17:11:11 +0200621 if (fw_has_capa(&mvm->fw->ucode_capa,
622 IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT))
Assaf Krauss226bcd42014-03-13 08:12:15 +0200623 hw->wiphy->features |= NL80211_FEATURE_QUIET;
Andrei Otcheretianskif1daa002014-07-01 12:54:25 +0300624
Johannes Berg859d9142015-06-01 17:11:11 +0200625 if (fw_has_capa(&mvm->fw->ucode_capa,
626 IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT))
Andrei Otcheretianski73897bd2014-07-09 18:59:14 +0300627 hw->wiphy->features |=
628 NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES;
629
Johannes Berg859d9142015-06-01 17:11:11 +0200630 if (fw_has_capa(&mvm->fw->ucode_capa,
631 IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT))
Andrei Otcheretianski73897bd2014-07-09 18:59:14 +0300632 hw->wiphy->features |= NL80211_FEATURE_WFA_TPC_IE_IN_PROBES;
633
Johannes Berg8ca151b2013-01-24 14:25:36 +0100634 mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
635
636#ifdef CONFIG_PM_SLEEP
Eliad Pellerd15a7472014-03-27 18:53:12 +0200637 if (iwl_mvm_is_d0i3_supported(mvm) &&
638 device_can_wakeup(mvm->trans->dev)) {
639 mvm->wowlan.flags = WIPHY_WOWLAN_ANY;
640 hw->wiphy->wowlan = &mvm->wowlan;
Eliad Peller91742442014-12-09 15:54:46 +0200641 }
642
643 if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
Johannes Berg8ca151b2013-01-24 14:25:36 +0100644 mvm->trans->ops->d3_suspend &&
645 mvm->trans->ops->d3_resume &&
646 device_can_wakeup(mvm->trans->dev)) {
Eliad Peller91742442014-12-09 15:54:46 +0200647 mvm->wowlan.flags |= WIPHY_WOWLAN_MAGIC_PKT |
648 WIPHY_WOWLAN_DISCONNECT |
649 WIPHY_WOWLAN_EAP_IDENTITY_REQ |
650 WIPHY_WOWLAN_RFKILL_RELEASE |
651 WIPHY_WOWLAN_NET_DETECT;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100652 if (!iwlwifi_mod_params.sw_crypto)
Johannes Berg964dc9e2013-06-03 17:25:34 +0200653 mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
654 WIPHY_WOWLAN_GTK_REKEY_FAILURE |
655 WIPHY_WOWLAN_4WAY_HANDSHAKE;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100656
Johannes Berg964dc9e2013-06-03 17:25:34 +0200657 mvm->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;
658 mvm->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;
659 mvm->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;
Luciano Coelhoc55385f2014-10-24 10:39:51 +0300660 mvm->wowlan.max_nd_match_sets = IWL_SCAN_MAX_PROFILES;
Johannes Berg964dc9e2013-06-03 17:25:34 +0200661 mvm->wowlan.tcp = &iwl_mvm_wowlan_tcp_support;
662 hw->wiphy->wowlan = &mvm->wowlan;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100663 }
664#endif
665
Eliad Peller77736922014-01-14 12:35:49 +0200666#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
667 /* assign default bcast filtering configuration */
668 mvm->bcast_filters = iwl_mvm_default_bcast_filters;
669#endif
670
Johannes Berg8ca151b2013-01-24 14:25:36 +0100671 ret = iwl_mvm_leds_init(mvm);
672 if (ret)
673 return ret;
674
Johannes Berg859d9142015-06-01 17:11:11 +0200675 if (fw_has_capa(&mvm->fw->ucode_capa,
676 IWL_UCODE_TLV_CAPA_TDLS_SUPPORT)) {
Arik Nemtsovd8f1c512014-05-11 18:13:04 +0300677 IWL_DEBUG_TDLS(mvm, "TDLS supported\n");
678 hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
Arik Nemtsov7c4f0842015-04-30 18:31:45 +0300679 ieee80211_hw_set(hw, TDLS_WIDER_BW);
Arik Nemtsovd8f1c512014-05-11 18:13:04 +0300680 }
681
Johannes Berg859d9142015-06-01 17:11:11 +0200682 if (fw_has_capa(&mvm->fw->ucode_capa,
683 IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH)) {
Arik Nemtsov1d3c3f62014-10-23 18:03:10 +0300684 IWL_DEBUG_TDLS(mvm, "TDLS channel switch supported\n");
685 hw->wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH;
686 }
687
Avri Altman93190fb2014-12-27 09:09:47 +0200688 hw->netdev_features |= mvm->cfg->features;
Sara Sharon5e6a98d2016-03-10 17:40:56 +0200689 if (!iwl_mvm_is_csum_supported(mvm)) {
690 hw->netdev_features &= ~(IWL_TX_CSUM_NETIF_FLAGS |
691 NETIF_F_RXCSUM);
692 /* We may support SW TX CSUM */
693 if (IWL_MVM_SW_TX_CSUM_OFFLOAD)
694 hw->netdev_features |= IWL_TX_CSUM_NETIF_FLAGS;
695 }
Emmanuel Grumbach41837ca92015-10-21 09:00:07 +0300696
Emmanuel Grumbachb7327d82013-06-24 15:44:03 +0300697 ret = ieee80211_register_hw(mvm->hw);
698 if (ret)
699 iwl_mvm_leds_exit(mvm);
700
701 return ret;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100702}
703
Arik Nemtsovb2492502014-03-13 12:21:50 +0200704static bool iwl_mvm_defer_tx(struct iwl_mvm *mvm,
705 struct ieee80211_sta *sta,
706 struct sk_buff *skb)
707{
708 struct iwl_mvm_sta *mvmsta;
709 bool defer = false;
710
711 /*
712 * double check the IN_D0I3 flag both before and after
713 * taking the spinlock, in order to prevent taking
714 * the spinlock when not needed.
715 */
716 if (likely(!test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)))
717 return false;
718
719 spin_lock(&mvm->d0i3_tx_lock);
720 /*
721 * testing the flag again ensures the skb dequeue
722 * loop (on d0i3 exit) hasn't run yet.
723 */
724 if (!test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status))
725 goto out;
726
727 mvmsta = iwl_mvm_sta_from_mac80211(sta);
728 if (mvmsta->sta_id == IWL_MVM_STATION_COUNT ||
729 mvmsta->sta_id != mvm->d0i3_ap_sta_id)
730 goto out;
731
732 __skb_queue_tail(&mvm->d0i3_tx, skb);
733 ieee80211_stop_queues(mvm->hw);
734
735 /* trigger wakeup */
736 iwl_mvm_ref(mvm, IWL_MVM_REF_TX);
737 iwl_mvm_unref(mvm, IWL_MVM_REF_TX);
738
739 defer = true;
740out:
741 spin_unlock(&mvm->d0i3_tx_lock);
742 return defer;
743}
744
Johannes Berg8ca151b2013-01-24 14:25:36 +0100745static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
746 struct ieee80211_tx_control *control,
747 struct sk_buff *skb)
748{
749 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Johannes Berg3e56ead2013-02-15 22:23:18 +0100750 struct ieee80211_sta *sta = control->sta;
751 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
752 struct ieee80211_hdr *hdr = (void *)skb->data;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100753
Eytan Lifshitz9ee718a2013-05-19 19:14:41 +0300754 if (iwl_mvm_is_radio_killed(mvm)) {
755 IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n");
Johannes Berg8ca151b2013-01-24 14:25:36 +0100756 goto drop;
757 }
758
Ilan Peer398e8c62013-03-13 15:20:35 +0200759 if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE &&
Matti Gottlieba6cc5162014-09-29 11:46:04 +0300760 !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status) &&
761 !test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status))
Johannes Berg8ca151b2013-01-24 14:25:36 +0100762 goto drop;
763
Johannes Berg3e56ead2013-02-15 22:23:18 +0100764 /* treat non-bufferable MMPDUs as broadcast if sta is sleeping */
765 if (unlikely(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER &&
766 ieee80211_is_mgmt(hdr->frame_control) &&
767 !ieee80211_is_deauth(hdr->frame_control) &&
768 !ieee80211_is_disassoc(hdr->frame_control) &&
769 !ieee80211_is_action(hdr->frame_control)))
770 sta = NULL;
771
772 if (sta) {
Arik Nemtsovb2492502014-03-13 12:21:50 +0200773 if (iwl_mvm_defer_tx(mvm, sta, skb))
774 return;
Johannes Berg3e56ead2013-02-15 22:23:18 +0100775 if (iwl_mvm_tx_skb(mvm, skb, sta))
Johannes Berg8ca151b2013-01-24 14:25:36 +0100776 goto drop;
777 return;
778 }
779
780 if (iwl_mvm_tx_skb_non_sta(mvm, skb))
781 goto drop;
782 return;
783 drop:
784 ieee80211_free_txskb(hw, skb);
785}
786
Emmanuel Grumbach205e2212014-02-12 15:15:05 +0200787static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg)
788{
789 if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
790 return false;
791 return true;
792}
793
794static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg)
795{
796 if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
797 return false;
798 if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG)
799 return true;
800
801 /* enabled by default */
802 return true;
803}
804
Emmanuel Grumbach42032632015-04-15 12:43:46 +0300805#define CHECK_BA_TRIGGER(_mvm, _trig, _tid_bm, _tid, _fmt...) \
806 do { \
807 if (!(le16_to_cpu(_tid_bm) & BIT(_tid))) \
808 break; \
809 iwl_mvm_fw_dbg_collect_trig(_mvm, _trig, _fmt); \
810 } while (0)
811
812static void
813iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
814 struct ieee80211_sta *sta, u16 tid, u16 rx_ba_ssn,
815 enum ieee80211_ampdu_mlme_action action)
816{
817 struct iwl_fw_dbg_trigger_tlv *trig;
818 struct iwl_fw_dbg_trigger_ba *ba_trig;
819
820 if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
821 return;
822
823 trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
824 ba_trig = (void *)trig->data;
825
826 if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
827 return;
828
829 switch (action) {
830 case IEEE80211_AMPDU_TX_OPERATIONAL: {
831 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
832 struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
833
834 CHECK_BA_TRIGGER(mvm, trig, ba_trig->tx_ba_start, tid,
835 "TX AGG START: MAC %pM tid %d ssn %d\n",
836 sta->addr, tid, tid_data->ssn);
837 break;
838 }
839 case IEEE80211_AMPDU_TX_STOP_CONT:
840 CHECK_BA_TRIGGER(mvm, trig, ba_trig->tx_ba_stop, tid,
841 "TX AGG STOP: MAC %pM tid %d\n",
842 sta->addr, tid);
843 break;
844 case IEEE80211_AMPDU_RX_START:
845 CHECK_BA_TRIGGER(mvm, trig, ba_trig->rx_ba_start, tid,
846 "RX AGG START: MAC %pM tid %d ssn %d\n",
847 sta->addr, tid, rx_ba_ssn);
848 break;
849 case IEEE80211_AMPDU_RX_STOP:
850 CHECK_BA_TRIGGER(mvm, trig, ba_trig->rx_ba_stop, tid,
851 "RX AGG STOP: MAC %pM tid %d\n",
852 sta->addr, tid);
853 break;
854 default:
855 break;
856 }
857}
858
Johannes Berg8ca151b2013-01-24 14:25:36 +0100859static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
860 struct ieee80211_vif *vif,
Sara Sharon50ea05e2015-12-30 16:06:04 +0200861 struct ieee80211_ampdu_params *params)
Johannes Berg8ca151b2013-01-24 14:25:36 +0100862{
863 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
864 int ret;
Arik Nemtsovb2492502014-03-13 12:21:50 +0200865 bool tx_agg_ref = false;
Sara Sharon50ea05e2015-12-30 16:06:04 +0200866 struct ieee80211_sta *sta = params->sta;
867 enum ieee80211_ampdu_mlme_action action = params->action;
868 u16 tid = params->tid;
869 u16 *ssn = &params->ssn;
870 u8 buf_size = params->buf_size;
Emmanuel Grumbachbb81bb62015-10-26 16:00:29 +0200871 bool amsdu = params->amsdu;
Sara Sharon10b2b202016-03-20 16:23:41 +0200872 u16 timeout = params->timeout;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100873
874 IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
875 sta->addr, tid, action);
876
877 if (!(mvm->nvm_data->sku_cap_11n_enable))
878 return -EACCES;
879
Arik Nemtsovb2492502014-03-13 12:21:50 +0200880 /* return from D0i3 before starting a new Tx aggregation */
Eliad Peller9256c202014-04-22 13:33:29 +0300881 switch (action) {
882 case IEEE80211_AMPDU_TX_START:
883 case IEEE80211_AMPDU_TX_STOP_CONT:
884 case IEEE80211_AMPDU_TX_STOP_FLUSH:
885 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
886 case IEEE80211_AMPDU_TX_OPERATIONAL:
Arik Nemtsovb2492502014-03-13 12:21:50 +0200887 /*
Eliad Peller9256c202014-04-22 13:33:29 +0300888 * for tx start, wait synchronously until D0i3 exit to
889 * get the correct sequence number for the tid.
890 * additionally, some other ampdu actions use direct
891 * target access, which is not handled automatically
892 * by the trans layer (unlike commands), so wait for
893 * d0i3 exit in these cases as well.
Arik Nemtsovb2492502014-03-13 12:21:50 +0200894 */
Gregory Greenmand40fc482014-06-25 14:08:50 +0200895 ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_TX_AGG);
896 if (ret)
897 return ret;
898
899 tx_agg_ref = true;
Eliad Peller9256c202014-04-22 13:33:29 +0300900 break;
901 default:
902 break;
Arik Nemtsovb2492502014-03-13 12:21:50 +0200903 }
904
Johannes Berg8ca151b2013-01-24 14:25:36 +0100905 mutex_lock(&mvm->mutex);
906
907 switch (action) {
908 case IEEE80211_AMPDU_RX_START:
Emmanuel Grumbach205e2212014-02-12 15:15:05 +0200909 if (!iwl_enable_rx_ampdu(mvm->cfg)) {
Johannes Berg8ca151b2013-01-24 14:25:36 +0100910 ret = -EINVAL;
911 break;
912 }
Sara Sharon10b2b202016-03-20 16:23:41 +0200913 ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true, buf_size,
914 timeout);
Johannes Berg8ca151b2013-01-24 14:25:36 +0100915 break;
916 case IEEE80211_AMPDU_RX_STOP:
Sara Sharon10b2b202016-03-20 16:23:41 +0200917 ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false, buf_size,
918 timeout);
Johannes Berg8ca151b2013-01-24 14:25:36 +0100919 break;
920 case IEEE80211_AMPDU_TX_START:
Emmanuel Grumbach205e2212014-02-12 15:15:05 +0200921 if (!iwl_enable_tx_ampdu(mvm->cfg)) {
Emmanuel Grumbach5d158ef2013-02-19 14:39:58 +0200922 ret = -EINVAL;
923 break;
924 }
Johannes Berg8ca151b2013-01-24 14:25:36 +0100925 ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn);
926 break;
927 case IEEE80211_AMPDU_TX_STOP_CONT:
Emmanuel Grumbache3d9e7c2013-02-19 16:13:53 +0200928 ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid);
929 break;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100930 case IEEE80211_AMPDU_TX_STOP_FLUSH:
931 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
Emmanuel Grumbache3d9e7c2013-02-19 16:13:53 +0200932 ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid);
Johannes Berg8ca151b2013-01-24 14:25:36 +0100933 break;
934 case IEEE80211_AMPDU_TX_OPERATIONAL:
Emmanuel Grumbachbb81bb62015-10-26 16:00:29 +0200935 ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid,
936 buf_size, amsdu);
Johannes Berg8ca151b2013-01-24 14:25:36 +0100937 break;
938 default:
939 WARN_ON_ONCE(1);
940 ret = -EINVAL;
941 break;
942 }
Emmanuel Grumbach42032632015-04-15 12:43:46 +0300943
944 if (!ret) {
945 u16 rx_ba_ssn = 0;
946
947 if (action == IEEE80211_AMPDU_RX_START)
948 rx_ba_ssn = *ssn;
949
950 iwl_mvm_ampdu_check_trigger(mvm, vif, sta, tid,
951 rx_ba_ssn, action);
952 }
Johannes Berg8ca151b2013-01-24 14:25:36 +0100953 mutex_unlock(&mvm->mutex);
954
Arik Nemtsovb2492502014-03-13 12:21:50 +0200955 /*
956 * If the tid is marked as started, we won't use it for offloaded
957 * traffic on the next D0i3 entry. It's safe to unref.
958 */
959 if (tx_agg_ref)
960 iwl_mvm_unref(mvm, IWL_MVM_REF_TX_AGG);
961
Johannes Berg8ca151b2013-01-24 14:25:36 +0100962 return ret;
963}
964
965static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
966 struct ieee80211_vif *vif)
967{
968 struct iwl_mvm *mvm = data;
969 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
970
971 mvmvif->uploaded = false;
972 mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
973
Johannes Berg8ca151b2013-01-24 14:25:36 +0100974 spin_lock_bh(&mvm->time_event_lock);
975 iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data);
976 spin_unlock_bh(&mvm->time_event_lock);
977
Ilan Peerfe0f2de2013-03-21 10:23:52 +0200978 mvmvif->phy_ctxt = NULL;
Emmanuel Grumbach8a275ba2014-07-13 09:12:11 +0300979 memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data));
Johannes Berg8ca151b2013-01-24 14:25:36 +0100980}
981
982static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
983{
Johannes Berg58629d92014-11-06 09:40:50 +0100984 /* clear the D3 reconfig, we only need it to avoid dumping a
985 * firmware coredump on reconfiguration, we shouldn't do that
986 * on D3->D0 transition
987 */
Emmanuel Grumbachb6eaa452015-01-29 14:58:20 +0200988 if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status)) {
989 mvm->fw_dump_desc = &iwl_mvm_dump_desc_assert;
Johannes Berg58629d92014-11-06 09:40:50 +0100990 iwl_mvm_fw_error_dump(mvm);
Emmanuel Grumbachb6eaa452015-01-29 14:58:20 +0200991 }
Emmanuel Grumbach1bd3cbc2014-03-18 21:15:06 +0200992
Eliad Peller744cb692014-12-10 18:44:13 +0200993 /* cleanup all stale references (scan, roc), but keep the
994 * ucode_down ref until reconfig is complete
995 */
996 iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
997
Chaya Rachel Ivgifcb6b922016-02-22 10:21:41 +0200998 iwl_mvm_stop_device(mvm);
Johannes Berg8ca151b2013-01-24 14:25:36 +0100999
Luciano Coelho9af91f42015-02-10 10:42:26 +02001000 mvm->scan_status = 0;
Luciano Coelhob1873302014-08-08 17:12:07 +03001001 mvm->ps_disabled = false;
Emmanuel Grumbach31b8b342014-11-02 15:48:09 +02001002 mvm->calibrating = false;
Johannes Berg8ca151b2013-01-24 14:25:36 +01001003
1004 /* just in case one was running */
Eliad Peller305d2362015-12-09 16:33:20 +02001005 iwl_mvm_cleanup_roc_te(mvm);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001006 ieee80211_remain_on_channel_expired(mvm->hw);
1007
Arik Nemtsov737719f2015-02-23 14:42:41 +02001008 /*
1009 * cleanup all interfaces, even inactive ones, as some might have
1010 * gone down during the HW restart
1011 */
1012 ieee80211_iterate_interfaces(mvm->hw, 0, iwl_mvm_cleanup_iterator, mvm);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001013
Ilan Peerfe0f2de2013-03-21 10:23:52 +02001014 mvm->p2p_device_vif = NULL;
Eliad Peller37577fe2013-12-05 17:19:39 +02001015 mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
Ilan Peerfe0f2de2013-03-21 10:23:52 +02001016
1017 iwl_mvm_reset_phy_ctxts(mvm);
Luca Coelho9c3deeb2015-11-11 01:06:17 +02001018 memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
Johannes Berg8ca151b2013-01-24 14:25:36 +01001019 memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
Liad Kaufman24afba72015-07-28 18:56:08 +03001020 memset(mvm->sta_deferred_frames, 0, sizeof(mvm->sta_deferred_frames));
Arik Nemtsova0f6bf22014-09-21 19:10:04 +03001021 memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained));
Emmanuel Grumbach8a275ba2014-07-13 09:12:11 +03001022 memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
1023 memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
1024 memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
1025 memset(&mvm->last_bt_ci_cmd_old, 0, sizeof(mvm->last_bt_ci_cmd_old));
1026 memset(&mvm->bt_ack_kill_msk, 0, sizeof(mvm->bt_ack_kill_msk));
1027 memset(&mvm->bt_cts_kill_msk, 0, sizeof(mvm->bt_cts_kill_msk));
Johannes Berg8ca151b2013-01-24 14:25:36 +01001028
1029 ieee80211_wake_queues(mvm->hw);
1030
Eliad Peller228670b2014-08-10 17:00:15 +03001031 /* clear any stale d0i3 state */
1032 clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
1033
Johannes Berg8ca151b2013-01-24 14:25:36 +01001034 mvm->vif_count = 0;
Emmanuel Grumbach113a0442013-07-02 14:16:38 +03001035 mvm->rx_ba_sessions = 0;
Emmanuel Grumbachd2709ad2015-01-29 14:58:06 +02001036 mvm->fw_dbg_conf = FW_DBG_INVALID;
Johannes Berg91a8bcd2015-01-14 18:12:41 +01001037
1038 /* keep statistics ticking */
1039 iwl_mvm_accu_radio_stats(mvm);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001040}
1041
Luciano Coelhoa0a09242014-09-04 12:29:15 +03001042int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
Johannes Berg8ca151b2013-01-24 14:25:36 +01001043{
Johannes Berg8ca151b2013-01-24 14:25:36 +01001044 int ret;
1045
Luciano Coelhoa0a09242014-09-04 12:29:15 +03001046 lockdep_assert_held(&mvm->mutex);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001047
Luca Coelhoa42b2af32015-11-25 22:15:32 +02001048 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
1049 /* Clean up some internal and mac80211 state on restart */
Johannes Berg8ca151b2013-01-24 14:25:36 +01001050 iwl_mvm_restart_cleanup(mvm);
Luca Coelhoa42b2af32015-11-25 22:15:32 +02001051 } else {
1052 /* Hold the reference to prevent runtime suspend while
1053 * the start procedure runs. It's a bit confusing
1054 * that the UCODE_DOWN reference is taken, but it just
1055 * means "UCODE is not UP yet". ( TODO: rename this
1056 * reference).
1057 */
1058 iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
1059 }
Johannes Berg8ca151b2013-01-24 14:25:36 +01001060 ret = iwl_mvm_up(mvm);
Johannes Bergc47af222014-04-30 16:34:45 +02001061
1062 if (ret && test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
1063 /* Something went wrong - we need to finish some cleanup
1064 * that normally iwl_mvm_mac_restart_complete() below
1065 * would do.
1066 */
1067 clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
1068 iwl_mvm_d0i3_enable_tx(mvm, NULL);
1069 }
1070
Luciano Coelhoa0a09242014-09-04 12:29:15 +03001071 return ret;
1072}
1073
1074static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
1075{
1076 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1077 int ret;
1078
Eliad Peller37948fc2014-12-11 10:48:18 +02001079 /* Some hw restart cleanups must not hold the mutex */
1080 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
1081 /*
1082 * Make sure we are out of d0i3. This is needed
1083 * to make sure the reference accounting is correct
1084 * (and there is no stale d0i3_exit_work).
1085 */
1086 wait_event_timeout(mvm->d0i3_exit_waitq,
1087 !test_bit(IWL_MVM_STATUS_IN_D0I3,
1088 &mvm->status),
1089 HZ);
1090 }
1091
Luciano Coelhoa0a09242014-09-04 12:29:15 +03001092 mutex_lock(&mvm->mutex);
1093 ret = __iwl_mvm_mac_start(mvm);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001094 mutex_unlock(&mvm->mutex);
1095
1096 return ret;
1097}
1098
Eliad Pellercf2c92d2014-11-04 11:43:54 +02001099static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)
Johannes Berg8ca151b2013-01-24 14:25:36 +01001100{
Johannes Berg8ca151b2013-01-24 14:25:36 +01001101 int ret;
1102
1103 mutex_lock(&mvm->mutex);
1104
1105 clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
Arik Nemtsovb2492502014-03-13 12:21:50 +02001106 iwl_mvm_d0i3_enable_tx(mvm, NULL);
Johannes Berge7afe892015-04-21 09:21:46 +02001107 ret = iwl_mvm_update_quotas(mvm, true, NULL);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001108 if (ret)
1109 IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n",
1110 ret);
1111
Eliad Peller7498cf42014-01-16 17:10:44 +02001112 /* allow transport/FW low power modes */
1113 iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN);
1114
Arik Nemtsovcbd2ae22014-09-14 19:13:54 +03001115 /*
1116 * If we have TDLS peers, remove them. We don't know the last seqno/PN
1117 * of packets the FW sent out, so we must reconnect.
1118 */
1119 iwl_mvm_teardown_tdls_peers(mvm);
1120
Johannes Berg8ca151b2013-01-24 14:25:36 +01001121 mutex_unlock(&mvm->mutex);
1122}
1123
Eliad Peller088070a2014-10-20 18:42:58 +03001124static void iwl_mvm_resume_complete(struct iwl_mvm *mvm)
1125{
Luca Coelhob7282642015-09-17 23:44:14 +03001126 if (iwl_mvm_is_d0i3_supported(mvm) &&
1127 iwl_mvm_enter_d0i3_on_suspend(mvm))
1128 WARN_ONCE(!wait_event_timeout(mvm->d0i3_exit_waitq,
1129 !test_bit(IWL_MVM_STATUS_IN_D0I3,
1130 &mvm->status),
1131 HZ),
1132 "D0i3 exit on resume timed out\n");
Eliad Peller088070a2014-10-20 18:42:58 +03001133}
1134
Eliad Pellercf2c92d2014-11-04 11:43:54 +02001135static void
1136iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw,
1137 enum ieee80211_reconfig_type reconfig_type)
1138{
1139 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1140
1141 switch (reconfig_type) {
1142 case IEEE80211_RECONFIG_TYPE_RESTART:
1143 iwl_mvm_restart_complete(mvm);
1144 break;
1145 case IEEE80211_RECONFIG_TYPE_SUSPEND:
Eliad Peller088070a2014-10-20 18:42:58 +03001146 iwl_mvm_resume_complete(mvm);
Eliad Pellercf2c92d2014-11-04 11:43:54 +02001147 break;
1148 }
1149}
1150
Luciano Coelhoa0a09242014-09-04 12:29:15 +03001151void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
Johannes Berg8ca151b2013-01-24 14:25:36 +01001152{
Luciano Coelhoa0a09242014-09-04 12:29:15 +03001153 lockdep_assert_held(&mvm->mutex);
Eliad Peller7498cf42014-01-16 17:10:44 +02001154
Johannes Berg91a8bcd2015-01-14 18:12:41 +01001155 /* firmware counters are obviously reset now, but we shouldn't
1156 * partially track so also clear the fw_reset_accu counters.
1157 */
1158 memset(&mvm->accu_radio_stats, 0, sizeof(mvm->accu_radio_stats));
1159
Johannes Berg8ca151b2013-01-24 14:25:36 +01001160 /* async_handlers_wk is now blocked */
1161
1162 /*
1163 * The work item could be running or queued if the
1164 * ROC time event stops just as we get here.
1165 */
Eliad Pellerc7792732015-04-19 11:41:04 +03001166 flush_work(&mvm->roc_done_wk);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001167
Chaya Rachel Ivgifcb6b922016-02-22 10:21:41 +02001168 iwl_mvm_stop_device(mvm);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001169
1170 iwl_mvm_async_handlers_purge(mvm);
1171 /* async_handlers_list is empty and will stay empty: HW is stopped */
1172
1173 /* the fw is stopped, the aux sta is dead: clean up driver state */
Johannes Berg712b24a2014-08-04 14:14:14 +02001174 iwl_mvm_del_aux_sta(mvm);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001175
Matti Gottlieb7fdf9662016-03-15 13:46:47 +02001176 iwl_free_fw_paging(mvm);
1177
Eliad Peller0a79a0c02014-12-04 10:27:20 +02001178 /*
1179 * Clear IN_HW_RESTART flag when stopping the hw (as restart_complete()
1180 * won't be called in this case).
Arik Nemtsov8b2b9fb2015-03-04 13:16:03 +02001181 * But make sure to cleanup interfaces that have gone down before/during
1182 * HW restart was requested.
Eliad Peller0a79a0c02014-12-04 10:27:20 +02001183 */
Arik Nemtsov8b2b9fb2015-03-04 13:16:03 +02001184 if (test_and_clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
1185 ieee80211_iterate_interfaces(mvm->hw, 0,
1186 iwl_mvm_cleanup_iterator, mvm);
Eliad Peller0a79a0c02014-12-04 10:27:20 +02001187
Alexander Bondar963221b2015-03-26 11:07:35 +02001188 /* We shouldn't have any UIDs still set. Loop over all the UIDs to
1189 * make sure there's nothing left there and warn if any is found.
1190 */
Johannes Berg859d9142015-06-01 17:11:11 +02001191 if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
Alexander Bondar963221b2015-03-26 11:07:35 +02001192 int i;
1193
Luciano Coelho507e4cd2015-03-19 22:58:33 +02001194 for (i = 0; i < mvm->max_scans; i++) {
Luciano Coelho6185af2a2015-05-07 11:13:24 +03001195 if (WARN_ONCE(mvm->scan_uid_status[i],
1196 "UMAC scan UID %d status was not cleaned\n",
1197 i))
1198 mvm->scan_uid_status[i] = 0;
Alexander Bondar963221b2015-03-26 11:07:35 +02001199 }
1200 }
Luciano Coelhoa0a09242014-09-04 12:29:15 +03001201}
Luciano Coelhobc448862014-08-20 11:49:11 +03001202
Luciano Coelhoa0a09242014-09-04 12:29:15 +03001203static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
1204{
1205 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1206
1207 flush_work(&mvm->d0i3_exit_work);
1208 flush_work(&mvm->async_handlers_wk);
Liad Kaufman24afba72015-07-28 18:56:08 +03001209 flush_work(&mvm->add_stream_wk);
Emmanuel Grumbachd2709ad2015-01-29 14:58:06 +02001210 cancel_delayed_work_sync(&mvm->fw_dump_wk);
Andrei Otcheretianskid3a108a2016-02-28 17:12:21 +02001211 cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork);
Luca Coelho69e04642016-05-03 12:18:33 +03001212 cancel_delayed_work_sync(&mvm->scan_timeout_dwork);
Emmanuel Grumbachb6eaa452015-01-29 14:58:20 +02001213 iwl_mvm_free_fw_dump_desc(mvm);
Luciano Coelhoa0a09242014-09-04 12:29:15 +03001214
1215 mutex_lock(&mvm->mutex);
1216 __iwl_mvm_mac_stop(mvm);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001217 mutex_unlock(&mvm->mutex);
1218
1219 /*
1220 * The worker might have been waiting for the mutex, let it run and
1221 * discover that its list is now empty.
1222 */
1223 cancel_work_sync(&mvm->async_handlers_wk);
1224}
1225
Ilan Peerfe0f2de2013-03-21 10:23:52 +02001226static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)
1227{
1228 u16 i;
1229
1230 lockdep_assert_held(&mvm->mutex);
1231
1232 for (i = 0; i < NUM_PHY_CTX; i++)
1233 if (!mvm->phy_ctxts[i].ref)
1234 return &mvm->phy_ctxts[i];
1235
1236 IWL_ERR(mvm, "No available PHY context\n");
1237 return NULL;
1238}
1239
Avri Altmand44c3fe2015-04-18 22:16:42 +03001240static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1241 s16 tx_power)
1242{
1243 struct iwl_dev_tx_power_cmd cmd = {
Johannes Bergda03f022015-08-18 15:15:36 +02001244 .v2.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC),
1245 .v2.mac_context_id =
Avri Altmand44c3fe2015-04-18 22:16:42 +03001246 cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id),
Johannes Bergda03f022015-08-18 15:15:36 +02001247 .v2.pwr_restriction = cpu_to_le16(8 * tx_power),
Avri Altmand44c3fe2015-04-18 22:16:42 +03001248 };
Johannes Bergda03f022015-08-18 15:15:36 +02001249 int len = sizeof(cmd);
Avri Altmand44c3fe2015-04-18 22:16:42 +03001250
Avri Altmand44c3fe2015-04-18 22:16:42 +03001251 if (tx_power == IWL_DEFAULT_MAX_TX_POWER)
Johannes Bergda03f022015-08-18 15:15:36 +02001252 cmd.v2.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER);
Avri Altmand44c3fe2015-04-18 22:16:42 +03001253
Johannes Bergda03f022015-08-18 15:15:36 +02001254 if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TX_POWER_CHAIN))
1255 len = sizeof(cmd.v2);
1256
1257 return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd);
Avri Altmand44c3fe2015-04-18 22:16:42 +03001258}
1259
Johannes Berg8ca151b2013-01-24 14:25:36 +01001260static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
1261 struct ieee80211_vif *vif)
1262{
1263 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1264 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1265 int ret;
1266
Emmanuel Grumbachaa5e1832015-03-07 19:35:37 +02001267 mvmvif->mvm = mvm;
1268
Johannes Berg8ca151b2013-01-24 14:25:36 +01001269 /*
Gregory Greenmand40fc482014-06-25 14:08:50 +02001270 * make sure D0i3 exit is completed, otherwise a target access
1271 * during tx queue configuration could be done when still in
1272 * D0i3 state.
1273 */
1274 ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_ADD_IF);
1275 if (ret)
1276 return ret;
1277
1278 /*
Johannes Berg8ca151b2013-01-24 14:25:36 +01001279 * Not much to do here. The stack will not allow interface
1280 * types or combinations that we didn't advertise, so we
1281 * don't really have to check the types.
1282 */
1283
1284 mutex_lock(&mvm->mutex);
1285
Johannes Berg33cef922015-01-21 21:41:29 +01001286 /* make sure that beacon statistics don't go backwards with FW reset */
1287 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
1288 mvmvif->beacon_stats.accu_num_beacons +=
1289 mvmvif->beacon_stats.num_beacons;
1290
Eliad Pellere89044d2013-07-16 17:33:26 +03001291 /* Allocate resources for the MAC context, and add it to the fw */
Johannes Berg8ca151b2013-01-24 14:25:36 +01001292 ret = iwl_mvm_mac_ctxt_init(mvm, vif);
1293 if (ret)
1294 goto out_unlock;
1295
Alexander Bondar1c2abf72013-08-27 20:31:48 +03001296 /* Counting number of interfaces is needed for legacy PM */
Ilan Peerea183d02013-07-23 14:41:53 +03001297 if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
1298 mvm->vif_count++;
Ilan Peerea183d02013-07-23 14:41:53 +03001299
1300 /*
Johannes Berg8ca151b2013-01-24 14:25:36 +01001301 * The AP binding flow can be done only after the beacon
1302 * template is configured (which happens only in the mac80211
1303 * start_ap() flow), and adding the broadcast station can happen
1304 * only after the binding.
1305 * In addition, since modifying the MAC before adding a bcast
1306 * station is not allowed by the FW, delay the adding of MAC context to
1307 * the point where we can also add the bcast station.
1308 * In short: there's not much we can do at this point, other than
1309 * allocating resources :)
1310 */
Johannes Berg5023d962013-07-31 14:07:43 +02001311 if (vif->type == NL80211_IFTYPE_AP ||
1312 vif->type == NL80211_IFTYPE_ADHOC) {
Johannes Berg013290a2014-08-04 13:38:48 +02001313 ret = iwl_mvm_alloc_bcast_sta(mvm, vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001314 if (ret) {
1315 IWL_ERR(mvm, "Failed to allocate bcast sta\n");
1316 goto out_release;
1317 }
1318
Emmanuel Grumbach77740cb2013-06-26 23:51:41 +03001319 iwl_mvm_vif_dbgfs_register(mvm, vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001320 goto out_unlock;
1321 }
1322
Avri Altman93190fb2014-12-27 09:09:47 +02001323 mvmvif->features |= hw->netdev_features;
1324
Johannes Berg8ca151b2013-01-24 14:25:36 +01001325 ret = iwl_mvm_mac_ctxt_add(mvm, vif);
1326 if (ret)
1327 goto out_release;
1328
Arik Nemtsov999609f2014-05-15 17:31:51 +03001329 ret = iwl_mvm_power_update_mac(mvm);
Emmanuel Grumbache5e7aa82014-01-27 16:57:33 +02001330 if (ret)
Luciano Coelhofd66fc12015-01-27 15:06:57 +02001331 goto out_remove_mac;
Johannes Berg8ca151b2013-01-24 14:25:36 +01001332
Hila Gonen7df15b12012-12-12 11:16:19 +02001333 /* beacon filtering */
Emmanuel Grumbacha1022922014-05-12 11:36:41 +03001334 ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
Eliad Pellerbd3351b2013-07-16 17:50:17 +03001335 if (ret)
1336 goto out_remove_mac;
1337
Hila Gonen7df15b12012-12-12 11:16:19 +02001338 if (!mvm->bf_allowed_vif &&
Emmanuel Grumbach73e5f2c2014-03-30 08:57:30 +03001339 vif->type == NL80211_IFTYPE_STATION && !vif->p2p) {
Hila Gonen7df15b12012-12-12 11:16:19 +02001340 mvm->bf_allowed_vif = mvmvif;
Andrei Otcheretianskia20fd392013-07-21 17:23:59 +03001341 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
1342 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Hila Gonen7df15b12012-12-12 11:16:19 +02001343 }
1344
Johannes Berg8ca151b2013-01-24 14:25:36 +01001345 /*
1346 * P2P_DEVICE interface does not have a channel context assigned to it,
1347 * so a dedicated PHY context is allocated to it and the corresponding
1348 * MAC context is bound to it at this stage.
1349 */
1350 if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
Johannes Berg8ca151b2013-01-24 14:25:36 +01001351
Ilan Peerfe0f2de2013-03-21 10:23:52 +02001352 mvmvif->phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
1353 if (!mvmvif->phy_ctxt) {
1354 ret = -ENOSPC;
Eliad Pellerbd3351b2013-07-16 17:50:17 +03001355 goto out_free_bf;
Ilan Peerfe0f2de2013-03-21 10:23:52 +02001356 }
Johannes Berg8ca151b2013-01-24 14:25:36 +01001357
Ilan Peer53a9d612013-04-28 11:55:08 +03001358 iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001359 ret = iwl_mvm_binding_add_vif(mvm, vif);
1360 if (ret)
Ilan Peer53a9d612013-04-28 11:55:08 +03001361 goto out_unref_phy;
Johannes Berg8ca151b2013-01-24 14:25:36 +01001362
Johannes Berg013290a2014-08-04 13:38:48 +02001363 ret = iwl_mvm_add_bcast_sta(mvm, vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001364 if (ret)
1365 goto out_unbind;
1366
1367 /* Save a pointer to p2p device vif, so it can later be used to
1368 * update the p2p device MAC when a GO is started/stopped */
1369 mvm->p2p_device_vif = vif;
1370 }
1371
Johannes Berg63494372013-03-26 10:47:53 +01001372 iwl_mvm_vif_dbgfs_register(mvm, vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001373 goto out_unlock;
1374
1375 out_unbind:
1376 iwl_mvm_binding_remove_vif(mvm, vif);
Ilan Peer53a9d612013-04-28 11:55:08 +03001377 out_unref_phy:
Ilan Peerfe0f2de2013-03-21 10:23:52 +02001378 iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
Eliad Pellerbd3351b2013-07-16 17:50:17 +03001379 out_free_bf:
1380 if (mvm->bf_allowed_vif == mvmvif) {
1381 mvm->bf_allowed_vif = NULL;
Andrei Otcheretianskia20fd392013-07-21 17:23:59 +03001382 vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |
1383 IEEE80211_VIF_SUPPORTS_CQM_RSSI);
Eliad Pellerbd3351b2013-07-16 17:50:17 +03001384 }
Johannes Berg8ca151b2013-01-24 14:25:36 +01001385 out_remove_mac:
1386 mvmvif->phy_ctxt = NULL;
1387 iwl_mvm_mac_ctxt_remove(mvm, vif);
1388 out_release:
Alexander Bondar5ee2b212013-03-05 10:16:40 +02001389 if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
1390 mvm->vif_count--;
Alexander Bondar1c2abf72013-08-27 20:31:48 +03001391
Johannes Berg8ca151b2013-01-24 14:25:36 +01001392 iwl_mvm_mac_ctxt_release(mvm, vif);
1393 out_unlock:
1394 mutex_unlock(&mvm->mutex);
1395
Gregory Greenmand40fc482014-06-25 14:08:50 +02001396 iwl_mvm_unref(mvm, IWL_MVM_REF_ADD_IF);
1397
Johannes Berg8ca151b2013-01-24 14:25:36 +01001398 return ret;
1399}
1400
Johannes Berg38a12b52013-02-22 14:07:56 +01001401static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
1402 struct ieee80211_vif *vif)
Johannes Berg8ca151b2013-01-24 14:25:36 +01001403{
Arik Nemtsovd92b732e2014-09-21 19:00:42 +03001404 u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001405
1406 if (tfd_msk) {
Emmanuel Grumbachfe92e322015-03-11 09:34:31 +02001407 /*
1408 * mac80211 first removes all the stations of the vif and
1409 * then removes the vif. When it removes a station it also
1410 * flushes the AMPDU session. So by now, all the AMPDU sessions
1411 * of all the stations of this vif are closed, and the queues
1412 * of these AMPDU sessions are properly closed.
1413 * We still need to take care of the shared queues of the vif.
1414 * Flush them here.
1415 */
Johannes Berg8ca151b2013-01-24 14:25:36 +01001416 mutex_lock(&mvm->mutex);
Luca Coelho5888a402015-10-06 09:54:57 +03001417 iwl_mvm_flush_tx_path(mvm, tfd_msk, 0);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001418 mutex_unlock(&mvm->mutex);
Emmanuel Grumbachfe92e322015-03-11 09:34:31 +02001419
1420 /*
1421 * There are transports that buffer a few frames in the host.
1422 * For these, the flush above isn't enough since while we were
1423 * flushing, the transport might have sent more frames to the
1424 * device. To solve this, wait here until the transport is
1425 * empty. Technically, this could have replaced the flush
1426 * above, but flush is much faster than draining. So flush
1427 * first, and drain to make sure we have no frames in the
1428 * transport anymore.
1429 * If a station still had frames on the shared queues, it is
1430 * already marked as draining, so to complete the draining, we
1431 * just need to wait until the transport is empty.
1432 */
1433 iwl_trans_wait_tx_queue_empty(mvm->trans, tfd_msk);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001434 }
1435
1436 if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
1437 /*
1438 * Flush the ROC worker which will flush the OFFCHANNEL queue.
1439 * We assume here that all the packets sent to the OFFCHANNEL
1440 * queue are sent in ROC session.
1441 */
1442 flush_work(&mvm->roc_done_wk);
1443 } else {
1444 /*
1445 * By now, all the AC queues are empty. The AGG queues are
1446 * empty too. We already got all the Tx responses for all the
1447 * packets in the queues. The drain work can have been
Emmanuel Grumbach0742a752013-06-10 14:10:33 +03001448 * triggered. Flush it.
Johannes Berg8ca151b2013-01-24 14:25:36 +01001449 */
1450 flush_work(&mvm->sta_drained_wk);
1451 }
Johannes Berg38a12b52013-02-22 14:07:56 +01001452}
1453
1454static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
1455 struct ieee80211_vif *vif)
1456{
1457 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1458 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1459
1460 iwl_mvm_prepare_mac_removal(mvm, vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001461
1462 mutex_lock(&mvm->mutex);
1463
Hila Gonen7df15b12012-12-12 11:16:19 +02001464 if (mvm->bf_allowed_vif == mvmvif) {
1465 mvm->bf_allowed_vif = NULL;
Andrei Otcheretianskia20fd392013-07-21 17:23:59 +03001466 vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |
1467 IEEE80211_VIF_SUPPORTS_CQM_RSSI);
Hila Gonen7df15b12012-12-12 11:16:19 +02001468 }
1469
Johannes Berg63494372013-03-26 10:47:53 +01001470 iwl_mvm_vif_dbgfs_clean(mvm, vif);
1471
Johannes Berg8ca151b2013-01-24 14:25:36 +01001472 /*
1473 * For AP/GO interface, the tear down of the resources allocated to the
Johannes Berg38a12b52013-02-22 14:07:56 +01001474 * interface is be handled as part of the stop_ap flow.
Johannes Berg8ca151b2013-01-24 14:25:36 +01001475 */
Johannes Berg5023d962013-07-31 14:07:43 +02001476 if (vif->type == NL80211_IFTYPE_AP ||
1477 vif->type == NL80211_IFTYPE_ADHOC) {
David Spinadel507cadf2013-07-31 18:07:21 +03001478#ifdef CONFIG_NL80211_TESTMODE
1479 if (vif == mvm->noa_vif) {
1480 mvm->noa_vif = NULL;
1481 mvm->noa_duration = 0;
1482 }
1483#endif
Johannes Berg013290a2014-08-04 13:38:48 +02001484 iwl_mvm_dealloc_bcast_sta(mvm, vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001485 goto out_release;
1486 }
1487
1488 if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
1489 mvm->p2p_device_vif = NULL;
Johannes Berg013290a2014-08-04 13:38:48 +02001490 iwl_mvm_rm_bcast_sta(mvm, vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001491 iwl_mvm_binding_remove_vif(mvm, vif);
Ilan Peerfe0f2de2013-03-21 10:23:52 +02001492 iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001493 mvmvif->phy_ctxt = NULL;
1494 }
1495
Alexander Bondar5ee2b212013-03-05 10:16:40 +02001496 if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE)
Johannes Berg8ca151b2013-01-24 14:25:36 +01001497 mvm->vif_count--;
Alexander Bondar1c2abf72013-08-27 20:31:48 +03001498
Arik Nemtsov999609f2014-05-15 17:31:51 +03001499 iwl_mvm_power_update_mac(mvm);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001500 iwl_mvm_mac_ctxt_remove(mvm, vif);
1501
1502out_release:
1503 iwl_mvm_mac_ctxt_release(mvm, vif);
1504 mutex_unlock(&mvm->mutex);
1505}
1506
1507static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed)
1508{
1509 return 0;
1510}
1511
Eliad Pellere59647e2013-11-28 14:08:50 +02001512struct iwl_mvm_mc_iter_data {
1513 struct iwl_mvm *mvm;
1514 int port_id;
1515};
1516
1517static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac,
1518 struct ieee80211_vif *vif)
1519{
1520 struct iwl_mvm_mc_iter_data *data = _data;
1521 struct iwl_mvm *mvm = data->mvm;
1522 struct iwl_mcast_filter_cmd *cmd = mvm->mcast_filter_cmd;
1523 int ret, len;
1524
1525 /* if we don't have free ports, mcast frames will be dropped */
1526 if (WARN_ON_ONCE(data->port_id >= MAX_PORT_ID_NUM))
1527 return;
1528
1529 if (vif->type != NL80211_IFTYPE_STATION ||
1530 !vif->bss_conf.assoc)
1531 return;
1532
1533 cmd->port_id = data->port_id++;
1534 memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN);
1535 len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4);
1536
Emmanuel Grumbach1c4abec2014-05-08 09:48:10 +03001537 ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_ASYNC, len, cmd);
Eliad Pellere59647e2013-11-28 14:08:50 +02001538 if (ret)
1539 IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret);
1540}
1541
1542static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm)
1543{
1544 struct iwl_mvm_mc_iter_data iter_data = {
1545 .mvm = mvm,
1546 };
1547
1548 lockdep_assert_held(&mvm->mutex);
1549
1550 if (WARN_ON_ONCE(!mvm->mcast_filter_cmd))
1551 return;
1552
Emmanuel Grumbach1c4abec2014-05-08 09:48:10 +03001553 ieee80211_iterate_active_interfaces_atomic(
Eliad Pellere59647e2013-11-28 14:08:50 +02001554 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1555 iwl_mvm_mc_iface_iterator, &iter_data);
1556}
1557
1558static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw,
1559 struct netdev_hw_addr_list *mc_list)
1560{
1561 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1562 struct iwl_mcast_filter_cmd *cmd;
1563 struct netdev_hw_addr *addr;
Max Stepanovf3bd58f2014-08-04 13:55:01 +03001564 int addr_count;
1565 bool pass_all;
Eliad Pellere59647e2013-11-28 14:08:50 +02001566 int len;
1567
Max Stepanovf3bd58f2014-08-04 13:55:01 +03001568 addr_count = netdev_hw_addr_list_count(mc_list);
1569 pass_all = addr_count > MAX_MCAST_FILTERING_ADDRESSES ||
1570 IWL_MVM_FW_MCAST_FILTER_PASS_ALL;
1571 if (pass_all)
Eliad Pellere59647e2013-11-28 14:08:50 +02001572 addr_count = 0;
Eliad Pellere59647e2013-11-28 14:08:50 +02001573
1574 len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4);
1575 cmd = kzalloc(len, GFP_ATOMIC);
1576 if (!cmd)
1577 return 0;
1578
1579 if (pass_all) {
1580 cmd->pass_all = 1;
1581 return (u64)(unsigned long)cmd;
1582 }
1583
1584 netdev_hw_addr_list_for_each(addr, mc_list) {
1585 IWL_DEBUG_MAC80211(mvm, "mcast addr (%d): %pM\n",
1586 cmd->count, addr->addr);
1587 memcpy(&cmd->addr_list[cmd->count * ETH_ALEN],
1588 addr->addr, ETH_ALEN);
1589 cmd->count++;
1590 }
1591
1592 return (u64)(unsigned long)cmd;
1593}
1594
Johannes Berg8ca151b2013-01-24 14:25:36 +01001595static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
1596 unsigned int changed_flags,
1597 unsigned int *total_flags,
1598 u64 multicast)
1599{
Eliad Pellere59647e2013-11-28 14:08:50 +02001600 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1601 struct iwl_mcast_filter_cmd *cmd = (void *)(unsigned long)multicast;
1602
1603 mutex_lock(&mvm->mutex);
1604
1605 /* replace previous configuration */
1606 kfree(mvm->mcast_filter_cmd);
1607 mvm->mcast_filter_cmd = cmd;
1608
1609 if (!cmd)
1610 goto out;
1611
1612 iwl_mvm_recalc_multicast(mvm);
1613out:
1614 mutex_unlock(&mvm->mutex);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001615 *total_flags = 0;
1616}
1617
Andrei Otcheretianskieffd1922015-06-30 12:08:28 +03001618static void iwl_mvm_config_iface_filter(struct ieee80211_hw *hw,
1619 struct ieee80211_vif *vif,
1620 unsigned int filter_flags,
1621 unsigned int changed_flags)
1622{
1623 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1624
1625 /* We support only filter for probe requests */
1626 if (!(changed_flags & FIF_PROBE_REQ))
1627 return;
1628
1629 /* Supported only for p2p client interfaces */
1630 if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc ||
1631 !vif->p2p)
1632 return;
1633
1634 mutex_lock(&mvm->mutex);
1635 iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
1636 mutex_unlock(&mvm->mutex);
1637}
1638
Eliad Pellerc87163b2014-01-08 10:11:11 +02001639#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
1640struct iwl_bcast_iter_data {
1641 struct iwl_mvm *mvm;
1642 struct iwl_bcast_filter_cmd *cmd;
1643 u8 current_filter;
1644};
1645
1646static void
1647iwl_mvm_set_bcast_filter(struct ieee80211_vif *vif,
1648 const struct iwl_fw_bcast_filter *in_filter,
1649 struct iwl_fw_bcast_filter *out_filter)
1650{
1651 struct iwl_fw_bcast_filter_attr *attr;
1652 int i;
1653
1654 memcpy(out_filter, in_filter, sizeof(*out_filter));
1655
1656 for (i = 0; i < ARRAY_SIZE(out_filter->attrs); i++) {
1657 attr = &out_filter->attrs[i];
1658
1659 if (!attr->mask)
1660 break;
1661
Eliad Peller2ee8f022014-01-13 19:07:09 +02001662 switch (attr->reserved1) {
1663 case cpu_to_le16(BC_FILTER_MAGIC_IP):
1664 if (vif->bss_conf.arp_addr_cnt != 1) {
1665 attr->mask = 0;
1666 continue;
1667 }
1668
1669 attr->val = vif->bss_conf.arp_addr_list[0];
1670 break;
1671 case cpu_to_le16(BC_FILTER_MAGIC_MAC):
1672 attr->val = *(__be32 *)&vif->addr[2];
1673 break;
1674 default:
1675 break;
1676 }
1677 attr->reserved1 = 0;
Eliad Pellerc87163b2014-01-08 10:11:11 +02001678 out_filter->num_attrs++;
1679 }
1680}
1681
1682static void iwl_mvm_bcast_filter_iterator(void *_data, u8 *mac,
1683 struct ieee80211_vif *vif)
1684{
1685 struct iwl_bcast_iter_data *data = _data;
1686 struct iwl_mvm *mvm = data->mvm;
1687 struct iwl_bcast_filter_cmd *cmd = data->cmd;
1688 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1689 struct iwl_fw_bcast_mac *bcast_mac;
1690 int i;
1691
1692 if (WARN_ON(mvmvif->id >= ARRAY_SIZE(cmd->macs)))
1693 return;
1694
1695 bcast_mac = &cmd->macs[mvmvif->id];
1696
Ilan Peere48393e2014-05-22 11:19:02 +03001697 /*
1698 * enable filtering only for associated stations, but not for P2P
1699 * Clients
1700 */
1701 if (vif->type != NL80211_IFTYPE_STATION || vif->p2p ||
1702 !vif->bss_conf.assoc)
Eliad Pellerc87163b2014-01-08 10:11:11 +02001703 return;
1704
1705 bcast_mac->default_discard = 1;
1706
1707 /* copy all configured filters */
1708 for (i = 0; mvm->bcast_filters[i].attrs[0].mask; i++) {
1709 /*
1710 * Make sure we don't exceed our filters limit.
1711 * if there is still a valid filter to be configured,
1712 * be on the safe side and just allow bcast for this mac.
1713 */
1714 if (WARN_ON_ONCE(data->current_filter >=
1715 ARRAY_SIZE(cmd->filters))) {
1716 bcast_mac->default_discard = 0;
1717 bcast_mac->attached_filters = 0;
1718 break;
1719 }
1720
1721 iwl_mvm_set_bcast_filter(vif,
1722 &mvm->bcast_filters[i],
1723 &cmd->filters[data->current_filter]);
1724
1725 /* skip current filter if it contains no attributes */
1726 if (!cmd->filters[data->current_filter].num_attrs)
1727 continue;
1728
1729 /* attach the filter to current mac */
1730 bcast_mac->attached_filters |=
1731 cpu_to_le16(BIT(data->current_filter));
1732
1733 data->current_filter++;
1734 }
1735}
1736
Eliad Pellerde06a592014-01-08 10:11:12 +02001737bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
1738 struct iwl_bcast_filter_cmd *cmd)
Eliad Pellerc87163b2014-01-08 10:11:11 +02001739{
Eliad Pellerc87163b2014-01-08 10:11:11 +02001740 struct iwl_bcast_iter_data iter_data = {
1741 .mvm = mvm,
Eliad Pellerde06a592014-01-08 10:11:12 +02001742 .cmd = cmd,
Eliad Pellerc87163b2014-01-08 10:11:11 +02001743 };
1744
Max Stepanov3b8983b2014-10-15 11:27:16 +03001745 if (IWL_MVM_FW_BCAST_FILTER_PASS_ALL)
1746 return false;
1747
Eliad Pellerde06a592014-01-08 10:11:12 +02001748 memset(cmd, 0, sizeof(*cmd));
1749 cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters);
1750 cmd->max_macs = ARRAY_SIZE(cmd->macs);
1751
1752#ifdef CONFIG_IWLWIFI_DEBUGFS
1753 /* use debugfs filters/macs if override is configured */
1754 if (mvm->dbgfs_bcast_filtering.override) {
1755 memcpy(cmd->filters, &mvm->dbgfs_bcast_filtering.cmd.filters,
1756 sizeof(cmd->filters));
1757 memcpy(cmd->macs, &mvm->dbgfs_bcast_filtering.cmd.macs,
1758 sizeof(cmd->macs));
1759 return true;
1760 }
1761#endif
Eliad Pellerc87163b2014-01-08 10:11:11 +02001762
1763 /* if no filters are configured, do nothing */
1764 if (!mvm->bcast_filters)
Eliad Pellerde06a592014-01-08 10:11:12 +02001765 return false;
Eliad Pellerc87163b2014-01-08 10:11:11 +02001766
1767 /* configure and attach these filters for each associated sta vif */
1768 ieee80211_iterate_active_interfaces(
1769 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1770 iwl_mvm_bcast_filter_iterator, &iter_data);
1771
Eliad Pellerde06a592014-01-08 10:11:12 +02001772 return true;
1773}
Eliad Peller34672bb2015-12-03 16:10:07 +02001774
1775static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm)
Eliad Pellerde06a592014-01-08 10:11:12 +02001776{
1777 struct iwl_bcast_filter_cmd cmd;
1778
1779 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING))
1780 return 0;
1781
1782 if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
1783 return 0;
1784
Emmanuel Grumbacha1022922014-05-12 11:36:41 +03001785 return iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
Eliad Pellerc87163b2014-01-08 10:11:11 +02001786 sizeof(cmd), &cmd);
1787}
1788#else
Eliad Peller34672bb2015-12-03 16:10:07 +02001789static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm)
Eliad Pellerc87163b2014-01-08 10:11:11 +02001790{
1791 return 0;
1792}
1793#endif
1794
Sara Sharona07a8f32015-11-15 11:11:59 +02001795static int iwl_mvm_update_mu_groups(struct iwl_mvm *mvm,
1796 struct ieee80211_vif *vif)
1797{
1798 struct iwl_mu_group_mgmt_cmd cmd = {};
1799
1800 memcpy(cmd.membership_status, vif->bss_conf.mu_group.membership,
1801 WLAN_MEMBERSHIP_LEN);
1802 memcpy(cmd.user_position, vif->bss_conf.mu_group.position,
1803 WLAN_USER_POSITION_LEN);
1804
1805 return iwl_mvm_send_cmd_pdu(mvm,
1806 WIDE_ID(DATA_PATH_GROUP,
1807 UPDATE_MU_GROUPS_CMD),
1808 0, sizeof(cmd), &cmd);
1809}
1810
Sara Sharonf92659a2016-02-03 15:04:49 +02001811static void iwl_mvm_mu_mimo_iface_iterator(void *_data, u8 *mac,
1812 struct ieee80211_vif *vif)
1813{
1814 if (vif->mu_mimo_owner) {
1815 struct iwl_mu_group_mgmt_notif *notif = _data;
1816
1817 /*
1818 * MU-MIMO Group Id action frame is little endian. We treat
1819 * the data received from firmware as if it came from the
1820 * action frame, so no conversion is needed.
1821 */
1822 ieee80211_update_mu_groups(vif,
1823 (u8 *)&notif->membership_status,
1824 (u8 *)&notif->user_position);
1825 }
1826}
1827
1828void iwl_mvm_mu_mimo_grp_notif(struct iwl_mvm *mvm,
1829 struct iwl_rx_cmd_buffer *rxb)
1830{
1831 struct iwl_rx_packet *pkt = rxb_addr(rxb);
1832 struct iwl_mu_group_mgmt_notif *notif = (void *)pkt->data;
1833
1834 ieee80211_iterate_active_interfaces_atomic(
1835 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1836 iwl_mvm_mu_mimo_iface_iterator, notif);
1837}
1838
Johannes Berg8ca151b2013-01-24 14:25:36 +01001839static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
1840 struct ieee80211_vif *vif,
1841 struct ieee80211_bss_conf *bss_conf,
1842 u32 changes)
1843{
1844 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1845 int ret;
1846
Ilan Peer6e97b0d2013-12-23 22:18:02 +02001847 /*
1848 * Re-calculate the tsf id, as the master-slave relations depend on the
1849 * beacon interval, which was not known when the station interface was
1850 * added.
1851 */
1852 if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc)
1853 iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
1854
Aviya Erenfeld03098262016-02-18 14:09:33 +02001855 if (changes & BSS_CHANGED_ASSOC && !bss_conf->assoc &&
1856 mvmvif->lqm_active)
1857 iwl_mvm_send_lqm_cmd(vif, LQM_CMD_OPERATION_STOP_MEASUREMENT,
1858 0, 0);
1859
Johannes Berg3dfd3a92014-08-11 21:37:30 +02001860 /*
1861 * If we're not associated yet, take the (new) BSSID before associating
1862 * so the firmware knows. If we're already associated, then use the old
1863 * BSSID here, and we'll send a cleared one later in the CHANGED_ASSOC
1864 * branch for disassociation below.
1865 */
1866 if (changes & BSS_CHANGED_BSSID && !mvmvif->associated)
1867 memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN);
1868
1869 ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, mvmvif->bssid);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001870 if (ret)
1871 IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
1872
Johannes Berg3dfd3a92014-08-11 21:37:30 +02001873 /* after sending it once, adopt mac80211 data */
1874 memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN);
1875 mvmvif->associated = bss_conf->assoc;
1876
Johannes Berg8ca151b2013-01-24 14:25:36 +01001877 if (changes & BSS_CHANGED_ASSOC) {
1878 if (bss_conf->assoc) {
Johannes Berg33cef922015-01-21 21:41:29 +01001879 /* clear statistics to get clean beacon counter */
1880 iwl_mvm_request_statistics(mvm, true);
1881 memset(&mvmvif->beacon_stats, 0,
1882 sizeof(mvmvif->beacon_stats));
1883
Johannes Berg8ca151b2013-01-24 14:25:36 +01001884 /* add quota for this interface */
Emmanuel Grumbach7754ae72015-02-26 15:14:35 +02001885 ret = iwl_mvm_update_quotas(mvm, true, NULL);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001886 if (ret) {
1887 IWL_ERR(mvm, "failed to update quotas\n");
1888 return;
1889 }
Johannes Berg016d27e2013-05-03 11:16:15 +02001890
1891 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
1892 &mvm->status)) {
1893 /*
1894 * If we're restarting then the firmware will
1895 * obviously have lost synchronisation with
1896 * the AP. It will attempt to synchronise by
1897 * itself, but we can make it more reliable by
1898 * scheduling a session protection time event.
1899 *
1900 * The firmware needs to receive a beacon to
1901 * catch up with synchronisation, use 110% of
1902 * the beacon interval.
1903 *
1904 * Set a large maximum delay to allow for more
1905 * than a single interface.
1906 */
1907 u32 dur = (11 * vif->bss_conf.beacon_int) / 10;
1908 iwl_mvm_protect_session(mvm, vif, dur, dur,
Liad Kaufmand20d37b2014-07-06 17:14:39 +03001909 5 * dur, false);
Johannes Berg016d27e2013-05-03 11:16:15 +02001910 }
Lilach Edelstein1f3b0ff2013-10-06 13:03:32 +02001911
1912 iwl_mvm_sf_update(mvm, vif, false);
Alexander Bondar175a70b2013-04-14 20:59:37 +03001913 iwl_mvm_power_vif_assoc(mvm, vif);
Emmanuel Grumbach697162a2014-07-30 15:56:42 +03001914 if (vif->p2p) {
Eliad Peller29a90a42013-11-05 14:06:29 +02001915 iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT);
Emmanuel Grumbach697162a2014-07-30 15:56:42 +03001916 iwl_mvm_update_smps(mvm, vif,
1917 IWL_MVM_SMPS_REQ_PROT,
1918 IEEE80211_SMPS_DYNAMIC);
1919 }
Johannes Berg8ca151b2013-01-24 14:25:36 +01001920 } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
Lilach Edelstein1f3b0ff2013-10-06 13:03:32 +02001921 /*
1922 * If update fails - SF might be running in associated
1923 * mode while disassociated - which is forbidden.
1924 */
1925 WARN_ONCE(iwl_mvm_sf_update(mvm, vif, false),
1926 "Failed to update SF upon disassociation\n");
1927
Johannes Berg8ca151b2013-01-24 14:25:36 +01001928 /* remove AP station now that the MAC is unassoc */
1929 ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
1930 if (ret)
1931 IWL_ERR(mvm, "failed to remove AP station\n");
Eliad Peller37577fe2013-12-05 17:19:39 +02001932
1933 if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id)
1934 mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
Johannes Berg8ca151b2013-01-24 14:25:36 +01001935 mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
1936 /* remove quota for this interface */
Emmanuel Grumbach7754ae72015-02-26 15:14:35 +02001937 ret = iwl_mvm_update_quotas(mvm, false, NULL);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001938 if (ret)
1939 IWL_ERR(mvm, "failed to update quotas\n");
Eliad Peller29a90a42013-11-05 14:06:29 +02001940
1941 if (vif->p2p)
1942 iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT);
Johannes Berg3dfd3a92014-08-11 21:37:30 +02001943
1944 /* this will take the cleared BSSID from bss_conf */
1945 ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
1946 if (ret)
1947 IWL_ERR(mvm,
1948 "failed to update MAC %pM (clear after unassoc)\n",
1949 vif->addr);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001950 }
Andrei Otcheretianskia20fd392013-07-21 17:23:59 +03001951
Sara Sharona07a8f32015-11-15 11:11:59 +02001952 /*
1953 * The firmware tracks the MU-MIMO group on its own.
Sara Sharonf92659a2016-02-03 15:04:49 +02001954 * However, on HW restart we should restore this data.
Sara Sharona07a8f32015-11-15 11:11:59 +02001955 */
1956 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
Sara Sharonf92659a2016-02-03 15:04:49 +02001957 (changes & BSS_CHANGED_MU_GROUPS) && vif->mu_mimo_owner) {
Sara Sharona07a8f32015-11-15 11:11:59 +02001958 ret = iwl_mvm_update_mu_groups(mvm, vif);
1959 if (ret)
1960 IWL_ERR(mvm,
1961 "failed to update VHT MU_MIMO groups\n");
1962 }
1963
Eliad Pellere59647e2013-11-28 14:08:50 +02001964 iwl_mvm_recalc_multicast(mvm);
Eliad Peller34672bb2015-12-03 16:10:07 +02001965 iwl_mvm_configure_bcast_filter(mvm);
Eliad Pellere59647e2013-11-28 14:08:50 +02001966
Andrei Otcheretianskia20fd392013-07-21 17:23:59 +03001967 /* reset rssi values */
1968 mvmvif->bf_data.ave_beacon_signal = 0;
1969
Emmanuel Grumbach8e484f02013-10-02 15:02:25 +03001970 iwl_mvm_bt_coex_vif_change(mvm);
Emmanuel Grumbachf94045e2014-01-06 13:38:55 +02001971 iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT,
1972 IEEE80211_SMPS_AUTOMATIC);
Avraham Stern355346b2015-11-26 11:22:33 +02001973 if (fw_has_capa(&mvm->fw->ucode_capa,
1974 IWL_UCODE_TLV_CAPA_UMAC_SCAN))
1975 iwl_mvm_config_scan(mvm);
Alexander Bondar989c6502013-05-16 17:34:17 +03001976 } else if (changes & BSS_CHANGED_BEACON_INFO) {
Johannes Berg210a5442013-01-24 23:48:23 +01001977 /*
1978 * We received a beacon _after_ association so
1979 * remove the session protection.
1980 */
1981 iwl_mvm_remove_time_event(mvm, mvmvif,
1982 &mvmvif->time_event_data);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001983 }
Eran Hararycc87d322014-07-15 14:04:23 +03001984
1985 if (changes & BSS_CHANGED_BEACON_INFO) {
1986 iwl_mvm_sf_update(mvm, vif, false);
1987 WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
1988 }
1989
Avri Altman283115f2016-01-24 22:16:08 +02001990 if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS |
1991 /*
1992 * Send power command on every beacon change,
1993 * because we may have not enabled beacon abort yet.
1994 */
1995 BSS_CHANGED_BEACON_INFO)) {
Johannes Berg1bc10d32014-08-26 14:25:46 +02001996 ret = iwl_mvm_power_update_mac(mvm);
1997 if (ret)
1998 IWL_ERR(mvm, "failed to update power mode\n");
1999 }
2000
Matti Gottlieb88f2fd72013-07-09 15:25:46 +03002001 if (changes & BSS_CHANGED_TXPOWER) {
2002 IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n",
2003 bss_conf->txpower);
2004 iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower);
2005 }
Andrei Otcheretianskia20fd392013-07-21 17:23:59 +03002006
2007 if (changes & BSS_CHANGED_CQM) {
Johannes Berg3c6acb62014-05-07 11:47:53 +02002008 IWL_DEBUG_MAC80211(mvm, "cqm info_changed\n");
Andrei Otcheretianskia20fd392013-07-21 17:23:59 +03002009 /* reset cqm events tracking */
2010 mvmvif->bf_data.last_cqm_event = 0;
Avri Altmanfa7b2e72014-05-20 08:03:24 +03002011 if (mvmvif->bf_data.bf_enabled) {
2012 ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0);
2013 if (ret)
2014 IWL_ERR(mvm,
2015 "failed to update CQM thresholds\n");
2016 }
Andrei Otcheretianskia20fd392013-07-21 17:23:59 +03002017 }
Eliad Peller2ee8f022014-01-13 19:07:09 +02002018
2019 if (changes & BSS_CHANGED_ARP_FILTER) {
Johannes Berg3c6acb62014-05-07 11:47:53 +02002020 IWL_DEBUG_MAC80211(mvm, "arp filter changed\n");
Eliad Peller34672bb2015-12-03 16:10:07 +02002021 iwl_mvm_configure_bcast_filter(mvm);
Eliad Peller2ee8f022014-01-13 19:07:09 +02002022 }
Johannes Berg8ca151b2013-01-24 14:25:36 +01002023}
2024
Johannes Berg5023d962013-07-31 14:07:43 +02002025static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
2026 struct ieee80211_vif *vif)
Johannes Berg8ca151b2013-01-24 14:25:36 +01002027{
2028 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2029 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
2030 int ret;
2031
Eliad Peller576eeee2014-07-01 18:38:38 +03002032 /*
2033 * iwl_mvm_mac_ctxt_add() might read directly from the device
2034 * (the system time), so make sure it is available.
2035 */
2036 ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_START_AP);
2037 if (ret)
2038 return ret;
2039
Johannes Berg8ca151b2013-01-24 14:25:36 +01002040 mutex_lock(&mvm->mutex);
2041
2042 /* Send the beacon template */
2043 ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif);
2044 if (ret)
2045 goto out_unlock;
2046
Ilan Peer6e97b0d2013-12-23 22:18:02 +02002047 /*
2048 * Re-calculate the tsf id, as the master-slave relations depend on the
2049 * beacon interval, which was not known when the AP interface was added.
2050 */
2051 if (vif->type == NL80211_IFTYPE_AP)
2052 iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
2053
Gregory Greenman94939082015-08-24 14:38:35 +03002054 mvmvif->ap_assoc_sta_count = 0;
2055
Johannes Berg8ca151b2013-01-24 14:25:36 +01002056 /* Add the mac context */
2057 ret = iwl_mvm_mac_ctxt_add(mvm, vif);
2058 if (ret)
2059 goto out_unlock;
2060
2061 /* Perform the binding */
2062 ret = iwl_mvm_binding_add_vif(mvm, vif);
2063 if (ret)
2064 goto out_remove;
2065
Johannes Berg8ca151b2013-01-24 14:25:36 +01002066 /* Send the bcast station. At this stage the TBTT and DTIM time events
2067 * are added and applied to the scheduler */
Johannes Berg013290a2014-08-04 13:38:48 +02002068 ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002069 if (ret)
2070 goto out_unbind;
2071
Ilan Peer5691e212013-12-31 21:05:50 +02002072 /* must be set before quota calculations */
2073 mvmvif->ap_ibss_active = true;
2074
Ilan Peera11e1442013-12-31 21:19:55 +02002075 /* power updated needs to be done before quotas */
Arik Nemtsov999609f2014-05-15 17:31:51 +03002076 iwl_mvm_power_update_mac(mvm);
Ilan Peera11e1442013-12-31 21:19:55 +02002077
Emmanuel Grumbach7754ae72015-02-26 15:14:35 +02002078 ret = iwl_mvm_update_quotas(mvm, false, NULL);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002079 if (ret)
Ilan Peera11e1442013-12-31 21:19:55 +02002080 goto out_quota_failed;
Johannes Berg8ca151b2013-01-24 14:25:36 +01002081
Johannes Berg5023d962013-07-31 14:07:43 +02002082 /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
Johannes Berg8ca151b2013-01-24 14:25:36 +01002083 if (vif->p2p && mvm->p2p_device_vif)
Johannes Berg3dfd3a92014-08-11 21:37:30 +02002084 iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002085
Eliad Peller29a90a42013-11-05 14:06:29 +02002086 iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS);
2087
Emmanuel Grumbach8e484f02013-10-02 15:02:25 +03002088 iwl_mvm_bt_coex_vif_change(mvm);
Emmanuel Grumbachdac94da2013-06-18 07:35:27 +03002089
Arik Nemtsovf6972672014-06-15 16:03:55 +03002090 /* we don't support TDLS during DCM */
2091 if (iwl_mvm_phy_ctx_count(mvm) > 1)
2092 iwl_mvm_teardown_tdls_peers(mvm);
2093
Arik Nemtsov939e4902015-03-08 12:19:42 +02002094 goto out_unlock;
Johannes Berg8ca151b2013-01-24 14:25:36 +01002095
Ilan Peera11e1442013-12-31 21:19:55 +02002096out_quota_failed:
Arik Nemtsov999609f2014-05-15 17:31:51 +03002097 iwl_mvm_power_update_mac(mvm);
Ilan Peer5691e212013-12-31 21:05:50 +02002098 mvmvif->ap_ibss_active = false;
Johannes Berg013290a2014-08-04 13:38:48 +02002099 iwl_mvm_send_rm_bcast_sta(mvm, vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002100out_unbind:
2101 iwl_mvm_binding_remove_vif(mvm, vif);
2102out_remove:
2103 iwl_mvm_mac_ctxt_remove(mvm, vif);
2104out_unlock:
2105 mutex_unlock(&mvm->mutex);
Eliad Peller576eeee2014-07-01 18:38:38 +03002106 iwl_mvm_unref(mvm, IWL_MVM_REF_START_AP);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002107 return ret;
2108}
2109
Johannes Berg5023d962013-07-31 14:07:43 +02002110static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
2111 struct ieee80211_vif *vif)
Johannes Berg8ca151b2013-01-24 14:25:36 +01002112{
2113 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2114 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
2115
Johannes Berg38a12b52013-02-22 14:07:56 +01002116 iwl_mvm_prepare_mac_removal(mvm, vif);
2117
Johannes Berg8ca151b2013-01-24 14:25:36 +01002118 mutex_lock(&mvm->mutex);
2119
Andrei Otcheretianski664322f2014-06-05 16:40:36 +03002120 /* Handle AP stop while in CSA */
Andrei Otcheretianski7f0a7c62014-05-04 11:48:12 +03002121 if (rcu_access_pointer(mvm->csa_vif) == vif) {
2122 iwl_mvm_remove_time_event(mvm, mvmvif,
2123 &mvmvif->time_event_data);
Andrei Otcheretianski664322f2014-06-05 16:40:36 +03002124 RCU_INIT_POINTER(mvm->csa_vif, NULL);
Avraham Sterne9cb0322015-08-31 11:08:27 +03002125 mvmvif->csa_countdown = false;
Andrei Otcheretianski7f0a7c62014-05-04 11:48:12 +03002126 }
Andrei Otcheretianski664322f2014-06-05 16:40:36 +03002127
Andrei Otcheretianski003e52362014-05-25 17:24:22 +03002128 if (rcu_access_pointer(mvm->csa_tx_blocked_vif) == vif) {
2129 RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL);
2130 mvm->csa_tx_block_bcn_timeout = 0;
2131 }
2132
Johannes Berg5023d962013-07-31 14:07:43 +02002133 mvmvif->ap_ibss_active = false;
David Spinadel1c87bba2014-02-27 16:41:52 +02002134 mvm->ap_last_beacon_gp2 = 0;
Johannes Berg8ca151b2013-01-24 14:25:36 +01002135
Emmanuel Grumbach8e484f02013-10-02 15:02:25 +03002136 iwl_mvm_bt_coex_vif_change(mvm);
Emmanuel Grumbachdac94da2013-06-18 07:35:27 +03002137
Eliad Peller29a90a42013-11-05 14:06:29 +02002138 iwl_mvm_unref(mvm, IWL_MVM_REF_AP_IBSS);
2139
Johannes Berg5023d962013-07-31 14:07:43 +02002140 /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
Johannes Berg8ca151b2013-01-24 14:25:36 +01002141 if (vif->p2p && mvm->p2p_device_vif)
Johannes Berg3dfd3a92014-08-11 21:37:30 +02002142 iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002143
Emmanuel Grumbach7754ae72015-02-26 15:14:35 +02002144 iwl_mvm_update_quotas(mvm, false, NULL);
Johannes Berg013290a2014-08-04 13:38:48 +02002145 iwl_mvm_send_rm_bcast_sta(mvm, vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002146 iwl_mvm_binding_remove_vif(mvm, vif);
Ilan Peera11e1442013-12-31 21:19:55 +02002147
Arik Nemtsov999609f2014-05-15 17:31:51 +03002148 iwl_mvm_power_update_mac(mvm);
Ilan Peera11e1442013-12-31 21:19:55 +02002149
Johannes Berg8ca151b2013-01-24 14:25:36 +01002150 iwl_mvm_mac_ctxt_remove(mvm, vif);
2151
2152 mutex_unlock(&mvm->mutex);
2153}
2154
Johannes Berg5023d962013-07-31 14:07:43 +02002155static void
2156iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
2157 struct ieee80211_vif *vif,
2158 struct ieee80211_bss_conf *bss_conf,
2159 u32 changes)
Johannes Berg8ca151b2013-01-24 14:25:36 +01002160{
Ilan Peerbe2056f2013-12-04 16:47:14 +02002161 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
Avri Altman8a5e3662013-11-12 19:16:03 +02002162
Ilan Peerbe2056f2013-12-04 16:47:14 +02002163 /* Changes will be applied when the AP/IBSS is started */
2164 if (!mvmvif->ap_ibss_active)
2165 return;
2166
Johannes Berg863230da2013-12-04 17:08:40 +01002167 if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT |
Johannes Bergf7d8b702014-09-09 15:49:19 +02002168 BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS) &&
Johannes Berg3dfd3a92014-08-11 21:37:30 +02002169 iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL))
Johannes Berg863230da2013-12-04 17:08:40 +01002170 IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
Avri Altman8a5e3662013-11-12 19:16:03 +02002171
Johannes Berg8ca151b2013-01-24 14:25:36 +01002172 /* Need to send a new beacon template to the FW */
Johannes Berg863230da2013-12-04 17:08:40 +01002173 if (changes & BSS_CHANGED_BEACON &&
2174 iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
2175 IWL_WARN(mvm, "Failed updating beacon data\n");
Haim Dreyfuss79b7a692014-09-14 12:40:00 +03002176
2177 if (changes & BSS_CHANGED_TXPOWER) {
2178 IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n",
2179 bss_conf->txpower);
2180 iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower);
2181 }
Johannes Berg8ca151b2013-01-24 14:25:36 +01002182}
2183
2184static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
2185 struct ieee80211_vif *vif,
2186 struct ieee80211_bss_conf *bss_conf,
2187 u32 changes)
2188{
2189 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2190
Eliad Peller576eeee2014-07-01 18:38:38 +03002191 /*
2192 * iwl_mvm_bss_info_changed_station() might call
2193 * iwl_mvm_protect_session(), which reads directly from
2194 * the device (the system time), so make sure it is available.
2195 */
2196 if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_BSS_CHANGED))
2197 return;
2198
Johannes Berg8ca151b2013-01-24 14:25:36 +01002199 mutex_lock(&mvm->mutex);
2200
David Spinadel723f02e2014-04-27 09:54:54 +03002201 if (changes & BSS_CHANGED_IDLE && !bss_conf->idle)
Luciano Coelhoc7d42482015-05-07 16:00:26 +03002202 iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true);
David Spinadel723f02e2014-04-27 09:54:54 +03002203
Johannes Berg8ca151b2013-01-24 14:25:36 +01002204 switch (vif->type) {
2205 case NL80211_IFTYPE_STATION:
2206 iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes);
2207 break;
2208 case NL80211_IFTYPE_AP:
Johannes Berg5023d962013-07-31 14:07:43 +02002209 case NL80211_IFTYPE_ADHOC:
2210 iwl_mvm_bss_info_changed_ap_ibss(mvm, vif, bss_conf, changes);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002211 break;
2212 default:
2213 /* shouldn't happen */
2214 WARN_ON_ONCE(1);
2215 }
2216
2217 mutex_unlock(&mvm->mutex);
Eliad Peller576eeee2014-07-01 18:38:38 +03002218 iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002219}
2220
2221static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
2222 struct ieee80211_vif *vif,
David Spinadelc56ef672014-02-05 15:21:13 +02002223 struct ieee80211_scan_request *hw_req)
Johannes Berg8ca151b2013-01-24 14:25:36 +01002224{
2225 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2226 int ret;
2227
Luciano Coelho6749dd82015-03-20 15:51:36 +02002228 if (hw_req->req.n_channels == 0 ||
2229 hw_req->req.n_channels > mvm->fw->ucode_capa.n_scan_channels)
Johannes Berg8ca151b2013-01-24 14:25:36 +01002230 return -EINVAL;
2231
2232 mutex_lock(&mvm->mutex);
Luciano Coelho6749dd82015-03-20 15:51:36 +02002233 ret = iwl_mvm_reg_scan_start(mvm, vif, &hw_req->req, &hw_req->ies);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002234 mutex_unlock(&mvm->mutex);
Luciano Coelho6749dd82015-03-20 15:51:36 +02002235
Johannes Berg8ca151b2013-01-24 14:25:36 +01002236 return ret;
2237}
2238
2239static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw,
2240 struct ieee80211_vif *vif)
2241{
2242 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2243
2244 mutex_lock(&mvm->mutex);
2245
Luciano Coelhoe7d3aba2015-02-06 10:19:05 +02002246 /* Due to a race condition, it's possible that mac80211 asks
2247 * us to stop a hw_scan when it's already stopped. This can
2248 * happen, for instance, if we stopped the scan ourselves,
2249 * called ieee80211_scan_completed() and the userspace called
2250 * cancel scan scan before ieee80211_scan_work() could run.
2251 * To handle that, simply return if the scan is not running.
2252 */
Luciano Coelho262888f2015-05-07 17:21:09 +03002253 if (mvm->scan_status & IWL_MVM_SCAN_REGULAR)
Luciano Coelhoc7d42482015-05-07 16:00:26 +03002254 iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002255
2256 mutex_unlock(&mvm->mutex);
2257}
2258
2259static void
2260iwl_mvm_mac_allow_buffered_frames(struct ieee80211_hw *hw,
Johannes Berg3e56ead2013-02-15 22:23:18 +01002261 struct ieee80211_sta *sta, u16 tids,
Johannes Berg8ca151b2013-01-24 14:25:36 +01002262 int num_frames,
2263 enum ieee80211_frame_release_type reason,
2264 bool more_data)
2265{
2266 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002267
Johannes Berg3e56ead2013-02-15 22:23:18 +01002268 /* Called when we need to transmit (a) frame(s) from mac80211 */
Johannes Berg8ca151b2013-01-24 14:25:36 +01002269
Johannes Berg3e56ead2013-02-15 22:23:18 +01002270 iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames,
2271 tids, more_data, false);
2272}
2273
2274static void
2275iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw,
2276 struct ieee80211_sta *sta, u16 tids,
2277 int num_frames,
2278 enum ieee80211_frame_release_type reason,
2279 bool more_data)
2280{
2281 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2282
2283 /* Called when we need to transmit (a) frame(s) from agg queue */
2284
2285 iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames,
2286 tids, more_data, true);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002287}
2288
2289static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
2290 struct ieee80211_vif *vif,
2291 enum sta_notify_cmd cmd,
2292 struct ieee80211_sta *sta)
2293{
2294 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Johannes Berg5b577a92013-11-14 18:20:04 +01002295 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
Emmanuel Grumbachc22b0ff2015-01-22 13:15:15 +02002296 unsigned long txqs = 0, tids = 0;
Johannes Berg3e56ead2013-02-15 22:23:18 +01002297 int tid;
Johannes Berg8ca151b2013-01-24 14:25:36 +01002298
Emmanuel Grumbachc22b0ff2015-01-22 13:15:15 +02002299 spin_lock_bh(&mvmsta->lock);
2300 for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
2301 struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
2302
2303 if (tid_data->state != IWL_AGG_ON &&
2304 tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA)
2305 continue;
2306
2307 __set_bit(tid_data->txq_id, &txqs);
2308
2309 if (iwl_mvm_tid_queued(tid_data) == 0)
2310 continue;
2311
2312 __set_bit(tid, &tids);
2313 }
2314
Johannes Berg8ca151b2013-01-24 14:25:36 +01002315 switch (cmd) {
2316 case STA_NOTIFY_SLEEP:
Emmanuel Grumbache3d4bc82013-05-07 14:08:24 +03002317 if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0)
Johannes Berg8ca151b2013-01-24 14:25:36 +01002318 ieee80211_sta_block_awake(hw, sta, true);
Johannes Berg3e56ead2013-02-15 22:23:18 +01002319
Emmanuel Grumbachc22b0ff2015-01-22 13:15:15 +02002320 for_each_set_bit(tid, &tids, IWL_MAX_TID_COUNT)
Johannes Berg3e56ead2013-02-15 22:23:18 +01002321 ieee80211_sta_set_buffered(sta, tid, true);
Emmanuel Grumbachc22b0ff2015-01-22 13:15:15 +02002322
2323 if (txqs)
2324 iwl_trans_freeze_txq_timer(mvm->trans, txqs, true);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002325 /*
2326 * The fw updates the STA to be asleep. Tx packets on the Tx
2327 * queues to this station will not be transmitted. The fw will
2328 * send a Tx response with TX_STATUS_FAIL_DEST_PS.
2329 */
2330 break;
2331 case STA_NOTIFY_AWAKE:
Emmanuel Grumbach881acd82013-03-19 16:16:00 +02002332 if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT))
Johannes Berg8ca151b2013-01-24 14:25:36 +01002333 break;
Emmanuel Grumbachc22b0ff2015-01-22 13:15:15 +02002334
2335 if (txqs)
2336 iwl_trans_freeze_txq_timer(mvm->trans, txqs, false);
Johannes Berg9cc40712013-02-15 22:47:48 +01002337 iwl_mvm_sta_modify_ps_wake(mvm, sta);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002338 break;
2339 default:
2340 break;
2341 }
Emmanuel Grumbachc22b0ff2015-01-22 13:15:15 +02002342 spin_unlock_bh(&mvmsta->lock);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002343}
2344
Johannes Berg1ddbbb02013-12-04 22:39:17 +01002345static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
2346 struct ieee80211_vif *vif,
2347 struct ieee80211_sta *sta)
2348{
2349 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Johannes Berg9d8ce6a2014-12-23 16:02:40 +01002350 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
Johannes Berg1ddbbb02013-12-04 22:39:17 +01002351
2352 /*
2353 * This is called before mac80211 does RCU synchronisation,
2354 * so here we already invalidate our internal RCU-protected
2355 * station pointer. The rest of the code will thus no longer
2356 * be able to find the station this way, and we don't rely
2357 * on further RCU synchronisation after the sta_state()
2358 * callback deleted the station.
2359 */
2360 mutex_lock(&mvm->mutex);
2361 if (sta == rcu_access_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id]))
2362 rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
2363 ERR_PTR(-ENOENT));
Gregory Greenman94939082015-08-24 14:38:35 +03002364
Johannes Berg1ddbbb02013-12-04 22:39:17 +01002365 mutex_unlock(&mvm->mutex);
2366}
2367
Johannes Bergbd1ba662014-11-13 20:53:45 +01002368static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
2369 const u8 *bssid)
2370{
2371 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT))
2372 return;
2373
Avraham Sternc5241b02016-04-20 09:29:18 +03002374 if (vif->p2p && !iwl_mvm_is_p2p_scm_uapsd_supported(mvm)) {
Avri Altmancee5a882016-02-03 16:28:25 +02002375 vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
2376 return;
2377 }
2378
Emmanuel Grumbach11dee0b2016-03-15 11:04:29 +02002379 if (!vif->p2p &&
2380 (iwlwifi_mod_params.uapsd_disable & IWL_DISABLE_UAPSD_BSS)) {
Johannes Bergbd1ba662014-11-13 20:53:45 +01002381 vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
2382 return;
2383 }
2384
2385 vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
2386}
2387
Golan Ben-Ami1e8f1322015-08-23 17:57:33 +03002388static void
2389iwl_mvm_tdls_check_trigger(struct iwl_mvm *mvm,
2390 struct ieee80211_vif *vif, u8 *peer_addr,
2391 enum nl80211_tdls_operation action)
2392{
2393 struct iwl_fw_dbg_trigger_tlv *trig;
2394 struct iwl_fw_dbg_trigger_tdls *tdls_trig;
2395
2396 if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TDLS))
2397 return;
2398
2399 trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TDLS);
2400 tdls_trig = (void *)trig->data;
2401 if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
2402 return;
2403
2404 if (!(tdls_trig->action_bitmap & BIT(action)))
2405 return;
2406
2407 if (tdls_trig->peer_mode &&
2408 memcmp(tdls_trig->peer, peer_addr, ETH_ALEN) != 0)
2409 return;
2410
2411 iwl_mvm_fw_dbg_collect_trig(mvm, trig,
2412 "TDLS event occurred, peer %pM, action %d",
2413 peer_addr, action);
2414}
2415
Liad Kaufman24afba72015-07-28 18:56:08 +03002416static void iwl_mvm_purge_deferred_tx_frames(struct iwl_mvm *mvm,
2417 struct iwl_mvm_sta *mvm_sta)
2418{
2419 struct iwl_mvm_tid_data *tid_data;
2420 struct sk_buff *skb;
2421 int i;
2422
2423 spin_lock_bh(&mvm_sta->lock);
2424 for (i = 0; i <= IWL_MAX_TID_COUNT; i++) {
2425 tid_data = &mvm_sta->tid_data[i];
2426 while ((skb = __skb_dequeue(&tid_data->deferred_tx_frames)))
2427 ieee80211_free_txskb(mvm->hw, skb);
2428 }
2429 spin_unlock_bh(&mvm_sta->lock);
2430}
2431
Johannes Berg8ca151b2013-01-24 14:25:36 +01002432static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
2433 struct ieee80211_vif *vif,
2434 struct ieee80211_sta *sta,
2435 enum ieee80211_sta_state old_state,
2436 enum ieee80211_sta_state new_state)
2437{
2438 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2439 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
2440 int ret;
2441
2442 IWL_DEBUG_MAC80211(mvm, "station %pM state change %d->%d\n",
2443 sta->addr, old_state, new_state);
2444
2445 /* this would be a mac80211 bug ... but don't crash */
2446 if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
2447 return -EINVAL;
2448
2449 /* if a STA is being removed, reuse its ID */
2450 flush_work(&mvm->sta_drained_wk);
2451
Liad Kaufman24afba72015-07-28 18:56:08 +03002452 /*
2453 * If we are in a STA removal flow and in DQA mode:
2454 *
2455 * This is after the sync_rcu part, so the queues have already been
2456 * flushed. No more TXs on their way in mac80211's path, and no more in
2457 * the queues.
2458 * Also, we won't be getting any new TX frames for this station.
2459 * What we might have are deferred TX frames that need to be taken care
2460 * of.
2461 *
2462 * Drop any still-queued deferred-frame before removing the STA, and
2463 * make sure the worker is no longer handling frames for this STA.
2464 */
2465 if (old_state == IEEE80211_STA_NONE &&
2466 new_state == IEEE80211_STA_NOTEXIST &&
2467 iwl_mvm_is_dqa_supported(mvm)) {
2468 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
2469
2470 iwl_mvm_purge_deferred_tx_frames(mvm, mvm_sta);
2471 flush_work(&mvm->add_stream_wk);
2472
2473 /*
2474 * No need to make sure deferred TX indication is off since the
2475 * worker will already remove it if it was on
2476 */
2477 }
2478
Johannes Berg8ca151b2013-01-24 14:25:36 +01002479 mutex_lock(&mvm->mutex);
2480 if (old_state == IEEE80211_STA_NOTEXIST &&
2481 new_state == IEEE80211_STA_NONE) {
Johannes Berg48bc1302013-07-04 15:55:29 +02002482 /*
2483 * Firmware bug - it'll crash if the beacon interval is less
2484 * than 16. We can't avoid connecting at all, so refuse the
2485 * station state change, this will cause mac80211 to abandon
2486 * attempts to connect to this AP, and eventually wpa_s will
2487 * blacklist the AP...
2488 */
2489 if (vif->type == NL80211_IFTYPE_STATION &&
2490 vif->bss_conf.beacon_int < 16) {
2491 IWL_ERR(mvm,
2492 "AP %pM beacon interval is %d, refusing due to firmware bug!\n",
2493 sta->addr, vif->bss_conf.beacon_int);
2494 ret = -EINVAL;
2495 goto out_unlock;
2496 }
Arik Nemtsovcf7b4912014-05-15 11:44:40 +03002497
2498 if (sta->tdls &&
2499 (vif->p2p ||
Arik Nemtsovfa3d07e2014-05-15 18:59:32 +03002500 iwl_mvm_tdls_sta_count(mvm, NULL) ==
2501 IWL_MVM_TDLS_STA_COUNT ||
Arik Nemtsovcf7b4912014-05-15 11:44:40 +03002502 iwl_mvm_phy_ctx_count(mvm) > 1)) {
2503 IWL_DEBUG_MAC80211(mvm, "refusing TDLS sta\n");
2504 ret = -EBUSY;
2505 goto out_unlock;
2506 }
2507
Johannes Berg8ca151b2013-01-24 14:25:36 +01002508 ret = iwl_mvm_add_sta(mvm, vif, sta);
Golan Ben-Ami1e8f1322015-08-23 17:57:33 +03002509 if (sta->tdls && ret == 0) {
Arik Nemtsovfa3d07e2014-05-15 18:59:32 +03002510 iwl_mvm_recalc_tdls_state(mvm, vif, true);
Golan Ben-Ami1e8f1322015-08-23 17:57:33 +03002511 iwl_mvm_tdls_check_trigger(mvm, vif, sta->addr,
2512 NL80211_TDLS_SETUP);
2513 }
Johannes Berg8ca151b2013-01-24 14:25:36 +01002514 } else if (old_state == IEEE80211_STA_NONE &&
2515 new_state == IEEE80211_STA_AUTH) {
Haim Dreyfusse820c2d2014-04-06 11:19:09 +03002516 /*
2517 * EBS may be disabled due to previous failures reported by FW.
2518 * Reset EBS status here assuming environment has been changed.
2519 */
2520 mvm->last_ebs_successful = true;
Johannes Bergbd1ba662014-11-13 20:53:45 +01002521 iwl_mvm_check_uapsd(mvm, vif, sta->addr);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002522 ret = 0;
2523 } else if (old_state == IEEE80211_STA_AUTH &&
2524 new_state == IEEE80211_STA_ASSOC) {
Ayala Beker8be30c12015-12-16 00:32:07 +02002525 if (vif->type == NL80211_IFTYPE_AP) {
2526 mvmvif->ap_assoc_sta_count++;
2527 iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
2528 }
Johannes Berg7a453972013-02-12 13:10:44 +01002529 ret = iwl_mvm_update_sta(mvm, vif, sta);
2530 if (ret == 0)
2531 iwl_mvm_rs_rate_init(mvm, sta,
Eyal Shapirab87c2172013-11-09 23:37:55 +02002532 mvmvif->phy_ctxt->channel->band,
2533 true);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002534 } else if (old_state == IEEE80211_STA_ASSOC &&
2535 new_state == IEEE80211_STA_AUTHORIZED) {
Arik Nemtsovf59e0e3c2014-06-10 19:56:27 +03002536
2537 /* we don't support TDLS during DCM */
2538 if (iwl_mvm_phy_ctx_count(mvm) > 1)
2539 iwl_mvm_teardown_tdls_peers(mvm);
2540
Golan Ben-Ami1e8f1322015-08-23 17:57:33 +03002541 if (sta->tdls)
2542 iwl_mvm_tdls_check_trigger(mvm, vif, sta->addr,
2543 NL80211_TDLS_ENABLE_LINK);
2544
Hila Gonen7df15b12012-12-12 11:16:19 +02002545 /* enable beacon filtering */
Avri Altmanfa7b2e72014-05-20 08:03:24 +03002546 WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
Johannes Berg8ca151b2013-01-24 14:25:36 +01002547 ret = 0;
2548 } else if (old_state == IEEE80211_STA_AUTHORIZED &&
2549 new_state == IEEE80211_STA_ASSOC) {
Hila Gonen7df15b12012-12-12 11:16:19 +02002550 /* disable beacon filtering */
Emmanuel Grumbacha1022922014-05-12 11:36:41 +03002551 WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif, 0));
Johannes Berg8ca151b2013-01-24 14:25:36 +01002552 ret = 0;
2553 } else if (old_state == IEEE80211_STA_ASSOC &&
2554 new_state == IEEE80211_STA_AUTH) {
Ayala Beker8be30c12015-12-16 00:32:07 +02002555 if (vif->type == NL80211_IFTYPE_AP) {
2556 mvmvif->ap_assoc_sta_count--;
2557 iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
2558 }
Johannes Berg8ca151b2013-01-24 14:25:36 +01002559 ret = 0;
2560 } else if (old_state == IEEE80211_STA_AUTH &&
2561 new_state == IEEE80211_STA_NONE) {
2562 ret = 0;
2563 } else if (old_state == IEEE80211_STA_NONE &&
2564 new_state == IEEE80211_STA_NOTEXIST) {
2565 ret = iwl_mvm_rm_sta(mvm, vif, sta);
Golan Ben-Ami1e8f1322015-08-23 17:57:33 +03002566 if (sta->tdls) {
Arik Nemtsovfa3d07e2014-05-15 18:59:32 +03002567 iwl_mvm_recalc_tdls_state(mvm, vif, false);
Golan Ben-Ami1e8f1322015-08-23 17:57:33 +03002568 iwl_mvm_tdls_check_trigger(mvm, vif, sta->addr,
2569 NL80211_TDLS_DISABLE_LINK);
2570 }
Johannes Berg8ca151b2013-01-24 14:25:36 +01002571 } else {
2572 ret = -EIO;
2573 }
Johannes Berg48bc1302013-07-04 15:55:29 +02002574 out_unlock:
Johannes Berg8ca151b2013-01-24 14:25:36 +01002575 mutex_unlock(&mvm->mutex);
2576
Liad Kaufman9c126cd2014-10-06 19:08:56 +02002577 if (sta->tdls && ret == 0) {
2578 if (old_state == IEEE80211_STA_NOTEXIST &&
2579 new_state == IEEE80211_STA_NONE)
2580 ieee80211_reserve_tid(sta, IWL_MVM_TDLS_FW_TID);
2581 else if (old_state == IEEE80211_STA_NONE &&
2582 new_state == IEEE80211_STA_NOTEXIST)
2583 ieee80211_unreserve_tid(sta, IWL_MVM_TDLS_FW_TID);
2584 }
2585
Johannes Berg8ca151b2013-01-24 14:25:36 +01002586 return ret;
2587}
2588
2589static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2590{
2591 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2592
2593 mvm->rts_threshold = value;
2594
2595 return 0;
2596}
2597
Lilach Edelstein1f3b0ff2013-10-06 13:03:32 +02002598static void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw,
2599 struct ieee80211_vif *vif,
2600 struct ieee80211_sta *sta, u32 changed)
2601{
2602 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2603
2604 if (vif->type == NL80211_IFTYPE_STATION &&
2605 changed & IEEE80211_RC_NSS_CHANGED)
2606 iwl_mvm_sf_update(mvm, vif, false);
2607}
2608
Johannes Berg8ca151b2013-01-24 14:25:36 +01002609static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw,
2610 struct ieee80211_vif *vif, u16 ac,
2611 const struct ieee80211_tx_queue_params *params)
2612{
2613 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2614 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
2615
2616 mvmvif->queue_params[ac] = *params;
2617
2618 /*
2619 * No need to update right away, we'll get BSS_CHANGED_QOS
2620 * The exception is P2P_DEVICE interface which needs immediate update.
2621 */
2622 if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
2623 int ret;
2624
2625 mutex_lock(&mvm->mutex);
Johannes Berg3dfd3a92014-08-11 21:37:30 +02002626 ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002627 mutex_unlock(&mvm->mutex);
2628 return ret;
2629 }
2630 return 0;
2631}
2632
2633static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
2634 struct ieee80211_vif *vif)
2635{
2636 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Sara Sharon7c70fee2016-02-02 11:55:53 +02002637 u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS;
2638 u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS;
Johannes Berg8ca151b2013-01-24 14:25:36 +01002639
2640 if (WARN_ON_ONCE(vif->bss_conf.assoc))
2641 return;
2642
Eliad Peller576eeee2014-07-01 18:38:38 +03002643 /*
2644 * iwl_mvm_protect_session() reads directly from the device
2645 * (the system time), so make sure it is available.
2646 */
2647 if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PREPARE_TX))
2648 return;
2649
Johannes Berg8ca151b2013-01-24 14:25:36 +01002650 mutex_lock(&mvm->mutex);
2651 /* Try really hard to protect the session and hear a beacon */
Liad Kaufmand20d37b2014-07-06 17:14:39 +03002652 iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002653 mutex_unlock(&mvm->mutex);
Eliad Peller576eeee2014-07-01 18:38:38 +03002654
2655 iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002656}
2657
David Spinadel35a000b2013-08-28 09:29:43 +03002658static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
2659 struct ieee80211_vif *vif,
2660 struct cfg80211_sched_scan_request *req,
David Spinadel633e2712014-02-06 16:15:23 +02002661 struct ieee80211_scan_ies *ies)
David Spinadel35a000b2013-08-28 09:29:43 +03002662{
2663 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Luciano Coelho6749dd82015-03-20 15:51:36 +02002664
David Spinadel35a000b2013-08-28 09:29:43 +03002665 int ret;
2666
2667 mutex_lock(&mvm->mutex);
2668
Luciano Coelho1f940382015-02-10 13:03:38 +02002669 if (!vif->bss_conf.idle) {
David Spinadelbd5e4742014-04-24 13:15:29 +03002670 ret = -EBUSY;
2671 goto out;
2672 }
2673
Luciano Coelho19945df2015-03-20 16:11:28 +02002674 ret = iwl_mvm_sched_scan_start(mvm, vif, req, ies, IWL_MVM_SCAN_SCHED);
David Spinadeld2496222014-05-20 12:46:37 +03002675
David Spinadel35a000b2013-08-28 09:29:43 +03002676out:
2677 mutex_unlock(&mvm->mutex);
2678 return ret;
2679}
2680
Johannes Berg37e33082014-02-17 10:48:17 +01002681static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
2682 struct ieee80211_vif *vif)
David Spinadel35a000b2013-08-28 09:29:43 +03002683{
2684 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Arik Nemtsov33ea27f2014-02-10 15:34:29 +02002685 int ret;
David Spinadel35a000b2013-08-28 09:29:43 +03002686
2687 mutex_lock(&mvm->mutex);
Luciano Coelhoe7d3aba2015-02-06 10:19:05 +02002688
2689 /* Due to a race condition, it's possible that mac80211 asks
2690 * us to stop a sched_scan when it's already stopped. This
2691 * can happen, for instance, if we stopped the scan ourselves,
2692 * called ieee80211_sched_scan_stopped() and the userspace called
2693 * stop sched scan scan before ieee80211_sched_scan_stopped_work()
2694 * could run. To handle this, simply return if the scan is
2695 * not running.
2696 */
Luciano Coelho262888f2015-05-07 17:21:09 +03002697 if (!(mvm->scan_status & IWL_MVM_SCAN_SCHED)) {
Luciano Coelhoe7d3aba2015-02-06 10:19:05 +02002698 mutex_unlock(&mvm->mutex);
2699 return 0;
2700 }
2701
Luciano Coelhoc7d42482015-05-07 16:00:26 +03002702 ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, false);
David Spinadel35a000b2013-08-28 09:29:43 +03002703 mutex_unlock(&mvm->mutex);
Arik Nemtsov33ea27f2014-02-10 15:34:29 +02002704 iwl_mvm_wait_for_async_handlers(mvm);
Johannes Berg37e33082014-02-17 10:48:17 +01002705
Arik Nemtsov33ea27f2014-02-10 15:34:29 +02002706 return ret;
David Spinadel35a000b2013-08-28 09:29:43 +03002707}
2708
Johannes Berg8ca151b2013-01-24 14:25:36 +01002709static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
2710 enum set_key_cmd cmd,
2711 struct ieee80211_vif *vif,
2712 struct ieee80211_sta *sta,
2713 struct ieee80211_key_conf *key)
2714{
2715 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Johannes Bergf5e28ea2015-12-06 14:58:08 +02002716 struct iwl_mvm_sta *mvmsta;
2717 struct iwl_mvm_key_pn *ptk_pn;
2718 int keyidx = key->keyidx;
Johannes Berg8ca151b2013-01-24 14:25:36 +01002719 int ret;
Luca Coelhod6ee54a2015-11-10 22:13:43 +02002720 u8 key_offset;
Johannes Berg8ca151b2013-01-24 14:25:36 +01002721
2722 if (iwlwifi_mod_params.sw_crypto) {
2723 IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n");
2724 return -EOPNOTSUPP;
2725 }
2726
2727 switch (key->cipher) {
2728 case WLAN_CIPHER_SUITE_TKIP:
2729 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
Eliad Peller1ad4f632016-02-14 13:56:36 +02002730 key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Johannes Berg8ca151b2013-01-24 14:25:36 +01002731 break;
Johannes Bergca8c0f42015-04-20 17:54:54 +02002732 case WLAN_CIPHER_SUITE_CCMP:
Ayala Beker2a53d162016-04-07 16:21:57 +03002733 case WLAN_CIPHER_SUITE_GCMP:
2734 case WLAN_CIPHER_SUITE_GCMP_256:
Johannes Bergca8c0f42015-04-20 17:54:54 +02002735 key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
2736 break;
Johannes Berg8ca151b2013-01-24 14:25:36 +01002737 case WLAN_CIPHER_SUITE_AES_CMAC:
Johannes Berg30686bf2015-06-02 21:39:54 +02002738 WARN_ON_ONCE(!ieee80211_hw_check(hw, MFP_CAPABLE));
Johannes Berg8ca151b2013-01-24 14:25:36 +01002739 break;
2740 case WLAN_CIPHER_SUITE_WEP40:
2741 case WLAN_CIPHER_SUITE_WEP104:
Johannes Bergba3943b2014-11-12 23:54:48 +01002742 /* For non-client mode, only use WEP keys for TX as we probably
2743 * don't have a station yet anyway and would then have to keep
2744 * track of the keys, linking them to each of the clients/peers
2745 * as they appear. For now, don't do that, for performance WEP
2746 * offload doesn't really matter much, but we need it for some
2747 * other offload features in client mode.
Johannes Berg8ca151b2013-01-24 14:25:36 +01002748 */
Johannes Bergba3943b2014-11-12 23:54:48 +01002749 if (vif->type != NL80211_IFTYPE_STATION)
2750 return 0;
2751 break;
Johannes Berg8ca151b2013-01-24 14:25:36 +01002752 default:
Max Stepanove36e5432013-08-27 19:56:13 +03002753 /* currently FW supports only one optional cipher scheme */
2754 if (hw->n_cipher_schemes &&
2755 hw->cipher_schemes->cipher == key->cipher)
2756 key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
2757 else
2758 return -EOPNOTSUPP;
Johannes Berg8ca151b2013-01-24 14:25:36 +01002759 }
2760
2761 mutex_lock(&mvm->mutex);
2762
2763 switch (cmd) {
2764 case SET_KEY:
Johannes Berg5023d962013-07-31 14:07:43 +02002765 if ((vif->type == NL80211_IFTYPE_ADHOC ||
2766 vif->type == NL80211_IFTYPE_AP) && !sta) {
2767 /*
2768 * GTK on AP interface is a TX-only key, return 0;
2769 * on IBSS they're per-station and because we're lazy
2770 * we don't support them for RX, so do the same.
Johannes Berg81279c42016-03-09 14:58:47 +01002771 * CMAC in AP/IBSS modes must be done in software.
Johannes Berg5023d962013-07-31 14:07:43 +02002772 */
Johannes Berg81279c42016-03-09 14:58:47 +01002773 if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
2774 ret = -EOPNOTSUPP;
2775 else
2776 ret = 0;
Johannes Berg6caffd42013-03-06 13:15:21 +01002777 key->hw_key_idx = STA_KEY_IDX_INVALID;
2778 break;
2779 }
2780
Johannes Bergb546dcd2015-04-20 17:31:10 +02002781 /* During FW restart, in order to restore the state as it was,
2782 * don't try to reprogram keys we previously failed for.
2783 */
2784 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
2785 key->hw_key_idx == STA_KEY_IDX_INVALID) {
2786 IWL_DEBUG_MAC80211(mvm,
2787 "skip invalid idx key programming during restart\n");
2788 ret = 0;
2789 break;
2790 }
2791
Johannes Bergf5e28ea2015-12-06 14:58:08 +02002792 if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
2793 sta && iwl_mvm_has_new_rx_api(mvm) &&
2794 key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&
2795 (key->cipher == WLAN_CIPHER_SUITE_CCMP ||
Ayala Beker2a53d162016-04-07 16:21:57 +03002796 key->cipher == WLAN_CIPHER_SUITE_GCMP ||
2797 key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) {
Johannes Bergf5e28ea2015-12-06 14:58:08 +02002798 struct ieee80211_key_seq seq;
2799 int tid, q;
2800
2801 mvmsta = iwl_mvm_sta_from_mac80211(sta);
2802 WARN_ON(rcu_access_pointer(mvmsta->ptk_pn[keyidx]));
2803 ptk_pn = kzalloc(sizeof(*ptk_pn) +
2804 mvm->trans->num_rx_queues *
2805 sizeof(ptk_pn->q[0]),
2806 GFP_KERNEL);
2807 if (!ptk_pn) {
2808 ret = -ENOMEM;
2809 break;
2810 }
2811
2812 for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
2813 ieee80211_get_key_rx_seq(key, tid, &seq);
2814 for (q = 0; q < mvm->trans->num_rx_queues; q++)
2815 memcpy(ptk_pn->q[q].pn[tid],
2816 seq.ccmp.pn,
2817 IEEE80211_CCMP_PN_LEN);
2818 }
2819
2820 rcu_assign_pointer(mvmsta->ptk_pn[keyidx], ptk_pn);
2821 }
2822
Luca Coelhod6ee54a2015-11-10 22:13:43 +02002823 /* in HW restart reuse the index, otherwise request a new one */
2824 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
2825 key_offset = key->hw_key_idx;
2826 else
2827 key_offset = STA_KEY_IDX_INVALID;
2828
Johannes Berg8ca151b2013-01-24 14:25:36 +01002829 IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
Luca Coelhod6ee54a2015-11-10 22:13:43 +02002830 ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset);
Johannes Berg8ca151b2013-01-24 14:25:36 +01002831 if (ret) {
2832 IWL_WARN(mvm, "set key failed\n");
2833 /*
2834 * can't add key for RX, but we don't need it
2835 * in the device for TX so still return 0
2836 */
Johannes Berg6caffd42013-03-06 13:15:21 +01002837 key->hw_key_idx = STA_KEY_IDX_INVALID;
Johannes Berg8ca151b2013-01-24 14:25:36 +01002838 ret = 0;
2839 }
2840
2841 break;
2842 case DISABLE_KEY:
Johannes Berg6caffd42013-03-06 13:15:21 +01002843 if (key->hw_key_idx == STA_KEY_IDX_INVALID) {
2844 ret = 0;
2845 break;
2846 }
2847
Johannes Bergf5e28ea2015-12-06 14:58:08 +02002848 if (sta && iwl_mvm_has_new_rx_api(mvm) &&
2849 key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&
2850 (key->cipher == WLAN_CIPHER_SUITE_CCMP ||
Ayala Beker2a53d162016-04-07 16:21:57 +03002851 key->cipher == WLAN_CIPHER_SUITE_GCMP ||
2852 key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) {
Johannes Bergf5e28ea2015-12-06 14:58:08 +02002853 mvmsta = iwl_mvm_sta_from_mac80211(sta);
2854 ptk_pn = rcu_dereference_protected(
2855 mvmsta->ptk_pn[keyidx],
2856 lockdep_is_held(&mvm->mutex));
2857 RCU_INIT_POINTER(mvmsta->ptk_pn[keyidx], NULL);
2858 if (ptk_pn)
2859 kfree_rcu(ptk_pn, rcu_head);
2860 }
2861
Johannes Berg8ca151b2013-01-24 14:25:36 +01002862 IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n");
2863 ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key);
2864 break;
2865 default:
2866 ret = -EINVAL;
2867 }
2868
2869 mutex_unlock(&mvm->mutex);
2870 return ret;
2871}
2872
2873static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
2874 struct ieee80211_vif *vif,
2875 struct ieee80211_key_conf *keyconf,
2876 struct ieee80211_sta *sta,
2877 u32 iv32, u16 *phase1key)
2878{
2879 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2880
Johannes Berg5023d962013-07-31 14:07:43 +02002881 if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID)
2882 return;
2883
Johannes Berg8ca151b2013-01-24 14:25:36 +01002884 iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key);
2885}
2886
2887
Ariej Marjiehb1128892014-07-16 21:11:12 +03002888static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait,
2889 struct iwl_rx_packet *pkt, void *data)
2890{
2891 struct iwl_mvm *mvm =
2892 container_of(notif_wait, struct iwl_mvm, notif_wait);
2893 struct iwl_hs20_roc_res *resp;
2894 int resp_len = iwl_rx_packet_payload_len(pkt);
2895 struct iwl_mvm_time_event_data *te_data = data;
2896
2897 if (WARN_ON(pkt->hdr.cmd != HOT_SPOT_CMD))
2898 return true;
2899
2900 if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
2901 IWL_ERR(mvm, "Invalid HOT_SPOT_CMD response\n");
2902 return true;
2903 }
2904
2905 resp = (void *)pkt->data;
2906
2907 IWL_DEBUG_TE(mvm,
2908 "Aux ROC: Recieved response from ucode: status=%d uid=%d\n",
2909 resp->status, resp->event_unique_id);
2910
2911 te_data->uid = le32_to_cpu(resp->event_unique_id);
2912 IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n",
2913 te_data->uid);
2914
2915 spin_lock_bh(&mvm->time_event_lock);
2916 list_add_tail(&te_data->list, &mvm->aux_roc_te_list);
2917 spin_unlock_bh(&mvm->time_event_lock);
2918
2919 return true;
2920}
2921
Matti Gottliebdc28e122015-11-22 10:08:56 +02002922#define AUX_ROC_MIN_DURATION MSEC_TO_TU(100)
2923#define AUX_ROC_MIN_DELAY MSEC_TO_TU(200)
2924#define AUX_ROC_MAX_DELAY MSEC_TO_TU(600)
2925#define AUX_ROC_SAFETY_BUFFER MSEC_TO_TU(20)
2926#define AUX_ROC_MIN_SAFETY_BUFFER MSEC_TO_TU(10)
Ariej Marjiehb1128892014-07-16 21:11:12 +03002927static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
2928 struct ieee80211_channel *channel,
2929 struct ieee80211_vif *vif,
2930 int duration)
2931{
2932 int res, time_reg = DEVICE_SYSTEM_TIME_REG;
2933 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
2934 struct iwl_mvm_time_event_data *te_data = &mvmvif->hs_time_event_data;
Sara Sharon6eb031d2015-07-13 14:50:47 +03002935 static const u16 time_event_response[] = { HOT_SPOT_CMD };
Ariej Marjiehb1128892014-07-16 21:11:12 +03002936 struct iwl_notification_wait wait_time_event;
Matti Gottliebdc28e122015-11-22 10:08:56 +02002937 u32 dtim_interval = vif->bss_conf.dtim_period *
2938 vif->bss_conf.beacon_int;
2939 u32 req_dur, delay;
Ariej Marjiehb1128892014-07-16 21:11:12 +03002940 struct iwl_hs20_roc_req aux_roc_req = {
2941 .action = cpu_to_le32(FW_CTXT_ACTION_ADD),
2942 .id_and_color =
2943 cpu_to_le32(FW_CMD_ID_AND_COLOR(MAC_INDEX_AUX, 0)),
2944 .sta_id_and_color = cpu_to_le32(mvm->aux_sta.sta_id),
2945 /* Set the channel info data */
Johannes Berg57fbcce2016-04-12 15:56:15 +02002946 .channel_info.band = (channel->band == NL80211_BAND_2GHZ) ?
Ariej Marjiehb1128892014-07-16 21:11:12 +03002947 PHY_BAND_24 : PHY_BAND_5,
2948 .channel_info.channel = channel->hw_value,
2949 .channel_info.width = PHY_VHT_CHANNEL_MODE20,
2950 /* Set the time and duration */
2951 .apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, time_reg)),
Ariej Marjiehb1128892014-07-16 21:11:12 +03002952 };
2953
Matti Gottliebdc28e122015-11-22 10:08:56 +02002954 delay = AUX_ROC_MIN_DELAY;
2955 req_dur = MSEC_TO_TU(duration);
2956
2957 /*
2958 * If we are associated we want the delay time to be at least one
2959 * dtim interval so that the FW can wait until after the DTIM and
2960 * then start the time event, this will potentially allow us to
2961 * remain off-channel for the max duration.
2962 * Since we want to use almost a whole dtim interval we would also
2963 * like the delay to be for 2-3 dtim intervals, in case there are
2964 * other time events with higher priority.
2965 */
2966 if (vif->bss_conf.assoc) {
2967 delay = min_t(u32, dtim_interval * 3, AUX_ROC_MAX_DELAY);
2968 /* We cannot remain off-channel longer than the DTIM interval */
2969 if (dtim_interval <= req_dur) {
2970 req_dur = dtim_interval - AUX_ROC_SAFETY_BUFFER;
2971 if (req_dur <= AUX_ROC_MIN_DURATION)
2972 req_dur = dtim_interval -
2973 AUX_ROC_MIN_SAFETY_BUFFER;
2974 }
2975 }
2976
2977 aux_roc_req.duration = cpu_to_le32(req_dur);
2978 aux_roc_req.apply_time_max_delay = cpu_to_le32(delay);
2979
2980 IWL_DEBUG_TE(mvm,
2981 "ROC: Requesting to remain on channel %u for %ums (requested = %ums, max_delay = %ums, dtim_interval = %ums)\n",
2982 channel->hw_value, req_dur, duration, delay,
2983 dtim_interval);
Ariej Marjiehb1128892014-07-16 21:11:12 +03002984 /* Set the node address */
2985 memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN);
2986
Matti Gottlieba6cc5162014-09-29 11:46:04 +03002987 lockdep_assert_held(&mvm->mutex);
2988
2989 spin_lock_bh(&mvm->time_event_lock);
2990
2991 if (WARN_ON(te_data->id == HOT_SPOT_CMD)) {
2992 spin_unlock_bh(&mvm->time_event_lock);
2993 return -EIO;
2994 }
2995
Ariej Marjiehb1128892014-07-16 21:11:12 +03002996 te_data->vif = vif;
2997 te_data->duration = duration;
2998 te_data->id = HOT_SPOT_CMD;
2999
Ariej Marjiehb1128892014-07-16 21:11:12 +03003000 spin_unlock_bh(&mvm->time_event_lock);
3001
3002 /*
3003 * Use a notification wait, which really just processes the
3004 * command response and doesn't wait for anything, in order
3005 * to be able to process the response and get the UID inside
3006 * the RX path. Using CMD_WANT_SKB doesn't work because it
3007 * stores the buffer and then wakes up this thread, by which
3008 * time another notification (that the time event started)
3009 * might already be processed unsuccessfully.
3010 */
3011 iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event,
3012 time_event_response,
3013 ARRAY_SIZE(time_event_response),
3014 iwl_mvm_rx_aux_roc, te_data);
3015
3016 res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, sizeof(aux_roc_req),
3017 &aux_roc_req);
3018
3019 if (res) {
3020 IWL_ERR(mvm, "Couldn't send HOT_SPOT_CMD: %d\n", res);
3021 iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
3022 goto out_clear_te;
3023 }
3024
3025 /* No need to wait for anything, so just pass 1 (0 isn't valid) */
3026 res = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1);
3027 /* should never fail */
3028 WARN_ON_ONCE(res);
3029
3030 if (res) {
3031 out_clear_te:
3032 spin_lock_bh(&mvm->time_event_lock);
3033 iwl_mvm_te_clear_data(mvm, te_data);
3034 spin_unlock_bh(&mvm->time_event_lock);
3035 }
3036
3037 return res;
3038}
3039
Johannes Berg8ca151b2013-01-24 14:25:36 +01003040static int iwl_mvm_roc(struct ieee80211_hw *hw,
3041 struct ieee80211_vif *vif,
3042 struct ieee80211_channel *channel,
Ilan Peerd339d5c2013-02-12 09:34:13 +02003043 int duration,
3044 enum ieee80211_roc_type type)
Johannes Berg8ca151b2013-01-24 14:25:36 +01003045{
3046 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Ilan Peerfe0f2de2013-03-21 10:23:52 +02003047 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01003048 struct cfg80211_chan_def chandef;
Ilan Peer31d385a2013-04-02 10:25:46 +03003049 struct iwl_mvm_phy_ctxt *phy_ctxt;
3050 int ret, i;
3051
3052 IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
3053 duration, type);
Johannes Berg8ca151b2013-01-24 14:25:36 +01003054
Matti Gottlieb6ed13162015-03-30 16:50:07 +03003055 flush_work(&mvm->roc_done_wk);
3056
Matti Gottlieba6cc5162014-09-29 11:46:04 +03003057 mutex_lock(&mvm->mutex);
3058
Ariej Marjiehb1128892014-07-16 21:11:12 +03003059 switch (vif->type) {
3060 case NL80211_IFTYPE_STATION:
Johannes Berg859d9142015-06-01 17:11:11 +02003061 if (fw_has_capa(&mvm->fw->ucode_capa,
3062 IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT)) {
Luciano Coelho5ac6c722014-10-21 16:12:18 +03003063 /* Use aux roc framework (HS20) */
3064 ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
3065 vif, duration);
3066 goto out_unlock;
3067 }
3068 IWL_ERR(mvm, "hotspot not supported\n");
3069 ret = -EINVAL;
Matti Gottlieba6cc5162014-09-29 11:46:04 +03003070 goto out_unlock;
Ariej Marjiehb1128892014-07-16 21:11:12 +03003071 case NL80211_IFTYPE_P2P_DEVICE:
3072 /* handle below */
3073 break;
3074 default:
3075 IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type);
Matti Gottlieba6cc5162014-09-29 11:46:04 +03003076 ret = -EINVAL;
3077 goto out_unlock;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003078 }
3079
Ilan Peer31d385a2013-04-02 10:25:46 +03003080 for (i = 0; i < NUM_PHY_CTX; i++) {
3081 phy_ctxt = &mvm->phy_ctxts[i];
3082 if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt)
3083 continue;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003084
Ilan Peer31d385a2013-04-02 10:25:46 +03003085 if (phy_ctxt->ref && channel == phy_ctxt->channel) {
3086 /*
3087 * Unbind the P2P_DEVICE from the current PHY context,
3088 * and if the PHY context is not used remove it.
3089 */
3090 ret = iwl_mvm_binding_remove_vif(mvm, vif);
3091 if (WARN(ret, "Failed unbinding P2P_DEVICE\n"))
3092 goto out_unlock;
3093
3094 iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
3095
3096 /* Bind the P2P_DEVICE to the current PHY Context */
3097 mvmvif->phy_ctxt = phy_ctxt;
3098
3099 ret = iwl_mvm_binding_add_vif(mvm, vif);
3100 if (WARN(ret, "Failed binding P2P_DEVICE\n"))
3101 goto out_unlock;
3102
3103 iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt);
3104 goto schedule_time_event;
3105 }
3106 }
3107
3108 /* Need to update the PHY context only if the ROC channel changed */
3109 if (channel == mvmvif->phy_ctxt->channel)
3110 goto schedule_time_event;
3111
3112 cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);
3113
3114 /*
3115 * Change the PHY context configuration as it is currently referenced
3116 * only by the P2P Device MAC
3117 */
3118 if (mvmvif->phy_ctxt->ref == 1) {
3119 ret = iwl_mvm_phy_ctxt_changed(mvm, mvmvif->phy_ctxt,
3120 &chandef, 1, 1);
3121 if (ret)
3122 goto out_unlock;
3123 } else {
3124 /*
3125 * The PHY context is shared with other MACs. Need to remove the
3126 * P2P Device from the binding, allocate an new PHY context and
3127 * create a new binding
3128 */
3129 phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
3130 if (!phy_ctxt) {
3131 ret = -ENOSPC;
3132 goto out_unlock;
3133 }
3134
3135 ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chandef,
3136 1, 1);
3137 if (ret) {
3138 IWL_ERR(mvm, "Failed to change PHY context\n");
3139 goto out_unlock;
3140 }
3141
3142 /* Unbind the P2P_DEVICE from the current PHY context */
3143 ret = iwl_mvm_binding_remove_vif(mvm, vif);
3144 if (WARN(ret, "Failed unbinding P2P_DEVICE\n"))
3145 goto out_unlock;
3146
3147 iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
3148
3149 /* Bind the P2P_DEVICE to the new allocated PHY context */
3150 mvmvif->phy_ctxt = phy_ctxt;
3151
3152 ret = iwl_mvm_binding_add_vif(mvm, vif);
3153 if (WARN(ret, "Failed binding P2P_DEVICE\n"))
3154 goto out_unlock;
3155
3156 iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt);
3157 }
3158
3159schedule_time_event:
Johannes Berg8ca151b2013-01-24 14:25:36 +01003160 /* Schedule the time events */
Ilan Peere635c792013-02-13 11:05:18 +02003161 ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type);
Johannes Berg8ca151b2013-01-24 14:25:36 +01003162
Ilan Peer31d385a2013-04-02 10:25:46 +03003163out_unlock:
Johannes Berg8ca151b2013-01-24 14:25:36 +01003164 mutex_unlock(&mvm->mutex);
3165 IWL_DEBUG_MAC80211(mvm, "leave\n");
Johannes Berg8ca151b2013-01-24 14:25:36 +01003166 return ret;
3167}
3168
3169static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw)
3170{
3171 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
3172
3173 IWL_DEBUG_MAC80211(mvm, "enter\n");
3174
3175 mutex_lock(&mvm->mutex);
Matti Gottliebbf5da872014-11-16 10:25:12 +02003176 iwl_mvm_stop_roc(mvm);
Johannes Berg8ca151b2013-01-24 14:25:36 +01003177 mutex_unlock(&mvm->mutex);
3178
3179 IWL_DEBUG_MAC80211(mvm, "leave\n");
3180 return 0;
3181}
3182
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003183static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm,
3184 struct ieee80211_chanctx_conf *ctx)
Johannes Berg8ca151b2013-01-24 14:25:36 +01003185{
Ilan Peerfe0f2de2013-03-21 10:23:52 +02003186 u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
3187 struct iwl_mvm_phy_ctxt *phy_ctxt;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003188 int ret;
3189
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003190 lockdep_assert_held(&mvm->mutex);
3191
Ilan Peer53a9d612013-04-28 11:55:08 +03003192 IWL_DEBUG_MAC80211(mvm, "Add channel context\n");
Ilan Peerfe0f2de2013-03-21 10:23:52 +02003193
Ilan Peerfe0f2de2013-03-21 10:23:52 +02003194 phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
3195 if (!phy_ctxt) {
3196 ret = -ENOSPC;
3197 goto out;
3198 }
3199
Eliad Pellerdcbc3e12013-10-31 14:31:25 +02003200 ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def,
Ilan Peer53a9d612013-04-28 11:55:08 +03003201 ctx->rx_chains_static,
3202 ctx->rx_chains_dynamic);
Ilan Peerfe0f2de2013-03-21 10:23:52 +02003203 if (ret) {
3204 IWL_ERR(mvm, "Failed to add PHY context\n");
3205 goto out;
3206 }
3207
Ilan Peer53a9d612013-04-28 11:55:08 +03003208 iwl_mvm_phy_ctxt_ref(mvm, phy_ctxt);
Ilan Peerfe0f2de2013-03-21 10:23:52 +02003209 *phy_ctxt_id = phy_ctxt->id;
3210out:
Johannes Berg8ca151b2013-01-24 14:25:36 +01003211 return ret;
3212}
3213
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003214static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw,
3215 struct ieee80211_chanctx_conf *ctx)
3216{
3217 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
3218 int ret;
3219
3220 mutex_lock(&mvm->mutex);
3221 ret = __iwl_mvm_add_chanctx(mvm, ctx);
3222 mutex_unlock(&mvm->mutex);
3223
3224 return ret;
3225}
3226
3227static void __iwl_mvm_remove_chanctx(struct iwl_mvm *mvm,
3228 struct ieee80211_chanctx_conf *ctx)
3229{
3230 u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
3231 struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
3232
3233 lockdep_assert_held(&mvm->mutex);
3234
3235 iwl_mvm_phy_ctxt_unref(mvm, phy_ctxt);
3236}
3237
Johannes Berg8ca151b2013-01-24 14:25:36 +01003238static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw,
3239 struct ieee80211_chanctx_conf *ctx)
3240{
3241 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Johannes Berg8ca151b2013-01-24 14:25:36 +01003242
3243 mutex_lock(&mvm->mutex);
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003244 __iwl_mvm_remove_chanctx(mvm, ctx);
Johannes Berg8ca151b2013-01-24 14:25:36 +01003245 mutex_unlock(&mvm->mutex);
3246}
3247
3248static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
3249 struct ieee80211_chanctx_conf *ctx,
3250 u32 changed)
3251{
3252 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Ilan Peerfe0f2de2013-03-21 10:23:52 +02003253 u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
3254 struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
Johannes Berg8ca151b2013-01-24 14:25:36 +01003255
Ilan Peer31d385a2013-04-02 10:25:46 +03003256 if (WARN_ONCE((phy_ctxt->ref > 1) &&
3257 (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH |
3258 IEEE80211_CHANCTX_CHANGE_RX_CHAINS |
Arik Nemtsov2dceeda2013-12-29 17:57:53 +02003259 IEEE80211_CHANCTX_CHANGE_RADAR |
3260 IEEE80211_CHANCTX_CHANGE_MIN_WIDTH)),
Ilan Peer31d385a2013-04-02 10:25:46 +03003261 "Cannot change PHY. Ref=%d, changed=0x%X\n",
3262 phy_ctxt->ref, changed))
3263 return;
3264
Johannes Berg8ca151b2013-01-24 14:25:36 +01003265 mutex_lock(&mvm->mutex);
Emmanuel Grumbach4d664492014-04-30 18:09:59 +03003266 iwl_mvm_bt_coex_vif_change(mvm);
Eliad Pellerdcbc3e12013-10-31 14:31:25 +02003267 iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def,
Johannes Berg8ca151b2013-01-24 14:25:36 +01003268 ctx->rx_chains_static,
3269 ctx->rx_chains_dynamic);
3270 mutex_unlock(&mvm->mutex);
3271}
3272
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003273static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
3274 struct ieee80211_vif *vif,
Luciano Coelhof0c97782014-03-05 15:41:48 +02003275 struct ieee80211_chanctx_conf *ctx,
3276 bool switching_chanctx)
Johannes Berg8ca151b2013-01-24 14:25:36 +01003277{
Ilan Peerfe0f2de2013-03-21 10:23:52 +02003278 u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
3279 struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
Johannes Berg8ca151b2013-01-24 14:25:36 +01003280 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
3281 int ret;
3282
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003283 lockdep_assert_held(&mvm->mutex);
Johannes Berg8ca151b2013-01-24 14:25:36 +01003284
Ilan Peerfe0f2de2013-03-21 10:23:52 +02003285 mvmvif->phy_ctxt = phy_ctxt;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003286
3287 switch (vif->type) {
3288 case NL80211_IFTYPE_AP:
Luciano Coelho4741dd02014-11-10 11:10:13 +02003289 /* only needed if we're switching chanctx (i.e. during CSA) */
3290 if (switching_chanctx) {
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +02003291 mvmvif->ap_ibss_active = true;
3292 break;
3293 }
Johannes Berg5023d962013-07-31 14:07:43 +02003294 case NL80211_IFTYPE_ADHOC:
Johannes Berg8ca151b2013-01-24 14:25:36 +01003295 /*
3296 * The AP binding flow is handled as part of the start_ap flow
Johannes Berg5023d962013-07-31 14:07:43 +02003297 * (in bss_info_changed), similarly for IBSS.
Johannes Berg8ca151b2013-01-24 14:25:36 +01003298 */
3299 ret = 0;
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003300 goto out;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003301 case NL80211_IFTYPE_STATION:
Luciano Coelho2533edc2014-08-08 19:50:46 +03003302 break;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003303 case NL80211_IFTYPE_MONITOR:
Luciano Coelho2533edc2014-08-08 19:50:46 +03003304 /* always disable PS when a monitor interface is active */
3305 mvmvif->ps_disabled = true;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003306 break;
3307 default:
3308 ret = -EINVAL;
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003309 goto out;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003310 }
3311
3312 ret = iwl_mvm_binding_add_vif(mvm, vif);
3313 if (ret)
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003314 goto out;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003315
3316 /*
Alexander Bondar92d85562013-10-23 11:50:34 +02003317 * Power state must be updated before quotas,
3318 * otherwise fw will complain.
3319 */
Arik Nemtsov999609f2014-05-15 17:31:51 +03003320 iwl_mvm_power_update_mac(mvm);
Alexander Bondar92d85562013-10-23 11:50:34 +02003321
3322 /* Setting the quota at this stage is only required for monitor
Johannes Berg8ca151b2013-01-24 14:25:36 +01003323 * interfaces. For the other types, the bss_info changed flow
3324 * will handle quota settings.
3325 */
3326 if (vif->type == NL80211_IFTYPE_MONITOR) {
Ilan Peer1e1391c2013-03-13 14:52:04 +02003327 mvmvif->monitor_active = true;
Emmanuel Grumbach7754ae72015-02-26 15:14:35 +02003328 ret = iwl_mvm_update_quotas(mvm, false, NULL);
Johannes Berg8ca151b2013-01-24 14:25:36 +01003329 if (ret)
3330 goto out_remove_binding;
Chaya Rachel Ivgi0e39eb02015-12-03 15:51:46 +02003331
3332 ret = iwl_mvm_add_snif_sta(mvm, vif);
3333 if (ret)
3334 goto out_remove_binding;
3335
Johannes Berg8ca151b2013-01-24 14:25:36 +01003336 }
3337
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +02003338 /* Handle binding during CSA */
Luciano Coelhoa57c6882014-11-10 11:10:16 +02003339 if (vif->type == NL80211_IFTYPE_AP) {
Emmanuel Grumbach7754ae72015-02-26 15:14:35 +02003340 iwl_mvm_update_quotas(mvm, false, NULL);
Johannes Berg3dfd3a92014-08-11 21:37:30 +02003341 iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +02003342 }
3343
Luciano Coelho4741dd02014-11-10 11:10:13 +02003344 if (switching_chanctx && vif->type == NL80211_IFTYPE_STATION) {
Luciano Coelho686e7fe2014-11-10 11:10:21 +02003345 u32 duration = 2 * vif->bss_conf.beacon_int;
3346
3347 /* iwl_mvm_protect_session() reads directly from the
3348 * device (the system time), so make sure it is
3349 * available.
3350 */
3351 ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_CSA);
3352 if (ret)
3353 goto out_remove_binding;
3354
3355 /* Protect the session to make sure we hear the first
3356 * beacon on the new channel.
3357 */
3358 iwl_mvm_protect_session(mvm, vif, duration, duration,
3359 vif->bss_conf.beacon_int / 2,
3360 true);
3361
3362 iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA);
3363
Emmanuel Grumbach7754ae72015-02-26 15:14:35 +02003364 iwl_mvm_update_quotas(mvm, false, NULL);
Luciano Coelho0ce04ce2014-05-08 16:03:39 +03003365 }
3366
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003367 goto out;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003368
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003369out_remove_binding:
Johannes Berg8ca151b2013-01-24 14:25:36 +01003370 iwl_mvm_binding_remove_vif(mvm, vif);
Arik Nemtsov999609f2014-05-15 17:31:51 +03003371 iwl_mvm_power_update_mac(mvm);
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003372out:
Johannes Berg8ca151b2013-01-24 14:25:36 +01003373 if (ret)
3374 mvmvif->phy_ctxt = NULL;
3375 return ret;
3376}
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003377static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
3378 struct ieee80211_vif *vif,
3379 struct ieee80211_chanctx_conf *ctx)
Johannes Berg8ca151b2013-01-24 14:25:36 +01003380{
3381 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003382 int ret;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003383
3384 mutex_lock(&mvm->mutex);
Luciano Coelhof0c97782014-03-05 15:41:48 +02003385 ret = __iwl_mvm_assign_vif_chanctx(mvm, vif, ctx, false);
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003386 mutex_unlock(&mvm->mutex);
3387
3388 return ret;
3389}
3390
3391static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
3392 struct ieee80211_vif *vif,
Luciano Coelhof0c97782014-03-05 15:41:48 +02003393 struct ieee80211_chanctx_conf *ctx,
3394 bool switching_chanctx)
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003395{
3396 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
Luciano Coelhof0c97782014-03-05 15:41:48 +02003397 struct ieee80211_vif *disabled_vif = NULL;
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003398
3399 lockdep_assert_held(&mvm->mutex);
Johannes Berg8ca151b2013-01-24 14:25:36 +01003400
3401 iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data);
3402
Johannes Berg8ca151b2013-01-24 14:25:36 +01003403 switch (vif->type) {
Johannes Berg5023d962013-07-31 14:07:43 +02003404 case NL80211_IFTYPE_ADHOC:
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003405 goto out;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003406 case NL80211_IFTYPE_MONITOR:
Ilan Peer1e1391c2013-03-13 14:52:04 +02003407 mvmvif->monitor_active = false;
Luciano Coelho2533edc2014-08-08 19:50:46 +03003408 mvmvif->ps_disabled = false;
Chaya Rachel Ivgi0e39eb02015-12-03 15:51:46 +02003409 iwl_mvm_rm_snif_sta(mvm, vif);
Johannes Berg8ca151b2013-01-24 14:25:36 +01003410 break;
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +02003411 case NL80211_IFTYPE_AP:
3412 /* This part is triggered only during CSA */
Luciano Coelho4741dd02014-11-10 11:10:13 +02003413 if (!switching_chanctx || !mvmvif->ap_ibss_active)
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003414 goto out;
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +02003415
Andrei Otcheretianski7ef0aab2014-11-10 11:10:11 +02003416 mvmvif->csa_countdown = false;
3417
Andrei Otcheretianski003e52362014-05-25 17:24:22 +03003418 /* Set CS bit on all the stations */
3419 iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true);
3420
3421 /* Save blocked iface, the timeout is set on the next beacon */
3422 rcu_assign_pointer(mvm->csa_tx_blocked_vif, vif);
3423
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +02003424 mvmvif->ap_ibss_active = false;
Luciano Coelhof0c97782014-03-05 15:41:48 +02003425 break;
3426 case NL80211_IFTYPE_STATION:
3427 if (!switching_chanctx)
3428 break;
3429
3430 disabled_vif = vif;
3431
Johannes Berg3dfd3a92014-08-11 21:37:30 +02003432 iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);
Luciano Coelhof0c97782014-03-05 15:41:48 +02003433 break;
Johannes Berg8ca151b2013-01-24 14:25:36 +01003434 default:
3435 break;
3436 }
3437
Emmanuel Grumbach7754ae72015-02-26 15:14:35 +02003438 iwl_mvm_update_quotas(mvm, false, disabled_vif);
Ilan Peer1e1391c2013-03-13 14:52:04 +02003439 iwl_mvm_binding_remove_vif(mvm, vif);
Alexander Bondar1c2abf72013-08-27 20:31:48 +03003440
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003441out:
Ilan Peera11e1442013-12-31 21:19:55 +02003442 mvmvif->phy_ctxt = NULL;
Arik Nemtsov999609f2014-05-15 17:31:51 +03003443 iwl_mvm_power_update_mac(mvm);
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003444}
3445
3446static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
3447 struct ieee80211_vif *vif,
3448 struct ieee80211_chanctx_conf *ctx)
3449{
3450 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
3451
3452 mutex_lock(&mvm->mutex);
Luciano Coelhof0c97782014-03-05 15:41:48 +02003453 __iwl_mvm_unassign_vif_chanctx(mvm, vif, ctx, false);
Johannes Berg8ca151b2013-01-24 14:25:36 +01003454 mutex_unlock(&mvm->mutex);
3455}
3456
Luciano Coelho50cc9572014-11-10 11:10:08 +02003457static int
3458iwl_mvm_switch_vif_chanctx_swap(struct iwl_mvm *mvm,
3459 struct ieee80211_vif_chanctx_switch *vifs)
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003460{
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003461 int ret;
3462
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003463 mutex_lock(&mvm->mutex);
Luciano Coelhof0c97782014-03-05 15:41:48 +02003464 __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, true);
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003465 __iwl_mvm_remove_chanctx(mvm, vifs[0].old_ctx);
3466
3467 ret = __iwl_mvm_add_chanctx(mvm, vifs[0].new_ctx);
3468 if (ret) {
3469 IWL_ERR(mvm, "failed to add new_ctx during channel switch\n");
3470 goto out_reassign;
3471 }
3472
Luciano Coelhof0c97782014-03-05 15:41:48 +02003473 ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].new_ctx,
3474 true);
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003475 if (ret) {
3476 IWL_ERR(mvm,
3477 "failed to assign new_ctx during channel switch\n");
3478 goto out_remove;
3479 }
3480
Arik Nemtsovf6972672014-06-15 16:03:55 +03003481 /* we don't support TDLS during DCM - can be caused by channel switch */
3482 if (iwl_mvm_phy_ctx_count(mvm) > 1)
3483 iwl_mvm_teardown_tdls_peers(mvm);
3484
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003485 goto out;
3486
3487out_remove:
3488 __iwl_mvm_remove_chanctx(mvm, vifs[0].new_ctx);
3489
3490out_reassign:
Luciano Coelho6fd1fb62014-11-10 11:10:10 +02003491 if (__iwl_mvm_add_chanctx(mvm, vifs[0].old_ctx)) {
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003492 IWL_ERR(mvm, "failed to add old_ctx back after failure.\n");
3493 goto out_restart;
3494 }
3495
Luciano Coelho6fd1fb62014-11-10 11:10:10 +02003496 if (__iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx,
3497 true)) {
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003498 IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n");
3499 goto out_restart;
3500 }
3501
3502 goto out;
3503
3504out_restart:
3505 /* things keep failing, better restart the hw */
3506 iwl_mvm_nic_restart(mvm, false);
3507
3508out:
3509 mutex_unlock(&mvm->mutex);
Luciano Coelho50cc9572014-11-10 11:10:08 +02003510
3511 return ret;
3512}
3513
Luciano Coelho48a256e2014-11-10 11:10:09 +02003514static int
3515iwl_mvm_switch_vif_chanctx_reassign(struct iwl_mvm *mvm,
3516 struct ieee80211_vif_chanctx_switch *vifs)
3517{
3518 int ret;
3519
3520 mutex_lock(&mvm->mutex);
3521 __iwl_mvm_unassign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx, true);
3522
3523 ret = __iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].new_ctx,
3524 true);
3525 if (ret) {
3526 IWL_ERR(mvm,
3527 "failed to assign new_ctx during channel switch\n");
3528 goto out_reassign;
3529 }
3530
3531 goto out;
3532
3533out_reassign:
3534 if (__iwl_mvm_assign_vif_chanctx(mvm, vifs[0].vif, vifs[0].old_ctx,
3535 true)) {
3536 IWL_ERR(mvm, "failed to reassign old_ctx after failure.\n");
3537 goto out_restart;
3538 }
3539
3540 goto out;
3541
3542out_restart:
3543 /* things keep failing, better restart the hw */
3544 iwl_mvm_nic_restart(mvm, false);
3545
3546out:
3547 mutex_unlock(&mvm->mutex);
3548
3549 return ret;
3550}
3551
Luciano Coelho50cc9572014-11-10 11:10:08 +02003552static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw,
3553 struct ieee80211_vif_chanctx_switch *vifs,
3554 int n_vifs,
3555 enum ieee80211_chanctx_switch_mode mode)
3556{
3557 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
3558 int ret;
3559
3560 /* we only support a single-vif right now */
3561 if (n_vifs > 1)
3562 return -EOPNOTSUPP;
3563
3564 switch (mode) {
3565 case CHANCTX_SWMODE_SWAP_CONTEXTS:
3566 ret = iwl_mvm_switch_vif_chanctx_swap(mvm, vifs);
3567 break;
3568 case CHANCTX_SWMODE_REASSIGN_VIF:
Luciano Coelho48a256e2014-11-10 11:10:09 +02003569 ret = iwl_mvm_switch_vif_chanctx_reassign(mvm, vifs);
Luciano Coelho50cc9572014-11-10 11:10:08 +02003570 break;
3571 default:
3572 ret = -EOPNOTSUPP;
3573 break;
3574 }
3575
Luciano Coelhob08c1d92014-05-20 23:31:05 +03003576 return ret;
3577}
3578
Johannes Berg8ca151b2013-01-24 14:25:36 +01003579static int iwl_mvm_set_tim(struct ieee80211_hw *hw,
3580 struct ieee80211_sta *sta,
3581 bool set)
3582{
3583 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Johannes Berg9d8ce6a2014-12-23 16:02:40 +01003584 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
Johannes Berg8ca151b2013-01-24 14:25:36 +01003585
3586 if (!mvm_sta || !mvm_sta->vif) {
3587 IWL_ERR(mvm, "Station is not associated to a vif\n");
3588 return -EINVAL;
3589 }
3590
3591 return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif);
3592}
3593
David Spinadel507cadf2013-07-31 18:07:21 +03003594#ifdef CONFIG_NL80211_TESTMODE
3595static const struct nla_policy iwl_mvm_tm_policy[IWL_MVM_TM_ATTR_MAX + 1] = {
3596 [IWL_MVM_TM_ATTR_CMD] = { .type = NLA_U32 },
3597 [IWL_MVM_TM_ATTR_NOA_DURATION] = { .type = NLA_U32 },
Johannes Bergf6c6ad422013-08-01 14:17:15 +02003598 [IWL_MVM_TM_ATTR_BEACON_FILTER_STATE] = { .type = NLA_U32 },
David Spinadel507cadf2013-07-31 18:07:21 +03003599};
3600
3601static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm,
3602 struct ieee80211_vif *vif,
3603 void *data, int len)
3604{
3605 struct nlattr *tb[IWL_MVM_TM_ATTR_MAX + 1];
3606 int err;
3607 u32 noa_duration;
3608
3609 err = nla_parse(tb, IWL_MVM_TM_ATTR_MAX, data, len, iwl_mvm_tm_policy);
3610 if (err)
3611 return err;
3612
3613 if (!tb[IWL_MVM_TM_ATTR_CMD])
3614 return -EINVAL;
3615
3616 switch (nla_get_u32(tb[IWL_MVM_TM_ATTR_CMD])) {
3617 case IWL_MVM_TM_CMD_SET_NOA:
3618 if (!vif || vif->type != NL80211_IFTYPE_AP || !vif->p2p ||
3619 !vif->bss_conf.enable_beacon ||
3620 !tb[IWL_MVM_TM_ATTR_NOA_DURATION])
3621 return -EINVAL;
3622
3623 noa_duration = nla_get_u32(tb[IWL_MVM_TM_ATTR_NOA_DURATION]);
3624 if (noa_duration >= vif->bss_conf.beacon_int)
3625 return -EINVAL;
3626
3627 mvm->noa_duration = noa_duration;
3628 mvm->noa_vif = vif;
3629
Emmanuel Grumbach7754ae72015-02-26 15:14:35 +02003630 return iwl_mvm_update_quotas(mvm, false, NULL);
Johannes Bergf6c6ad422013-08-01 14:17:15 +02003631 case IWL_MVM_TM_CMD_SET_BEACON_FILTER:
3632 /* must be associated client vif - ignore authorized */
3633 if (!vif || vif->type != NL80211_IFTYPE_STATION ||
3634 !vif->bss_conf.assoc || !vif->bss_conf.dtim_period ||
3635 !tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE])
3636 return -EINVAL;
3637
3638 if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE]))
Emmanuel Grumbacha1022922014-05-12 11:36:41 +03003639 return iwl_mvm_enable_beacon_filter(mvm, vif, 0);
3640 return iwl_mvm_disable_beacon_filter(mvm, vif, 0);
David Spinadel507cadf2013-07-31 18:07:21 +03003641 }
3642
3643 return -EOPNOTSUPP;
3644}
3645
3646static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw,
3647 struct ieee80211_vif *vif,
3648 void *data, int len)
3649{
3650 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
3651 int err;
3652
3653 mutex_lock(&mvm->mutex);
3654 err = __iwl_mvm_mac_testmode_cmd(mvm, vif, data, len);
3655 mutex_unlock(&mvm->mutex);
3656
3657 return err;
3658}
3659#endif
3660
Luciano Coelho622e3f92014-11-10 11:10:17 +02003661static void iwl_mvm_channel_switch(struct ieee80211_hw *hw,
3662 struct ieee80211_vif *vif,
3663 struct ieee80211_channel_switch *chsw)
3664{
3665 /* By implementing this operation, we prevent mac80211 from
3666 * starting its own channel switch timer, so that we can call
3667 * ieee80211_chswitch_done() ourselves at the right time
3668 * (which is when the absence time event starts).
3669 */
3670
3671 IWL_DEBUG_MAC80211(IWL_MAC80211_GET_MVM(hw),
3672 "dummy channel switch op\n");
3673}
3674
Luciano Coelhof0289052014-11-10 11:10:06 +02003675static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
3676 struct ieee80211_vif *vif,
3677 struct ieee80211_channel_switch *chsw)
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +02003678{
3679 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Andrei Otcheretianski664322f2014-06-05 16:40:36 +03003680 struct ieee80211_vif *csa_vif;
Luciano Coelhof6c34822014-11-10 11:10:12 +02003681 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
Luciano Coelhodc88b4b2014-11-10 11:10:14 +02003682 u32 apply_time;
Luciano Coelhof0289052014-11-10 11:10:06 +02003683 int ret;
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +02003684
3685 mutex_lock(&mvm->mutex);
Andrei Otcheretianski664322f2014-06-05 16:40:36 +03003686
Johannes Berg81d62d52015-03-10 14:44:00 +01003687 mvmvif->csa_failed = false;
3688
Luciano Coelho6b20d772014-11-10 11:10:07 +02003689 IWL_DEBUG_MAC80211(mvm, "pre CSA to freq %d\n",
Luciano Coelhof0289052014-11-10 11:10:06 +02003690 chsw->chandef.center_freq1);
Luciano Coelho6b20d772014-11-10 11:10:07 +02003691
Johannes Berg21023b12015-03-31 08:58:16 +02003692 iwl_fw_dbg_trigger_simple_stop(mvm, vif, FW_DBG_TRIGGER_CHANNEL_SWITCH);
Emmanuel Grumbachf35d9c52015-02-10 10:49:51 +02003693
Luciano Coelho6b20d772014-11-10 11:10:07 +02003694 switch (vif->type) {
3695 case NL80211_IFTYPE_AP:
3696 csa_vif =
3697 rcu_dereference_protected(mvm->csa_vif,
3698 lockdep_is_held(&mvm->mutex));
3699 if (WARN_ONCE(csa_vif && csa_vif->csa_active,
3700 "Another CSA is already in progress")) {
3701 ret = -EBUSY;
3702 goto out_unlock;
3703 }
3704
Andrei Otcheretianskid3a108a2016-02-28 17:12:21 +02003705 /* we still didn't unblock tx. prevent new CS meanwhile */
3706 if (rcu_dereference_protected(mvm->csa_tx_blocked_vif,
3707 lockdep_is_held(&mvm->mutex))) {
3708 ret = -EBUSY;
3709 goto out_unlock;
3710 }
3711
Luciano Coelho6b20d772014-11-10 11:10:07 +02003712 rcu_assign_pointer(mvm->csa_vif, vif);
Andrei Otcheretianski7ef0aab2014-11-10 11:10:11 +02003713
Andrei Otcheretianski7ef0aab2014-11-10 11:10:11 +02003714 if (WARN_ONCE(mvmvif->csa_countdown,
3715 "Previous CSA countdown didn't complete")) {
3716 ret = -EBUSY;
3717 goto out_unlock;
3718 }
3719
Andrei Otcheretianskid3a108a2016-02-28 17:12:21 +02003720 mvmvif->csa_target_freq = chsw->chandef.chan->center_freq;
3721
Luciano Coelho6b20d772014-11-10 11:10:07 +02003722 break;
Luciano Coelhodc88b4b2014-11-10 11:10:14 +02003723 case NL80211_IFTYPE_STATION:
Aviya Erenfeld03098262016-02-18 14:09:33 +02003724 if (mvmvif->lqm_active)
3725 iwl_mvm_send_lqm_cmd(vif,
3726 LQM_CMD_OPERATION_STOP_MEASUREMENT,
3727 0, 0);
3728
Luciano Coelho4500e132014-11-10 11:10:15 +02003729 /* Schedule the time event to a bit before beacon 1,
3730 * to make sure we're in the new channel when the
3731 * GO/AP arrives.
3732 */
3733 apply_time = chsw->device_timestamp +
3734 ((vif->bss_conf.beacon_int * (chsw->count - 1) -
3735 IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT) * 1024);
Luciano Coelhodc88b4b2014-11-10 11:10:14 +02003736
3737 if (chsw->block_tx)
3738 iwl_mvm_csa_client_absent(mvm, vif);
3739
Luciano Coelho4500e132014-11-10 11:10:15 +02003740 iwl_mvm_schedule_csa_period(mvm, vif, vif->bss_conf.beacon_int,
Luciano Coelhodc88b4b2014-11-10 11:10:14 +02003741 apply_time);
Luciano Coelhoc6e0a3e02014-11-10 11:10:18 +02003742 if (mvmvif->bf_data.bf_enabled) {
3743 ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
3744 if (ret)
3745 goto out_unlock;
3746 }
3747
Luciano Coelhodc88b4b2014-11-10 11:10:14 +02003748 break;
Luciano Coelho6b20d772014-11-10 11:10:07 +02003749 default:
3750 break;
3751 }
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +02003752
Luciano Coelhof6c34822014-11-10 11:10:12 +02003753 mvmvif->ps_disabled = true;
3754
3755 ret = iwl_mvm_power_update_ps(mvm);
3756 if (ret)
3757 goto out_unlock;
Luciano Coelhof0289052014-11-10 11:10:06 +02003758
Arik Nemtsove198f5e2014-09-14 19:13:54 +03003759 /* we won't be on this channel any longer */
3760 iwl_mvm_teardown_tdls_peers(mvm);
3761
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +02003762out_unlock:
3763 mutex_unlock(&mvm->mutex);
Luciano Coelhof0289052014-11-10 11:10:06 +02003764
3765 return ret;
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +02003766}
3767
Luciano Coelhof6c34822014-11-10 11:10:12 +02003768static int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw,
3769 struct ieee80211_vif *vif)
3770{
3771 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
3772 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
3773 int ret;
3774
3775 mutex_lock(&mvm->mutex);
3776
Johannes Berg81d62d52015-03-10 14:44:00 +01003777 if (mvmvif->csa_failed) {
3778 mvmvif->csa_failed = false;
3779 ret = -EIO;
3780 goto out_unlock;
3781 }
3782
Luciano Coelhoa57c6882014-11-10 11:10:16 +02003783 if (vif->type == NL80211_IFTYPE_STATION) {
3784 struct iwl_mvm_sta *mvmsta;
3785
3786 mvmsta = iwl_mvm_sta_from_staid_protected(mvm,
3787 mvmvif->ap_sta_id);
3788
3789 if (WARN_ON(!mvmsta)) {
3790 ret = -EIO;
3791 goto out_unlock;
3792 }
3793
3794 iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false);
3795
3796 iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
Luciano Coelhoc6e0a3e02014-11-10 11:10:18 +02003797
3798 ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0);
3799 if (ret)
3800 goto out_unlock;
Luciano Coelho686e7fe2014-11-10 11:10:21 +02003801
3802 iwl_mvm_stop_session_protection(mvm, vif);
Luciano Coelhoa57c6882014-11-10 11:10:16 +02003803 }
3804
Luciano Coelhof6c34822014-11-10 11:10:12 +02003805 mvmvif->ps_disabled = false;
3806
3807 ret = iwl_mvm_power_update_ps(mvm);
3808
Luciano Coelhoa57c6882014-11-10 11:10:16 +02003809out_unlock:
Luciano Coelhof6c34822014-11-10 11:10:12 +02003810 mutex_unlock(&mvm->mutex);
3811
3812 return ret;
3813}
3814
Emmanuel Grumbachc5b0e7c2014-03-24 12:08:53 +02003815static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
3816 struct ieee80211_vif *vif, u32 queues, bool drop)
3817{
3818 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
3819 struct iwl_mvm_vif *mvmvif;
3820 struct iwl_mvm_sta *mvmsta;
Arik Nemtsova0f6bf22014-09-21 19:10:04 +03003821 struct ieee80211_sta *sta;
3822 int i;
3823 u32 msk = 0;
Emmanuel Grumbachc5b0e7c2014-03-24 12:08:53 +02003824
3825 if (!vif || vif->type != NL80211_IFTYPE_STATION)
3826 return;
3827
Liad Kaufman24afba72015-07-28 18:56:08 +03003828 /* Make sure we're done with the deferred traffic before flushing */
3829 if (iwl_mvm_is_dqa_supported(mvm))
3830 flush_work(&mvm->add_stream_wk);
3831
Emmanuel Grumbachc5b0e7c2014-03-24 12:08:53 +02003832 mutex_lock(&mvm->mutex);
3833 mvmvif = iwl_mvm_vif_from_mac80211(vif);
Emmanuel Grumbachc5b0e7c2014-03-24 12:08:53 +02003834
Arik Nemtsova0f6bf22014-09-21 19:10:04 +03003835 /* flush the AP-station and all TDLS peers */
3836 for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
3837 sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
3838 lockdep_is_held(&mvm->mutex));
3839 if (IS_ERR_OR_NULL(sta))
3840 continue;
3841
3842 mvmsta = iwl_mvm_sta_from_mac80211(sta);
3843 if (mvmsta->vif != vif)
3844 continue;
3845
3846 /* make sure only TDLS peers or the AP are flushed */
3847 WARN_ON(i != mvmvif->ap_sta_id && !sta->tdls);
3848
3849 msk |= mvmsta->tfd_queue_msk;
Johannes Berg480acbc2014-10-10 08:59:27 +02003850 }
Emmanuel Grumbachc5b0e7c2014-03-24 12:08:53 +02003851
Emmanuel Grumbach6d440b22015-01-20 09:25:19 +02003852 if (drop) {
Luca Coelho5888a402015-10-06 09:54:57 +03003853 if (iwl_mvm_flush_tx_path(mvm, msk, 0))
Emmanuel Grumbach6d440b22015-01-20 09:25:19 +02003854 IWL_ERR(mvm, "flush request fail\n");
3855 mutex_unlock(&mvm->mutex);
3856 } else {
3857 mutex_unlock(&mvm->mutex);
Johannes Berg480acbc2014-10-10 08:59:27 +02003858
Emmanuel Grumbach6d440b22015-01-20 09:25:19 +02003859 /* this can take a while, and we may need/want other operations
3860 * to succeed while doing this, so do it without the mutex held
3861 */
3862 iwl_trans_wait_tx_queue_empty(mvm->trans, msk);
3863 }
Emmanuel Grumbachc5b0e7c2014-03-24 12:08:53 +02003864}
3865
Johannes Berg91a8bcd2015-01-14 18:12:41 +01003866static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
3867 struct survey_info *survey)
3868{
3869 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
3870 int ret;
3871
3872 memset(survey, 0, sizeof(*survey));
3873
3874 /* only support global statistics right now */
3875 if (idx != 0)
3876 return -ENOENT;
3877
Johannes Berg859d9142015-06-01 17:11:11 +02003878 if (fw_has_capa(&mvm->fw->ucode_capa,
Johannes Berg91a8bcd2015-01-14 18:12:41 +01003879 IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
3880 return -ENOENT;
3881
3882 mutex_lock(&mvm->mutex);
3883
3884 if (mvm->ucode_loaded) {
Johannes Berg33cef922015-01-21 21:41:29 +01003885 ret = iwl_mvm_request_statistics(mvm, false);
Johannes Berg91a8bcd2015-01-14 18:12:41 +01003886 if (ret)
3887 goto out;
3888 }
3889
3890 survey->filled = SURVEY_INFO_TIME |
3891 SURVEY_INFO_TIME_RX |
3892 SURVEY_INFO_TIME_TX |
3893 SURVEY_INFO_TIME_SCAN;
3894 survey->time = mvm->accu_radio_stats.on_time_rf +
3895 mvm->radio_stats.on_time_rf;
3896 do_div(survey->time, USEC_PER_MSEC);
3897
3898 survey->time_rx = mvm->accu_radio_stats.rx_time +
3899 mvm->radio_stats.rx_time;
3900 do_div(survey->time_rx, USEC_PER_MSEC);
3901
3902 survey->time_tx = mvm->accu_radio_stats.tx_time +
3903 mvm->radio_stats.tx_time;
3904 do_div(survey->time_tx, USEC_PER_MSEC);
3905
3906 survey->time_scan = mvm->accu_radio_stats.on_time_scan +
3907 mvm->radio_stats.on_time_scan;
3908 do_div(survey->time_scan, USEC_PER_MSEC);
3909
Johannes Berg10a7c0282015-04-01 10:00:31 +02003910 ret = 0;
Johannes Berg91a8bcd2015-01-14 18:12:41 +01003911 out:
3912 mutex_unlock(&mvm->mutex);
3913 return ret;
3914}
3915
Johannes Berg33cef922015-01-21 21:41:29 +01003916static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
3917 struct ieee80211_vif *vif,
3918 struct ieee80211_sta *sta,
3919 struct station_info *sinfo)
3920{
3921 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
3922 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
3923 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
3924
Sara Sharon988b5962016-04-10 15:06:55 +03003925 if (mvmsta->avg_energy) {
3926 sinfo->signal_avg = mvmsta->avg_energy;
3927 sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
3928 }
3929
Johannes Berg859d9142015-06-01 17:11:11 +02003930 if (fw_has_capa(&mvm->fw->ucode_capa,
3931 IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
Johannes Berg33cef922015-01-21 21:41:29 +01003932 return;
3933
3934 /* if beacon filtering isn't on mac80211 does it anyway */
3935 if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER))
3936 return;
3937
3938 if (!vif->bss_conf.assoc)
3939 return;
3940
3941 mutex_lock(&mvm->mutex);
3942
3943 if (mvmvif->ap_sta_id != mvmsta->sta_id)
3944 goto unlock;
3945
3946 if (iwl_mvm_request_statistics(mvm, false))
3947 goto unlock;
3948
3949 sinfo->rx_beacon = mvmvif->beacon_stats.num_beacons +
3950 mvmvif->beacon_stats.accu_num_beacons;
3951 sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_RX);
3952 if (mvmvif->beacon_stats.avg_signal) {
3953 /* firmware only reports a value after RXing a few beacons */
3954 sinfo->rx_beacon_signal_avg = mvmvif->beacon_stats.avg_signal;
3955 sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG);
3956 }
3957 unlock:
3958 mutex_unlock(&mvm->mutex);
3959}
3960
Emmanuel Grumbach42032632015-04-15 12:43:46 +03003961static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm,
3962 struct ieee80211_vif *vif,
3963 const struct ieee80211_event *event)
Emmanuel Grumbachd42f5352015-02-10 14:29:48 +02003964{
Johannes Berg5d4f9292015-03-31 09:12:54 +02003965#define CHECK_MLME_TRIGGER(_mvm, _trig, _buf, _cnt, _fmt...) \
Emmanuel Grumbachd42f5352015-02-10 14:29:48 +02003966 do { \
3967 if ((_cnt) && --(_cnt)) \
3968 break; \
Johannes Berg5d4f9292015-03-31 09:12:54 +02003969 iwl_mvm_fw_dbg_collect_trig(_mvm, _trig, _fmt);\
Emmanuel Grumbachd42f5352015-02-10 14:29:48 +02003970 } while (0)
3971
Emmanuel Grumbachd42f5352015-02-10 14:29:48 +02003972 struct iwl_fw_dbg_trigger_tlv *trig;
3973 struct iwl_fw_dbg_trigger_mlme *trig_mlme;
Emmanuel Grumbachd42f5352015-02-10 14:29:48 +02003974
3975 if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_MLME))
3976 return;
3977
Emmanuel Grumbachd42f5352015-02-10 14:29:48 +02003978 trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME);
3979 trig_mlme = (void *)trig->data;
3980 if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
3981 return;
3982
Emmanuel Grumbachd42f5352015-02-10 14:29:48 +02003983 if (event->u.mlme.data == ASSOC_EVENT) {
3984 if (event->u.mlme.status == MLME_DENIED)
3985 CHECK_MLME_TRIGGER(mvm, trig, buf,
3986 trig_mlme->stop_assoc_denied,
3987 "DENIED ASSOC: reason %d",
3988 event->u.mlme.reason);
3989 else if (event->u.mlme.status == MLME_TIMEOUT)
3990 CHECK_MLME_TRIGGER(mvm, trig, buf,
3991 trig_mlme->stop_assoc_timeout,
3992 "ASSOC TIMEOUT");
3993 } else if (event->u.mlme.data == AUTH_EVENT) {
3994 if (event->u.mlme.status == MLME_DENIED)
3995 CHECK_MLME_TRIGGER(mvm, trig, buf,
3996 trig_mlme->stop_auth_denied,
3997 "DENIED AUTH: reason %d",
3998 event->u.mlme.reason);
3999 else if (event->u.mlme.status == MLME_TIMEOUT)
4000 CHECK_MLME_TRIGGER(mvm, trig, buf,
4001 trig_mlme->stop_auth_timeout,
4002 "AUTH TIMEOUT");
4003 } else if (event->u.mlme.data == DEAUTH_RX_EVENT) {
4004 CHECK_MLME_TRIGGER(mvm, trig, buf,
4005 trig_mlme->stop_rx_deauth,
4006 "DEAUTH RX %d", event->u.mlme.reason);
4007 } else if (event->u.mlme.data == DEAUTH_TX_EVENT) {
4008 CHECK_MLME_TRIGGER(mvm, trig, buf,
4009 trig_mlme->stop_tx_deauth,
4010 "DEAUTH TX %d", event->u.mlme.reason);
4011 }
4012#undef CHECK_MLME_TRIGGER
4013}
4014
Emmanuel Grumbach42032632015-04-15 12:43:46 +03004015static void iwl_mvm_event_bar_rx_callback(struct iwl_mvm *mvm,
4016 struct ieee80211_vif *vif,
4017 const struct ieee80211_event *event)
4018{
4019 struct iwl_fw_dbg_trigger_tlv *trig;
4020 struct iwl_fw_dbg_trigger_ba *ba_trig;
4021
4022 if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
4023 return;
4024
4025 trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
4026 ba_trig = (void *)trig->data;
4027 if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
4028 return;
4029
4030 if (!(le16_to_cpu(ba_trig->rx_bar) & BIT(event->u.ba.tid)))
4031 return;
4032
4033 iwl_mvm_fw_dbg_collect_trig(mvm, trig,
4034 "BAR received from %pM, tid %d, ssn %d",
4035 event->u.ba.sta->addr, event->u.ba.tid,
4036 event->u.ba.ssn);
4037}
4038
4039static void
4040iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm,
4041 struct ieee80211_vif *vif,
4042 const struct ieee80211_event *event)
4043{
4044 struct iwl_fw_dbg_trigger_tlv *trig;
4045 struct iwl_fw_dbg_trigger_ba *ba_trig;
4046
4047 if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
4048 return;
4049
4050 trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
4051 ba_trig = (void *)trig->data;
4052 if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig))
4053 return;
4054
4055 if (!(le16_to_cpu(ba_trig->frame_timeout) & BIT(event->u.ba.tid)))
4056 return;
4057
4058 iwl_mvm_fw_dbg_collect_trig(mvm, trig,
4059 "Frame from %pM timed out, tid %d",
4060 event->u.ba.sta->addr, event->u.ba.tid);
4061}
4062
4063static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
4064 struct ieee80211_vif *vif,
4065 const struct ieee80211_event *event)
4066{
4067 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
4068
4069 switch (event->type) {
4070 case MLME_EVENT:
4071 iwl_mvm_event_mlme_callback(mvm, vif, event);
4072 break;
4073 case BAR_RX_EVENT:
4074 iwl_mvm_event_bar_rx_callback(mvm, vif, event);
4075 break;
4076 case BA_FRAME_TIMEOUT:
4077 iwl_mvm_event_frame_timeout_callback(mvm, vif, event);
4078 break;
4079 default:
4080 break;
4081 }
4082}
4083
Sara Sharond0ff5d22016-03-23 16:31:43 +02004084void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
4085 struct iwl_mvm_internal_rxq_notif *notif,
4086 u32 size)
Sara Sharon0636b932016-02-18 14:21:12 +02004087{
Sara Sharon0636b932016-02-18 14:21:12 +02004088 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(notif_waitq);
4089 u32 qmask = BIT(mvm->trans->num_rx_queues) - 1;
4090 int ret;
4091
4092 lockdep_assert_held(&mvm->mutex);
4093
4094 if (!iwl_mvm_has_new_rx_api(mvm))
4095 return;
4096
Sara Sharond0ff5d22016-03-23 16:31:43 +02004097 notif->cookie = mvm->queue_sync_cookie;
Sara Sharon0636b932016-02-18 14:21:12 +02004098
Sara Sharond0ff5d22016-03-23 16:31:43 +02004099 if (notif->sync)
4100 atomic_set(&mvm->queue_sync_counter,
4101 mvm->trans->num_rx_queues);
4102
4103 ret = iwl_mvm_notify_rx_queue(mvm, qmask, (u8 *)notif, size);
Sara Sharon0636b932016-02-18 14:21:12 +02004104 if (ret) {
4105 IWL_ERR(mvm, "Failed to trigger RX queues sync (%d)\n", ret);
4106 goto out;
4107 }
Sara Sharond0ff5d22016-03-23 16:31:43 +02004108
4109 if (notif->sync)
4110 ret = wait_event_timeout(notif_waitq,
4111 atomic_read(&mvm->queue_sync_counter) == 0,
4112 HZ);
Sara Sharon0636b932016-02-18 14:21:12 +02004113 WARN_ON_ONCE(!ret);
4114
4115out:
4116 atomic_set(&mvm->queue_sync_counter, 0);
4117 mvm->queue_sync_cookie++;
4118}
4119
4120static void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw)
4121{
4122 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
Sara Sharond0ff5d22016-03-23 16:31:43 +02004123 struct iwl_mvm_internal_rxq_notif data = {
4124 .type = IWL_MVM_RXQ_EMPTY,
4125 .sync = 1,
4126 };
Sara Sharon0636b932016-02-18 14:21:12 +02004127
4128 mutex_lock(&mvm->mutex);
Sara Sharond0ff5d22016-03-23 16:31:43 +02004129 iwl_mvm_sync_rx_queues_internal(mvm, &data, sizeof(data));
Sara Sharon0636b932016-02-18 14:21:12 +02004130 mutex_unlock(&mvm->mutex);
4131}
4132
Johannes Berge5209262014-01-20 23:38:59 +01004133const struct ieee80211_ops iwl_mvm_hw_ops = {
Johannes Berg8ca151b2013-01-24 14:25:36 +01004134 .tx = iwl_mvm_mac_tx,
4135 .ampdu_action = iwl_mvm_mac_ampdu_action,
4136 .start = iwl_mvm_mac_start,
Eliad Pellercf2c92d2014-11-04 11:43:54 +02004137 .reconfig_complete = iwl_mvm_mac_reconfig_complete,
Johannes Berg8ca151b2013-01-24 14:25:36 +01004138 .stop = iwl_mvm_mac_stop,
4139 .add_interface = iwl_mvm_mac_add_interface,
4140 .remove_interface = iwl_mvm_mac_remove_interface,
4141 .config = iwl_mvm_mac_config,
Eliad Pellere59647e2013-11-28 14:08:50 +02004142 .prepare_multicast = iwl_mvm_prepare_multicast,
Johannes Berg8ca151b2013-01-24 14:25:36 +01004143 .configure_filter = iwl_mvm_configure_filter,
Andrei Otcheretianskieffd1922015-06-30 12:08:28 +03004144 .config_iface_filter = iwl_mvm_config_iface_filter,
Johannes Berg8ca151b2013-01-24 14:25:36 +01004145 .bss_info_changed = iwl_mvm_bss_info_changed,
4146 .hw_scan = iwl_mvm_mac_hw_scan,
4147 .cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan,
Johannes Berg1ddbbb02013-12-04 22:39:17 +01004148 .sta_pre_rcu_remove = iwl_mvm_sta_pre_rcu_remove,
Johannes Berg8ca151b2013-01-24 14:25:36 +01004149 .sta_state = iwl_mvm_mac_sta_state,
4150 .sta_notify = iwl_mvm_mac_sta_notify,
4151 .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
Johannes Berg3e56ead2013-02-15 22:23:18 +01004152 .release_buffered_frames = iwl_mvm_mac_release_buffered_frames,
Johannes Berg8ca151b2013-01-24 14:25:36 +01004153 .set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
Lilach Edelstein1f3b0ff2013-10-06 13:03:32 +02004154 .sta_rc_update = iwl_mvm_sta_rc_update,
Johannes Berg8ca151b2013-01-24 14:25:36 +01004155 .conf_tx = iwl_mvm_mac_conf_tx,
4156 .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
Arik Nemtsov07ecd892014-05-20 18:16:42 +03004157 .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover,
Emmanuel Grumbachc5b0e7c2014-03-24 12:08:53 +02004158 .flush = iwl_mvm_mac_flush,
David Spinadel35a000b2013-08-28 09:29:43 +03004159 .sched_scan_start = iwl_mvm_mac_sched_scan_start,
4160 .sched_scan_stop = iwl_mvm_mac_sched_scan_stop,
Johannes Berg8ca151b2013-01-24 14:25:36 +01004161 .set_key = iwl_mvm_mac_set_key,
4162 .update_tkip_key = iwl_mvm_mac_update_tkip_key,
4163 .remain_on_channel = iwl_mvm_roc,
4164 .cancel_remain_on_channel = iwl_mvm_cancel_roc,
Johannes Berg8ca151b2013-01-24 14:25:36 +01004165 .add_chanctx = iwl_mvm_add_chanctx,
4166 .remove_chanctx = iwl_mvm_remove_chanctx,
4167 .change_chanctx = iwl_mvm_change_chanctx,
4168 .assign_vif_chanctx = iwl_mvm_assign_vif_chanctx,
4169 .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx,
Luciano Coelhob08c1d92014-05-20 23:31:05 +03004170 .switch_vif_chanctx = iwl_mvm_switch_vif_chanctx,
Johannes Berg8ca151b2013-01-24 14:25:36 +01004171
Johannes Berg5023d962013-07-31 14:07:43 +02004172 .start_ap = iwl_mvm_start_ap_ibss,
4173 .stop_ap = iwl_mvm_stop_ap_ibss,
4174 .join_ibss = iwl_mvm_start_ap_ibss,
4175 .leave_ibss = iwl_mvm_stop_ap_ibss,
Johannes Berg8ca151b2013-01-24 14:25:36 +01004176
4177 .set_tim = iwl_mvm_set_tim,
4178
Luciano Coelho622e3f92014-11-10 11:10:17 +02004179 .channel_switch = iwl_mvm_channel_switch,
Luciano Coelhof0289052014-11-10 11:10:06 +02004180 .pre_channel_switch = iwl_mvm_pre_channel_switch,
Luciano Coelhof6c34822014-11-10 11:10:12 +02004181 .post_channel_switch = iwl_mvm_post_channel_switch,
Andrei Otcheretianskibd3398e2013-10-22 05:01:12 +02004182
Arik Nemtsov1d3c3f62014-10-23 18:03:10 +03004183 .tdls_channel_switch = iwl_mvm_tdls_channel_switch,
4184 .tdls_cancel_channel_switch = iwl_mvm_tdls_cancel_channel_switch,
4185 .tdls_recv_channel_switch = iwl_mvm_tdls_recv_channel_switch,
4186
Emmanuel Grumbachd42f5352015-02-10 14:29:48 +02004187 .event_callback = iwl_mvm_mac_event_callback,
4188
Sara Sharon0636b932016-02-18 14:21:12 +02004189 .sync_rx_queues = iwl_mvm_sync_rx_queues,
4190
David Spinadel507cadf2013-07-31 18:07:21 +03004191 CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd)
4192
Johannes Berg8ca151b2013-01-24 14:25:36 +01004193#ifdef CONFIG_PM_SLEEP
4194 /* look at d3.c */
4195 .suspend = iwl_mvm_suspend,
4196 .resume = iwl_mvm_resume,
4197 .set_wakeup = iwl_mvm_set_wakeup,
4198 .set_rekey_data = iwl_mvm_set_rekey_data,
4199#if IS_ENABLED(CONFIG_IPV6)
4200 .ipv6_addr_change = iwl_mvm_ipv6_addr_change,
4201#endif
4202 .set_default_unicast_key = iwl_mvm_set_default_unicast_key,
4203#endif
Johannes Berg91a8bcd2015-01-14 18:12:41 +01004204 .get_survey = iwl_mvm_mac_get_survey,
Johannes Berg33cef922015-01-21 21:41:29 +01004205 .sta_statistics = iwl_mvm_mac_sta_statistics,
Johannes Berg8ca151b2013-01-24 14:25:36 +01004206};