1e705c121SKalle Valo /******************************************************************************
2e705c121SKalle Valo  *
3e705c121SKalle Valo  * This file is provided under a dual BSD/GPLv2 license.  When using or
4e705c121SKalle Valo  * redistributing this file, you may do so under either license.
5e705c121SKalle Valo  *
6e705c121SKalle Valo  * GPL LICENSE SUMMARY
7e705c121SKalle Valo  *
8e705c121SKalle Valo  * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved.
9e705c121SKalle Valo  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
10854c5705SSara Sharon  * Copyright(c) 2016 Intel Deutschland GmbH
11e705c121SKalle Valo  *
12e705c121SKalle Valo  * This program is free software; you can redistribute it and/or modify
13e705c121SKalle Valo  * it under the terms of version 2 of the GNU General Public License as
14e705c121SKalle Valo  * published by the Free Software Foundation.
15e705c121SKalle Valo  *
16e705c121SKalle Valo  * This program is distributed in the hope that it will be useful, but
17e705c121SKalle Valo  * WITHOUT ANY WARRANTY; without even the implied warranty of
18e705c121SKalle Valo  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19e705c121SKalle Valo  * General Public License for more details.
20e705c121SKalle Valo  *
21e705c121SKalle Valo  * You should have received a copy of the GNU General Public License
22e705c121SKalle Valo  * along with this program; if not, write to the Free Software
23e705c121SKalle Valo  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
24e705c121SKalle Valo  * USA
25e705c121SKalle Valo  *
26e705c121SKalle Valo  * The full GNU General Public License is included in this distribution
27e705c121SKalle Valo  * in the file called COPYING.
28e705c121SKalle Valo  *
29e705c121SKalle Valo  * Contact Information:
30cb2f8277SEmmanuel Grumbach  *  Intel Linux Wireless <linuxwifi@intel.com>
31e705c121SKalle Valo  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
32e705c121SKalle Valo  *
33e705c121SKalle Valo  * BSD LICENSE
34e705c121SKalle Valo  *
35e705c121SKalle Valo  * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved.
36e705c121SKalle Valo  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
37854c5705SSara Sharon  * Copyright(c) 2016 Intel Deutschland GmbH
38e705c121SKalle Valo  * All rights reserved.
39e705c121SKalle Valo  *
40e705c121SKalle Valo  * Redistribution and use in source and binary forms, with or without
41e705c121SKalle Valo  * modification, are permitted provided that the following conditions
42e705c121SKalle Valo  * are met:
43e705c121SKalle Valo  *
44e705c121SKalle Valo  *  * Redistributions of source code must retain the above copyright
45e705c121SKalle Valo  *    notice, this list of conditions and the following disclaimer.
46e705c121SKalle Valo  *  * Redistributions in binary form must reproduce the above copyright
47e705c121SKalle Valo  *    notice, this list of conditions and the following disclaimer in
48e705c121SKalle Valo  *    the documentation and/or other materials provided with the
49e705c121SKalle Valo  *    distribution.
50e705c121SKalle Valo  *  * Neither the name Intel Corporation nor the names of its
51e705c121SKalle Valo  *    contributors may be used to endorse or promote products derived
52e705c121SKalle Valo  *    from this software without specific prior written permission.
53e705c121SKalle Valo  *
54e705c121SKalle Valo  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
55e705c121SKalle Valo  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
56e705c121SKalle Valo  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
57e705c121SKalle Valo  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
58e705c121SKalle Valo  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59e705c121SKalle Valo  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
60e705c121SKalle Valo  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
61e705c121SKalle Valo  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
62e705c121SKalle Valo  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63e705c121SKalle Valo  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
64e705c121SKalle Valo  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65e705c121SKalle Valo  *
66e705c121SKalle Valo  *****************************************************************************/
67e705c121SKalle Valo #include <net/mac80211.h>
68e705c121SKalle Valo 
69e705c121SKalle Valo #include "mvm.h"
70e705c121SKalle Valo #include "sta.h"
71e705c121SKalle Valo #include "rs.h"
72e705c121SKalle Valo 
73854c5705SSara Sharon /*
74854c5705SSara Sharon  * New version of ADD_STA_sta command added new fields at the end of the
75854c5705SSara Sharon  * structure, so sending the size of the relevant API's structure is enough to
76854c5705SSara Sharon  * support both API versions.
77854c5705SSara Sharon  */
78854c5705SSara Sharon static inline int iwl_mvm_add_sta_cmd_size(struct iwl_mvm *mvm)
79854c5705SSara Sharon {
80854c5705SSara Sharon 	return iwl_mvm_has_new_rx_api(mvm) ?
81854c5705SSara Sharon 		sizeof(struct iwl_mvm_add_sta_cmd) :
82854c5705SSara Sharon 		sizeof(struct iwl_mvm_add_sta_cmd_v7);
83854c5705SSara Sharon }
84854c5705SSara Sharon 
85e705c121SKalle Valo static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm,
86e705c121SKalle Valo 				    enum nl80211_iftype iftype)
87e705c121SKalle Valo {
88e705c121SKalle Valo 	int sta_id;
89e705c121SKalle Valo 	u32 reserved_ids = 0;
90e705c121SKalle Valo 
91e705c121SKalle Valo 	BUILD_BUG_ON(IWL_MVM_STATION_COUNT > 32);
92e705c121SKalle Valo 	WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status));
93e705c121SKalle Valo 
94e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
95e705c121SKalle Valo 
96e705c121SKalle Valo 	/* d0i3/d3 assumes the AP's sta_id (of sta vif) is 0. reserve it. */
97e705c121SKalle Valo 	if (iftype != NL80211_IFTYPE_STATION)
98e705c121SKalle Valo 		reserved_ids = BIT(0);
99e705c121SKalle Valo 
100e705c121SKalle Valo 	/* Don't take rcu_read_lock() since we are protected by mvm->mutex */
101e705c121SKalle Valo 	for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++) {
102e705c121SKalle Valo 		if (BIT(sta_id) & reserved_ids)
103e705c121SKalle Valo 			continue;
104e705c121SKalle Valo 
105e705c121SKalle Valo 		if (!rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
106e705c121SKalle Valo 					       lockdep_is_held(&mvm->mutex)))
107e705c121SKalle Valo 			return sta_id;
108e705c121SKalle Valo 	}
109e705c121SKalle Valo 	return IWL_MVM_STATION_COUNT;
110e705c121SKalle Valo }
111e705c121SKalle Valo 
112e705c121SKalle Valo /* send station add/update command to firmware */
113e705c121SKalle Valo int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
114e705c121SKalle Valo 			   bool update)
115e705c121SKalle Valo {
116e705c121SKalle Valo 	struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
117e705c121SKalle Valo 	struct iwl_mvm_add_sta_cmd add_sta_cmd = {
118e705c121SKalle Valo 		.sta_id = mvm_sta->sta_id,
119e705c121SKalle Valo 		.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color),
120e705c121SKalle Valo 		.add_modify = update ? 1 : 0,
121e705c121SKalle Valo 		.station_flags_msk = cpu_to_le32(STA_FLG_FAT_EN_MSK |
122e705c121SKalle Valo 						 STA_FLG_MIMO_EN_MSK),
123cf0cda19SLiad Kaufman 		.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg),
124e705c121SKalle Valo 	};
125e705c121SKalle Valo 	int ret;
126e705c121SKalle Valo 	u32 status;
127e705c121SKalle Valo 	u32 agg_size = 0, mpdu_dens = 0;
128e705c121SKalle Valo 
129e705c121SKalle Valo 	if (!update) {
130e705c121SKalle Valo 		add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk);
131e705c121SKalle Valo 		memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN);
132e705c121SKalle Valo 	}
133e705c121SKalle Valo 
134e705c121SKalle Valo 	switch (sta->bandwidth) {
135e705c121SKalle Valo 	case IEEE80211_STA_RX_BW_160:
136e705c121SKalle Valo 		add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_160MHZ);
137e705c121SKalle Valo 		/* fall through */
138e705c121SKalle Valo 	case IEEE80211_STA_RX_BW_80:
139e705c121SKalle Valo 		add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_80MHZ);
140e705c121SKalle Valo 		/* fall through */
141e705c121SKalle Valo 	case IEEE80211_STA_RX_BW_40:
142e705c121SKalle Valo 		add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_40MHZ);
143e705c121SKalle Valo 		/* fall through */
144e705c121SKalle Valo 	case IEEE80211_STA_RX_BW_20:
145e705c121SKalle Valo 		if (sta->ht_cap.ht_supported)
146e705c121SKalle Valo 			add_sta_cmd.station_flags |=
147e705c121SKalle Valo 				cpu_to_le32(STA_FLG_FAT_EN_20MHZ);
148e705c121SKalle Valo 		break;
149e705c121SKalle Valo 	}
150e705c121SKalle Valo 
151e705c121SKalle Valo 	switch (sta->rx_nss) {
152e705c121SKalle Valo 	case 1:
153e705c121SKalle Valo 		add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_SISO);
154e705c121SKalle Valo 		break;
155e705c121SKalle Valo 	case 2:
156e705c121SKalle Valo 		add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_MIMO2);
157e705c121SKalle Valo 		break;
158e705c121SKalle Valo 	case 3 ... 8:
159e705c121SKalle Valo 		add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_MIMO3);
160e705c121SKalle Valo 		break;
161e705c121SKalle Valo 	}
162e705c121SKalle Valo 
163e705c121SKalle Valo 	switch (sta->smps_mode) {
164e705c121SKalle Valo 	case IEEE80211_SMPS_AUTOMATIC:
165e705c121SKalle Valo 	case IEEE80211_SMPS_NUM_MODES:
166e705c121SKalle Valo 		WARN_ON(1);
167e705c121SKalle Valo 		break;
168e705c121SKalle Valo 	case IEEE80211_SMPS_STATIC:
169e705c121SKalle Valo 		/* override NSS */
170e705c121SKalle Valo 		add_sta_cmd.station_flags &= ~cpu_to_le32(STA_FLG_MIMO_EN_MSK);
171e705c121SKalle Valo 		add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_SISO);
172e705c121SKalle Valo 		break;
173e705c121SKalle Valo 	case IEEE80211_SMPS_DYNAMIC:
174e705c121SKalle Valo 		add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_RTS_MIMO_PROT);
175e705c121SKalle Valo 		break;
176e705c121SKalle Valo 	case IEEE80211_SMPS_OFF:
177e705c121SKalle Valo 		/* nothing */
178e705c121SKalle Valo 		break;
179e705c121SKalle Valo 	}
180e705c121SKalle Valo 
181e705c121SKalle Valo 	if (sta->ht_cap.ht_supported) {
182e705c121SKalle Valo 		add_sta_cmd.station_flags_msk |=
183e705c121SKalle Valo 			cpu_to_le32(STA_FLG_MAX_AGG_SIZE_MSK |
184e705c121SKalle Valo 				    STA_FLG_AGG_MPDU_DENS_MSK);
185e705c121SKalle Valo 
186e705c121SKalle Valo 		mpdu_dens = sta->ht_cap.ampdu_density;
187e705c121SKalle Valo 	}
188e705c121SKalle Valo 
189e705c121SKalle Valo 	if (sta->vht_cap.vht_supported) {
190e705c121SKalle Valo 		agg_size = sta->vht_cap.cap &
191e705c121SKalle Valo 			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
192e705c121SKalle Valo 		agg_size >>=
193e705c121SKalle Valo 			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
194e705c121SKalle Valo 	} else if (sta->ht_cap.ht_supported) {
195e705c121SKalle Valo 		agg_size = sta->ht_cap.ampdu_factor;
196e705c121SKalle Valo 	}
197e705c121SKalle Valo 
198e705c121SKalle Valo 	add_sta_cmd.station_flags |=
199e705c121SKalle Valo 		cpu_to_le32(agg_size << STA_FLG_MAX_AGG_SIZE_SHIFT);
200e705c121SKalle Valo 	add_sta_cmd.station_flags |=
201e705c121SKalle Valo 		cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT);
202e705c121SKalle Valo 
203e705c121SKalle Valo 	status = ADD_STA_SUCCESS;
204854c5705SSara Sharon 	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
205854c5705SSara Sharon 					  iwl_mvm_add_sta_cmd_size(mvm),
206e705c121SKalle Valo 					  &add_sta_cmd, &status);
207e705c121SKalle Valo 	if (ret)
208e705c121SKalle Valo 		return ret;
209e705c121SKalle Valo 
210837c4da9SSara Sharon 	switch (status & IWL_ADD_STA_STATUS_MASK) {
211e705c121SKalle Valo 	case ADD_STA_SUCCESS:
212e705c121SKalle Valo 		IWL_DEBUG_ASSOC(mvm, "ADD_STA PASSED\n");
213e705c121SKalle Valo 		break;
214e705c121SKalle Valo 	default:
215e705c121SKalle Valo 		ret = -EIO;
216e705c121SKalle Valo 		IWL_ERR(mvm, "ADD_STA failed\n");
217e705c121SKalle Valo 		break;
218e705c121SKalle Valo 	}
219e705c121SKalle Valo 
220e705c121SKalle Valo 	return ret;
221e705c121SKalle Valo }
222e705c121SKalle Valo 
223e705c121SKalle Valo static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm,
224e705c121SKalle Valo 				 struct ieee80211_sta *sta)
225e705c121SKalle Valo {
226e705c121SKalle Valo 	unsigned long used_hw_queues;
227e705c121SKalle Valo 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
228e705c121SKalle Valo 	unsigned int wdg_timeout =
229e705c121SKalle Valo 		iwl_mvm_get_wd_timeout(mvm, NULL, true, false);
230e705c121SKalle Valo 	u32 ac;
231e705c121SKalle Valo 
232e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
233e705c121SKalle Valo 
234e705c121SKalle Valo 	used_hw_queues = iwl_mvm_get_used_hw_queues(mvm, NULL);
235e705c121SKalle Valo 
236e705c121SKalle Valo 	/* Find available queues, and allocate them to the ACs */
237e705c121SKalle Valo 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
238e705c121SKalle Valo 		u8 queue = find_first_zero_bit(&used_hw_queues,
239e705c121SKalle Valo 					       mvm->first_agg_queue);
240e705c121SKalle Valo 
241e705c121SKalle Valo 		if (queue >= mvm->first_agg_queue) {
242e705c121SKalle Valo 			IWL_ERR(mvm, "Failed to allocate STA queue\n");
243e705c121SKalle Valo 			return -EBUSY;
244e705c121SKalle Valo 		}
245e705c121SKalle Valo 
246e705c121SKalle Valo 		__set_bit(queue, &used_hw_queues);
247e705c121SKalle Valo 		mvmsta->hw_queue[ac] = queue;
248e705c121SKalle Valo 	}
249e705c121SKalle Valo 
250e705c121SKalle Valo 	/* Found a place for all queues - enable them */
251e705c121SKalle Valo 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
252e705c121SKalle Valo 		iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac],
253e705c121SKalle Valo 				      mvmsta->hw_queue[ac],
254e705c121SKalle Valo 				      iwl_mvm_ac_to_tx_fifo[ac], 0,
255e705c121SKalle Valo 				      wdg_timeout);
256e705c121SKalle Valo 		mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]);
257e705c121SKalle Valo 	}
258e705c121SKalle Valo 
259e705c121SKalle Valo 	return 0;
260e705c121SKalle Valo }
261e705c121SKalle Valo 
262e705c121SKalle Valo static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm,
263e705c121SKalle Valo 				    struct ieee80211_sta *sta)
264e705c121SKalle Valo {
265e705c121SKalle Valo 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
266e705c121SKalle Valo 	unsigned long sta_msk;
267e705c121SKalle Valo 	int i;
268e705c121SKalle Valo 
269e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
270e705c121SKalle Valo 
271e705c121SKalle Valo 	/* disable the TDLS STA-specific queues */
272e705c121SKalle Valo 	sta_msk = mvmsta->tfd_queue_msk;
273e705c121SKalle Valo 	for_each_set_bit(i, &sta_msk, sizeof(sta_msk) * BITS_PER_BYTE)
274e705c121SKalle Valo 		iwl_mvm_disable_txq(mvm, i, i, IWL_MAX_TID_COUNT, 0);
275e705c121SKalle Valo }
276e705c121SKalle Valo 
277e705c121SKalle Valo int iwl_mvm_add_sta(struct iwl_mvm *mvm,
278e705c121SKalle Valo 		    struct ieee80211_vif *vif,
279e705c121SKalle Valo 		    struct ieee80211_sta *sta)
280e705c121SKalle Valo {
281e705c121SKalle Valo 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
282e705c121SKalle Valo 	struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
283e705c121SKalle Valo 	int i, ret, sta_id;
284e705c121SKalle Valo 
285e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
286e705c121SKalle Valo 
287e705c121SKalle Valo 	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
288e705c121SKalle Valo 		sta_id = iwl_mvm_find_free_sta_id(mvm,
289e705c121SKalle Valo 						  ieee80211_vif_type_p2p(vif));
290e705c121SKalle Valo 	else
291e705c121SKalle Valo 		sta_id = mvm_sta->sta_id;
292e705c121SKalle Valo 
293e705c121SKalle Valo 	if (sta_id == IWL_MVM_STATION_COUNT)
294e705c121SKalle Valo 		return -ENOSPC;
295e705c121SKalle Valo 
296e705c121SKalle Valo 	spin_lock_init(&mvm_sta->lock);
297e705c121SKalle Valo 
298e705c121SKalle Valo 	mvm_sta->sta_id = sta_id;
299e705c121SKalle Valo 	mvm_sta->mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id,
300e705c121SKalle Valo 						      mvmvif->color);
301e705c121SKalle Valo 	mvm_sta->vif = vif;
302e705c121SKalle Valo 	mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
303e705c121SKalle Valo 	mvm_sta->tx_protection = 0;
304e705c121SKalle Valo 	mvm_sta->tt_tx_protection = false;
305e705c121SKalle Valo 
306e705c121SKalle Valo 	/* HW restart, don't assume the memory has been zeroed */
307e705c121SKalle Valo 	atomic_set(&mvm->pending_frames[sta_id], 0);
308e705c121SKalle Valo 	mvm_sta->tid_disable_agg = 0xffff; /* No aggs at first */
309e705c121SKalle Valo 	mvm_sta->tfd_queue_msk = 0;
310e705c121SKalle Valo 
311e705c121SKalle Valo 	/* allocate new queues for a TDLS station */
312e705c121SKalle Valo 	if (sta->tdls) {
313e705c121SKalle Valo 		ret = iwl_mvm_tdls_sta_init(mvm, sta);
314e705c121SKalle Valo 		if (ret)
315e705c121SKalle Valo 			return ret;
316e705c121SKalle Valo 	} else {
317e705c121SKalle Valo 		for (i = 0; i < IEEE80211_NUM_ACS; i++)
318e705c121SKalle Valo 			if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE)
319e705c121SKalle Valo 				mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]);
320e705c121SKalle Valo 	}
321e705c121SKalle Valo 
322e705c121SKalle Valo 	/* for HW restart - reset everything but the sequence number */
323e705c121SKalle Valo 	for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
324e705c121SKalle Valo 		u16 seq = mvm_sta->tid_data[i].seq_number;
325e705c121SKalle Valo 		memset(&mvm_sta->tid_data[i], 0, sizeof(mvm_sta->tid_data[i]));
326e705c121SKalle Valo 		mvm_sta->tid_data[i].seq_number = seq;
327e705c121SKalle Valo 	}
328e705c121SKalle Valo 	mvm_sta->agg_tids = 0;
329e705c121SKalle Valo 
330e705c121SKalle Valo 	ret = iwl_mvm_sta_send_to_fw(mvm, sta, false);
331e705c121SKalle Valo 	if (ret)
332e705c121SKalle Valo 		goto err;
333e705c121SKalle Valo 
334e705c121SKalle Valo 	if (vif->type == NL80211_IFTYPE_STATION) {
335e705c121SKalle Valo 		if (!sta->tdls) {
336e705c121SKalle Valo 			WARN_ON(mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT);
337e705c121SKalle Valo 			mvmvif->ap_sta_id = sta_id;
338e705c121SKalle Valo 		} else {
339e705c121SKalle Valo 			WARN_ON(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT);
340e705c121SKalle Valo 		}
341e705c121SKalle Valo 	}
342e705c121SKalle Valo 
343e705c121SKalle Valo 	rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
344e705c121SKalle Valo 
345e705c121SKalle Valo 	return 0;
346e705c121SKalle Valo 
347e705c121SKalle Valo err:
348e705c121SKalle Valo 	iwl_mvm_tdls_sta_deinit(mvm, sta);
349e705c121SKalle Valo 	return ret;
350e705c121SKalle Valo }
351e705c121SKalle Valo 
352e705c121SKalle Valo int iwl_mvm_update_sta(struct iwl_mvm *mvm,
353e705c121SKalle Valo 		       struct ieee80211_vif *vif,
354e705c121SKalle Valo 		       struct ieee80211_sta *sta)
355e705c121SKalle Valo {
356e705c121SKalle Valo 	return iwl_mvm_sta_send_to_fw(mvm, sta, true);
357e705c121SKalle Valo }
358e705c121SKalle Valo 
359e705c121SKalle Valo int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
360e705c121SKalle Valo 		      bool drain)
361e705c121SKalle Valo {
362e705c121SKalle Valo 	struct iwl_mvm_add_sta_cmd cmd = {};
363e705c121SKalle Valo 	int ret;
364e705c121SKalle Valo 	u32 status;
365e705c121SKalle Valo 
366e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
367e705c121SKalle Valo 
368e705c121SKalle Valo 	cmd.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color);
369e705c121SKalle Valo 	cmd.sta_id = mvmsta->sta_id;
370e705c121SKalle Valo 	cmd.add_modify = STA_MODE_MODIFY;
371e705c121SKalle Valo 	cmd.station_flags = drain ? cpu_to_le32(STA_FLG_DRAIN_FLOW) : 0;
372e705c121SKalle Valo 	cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW);
373e705c121SKalle Valo 
374e705c121SKalle Valo 	status = ADD_STA_SUCCESS;
375854c5705SSara Sharon 	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
376854c5705SSara Sharon 					  iwl_mvm_add_sta_cmd_size(mvm),
377e705c121SKalle Valo 					  &cmd, &status);
378e705c121SKalle Valo 	if (ret)
379e705c121SKalle Valo 		return ret;
380e705c121SKalle Valo 
381837c4da9SSara Sharon 	switch (status & IWL_ADD_STA_STATUS_MASK) {
382e705c121SKalle Valo 	case ADD_STA_SUCCESS:
383e705c121SKalle Valo 		IWL_DEBUG_INFO(mvm, "Frames for staid %d will drained in fw\n",
384e705c121SKalle Valo 			       mvmsta->sta_id);
385e705c121SKalle Valo 		break;
386e705c121SKalle Valo 	default:
387e705c121SKalle Valo 		ret = -EIO;
388e705c121SKalle Valo 		IWL_ERR(mvm, "Couldn't drain frames for staid %d\n",
389e705c121SKalle Valo 			mvmsta->sta_id);
390e705c121SKalle Valo 		break;
391e705c121SKalle Valo 	}
392e705c121SKalle Valo 
393e705c121SKalle Valo 	return ret;
394e705c121SKalle Valo }
395e705c121SKalle Valo 
396e705c121SKalle Valo /*
397e705c121SKalle Valo  * Remove a station from the FW table. Before sending the command to remove
398e705c121SKalle Valo  * the station validate that the station is indeed known to the driver (sanity
399e705c121SKalle Valo  * only).
400e705c121SKalle Valo  */
401e705c121SKalle Valo static int iwl_mvm_rm_sta_common(struct iwl_mvm *mvm, u8 sta_id)
402e705c121SKalle Valo {
403e705c121SKalle Valo 	struct ieee80211_sta *sta;
404e705c121SKalle Valo 	struct iwl_mvm_rm_sta_cmd rm_sta_cmd = {
405e705c121SKalle Valo 		.sta_id = sta_id,
406e705c121SKalle Valo 	};
407e705c121SKalle Valo 	int ret;
408e705c121SKalle Valo 
409e705c121SKalle Valo 	sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
410e705c121SKalle Valo 					lockdep_is_held(&mvm->mutex));
411e705c121SKalle Valo 
412e705c121SKalle Valo 	/* Note: internal stations are marked as error values */
413e705c121SKalle Valo 	if (!sta) {
414e705c121SKalle Valo 		IWL_ERR(mvm, "Invalid station id\n");
415e705c121SKalle Valo 		return -EINVAL;
416e705c121SKalle Valo 	}
417e705c121SKalle Valo 
418e705c121SKalle Valo 	ret = iwl_mvm_send_cmd_pdu(mvm, REMOVE_STA, 0,
419e705c121SKalle Valo 				   sizeof(rm_sta_cmd), &rm_sta_cmd);
420e705c121SKalle Valo 	if (ret) {
421e705c121SKalle Valo 		IWL_ERR(mvm, "Failed to remove station. Id=%d\n", sta_id);
422e705c121SKalle Valo 		return ret;
423e705c121SKalle Valo 	}
424e705c121SKalle Valo 
425e705c121SKalle Valo 	return 0;
426e705c121SKalle Valo }
427e705c121SKalle Valo 
428e705c121SKalle Valo void iwl_mvm_sta_drained_wk(struct work_struct *wk)
429e705c121SKalle Valo {
430e705c121SKalle Valo 	struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, sta_drained_wk);
431e705c121SKalle Valo 	u8 sta_id;
432e705c121SKalle Valo 
433e705c121SKalle Valo 	/*
434e705c121SKalle Valo 	 * The mutex is needed because of the SYNC cmd, but not only: if the
435e705c121SKalle Valo 	 * work would run concurrently with iwl_mvm_rm_sta, it would run before
436e705c121SKalle Valo 	 * iwl_mvm_rm_sta sets the station as busy, and exit. Then
437e705c121SKalle Valo 	 * iwl_mvm_rm_sta would set the station as busy, and nobody will clean
438e705c121SKalle Valo 	 * that later.
439e705c121SKalle Valo 	 */
440e705c121SKalle Valo 	mutex_lock(&mvm->mutex);
441e705c121SKalle Valo 
442e705c121SKalle Valo 	for_each_set_bit(sta_id, mvm->sta_drained, IWL_MVM_STATION_COUNT) {
443e705c121SKalle Valo 		int ret;
444e705c121SKalle Valo 		struct ieee80211_sta *sta =
445e705c121SKalle Valo 			rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
446e705c121SKalle Valo 						  lockdep_is_held(&mvm->mutex));
447e705c121SKalle Valo 
448e705c121SKalle Valo 		/*
449e705c121SKalle Valo 		 * This station is in use or RCU-removed; the latter happens in
450e705c121SKalle Valo 		 * managed mode, where mac80211 removes the station before we
451e705c121SKalle Valo 		 * can remove it from firmware (we can only do that after the
452e705c121SKalle Valo 		 * MAC is marked unassociated), and possibly while the deauth
453e705c121SKalle Valo 		 * frame to disconnect from the AP is still queued. Then, the
454e705c121SKalle Valo 		 * station pointer is -ENOENT when the last skb is reclaimed.
455e705c121SKalle Valo 		 */
456e705c121SKalle Valo 		if (!IS_ERR(sta) || PTR_ERR(sta) == -ENOENT)
457e705c121SKalle Valo 			continue;
458e705c121SKalle Valo 
459e705c121SKalle Valo 		if (PTR_ERR(sta) == -EINVAL) {
460e705c121SKalle Valo 			IWL_ERR(mvm, "Drained sta %d, but it is internal?\n",
461e705c121SKalle Valo 				sta_id);
462e705c121SKalle Valo 			continue;
463e705c121SKalle Valo 		}
464e705c121SKalle Valo 
465e705c121SKalle Valo 		if (!sta) {
466e705c121SKalle Valo 			IWL_ERR(mvm, "Drained sta %d, but it was NULL?\n",
467e705c121SKalle Valo 				sta_id);
468e705c121SKalle Valo 			continue;
469e705c121SKalle Valo 		}
470e705c121SKalle Valo 
471e705c121SKalle Valo 		WARN_ON(PTR_ERR(sta) != -EBUSY);
472e705c121SKalle Valo 		/* This station was removed and we waited until it got drained,
473e705c121SKalle Valo 		 * we can now proceed and remove it.
474e705c121SKalle Valo 		 */
475e705c121SKalle Valo 		ret = iwl_mvm_rm_sta_common(mvm, sta_id);
476e705c121SKalle Valo 		if (ret) {
477e705c121SKalle Valo 			IWL_ERR(mvm,
478e705c121SKalle Valo 				"Couldn't remove sta %d after it was drained\n",
479e705c121SKalle Valo 				sta_id);
480e705c121SKalle Valo 			continue;
481e705c121SKalle Valo 		}
482e705c121SKalle Valo 		RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL);
483e705c121SKalle Valo 		clear_bit(sta_id, mvm->sta_drained);
484e705c121SKalle Valo 
485e705c121SKalle Valo 		if (mvm->tfd_drained[sta_id]) {
486e705c121SKalle Valo 			unsigned long i, msk = mvm->tfd_drained[sta_id];
487e705c121SKalle Valo 
488e705c121SKalle Valo 			for_each_set_bit(i, &msk, sizeof(msk) * BITS_PER_BYTE)
489e705c121SKalle Valo 				iwl_mvm_disable_txq(mvm, i, i,
490e705c121SKalle Valo 						    IWL_MAX_TID_COUNT, 0);
491e705c121SKalle Valo 
492e705c121SKalle Valo 			mvm->tfd_drained[sta_id] = 0;
493e705c121SKalle Valo 			IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n",
494e705c121SKalle Valo 				       sta_id, msk);
495e705c121SKalle Valo 		}
496e705c121SKalle Valo 	}
497e705c121SKalle Valo 
498e705c121SKalle Valo 	mutex_unlock(&mvm->mutex);
499e705c121SKalle Valo }
500e705c121SKalle Valo 
501e705c121SKalle Valo int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
502e705c121SKalle Valo 		   struct ieee80211_vif *vif,
503e705c121SKalle Valo 		   struct ieee80211_sta *sta)
504e705c121SKalle Valo {
505e705c121SKalle Valo 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
506e705c121SKalle Valo 	struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
507e705c121SKalle Valo 	int ret;
508e705c121SKalle Valo 
509e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
510e705c121SKalle Valo 
511e705c121SKalle Valo 	if (vif->type == NL80211_IFTYPE_STATION &&
512e705c121SKalle Valo 	    mvmvif->ap_sta_id == mvm_sta->sta_id) {
513e705c121SKalle Valo 		ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
514e705c121SKalle Valo 		if (ret)
515e705c121SKalle Valo 			return ret;
516e705c121SKalle Valo 		/* flush its queues here since we are freeing mvm_sta */
517e705c121SKalle Valo 		ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, 0);
518e705c121SKalle Valo 		if (ret)
519e705c121SKalle Valo 			return ret;
520e705c121SKalle Valo 		ret = iwl_trans_wait_tx_queue_empty(mvm->trans,
521e705c121SKalle Valo 						    mvm_sta->tfd_queue_msk);
522e705c121SKalle Valo 		if (ret)
523e705c121SKalle Valo 			return ret;
524e705c121SKalle Valo 		ret = iwl_mvm_drain_sta(mvm, mvm_sta, false);
525e705c121SKalle Valo 
526e705c121SKalle Valo 		/* if we are associated - we can't remove the AP STA now */
527e705c121SKalle Valo 		if (vif->bss_conf.assoc)
528e705c121SKalle Valo 			return ret;
529e705c121SKalle Valo 
530e705c121SKalle Valo 		/* unassoc - go ahead - remove the AP STA now */
531e705c121SKalle Valo 		mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
532e705c121SKalle Valo 
533e705c121SKalle Valo 		/* clear d0i3_ap_sta_id if no longer relevant */
534e705c121SKalle Valo 		if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id)
535e705c121SKalle Valo 			mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
536e705c121SKalle Valo 	}
537e705c121SKalle Valo 
538e705c121SKalle Valo 	/*
539e705c121SKalle Valo 	 * This shouldn't happen - the TDLS channel switch should be canceled
540e705c121SKalle Valo 	 * before the STA is removed.
541e705c121SKalle Valo 	 */
542e705c121SKalle Valo 	if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == mvm_sta->sta_id)) {
543e705c121SKalle Valo 		mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT;
544e705c121SKalle Valo 		cancel_delayed_work(&mvm->tdls_cs.dwork);
545e705c121SKalle Valo 	}
546e705c121SKalle Valo 
547e705c121SKalle Valo 	/*
548e705c121SKalle Valo 	 * Make sure that the tx response code sees the station as -EBUSY and
549e705c121SKalle Valo 	 * calls the drain worker.
550e705c121SKalle Valo 	 */
551e705c121SKalle Valo 	spin_lock_bh(&mvm_sta->lock);
552e705c121SKalle Valo 	/*
553e705c121SKalle Valo 	 * There are frames pending on the AC queues for this station.
554e705c121SKalle Valo 	 * We need to wait until all the frames are drained...
555e705c121SKalle Valo 	 */
556e705c121SKalle Valo 	if (atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) {
557e705c121SKalle Valo 		rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
558e705c121SKalle Valo 				   ERR_PTR(-EBUSY));
559e705c121SKalle Valo 		spin_unlock_bh(&mvm_sta->lock);
560e705c121SKalle Valo 
561e705c121SKalle Valo 		/* disable TDLS sta queues on drain complete */
562e705c121SKalle Valo 		if (sta->tdls) {
563e705c121SKalle Valo 			mvm->tfd_drained[mvm_sta->sta_id] =
564e705c121SKalle Valo 							mvm_sta->tfd_queue_msk;
565e705c121SKalle Valo 			IWL_DEBUG_TDLS(mvm, "Draining TDLS sta %d\n",
566e705c121SKalle Valo 				       mvm_sta->sta_id);
567e705c121SKalle Valo 		}
568e705c121SKalle Valo 
569e705c121SKalle Valo 		ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
570e705c121SKalle Valo 	} else {
571e705c121SKalle Valo 		spin_unlock_bh(&mvm_sta->lock);
572e705c121SKalle Valo 
573e705c121SKalle Valo 		if (sta->tdls)
574e705c121SKalle Valo 			iwl_mvm_tdls_sta_deinit(mvm, sta);
575e705c121SKalle Valo 
576e705c121SKalle Valo 		ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id);
577e705c121SKalle Valo 		RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL);
578e705c121SKalle Valo 	}
579e705c121SKalle Valo 
580e705c121SKalle Valo 	return ret;
581e705c121SKalle Valo }
582e705c121SKalle Valo 
583e705c121SKalle Valo int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
584e705c121SKalle Valo 		      struct ieee80211_vif *vif,
585e705c121SKalle Valo 		      u8 sta_id)
586e705c121SKalle Valo {
587e705c121SKalle Valo 	int ret = iwl_mvm_rm_sta_common(mvm, sta_id);
588e705c121SKalle Valo 
589e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
590e705c121SKalle Valo 
591e705c121SKalle Valo 	RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL);
592e705c121SKalle Valo 	return ret;
593e705c121SKalle Valo }
594e705c121SKalle Valo 
5950e39eb03SChaya Rachel Ivgi int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,
596e705c121SKalle Valo 			     struct iwl_mvm_int_sta *sta,
597e705c121SKalle Valo 			     u32 qmask, enum nl80211_iftype iftype)
598e705c121SKalle Valo {
599e705c121SKalle Valo 	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
600e705c121SKalle Valo 		sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype);
601e705c121SKalle Valo 		if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT))
602e705c121SKalle Valo 			return -ENOSPC;
603e705c121SKalle Valo 	}
604e705c121SKalle Valo 
605e705c121SKalle Valo 	sta->tfd_queue_msk = qmask;
606e705c121SKalle Valo 
607e705c121SKalle Valo 	/* put a non-NULL value so iterating over the stations won't stop */
608e705c121SKalle Valo 	rcu_assign_pointer(mvm->fw_id_to_mac_id[sta->sta_id], ERR_PTR(-EINVAL));
609e705c121SKalle Valo 	return 0;
610e705c121SKalle Valo }
611e705c121SKalle Valo 
612e705c121SKalle Valo static void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm,
613e705c121SKalle Valo 				    struct iwl_mvm_int_sta *sta)
614e705c121SKalle Valo {
615e705c121SKalle Valo 	RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL);
616e705c121SKalle Valo 	memset(sta, 0, sizeof(struct iwl_mvm_int_sta));
617e705c121SKalle Valo 	sta->sta_id = IWL_MVM_STATION_COUNT;
618e705c121SKalle Valo }
619e705c121SKalle Valo 
620e705c121SKalle Valo static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
621e705c121SKalle Valo 				      struct iwl_mvm_int_sta *sta,
622e705c121SKalle Valo 				      const u8 *addr,
623e705c121SKalle Valo 				      u16 mac_id, u16 color)
624e705c121SKalle Valo {
625e705c121SKalle Valo 	struct iwl_mvm_add_sta_cmd cmd;
626e705c121SKalle Valo 	int ret;
627e705c121SKalle Valo 	u32 status;
628e705c121SKalle Valo 
629e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
630e705c121SKalle Valo 
631e705c121SKalle Valo 	memset(&cmd, 0, sizeof(cmd));
632e705c121SKalle Valo 	cmd.sta_id = sta->sta_id;
633e705c121SKalle Valo 	cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id,
634e705c121SKalle Valo 							     color));
635e705c121SKalle Valo 
636e705c121SKalle Valo 	cmd.tfd_queue_msk = cpu_to_le32(sta->tfd_queue_msk);
637cf0cda19SLiad Kaufman 	cmd.tid_disable_tx = cpu_to_le16(0xffff);
638e705c121SKalle Valo 
639e705c121SKalle Valo 	if (addr)
640e705c121SKalle Valo 		memcpy(cmd.addr, addr, ETH_ALEN);
641e705c121SKalle Valo 
642854c5705SSara Sharon 	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
643854c5705SSara Sharon 					  iwl_mvm_add_sta_cmd_size(mvm),
644e705c121SKalle Valo 					  &cmd, &status);
645e705c121SKalle Valo 	if (ret)
646e705c121SKalle Valo 		return ret;
647e705c121SKalle Valo 
648837c4da9SSara Sharon 	switch (status & IWL_ADD_STA_STATUS_MASK) {
649e705c121SKalle Valo 	case ADD_STA_SUCCESS:
650e705c121SKalle Valo 		IWL_DEBUG_INFO(mvm, "Internal station added.\n");
651e705c121SKalle Valo 		return 0;
652e705c121SKalle Valo 	default:
653e705c121SKalle Valo 		ret = -EIO;
654e705c121SKalle Valo 		IWL_ERR(mvm, "Add internal station failed, status=0x%x\n",
655e705c121SKalle Valo 			status);
656e705c121SKalle Valo 		break;
657e705c121SKalle Valo 	}
658e705c121SKalle Valo 	return ret;
659e705c121SKalle Valo }
660e705c121SKalle Valo 
661e705c121SKalle Valo int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
662e705c121SKalle Valo {
663e705c121SKalle Valo 	unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ?
664e705c121SKalle Valo 					mvm->cfg->base_params->wd_timeout :
665e705c121SKalle Valo 					IWL_WATCHDOG_DISABLED;
666e705c121SKalle Valo 	int ret;
667e705c121SKalle Valo 
668e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
669e705c121SKalle Valo 
670e705c121SKalle Valo 	/* Map Aux queue to fifo - needs to happen before adding Aux station */
671e705c121SKalle Valo 	iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, mvm->aux_queue,
672e705c121SKalle Valo 			      IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout);
673e705c121SKalle Valo 
674e705c121SKalle Valo 	/* Allocate aux station and assign to it the aux queue */
675e705c121SKalle Valo 	ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue),
676e705c121SKalle Valo 				       NL80211_IFTYPE_UNSPECIFIED);
677e705c121SKalle Valo 	if (ret)
678e705c121SKalle Valo 		return ret;
679e705c121SKalle Valo 
680e705c121SKalle Valo 	ret = iwl_mvm_add_int_sta_common(mvm, &mvm->aux_sta, NULL,
681e705c121SKalle Valo 					 MAC_INDEX_AUX, 0);
682e705c121SKalle Valo 
683e705c121SKalle Valo 	if (ret)
684e705c121SKalle Valo 		iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
685e705c121SKalle Valo 	return ret;
686e705c121SKalle Valo }
687e705c121SKalle Valo 
6880e39eb03SChaya Rachel Ivgi int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
6890e39eb03SChaya Rachel Ivgi {
6900e39eb03SChaya Rachel Ivgi 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
6910e39eb03SChaya Rachel Ivgi 
6920e39eb03SChaya Rachel Ivgi 	lockdep_assert_held(&mvm->mutex);
6930e39eb03SChaya Rachel Ivgi 	return iwl_mvm_add_int_sta_common(mvm, &mvm->snif_sta, vif->addr,
6940e39eb03SChaya Rachel Ivgi 					 mvmvif->id, 0);
6950e39eb03SChaya Rachel Ivgi }
6960e39eb03SChaya Rachel Ivgi 
6970e39eb03SChaya Rachel Ivgi int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
6980e39eb03SChaya Rachel Ivgi {
6990e39eb03SChaya Rachel Ivgi 	int ret;
7000e39eb03SChaya Rachel Ivgi 
7010e39eb03SChaya Rachel Ivgi 	lockdep_assert_held(&mvm->mutex);
7020e39eb03SChaya Rachel Ivgi 
7030e39eb03SChaya Rachel Ivgi 	ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id);
7040e39eb03SChaya Rachel Ivgi 	if (ret)
7050e39eb03SChaya Rachel Ivgi 		IWL_WARN(mvm, "Failed sending remove station\n");
7060e39eb03SChaya Rachel Ivgi 
7070e39eb03SChaya Rachel Ivgi 	return ret;
7080e39eb03SChaya Rachel Ivgi }
7090e39eb03SChaya Rachel Ivgi 
7100e39eb03SChaya Rachel Ivgi void iwl_mvm_dealloc_snif_sta(struct iwl_mvm *mvm)
7110e39eb03SChaya Rachel Ivgi {
7120e39eb03SChaya Rachel Ivgi 	iwl_mvm_dealloc_int_sta(mvm, &mvm->snif_sta);
7130e39eb03SChaya Rachel Ivgi }
7140e39eb03SChaya Rachel Ivgi 
715e705c121SKalle Valo void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm)
716e705c121SKalle Valo {
717e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
718e705c121SKalle Valo 
719e705c121SKalle Valo 	iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
720e705c121SKalle Valo }
721e705c121SKalle Valo 
722e705c121SKalle Valo /*
723e705c121SKalle Valo  * Send the add station command for the vif's broadcast station.
724e705c121SKalle Valo  * Assumes that the station was already allocated.
725e705c121SKalle Valo  *
726e705c121SKalle Valo  * @mvm: the mvm component
727e705c121SKalle Valo  * @vif: the interface to which the broadcast station is added
728e705c121SKalle Valo  * @bsta: the broadcast station to add.
729e705c121SKalle Valo  */
730e705c121SKalle Valo int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
731e705c121SKalle Valo {
732e705c121SKalle Valo 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
733e705c121SKalle Valo 	struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta;
734e705c121SKalle Valo 	static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
735e705c121SKalle Valo 	const u8 *baddr = _baddr;
736e705c121SKalle Valo 
737e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
738e705c121SKalle Valo 
739e705c121SKalle Valo 	if (vif->type == NL80211_IFTYPE_ADHOC)
740e705c121SKalle Valo 		baddr = vif->bss_conf.bssid;
741e705c121SKalle Valo 
742e705c121SKalle Valo 	if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_STATION_COUNT))
743e705c121SKalle Valo 		return -ENOSPC;
744e705c121SKalle Valo 
745e705c121SKalle Valo 	return iwl_mvm_add_int_sta_common(mvm, bsta, baddr,
746e705c121SKalle Valo 					  mvmvif->id, mvmvif->color);
747e705c121SKalle Valo }
748e705c121SKalle Valo 
749e705c121SKalle Valo /* Send the FW a request to remove the station from it's internal data
750e705c121SKalle Valo  * structures, but DO NOT remove the entry from the local data structures. */
751e705c121SKalle Valo int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
752e705c121SKalle Valo {
753e705c121SKalle Valo 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
754e705c121SKalle Valo 	int ret;
755e705c121SKalle Valo 
756e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
757e705c121SKalle Valo 
758e705c121SKalle Valo 	ret = iwl_mvm_rm_sta_common(mvm, mvmvif->bcast_sta.sta_id);
759e705c121SKalle Valo 	if (ret)
760e705c121SKalle Valo 		IWL_WARN(mvm, "Failed sending remove station\n");
761e705c121SKalle Valo 	return ret;
762e705c121SKalle Valo }
763e705c121SKalle Valo 
764e705c121SKalle Valo int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
765e705c121SKalle Valo {
766e705c121SKalle Valo 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
767e705c121SKalle Valo 	u32 qmask;
768e705c121SKalle Valo 
769e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
770e705c121SKalle Valo 
771e705c121SKalle Valo 	qmask = iwl_mvm_mac_get_queues_mask(vif);
772e705c121SKalle Valo 
773e705c121SKalle Valo 	/*
774e705c121SKalle Valo 	 * The firmware defines the TFD queue mask to only be relevant
775e705c121SKalle Valo 	 * for *unicast* queues, so the multicast (CAB) queue shouldn't
776e705c121SKalle Valo 	 * be included.
777e705c121SKalle Valo 	 */
778e705c121SKalle Valo 	if (vif->type == NL80211_IFTYPE_AP)
779e705c121SKalle Valo 		qmask &= ~BIT(vif->cab_queue);
780e705c121SKalle Valo 
781e705c121SKalle Valo 	return iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, qmask,
782e705c121SKalle Valo 					ieee80211_vif_type_p2p(vif));
783e705c121SKalle Valo }
784e705c121SKalle Valo 
785e705c121SKalle Valo /* Allocate a new station entry for the broadcast station to the given vif,
786e705c121SKalle Valo  * and send it to the FW.
787e705c121SKalle Valo  * Note that each P2P mac should have its own broadcast station.
788e705c121SKalle Valo  *
789e705c121SKalle Valo  * @mvm: the mvm component
790e705c121SKalle Valo  * @vif: the interface to which the broadcast station is added
791e705c121SKalle Valo  * @bsta: the broadcast station to add. */
792e705c121SKalle Valo int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
793e705c121SKalle Valo {
794e705c121SKalle Valo 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
795e705c121SKalle Valo 	struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta;
796e705c121SKalle Valo 	int ret;
797e705c121SKalle Valo 
798e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
799e705c121SKalle Valo 
800e705c121SKalle Valo 	ret = iwl_mvm_alloc_bcast_sta(mvm, vif);
801e705c121SKalle Valo 	if (ret)
802e705c121SKalle Valo 		return ret;
803e705c121SKalle Valo 
804e705c121SKalle Valo 	ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
805e705c121SKalle Valo 
806e705c121SKalle Valo 	if (ret)
807e705c121SKalle Valo 		iwl_mvm_dealloc_int_sta(mvm, bsta);
808e705c121SKalle Valo 
809e705c121SKalle Valo 	return ret;
810e705c121SKalle Valo }
811e705c121SKalle Valo 
812e705c121SKalle Valo void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
813e705c121SKalle Valo {
814e705c121SKalle Valo 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
815e705c121SKalle Valo 
816e705c121SKalle Valo 	iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
817e705c121SKalle Valo }
818e705c121SKalle Valo 
819e705c121SKalle Valo /*
820e705c121SKalle Valo  * Send the FW a request to remove the station from it's internal data
821e705c121SKalle Valo  * structures, and in addition remove it from the local data structure.
822e705c121SKalle Valo  */
823e705c121SKalle Valo int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
824e705c121SKalle Valo {
825e705c121SKalle Valo 	int ret;
826e705c121SKalle Valo 
827e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
828e705c121SKalle Valo 
829e705c121SKalle Valo 	ret = iwl_mvm_send_rm_bcast_sta(mvm, vif);
830e705c121SKalle Valo 
831e705c121SKalle Valo 	iwl_mvm_dealloc_bcast_sta(mvm, vif);
832e705c121SKalle Valo 
833e705c121SKalle Valo 	return ret;
834e705c121SKalle Valo }
835e705c121SKalle Valo 
836e705c121SKalle Valo #define IWL_MAX_RX_BA_SESSIONS 16
837e705c121SKalle Valo 
838e705c121SKalle Valo int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
839854c5705SSara Sharon 		       int tid, u16 ssn, bool start, u8 buf_size)
840e705c121SKalle Valo {
841e705c121SKalle Valo 	struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
842e705c121SKalle Valo 	struct iwl_mvm_add_sta_cmd cmd = {};
843e705c121SKalle Valo 	int ret;
844e705c121SKalle Valo 	u32 status;
845e705c121SKalle Valo 
846e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
847e705c121SKalle Valo 
848e705c121SKalle Valo 	if (start && mvm->rx_ba_sessions >= IWL_MAX_RX_BA_SESSIONS) {
849e705c121SKalle Valo 		IWL_WARN(mvm, "Not enough RX BA SESSIONS\n");
850e705c121SKalle Valo 		return -ENOSPC;
851e705c121SKalle Valo 	}
852e705c121SKalle Valo 
853e705c121SKalle Valo 	cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
854e705c121SKalle Valo 	cmd.sta_id = mvm_sta->sta_id;
855e705c121SKalle Valo 	cmd.add_modify = STA_MODE_MODIFY;
856e705c121SKalle Valo 	if (start) {
857e705c121SKalle Valo 		cmd.add_immediate_ba_tid = (u8) tid;
858e705c121SKalle Valo 		cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
859854c5705SSara Sharon 		cmd.rx_ba_window = cpu_to_le16((u16)buf_size);
860e705c121SKalle Valo 	} else {
861e705c121SKalle Valo 		cmd.remove_immediate_ba_tid = (u8) tid;
862e705c121SKalle Valo 	}
863e705c121SKalle Valo 	cmd.modify_mask = start ? STA_MODIFY_ADD_BA_TID :
864e705c121SKalle Valo 				  STA_MODIFY_REMOVE_BA_TID;
865e705c121SKalle Valo 
866e705c121SKalle Valo 	status = ADD_STA_SUCCESS;
867854c5705SSara Sharon 	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
868854c5705SSara Sharon 					  iwl_mvm_add_sta_cmd_size(mvm),
869e705c121SKalle Valo 					  &cmd, &status);
870e705c121SKalle Valo 	if (ret)
871e705c121SKalle Valo 		return ret;
872e705c121SKalle Valo 
873837c4da9SSara Sharon 	switch (status & IWL_ADD_STA_STATUS_MASK) {
874e705c121SKalle Valo 	case ADD_STA_SUCCESS:
875e705c121SKalle Valo 		IWL_DEBUG_INFO(mvm, "RX BA Session %sed in fw\n",
876e705c121SKalle Valo 			       start ? "start" : "stopp");
877e705c121SKalle Valo 		break;
878e705c121SKalle Valo 	case ADD_STA_IMMEDIATE_BA_FAILURE:
879e705c121SKalle Valo 		IWL_WARN(mvm, "RX BA Session refused by fw\n");
880e705c121SKalle Valo 		ret = -ENOSPC;
881e705c121SKalle Valo 		break;
882e705c121SKalle Valo 	default:
883e705c121SKalle Valo 		ret = -EIO;
884e705c121SKalle Valo 		IWL_ERR(mvm, "RX BA Session failed %sing, status 0x%x\n",
885e705c121SKalle Valo 			start ? "start" : "stopp", status);
886e705c121SKalle Valo 		break;
887e705c121SKalle Valo 	}
888e705c121SKalle Valo 
889e705c121SKalle Valo 	if (!ret) {
890e705c121SKalle Valo 		if (start)
891e705c121SKalle Valo 			mvm->rx_ba_sessions++;
892e705c121SKalle Valo 		else if (mvm->rx_ba_sessions > 0)
893e705c121SKalle Valo 			/* check that restart flow didn't zero the counter */
894e705c121SKalle Valo 			mvm->rx_ba_sessions--;
895e705c121SKalle Valo 	}
896e705c121SKalle Valo 
897e705c121SKalle Valo 	return ret;
898e705c121SKalle Valo }
899e705c121SKalle Valo 
900e705c121SKalle Valo static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
901e705c121SKalle Valo 			      int tid, u8 queue, bool start)
902e705c121SKalle Valo {
903e705c121SKalle Valo 	struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
904e705c121SKalle Valo 	struct iwl_mvm_add_sta_cmd cmd = {};
905e705c121SKalle Valo 	int ret;
906e705c121SKalle Valo 	u32 status;
907e705c121SKalle Valo 
908e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
909e705c121SKalle Valo 
910e705c121SKalle Valo 	if (start) {
911e705c121SKalle Valo 		mvm_sta->tfd_queue_msk |= BIT(queue);
912e705c121SKalle Valo 		mvm_sta->tid_disable_agg &= ~BIT(tid);
913e705c121SKalle Valo 	} else {
914e705c121SKalle Valo 		mvm_sta->tfd_queue_msk &= ~BIT(queue);
915e705c121SKalle Valo 		mvm_sta->tid_disable_agg |= BIT(tid);
916e705c121SKalle Valo 	}
917e705c121SKalle Valo 
918e705c121SKalle Valo 	cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
919e705c121SKalle Valo 	cmd.sta_id = mvm_sta->sta_id;
920e705c121SKalle Valo 	cmd.add_modify = STA_MODE_MODIFY;
921e705c121SKalle Valo 	cmd.modify_mask = STA_MODIFY_QUEUES | STA_MODIFY_TID_DISABLE_TX;
922e705c121SKalle Valo 	cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk);
923e705c121SKalle Valo 	cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg);
924e705c121SKalle Valo 
925e705c121SKalle Valo 	status = ADD_STA_SUCCESS;
926854c5705SSara Sharon 	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
927854c5705SSara Sharon 					  iwl_mvm_add_sta_cmd_size(mvm),
928e705c121SKalle Valo 					  &cmd, &status);
929e705c121SKalle Valo 	if (ret)
930e705c121SKalle Valo 		return ret;
931e705c121SKalle Valo 
932837c4da9SSara Sharon 	switch (status & IWL_ADD_STA_STATUS_MASK) {
933e705c121SKalle Valo 	case ADD_STA_SUCCESS:
934e705c121SKalle Valo 		break;
935e705c121SKalle Valo 	default:
936e705c121SKalle Valo 		ret = -EIO;
937e705c121SKalle Valo 		IWL_ERR(mvm, "TX BA Session failed %sing, status 0x%x\n",
938e705c121SKalle Valo 			start ? "start" : "stopp", status);
939e705c121SKalle Valo 		break;
940e705c121SKalle Valo 	}
941e705c121SKalle Valo 
942e705c121SKalle Valo 	return ret;
943e705c121SKalle Valo }
944e705c121SKalle Valo 
945e705c121SKalle Valo const u8 tid_to_mac80211_ac[] = {
946e705c121SKalle Valo 	IEEE80211_AC_BE,
947e705c121SKalle Valo 	IEEE80211_AC_BK,
948e705c121SKalle Valo 	IEEE80211_AC_BK,
949e705c121SKalle Valo 	IEEE80211_AC_BE,
950e705c121SKalle Valo 	IEEE80211_AC_VI,
951e705c121SKalle Valo 	IEEE80211_AC_VI,
952e705c121SKalle Valo 	IEEE80211_AC_VO,
953e705c121SKalle Valo 	IEEE80211_AC_VO,
954e705c121SKalle Valo };
955e705c121SKalle Valo 
956e705c121SKalle Valo static const u8 tid_to_ucode_ac[] = {
957e705c121SKalle Valo 	AC_BE,
958e705c121SKalle Valo 	AC_BK,
959e705c121SKalle Valo 	AC_BK,
960e705c121SKalle Valo 	AC_BE,
961e705c121SKalle Valo 	AC_VI,
962e705c121SKalle Valo 	AC_VI,
963e705c121SKalle Valo 	AC_VO,
964e705c121SKalle Valo 	AC_VO,
965e705c121SKalle Valo };
966e705c121SKalle Valo 
967e705c121SKalle Valo int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
968e705c121SKalle Valo 			     struct ieee80211_sta *sta, u16 tid, u16 *ssn)
969e705c121SKalle Valo {
970e705c121SKalle Valo 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
971e705c121SKalle Valo 	struct iwl_mvm_tid_data *tid_data;
972e705c121SKalle Valo 	int txq_id;
973e705c121SKalle Valo 	int ret;
974e705c121SKalle Valo 
975e705c121SKalle Valo 	if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
976e705c121SKalle Valo 		return -EINVAL;
977e705c121SKalle Valo 
978e705c121SKalle Valo 	if (mvmsta->tid_data[tid].state != IWL_AGG_OFF) {
979e705c121SKalle Valo 		IWL_ERR(mvm, "Start AGG when state is not IWL_AGG_OFF %d!\n",
980e705c121SKalle Valo 			mvmsta->tid_data[tid].state);
981e705c121SKalle Valo 		return -ENXIO;
982e705c121SKalle Valo 	}
983e705c121SKalle Valo 
984e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
985e705c121SKalle Valo 
986e705c121SKalle Valo 	spin_lock_bh(&mvmsta->lock);
987e705c121SKalle Valo 
988e705c121SKalle Valo 	/* possible race condition - we entered D0i3 while starting agg */
989e705c121SKalle Valo 	if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status)) {
990e705c121SKalle Valo 		spin_unlock_bh(&mvmsta->lock);
991e705c121SKalle Valo 		IWL_ERR(mvm, "Entered D0i3 while starting Tx agg\n");
992e705c121SKalle Valo 		return -EIO;
993e705c121SKalle Valo 	}
994e705c121SKalle Valo 
995e705c121SKalle Valo 	spin_lock_bh(&mvm->queue_info_lock);
996e705c121SKalle Valo 
997e705c121SKalle Valo 	txq_id = iwl_mvm_find_free_queue(mvm, mvm->first_agg_queue,
998e705c121SKalle Valo 					 mvm->last_agg_queue);
999e705c121SKalle Valo 	if (txq_id < 0) {
1000e705c121SKalle Valo 		ret = txq_id;
1001e705c121SKalle Valo 		spin_unlock_bh(&mvm->queue_info_lock);
1002e705c121SKalle Valo 		IWL_ERR(mvm, "Failed to allocate agg queue\n");
1003e705c121SKalle Valo 		goto release_locks;
1004e705c121SKalle Valo 	}
1005e705c121SKalle Valo 	mvm->queue_info[txq_id].setup_reserved = true;
1006e705c121SKalle Valo 	spin_unlock_bh(&mvm->queue_info_lock);
1007e705c121SKalle Valo 
1008e705c121SKalle Valo 	tid_data = &mvmsta->tid_data[tid];
1009e705c121SKalle Valo 	tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
1010e705c121SKalle Valo 	tid_data->txq_id = txq_id;
1011e705c121SKalle Valo 	*ssn = tid_data->ssn;
1012e705c121SKalle Valo 
1013e705c121SKalle Valo 	IWL_DEBUG_TX_QUEUES(mvm,
1014e705c121SKalle Valo 			    "Start AGG: sta %d tid %d queue %d - ssn = %d, next_recl = %d\n",
1015e705c121SKalle Valo 			    mvmsta->sta_id, tid, txq_id, tid_data->ssn,
1016e705c121SKalle Valo 			    tid_data->next_reclaimed);
1017e705c121SKalle Valo 
1018e705c121SKalle Valo 	if (tid_data->ssn == tid_data->next_reclaimed) {
1019e705c121SKalle Valo 		tid_data->state = IWL_AGG_STARTING;
1020e705c121SKalle Valo 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1021e705c121SKalle Valo 	} else {
1022e705c121SKalle Valo 		tid_data->state = IWL_EMPTYING_HW_QUEUE_ADDBA;
1023e705c121SKalle Valo 	}
1024e705c121SKalle Valo 
1025e705c121SKalle Valo 	ret = 0;
1026e705c121SKalle Valo 
1027e705c121SKalle Valo release_locks:
1028e705c121SKalle Valo 	spin_unlock_bh(&mvmsta->lock);
1029e705c121SKalle Valo 
1030e705c121SKalle Valo 	return ret;
1031e705c121SKalle Valo }
1032e705c121SKalle Valo 
1033e705c121SKalle Valo int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1034bb81bb68SEmmanuel Grumbach 			    struct ieee80211_sta *sta, u16 tid, u8 buf_size,
1035bb81bb68SEmmanuel Grumbach 			    bool amsdu)
1036e705c121SKalle Valo {
1037e705c121SKalle Valo 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1038e705c121SKalle Valo 	struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
1039e705c121SKalle Valo 	unsigned int wdg_timeout =
1040e705c121SKalle Valo 		iwl_mvm_get_wd_timeout(mvm, vif, sta->tdls, false);
1041e705c121SKalle Valo 	int queue, fifo, ret;
1042e705c121SKalle Valo 	u16 ssn;
1043e705c121SKalle Valo 
1044e705c121SKalle Valo 	BUILD_BUG_ON((sizeof(mvmsta->agg_tids) * BITS_PER_BYTE)
1045e705c121SKalle Valo 		     != IWL_MAX_TID_COUNT);
1046e705c121SKalle Valo 
1047e705c121SKalle Valo 	buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
1048e705c121SKalle Valo 
1049e705c121SKalle Valo 	spin_lock_bh(&mvmsta->lock);
1050e705c121SKalle Valo 	ssn = tid_data->ssn;
1051e705c121SKalle Valo 	queue = tid_data->txq_id;
1052e705c121SKalle Valo 	tid_data->state = IWL_AGG_ON;
1053e705c121SKalle Valo 	mvmsta->agg_tids |= BIT(tid);
1054e705c121SKalle Valo 	tid_data->ssn = 0xffff;
1055bb81bb68SEmmanuel Grumbach 	tid_data->amsdu_in_ampdu_allowed = amsdu;
1056e705c121SKalle Valo 	spin_unlock_bh(&mvmsta->lock);
1057e705c121SKalle Valo 
1058e705c121SKalle Valo 	fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
1059e705c121SKalle Valo 
1060e705c121SKalle Valo 	iwl_mvm_enable_agg_txq(mvm, queue,
1061e705c121SKalle Valo 			       vif->hw_queue[tid_to_mac80211_ac[tid]], fifo,
1062e705c121SKalle Valo 			       mvmsta->sta_id, tid, buf_size, ssn, wdg_timeout);
1063e705c121SKalle Valo 
1064e705c121SKalle Valo 	ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
1065e705c121SKalle Valo 	if (ret)
1066e705c121SKalle Valo 		return -EIO;
1067e705c121SKalle Valo 
1068e705c121SKalle Valo 	/* No need to mark as reserved */
1069e705c121SKalle Valo 	spin_lock_bh(&mvm->queue_info_lock);
1070e705c121SKalle Valo 	mvm->queue_info[queue].setup_reserved = false;
1071e705c121SKalle Valo 	spin_unlock_bh(&mvm->queue_info_lock);
1072e705c121SKalle Valo 
1073e705c121SKalle Valo 	/*
1074e705c121SKalle Valo 	 * Even though in theory the peer could have different
1075e705c121SKalle Valo 	 * aggregation reorder buffer sizes for different sessions,
1076e705c121SKalle Valo 	 * our ucode doesn't allow for that and has a global limit
1077e705c121SKalle Valo 	 * for each station. Therefore, use the minimum of all the
1078e705c121SKalle Valo 	 * aggregation sessions and our default value.
1079e705c121SKalle Valo 	 */
1080e705c121SKalle Valo 	mvmsta->max_agg_bufsize =
1081e705c121SKalle Valo 		min(mvmsta->max_agg_bufsize, buf_size);
1082e705c121SKalle Valo 	mvmsta->lq_sta.lq.agg_frame_cnt_limit = mvmsta->max_agg_bufsize;
1083e705c121SKalle Valo 
1084e705c121SKalle Valo 	IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n",
1085e705c121SKalle Valo 		     sta->addr, tid);
1086e705c121SKalle Valo 
1087e705c121SKalle Valo 	return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, false);
1088e705c121SKalle Valo }
1089e705c121SKalle Valo 
1090e705c121SKalle Valo int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1091e705c121SKalle Valo 			    struct ieee80211_sta *sta, u16 tid)
1092e705c121SKalle Valo {
1093e705c121SKalle Valo 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1094e705c121SKalle Valo 	struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
1095e705c121SKalle Valo 	u16 txq_id;
1096e705c121SKalle Valo 	int err;
1097e705c121SKalle Valo 
1098e705c121SKalle Valo 
1099e705c121SKalle Valo 	/*
1100e705c121SKalle Valo 	 * If mac80211 is cleaning its state, then say that we finished since
1101e705c121SKalle Valo 	 * our state has been cleared anyway.
1102e705c121SKalle Valo 	 */
1103e705c121SKalle Valo 	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
1104e705c121SKalle Valo 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1105e705c121SKalle Valo 		return 0;
1106e705c121SKalle Valo 	}
1107e705c121SKalle Valo 
1108e705c121SKalle Valo 	spin_lock_bh(&mvmsta->lock);
1109e705c121SKalle Valo 
1110e705c121SKalle Valo 	txq_id = tid_data->txq_id;
1111e705c121SKalle Valo 
1112e705c121SKalle Valo 	IWL_DEBUG_TX_QUEUES(mvm, "Stop AGG: sta %d tid %d q %d state %d\n",
1113e705c121SKalle Valo 			    mvmsta->sta_id, tid, txq_id, tid_data->state);
1114e705c121SKalle Valo 
1115e705c121SKalle Valo 	mvmsta->agg_tids &= ~BIT(tid);
1116e705c121SKalle Valo 
1117e705c121SKalle Valo 	/* No need to mark as reserved anymore */
1118e705c121SKalle Valo 	spin_lock_bh(&mvm->queue_info_lock);
1119e705c121SKalle Valo 	mvm->queue_info[txq_id].setup_reserved = false;
1120e705c121SKalle Valo 	spin_unlock_bh(&mvm->queue_info_lock);
1121e705c121SKalle Valo 
1122e705c121SKalle Valo 	switch (tid_data->state) {
1123e705c121SKalle Valo 	case IWL_AGG_ON:
1124e705c121SKalle Valo 		tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
1125e705c121SKalle Valo 
1126e705c121SKalle Valo 		IWL_DEBUG_TX_QUEUES(mvm,
1127e705c121SKalle Valo 				    "ssn = %d, next_recl = %d\n",
1128e705c121SKalle Valo 				    tid_data->ssn, tid_data->next_reclaimed);
1129e705c121SKalle Valo 
1130e705c121SKalle Valo 		/* There are still packets for this RA / TID in the HW */
1131e705c121SKalle Valo 		if (tid_data->ssn != tid_data->next_reclaimed) {
1132e705c121SKalle Valo 			tid_data->state = IWL_EMPTYING_HW_QUEUE_DELBA;
1133e705c121SKalle Valo 			err = 0;
1134e705c121SKalle Valo 			break;
1135e705c121SKalle Valo 		}
1136e705c121SKalle Valo 
1137e705c121SKalle Valo 		tid_data->ssn = 0xffff;
1138e705c121SKalle Valo 		tid_data->state = IWL_AGG_OFF;
1139e705c121SKalle Valo 		spin_unlock_bh(&mvmsta->lock);
1140e705c121SKalle Valo 
1141e705c121SKalle Valo 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1142e705c121SKalle Valo 
1143e705c121SKalle Valo 		iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
1144e705c121SKalle Valo 
1145e705c121SKalle Valo 		iwl_mvm_disable_txq(mvm, txq_id,
1146e705c121SKalle Valo 				    vif->hw_queue[tid_to_mac80211_ac[tid]], tid,
1147e705c121SKalle Valo 				    0);
1148e705c121SKalle Valo 		return 0;
1149e705c121SKalle Valo 	case IWL_AGG_STARTING:
1150e705c121SKalle Valo 	case IWL_EMPTYING_HW_QUEUE_ADDBA:
1151e705c121SKalle Valo 		/*
1152e705c121SKalle Valo 		 * The agg session has been stopped before it was set up. This
1153e705c121SKalle Valo 		 * can happen when the AddBA timer times out for example.
1154e705c121SKalle Valo 		 */
1155e705c121SKalle Valo 
1156e705c121SKalle Valo 		/* No barriers since we are under mutex */
1157e705c121SKalle Valo 		lockdep_assert_held(&mvm->mutex);
1158e705c121SKalle Valo 
1159e705c121SKalle Valo 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1160e705c121SKalle Valo 		tid_data->state = IWL_AGG_OFF;
1161e705c121SKalle Valo 		err = 0;
1162e705c121SKalle Valo 		break;
1163e705c121SKalle Valo 	default:
1164e705c121SKalle Valo 		IWL_ERR(mvm,
1165e705c121SKalle Valo 			"Stopping AGG while state not ON or starting for %d on %d (%d)\n",
1166e705c121SKalle Valo 			mvmsta->sta_id, tid, tid_data->state);
1167e705c121SKalle Valo 		IWL_ERR(mvm,
1168e705c121SKalle Valo 			"\ttid_data->txq_id = %d\n", tid_data->txq_id);
1169e705c121SKalle Valo 		err = -EINVAL;
1170e705c121SKalle Valo 	}
1171e705c121SKalle Valo 
1172e705c121SKalle Valo 	spin_unlock_bh(&mvmsta->lock);
1173e705c121SKalle Valo 
1174e705c121SKalle Valo 	return err;
1175e705c121SKalle Valo }
1176e705c121SKalle Valo 
1177e705c121SKalle Valo int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1178e705c121SKalle Valo 			    struct ieee80211_sta *sta, u16 tid)
1179e705c121SKalle Valo {
1180e705c121SKalle Valo 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1181e705c121SKalle Valo 	struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
1182e705c121SKalle Valo 	u16 txq_id;
1183e705c121SKalle Valo 	enum iwl_mvm_agg_state old_state;
1184e705c121SKalle Valo 
1185e705c121SKalle Valo 	/*
1186e705c121SKalle Valo 	 * First set the agg state to OFF to avoid calling
1187e705c121SKalle Valo 	 * ieee80211_stop_tx_ba_cb in iwl_mvm_check_ratid_empty.
1188e705c121SKalle Valo 	 */
1189e705c121SKalle Valo 	spin_lock_bh(&mvmsta->lock);
1190e705c121SKalle Valo 	txq_id = tid_data->txq_id;
1191e705c121SKalle Valo 	IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n",
1192e705c121SKalle Valo 			    mvmsta->sta_id, tid, txq_id, tid_data->state);
1193e705c121SKalle Valo 	old_state = tid_data->state;
1194e705c121SKalle Valo 	tid_data->state = IWL_AGG_OFF;
1195e705c121SKalle Valo 	mvmsta->agg_tids &= ~BIT(tid);
1196e705c121SKalle Valo 	spin_unlock_bh(&mvmsta->lock);
1197e705c121SKalle Valo 
1198e705c121SKalle Valo 	/* No need to mark as reserved */
1199e705c121SKalle Valo 	spin_lock_bh(&mvm->queue_info_lock);
1200e705c121SKalle Valo 	mvm->queue_info[txq_id].setup_reserved = false;
1201e705c121SKalle Valo 	spin_unlock_bh(&mvm->queue_info_lock);
1202e705c121SKalle Valo 
1203e705c121SKalle Valo 	if (old_state >= IWL_AGG_ON) {
1204e705c121SKalle Valo 		iwl_mvm_drain_sta(mvm, mvmsta, true);
1205e705c121SKalle Valo 		if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), 0))
1206e705c121SKalle Valo 			IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
1207e705c121SKalle Valo 		iwl_trans_wait_tx_queue_empty(mvm->trans,
1208e705c121SKalle Valo 					      mvmsta->tfd_queue_msk);
1209e705c121SKalle Valo 		iwl_mvm_drain_sta(mvm, mvmsta, false);
1210e705c121SKalle Valo 
1211e705c121SKalle Valo 		iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
1212e705c121SKalle Valo 
1213e705c121SKalle Valo 		iwl_mvm_disable_txq(mvm, tid_data->txq_id,
1214e705c121SKalle Valo 				    vif->hw_queue[tid_to_mac80211_ac[tid]], tid,
1215e705c121SKalle Valo 				    0);
1216e705c121SKalle Valo 	}
1217e705c121SKalle Valo 
1218e705c121SKalle Valo 	return 0;
1219e705c121SKalle Valo }
1220e705c121SKalle Valo 
1221e705c121SKalle Valo static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
1222e705c121SKalle Valo {
1223e705c121SKalle Valo 	int i, max = -1, max_offs = -1;
1224e705c121SKalle Valo 
1225e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
1226e705c121SKalle Valo 
1227e705c121SKalle Valo 	/* Pick the unused key offset with the highest 'deleted'
1228e705c121SKalle Valo 	 * counter. Every time a key is deleted, all the counters
1229e705c121SKalle Valo 	 * are incremented and the one that was just deleted is
1230e705c121SKalle Valo 	 * reset to zero. Thus, the highest counter is the one
1231e705c121SKalle Valo 	 * that was deleted longest ago. Pick that one.
1232e705c121SKalle Valo 	 */
1233e705c121SKalle Valo 	for (i = 0; i < STA_KEY_MAX_NUM; i++) {
1234e705c121SKalle Valo 		if (test_bit(i, mvm->fw_key_table))
1235e705c121SKalle Valo 			continue;
1236e705c121SKalle Valo 		if (mvm->fw_key_deleted[i] > max) {
1237e705c121SKalle Valo 			max = mvm->fw_key_deleted[i];
1238e705c121SKalle Valo 			max_offs = i;
1239e705c121SKalle Valo 		}
1240e705c121SKalle Valo 	}
1241e705c121SKalle Valo 
1242e705c121SKalle Valo 	if (max_offs < 0)
1243e705c121SKalle Valo 		return STA_KEY_IDX_INVALID;
1244e705c121SKalle Valo 
1245e705c121SKalle Valo 	return max_offs;
1246e705c121SKalle Valo }
1247e705c121SKalle Valo 
12485f7a1847SJohannes Berg static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm,
12494615fd15SEmmanuel Grumbach 					       struct ieee80211_vif *vif,
1250e705c121SKalle Valo 					       struct ieee80211_sta *sta)
1251e705c121SKalle Valo {
1252e705c121SKalle Valo 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1253e705c121SKalle Valo 
12545f7a1847SJohannes Berg 	if (sta)
12555f7a1847SJohannes Berg 		return iwl_mvm_sta_from_mac80211(sta);
1256e705c121SKalle Valo 
1257e705c121SKalle Valo 	/*
1258e705c121SKalle Valo 	 * The device expects GTKs for station interfaces to be
1259e705c121SKalle Valo 	 * installed as GTKs for the AP station. If we have no
1260e705c121SKalle Valo 	 * station ID, then use AP's station ID.
1261e705c121SKalle Valo 	 */
1262e705c121SKalle Valo 	if (vif->type == NL80211_IFTYPE_STATION &&
12634615fd15SEmmanuel Grumbach 	    mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
12644615fd15SEmmanuel Grumbach 		u8 sta_id = mvmvif->ap_sta_id;
12654615fd15SEmmanuel Grumbach 
126612f17211SEmmanuel Grumbach 		sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id],
12674615fd15SEmmanuel Grumbach 					    lockdep_is_held(&mvm->mutex));
12684615fd15SEmmanuel Grumbach 		/*
12694615fd15SEmmanuel Grumbach 		 * It is possible that the 'sta' parameter is NULL,
12704615fd15SEmmanuel Grumbach 		 * for example when a GTK is removed - the sta_id will then
12714615fd15SEmmanuel Grumbach 		 * be the AP ID, and no station was passed by mac80211.
12724615fd15SEmmanuel Grumbach 		 */
12734615fd15SEmmanuel Grumbach 		if (IS_ERR_OR_NULL(sta))
12745f7a1847SJohannes Berg 			return NULL;
12754615fd15SEmmanuel Grumbach 
12765f7a1847SJohannes Berg 		return iwl_mvm_sta_from_mac80211(sta);
12774615fd15SEmmanuel Grumbach 	}
1278e705c121SKalle Valo 
12795f7a1847SJohannes Berg 	return NULL;
1280e705c121SKalle Valo }
1281e705c121SKalle Valo 
1282e705c121SKalle Valo static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
1283e705c121SKalle Valo 				struct iwl_mvm_sta *mvm_sta,
1284e705c121SKalle Valo 				struct ieee80211_key_conf *keyconf, bool mcast,
12854615fd15SEmmanuel Grumbach 				u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags,
12864615fd15SEmmanuel Grumbach 				u8 key_offset)
1287e705c121SKalle Valo {
1288e705c121SKalle Valo 	struct iwl_mvm_add_sta_key_cmd cmd = {};
1289e705c121SKalle Valo 	__le16 key_flags;
1290e705c121SKalle Valo 	int ret;
1291e705c121SKalle Valo 	u32 status;
1292e705c121SKalle Valo 	u16 keyidx;
1293e705c121SKalle Valo 	int i;
1294e705c121SKalle Valo 	u8 sta_id = mvm_sta->sta_id;
1295e705c121SKalle Valo 
1296e705c121SKalle Valo 	keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
1297e705c121SKalle Valo 		 STA_KEY_FLG_KEYID_MSK;
1298e705c121SKalle Valo 	key_flags = cpu_to_le16(keyidx);
1299e705c121SKalle Valo 	key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_KEY_MAP);
1300e705c121SKalle Valo 
1301e705c121SKalle Valo 	switch (keyconf->cipher) {
1302e705c121SKalle Valo 	case WLAN_CIPHER_SUITE_TKIP:
1303e705c121SKalle Valo 		key_flags |= cpu_to_le16(STA_KEY_FLG_TKIP);
1304e705c121SKalle Valo 		cmd.tkip_rx_tsc_byte2 = tkip_iv32;
1305e705c121SKalle Valo 		for (i = 0; i < 5; i++)
1306e705c121SKalle Valo 			cmd.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]);
1307e705c121SKalle Valo 		memcpy(cmd.key, keyconf->key, keyconf->keylen);
1308e705c121SKalle Valo 		break;
1309e705c121SKalle Valo 	case WLAN_CIPHER_SUITE_CCMP:
1310e705c121SKalle Valo 		key_flags |= cpu_to_le16(STA_KEY_FLG_CCM);
1311e705c121SKalle Valo 		memcpy(cmd.key, keyconf->key, keyconf->keylen);
1312e705c121SKalle Valo 		break;
1313e705c121SKalle Valo 	case WLAN_CIPHER_SUITE_WEP104:
1314e705c121SKalle Valo 		key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_13BYTES);
1315e705c121SKalle Valo 		/* fall through */
1316e705c121SKalle Valo 	case WLAN_CIPHER_SUITE_WEP40:
1317e705c121SKalle Valo 		key_flags |= cpu_to_le16(STA_KEY_FLG_WEP);
1318e705c121SKalle Valo 		memcpy(cmd.key + 3, keyconf->key, keyconf->keylen);
1319e705c121SKalle Valo 		break;
1320e705c121SKalle Valo 	default:
1321e705c121SKalle Valo 		key_flags |= cpu_to_le16(STA_KEY_FLG_EXT);
1322e705c121SKalle Valo 		memcpy(cmd.key, keyconf->key, keyconf->keylen);
1323e705c121SKalle Valo 	}
1324e705c121SKalle Valo 
1325e705c121SKalle Valo 	if (mcast)
1326e705c121SKalle Valo 		key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
1327e705c121SKalle Valo 
13284615fd15SEmmanuel Grumbach 	cmd.key_offset = key_offset;
1329e705c121SKalle Valo 	cmd.key_flags = key_flags;
1330e705c121SKalle Valo 	cmd.sta_id = sta_id;
1331e705c121SKalle Valo 
1332e705c121SKalle Valo 	status = ADD_STA_SUCCESS;
1333e705c121SKalle Valo 	if (cmd_flags & CMD_ASYNC)
1334e705c121SKalle Valo 		ret =  iwl_mvm_send_cmd_pdu(mvm, ADD_STA_KEY, CMD_ASYNC,
1335e705c121SKalle Valo 					    sizeof(cmd), &cmd);
1336e705c121SKalle Valo 	else
1337e705c121SKalle Valo 		ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, sizeof(cmd),
1338e705c121SKalle Valo 						  &cmd, &status);
1339e705c121SKalle Valo 
1340e705c121SKalle Valo 	switch (status) {
1341e705c121SKalle Valo 	case ADD_STA_SUCCESS:
1342e705c121SKalle Valo 		IWL_DEBUG_WEP(mvm, "MODIFY_STA: set dynamic key passed\n");
1343e705c121SKalle Valo 		break;
1344e705c121SKalle Valo 	default:
1345e705c121SKalle Valo 		ret = -EIO;
1346e705c121SKalle Valo 		IWL_ERR(mvm, "MODIFY_STA: set dynamic key failed\n");
1347e705c121SKalle Valo 		break;
1348e705c121SKalle Valo 	}
1349e705c121SKalle Valo 
1350e705c121SKalle Valo 	return ret;
1351e705c121SKalle Valo }
1352e705c121SKalle Valo 
1353e705c121SKalle Valo static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,
1354e705c121SKalle Valo 				 struct ieee80211_key_conf *keyconf,
1355e705c121SKalle Valo 				 u8 sta_id, bool remove_key)
1356e705c121SKalle Valo {
1357e705c121SKalle Valo 	struct iwl_mvm_mgmt_mcast_key_cmd igtk_cmd = {};
1358e705c121SKalle Valo 
1359e705c121SKalle Valo 	/* verify the key details match the required command's expectations */
1360e705c121SKalle Valo 	if (WARN_ON((keyconf->cipher != WLAN_CIPHER_SUITE_AES_CMAC) ||
1361e705c121SKalle Valo 		    (keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE) ||
1362e705c121SKalle Valo 		    (keyconf->keyidx != 4 && keyconf->keyidx != 5)))
1363e705c121SKalle Valo 		return -EINVAL;
1364e705c121SKalle Valo 
1365e705c121SKalle Valo 	igtk_cmd.key_id = cpu_to_le32(keyconf->keyidx);
1366e705c121SKalle Valo 	igtk_cmd.sta_id = cpu_to_le32(sta_id);
1367e705c121SKalle Valo 
1368e705c121SKalle Valo 	if (remove_key) {
1369e705c121SKalle Valo 		igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_NOT_VALID);
1370e705c121SKalle Valo 	} else {
1371e705c121SKalle Valo 		struct ieee80211_key_seq seq;
1372e705c121SKalle Valo 		const u8 *pn;
1373e705c121SKalle Valo 
1374e705c121SKalle Valo 		memcpy(igtk_cmd.IGTK, keyconf->key, keyconf->keylen);
1375e705c121SKalle Valo 		ieee80211_get_key_rx_seq(keyconf, 0, &seq);
1376e705c121SKalle Valo 		pn = seq.aes_cmac.pn;
1377e705c121SKalle Valo 		igtk_cmd.receive_seq_cnt = cpu_to_le64(((u64) pn[5] << 0) |
1378e705c121SKalle Valo 						       ((u64) pn[4] << 8) |
1379e705c121SKalle Valo 						       ((u64) pn[3] << 16) |
1380e705c121SKalle Valo 						       ((u64) pn[2] << 24) |
1381e705c121SKalle Valo 						       ((u64) pn[1] << 32) |
1382e705c121SKalle Valo 						       ((u64) pn[0] << 40));
1383e705c121SKalle Valo 	}
1384e705c121SKalle Valo 
1385e705c121SKalle Valo 	IWL_DEBUG_INFO(mvm, "%s igtk for sta %u\n",
1386e705c121SKalle Valo 		       remove_key ? "removing" : "installing",
1387e705c121SKalle Valo 		       igtk_cmd.sta_id);
1388e705c121SKalle Valo 
1389e705c121SKalle Valo 	return iwl_mvm_send_cmd_pdu(mvm, MGMT_MCAST_KEY, 0,
1390e705c121SKalle Valo 				    sizeof(igtk_cmd), &igtk_cmd);
1391e705c121SKalle Valo }
1392e705c121SKalle Valo 
1393e705c121SKalle Valo 
1394e705c121SKalle Valo static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm,
1395e705c121SKalle Valo 				       struct ieee80211_vif *vif,
1396e705c121SKalle Valo 				       struct ieee80211_sta *sta)
1397e705c121SKalle Valo {
1398e705c121SKalle Valo 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1399e705c121SKalle Valo 
1400e705c121SKalle Valo 	if (sta)
1401e705c121SKalle Valo 		return sta->addr;
1402e705c121SKalle Valo 
1403e705c121SKalle Valo 	if (vif->type == NL80211_IFTYPE_STATION &&
1404e705c121SKalle Valo 	    mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
1405e705c121SKalle Valo 		u8 sta_id = mvmvif->ap_sta_id;
1406e705c121SKalle Valo 		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
1407e705c121SKalle Valo 						lockdep_is_held(&mvm->mutex));
1408e705c121SKalle Valo 		return sta->addr;
1409e705c121SKalle Valo 	}
1410e705c121SKalle Valo 
1411e705c121SKalle Valo 
1412e705c121SKalle Valo 	return NULL;
1413e705c121SKalle Valo }
1414e705c121SKalle Valo 
1415e705c121SKalle Valo static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
1416e705c121SKalle Valo 				 struct ieee80211_vif *vif,
1417e705c121SKalle Valo 				 struct ieee80211_sta *sta,
1418e705c121SKalle Valo 				 struct ieee80211_key_conf *keyconf,
14194615fd15SEmmanuel Grumbach 				 u8 key_offset,
1420e705c121SKalle Valo 				 bool mcast)
1421e705c121SKalle Valo {
1422e705c121SKalle Valo 	struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
1423e705c121SKalle Valo 	int ret;
1424e705c121SKalle Valo 	const u8 *addr;
1425e705c121SKalle Valo 	struct ieee80211_key_seq seq;
1426e705c121SKalle Valo 	u16 p1k[5];
1427e705c121SKalle Valo 
1428e705c121SKalle Valo 	switch (keyconf->cipher) {
1429e705c121SKalle Valo 	case WLAN_CIPHER_SUITE_TKIP:
1430e705c121SKalle Valo 		addr = iwl_mvm_get_mac_addr(mvm, vif, sta);
1431e705c121SKalle Valo 		/* get phase 1 key from mac80211 */
1432e705c121SKalle Valo 		ieee80211_get_key_rx_seq(keyconf, 0, &seq);
1433e705c121SKalle Valo 		ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
1434e705c121SKalle Valo 		ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
14354615fd15SEmmanuel Grumbach 					   seq.tkip.iv32, p1k, 0, key_offset);
1436e705c121SKalle Valo 		break;
1437e705c121SKalle Valo 	case WLAN_CIPHER_SUITE_CCMP:
1438e705c121SKalle Valo 	case WLAN_CIPHER_SUITE_WEP40:
1439e705c121SKalle Valo 	case WLAN_CIPHER_SUITE_WEP104:
1440e705c121SKalle Valo 		ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
14414615fd15SEmmanuel Grumbach 					   0, NULL, 0, key_offset);
1442e705c121SKalle Valo 		break;
1443e705c121SKalle Valo 	default:
1444e705c121SKalle Valo 		ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
14454615fd15SEmmanuel Grumbach 					   0, NULL, 0, key_offset);
1446e705c121SKalle Valo 	}
1447e705c121SKalle Valo 
1448e705c121SKalle Valo 	return ret;
1449e705c121SKalle Valo }
1450e705c121SKalle Valo 
1451e705c121SKalle Valo static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id,
1452e705c121SKalle Valo 				    struct ieee80211_key_conf *keyconf,
1453e705c121SKalle Valo 				    bool mcast)
1454e705c121SKalle Valo {
1455e705c121SKalle Valo 	struct iwl_mvm_add_sta_key_cmd cmd = {};
1456e705c121SKalle Valo 	__le16 key_flags;
1457e705c121SKalle Valo 	int ret;
1458e705c121SKalle Valo 	u32 status;
1459e705c121SKalle Valo 
1460e705c121SKalle Valo 	key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
1461e705c121SKalle Valo 				 STA_KEY_FLG_KEYID_MSK);
1462e705c121SKalle Valo 	key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP);
1463e705c121SKalle Valo 	key_flags |= cpu_to_le16(STA_KEY_NOT_VALID);
1464e705c121SKalle Valo 
1465e705c121SKalle Valo 	if (mcast)
1466e705c121SKalle Valo 		key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
1467e705c121SKalle Valo 
1468e705c121SKalle Valo 	cmd.key_flags = key_flags;
1469e705c121SKalle Valo 	cmd.key_offset = keyconf->hw_key_idx;
1470e705c121SKalle Valo 	cmd.sta_id = sta_id;
1471e705c121SKalle Valo 
1472e705c121SKalle Valo 	status = ADD_STA_SUCCESS;
1473e705c121SKalle Valo 	ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, sizeof(cmd),
1474e705c121SKalle Valo 					  &cmd, &status);
1475e705c121SKalle Valo 
1476e705c121SKalle Valo 	switch (status) {
1477e705c121SKalle Valo 	case ADD_STA_SUCCESS:
1478e705c121SKalle Valo 		IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n");
1479e705c121SKalle Valo 		break;
1480e705c121SKalle Valo 	default:
1481e705c121SKalle Valo 		ret = -EIO;
1482e705c121SKalle Valo 		IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n");
1483e705c121SKalle Valo 		break;
1484e705c121SKalle Valo 	}
1485e705c121SKalle Valo 
1486e705c121SKalle Valo 	return ret;
1487e705c121SKalle Valo }
1488e705c121SKalle Valo 
1489e705c121SKalle Valo int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
1490e705c121SKalle Valo 			struct ieee80211_vif *vif,
1491e705c121SKalle Valo 			struct ieee80211_sta *sta,
1492e705c121SKalle Valo 			struct ieee80211_key_conf *keyconf,
14934615fd15SEmmanuel Grumbach 			u8 key_offset)
1494e705c121SKalle Valo {
1495e705c121SKalle Valo 	bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
14965f7a1847SJohannes Berg 	struct iwl_mvm_sta *mvm_sta;
1497e705c121SKalle Valo 	u8 sta_id;
1498e705c121SKalle Valo 	int ret;
1499e705c121SKalle Valo 	static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0};
1500e705c121SKalle Valo 
1501e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
1502e705c121SKalle Valo 
1503e705c121SKalle Valo 	/* Get the station id from the mvm local station table */
15045f7a1847SJohannes Berg 	mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta);
15055f7a1847SJohannes Berg 	if (!mvm_sta) {
15065f7a1847SJohannes Berg 		IWL_ERR(mvm, "Failed to find station\n");
1507e705c121SKalle Valo 		return -EINVAL;
1508e705c121SKalle Valo 	}
15095f7a1847SJohannes Berg 	sta_id = mvm_sta->sta_id;
1510e705c121SKalle Valo 
1511e705c121SKalle Valo 	if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
1512e705c121SKalle Valo 		ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false);
1513e705c121SKalle Valo 		goto end;
1514e705c121SKalle Valo 	}
1515e705c121SKalle Valo 
1516e705c121SKalle Valo 	/*
1517e705c121SKalle Valo 	 * It is possible that the 'sta' parameter is NULL, and thus
1518e705c121SKalle Valo 	 * there is a need to retrieve  the sta from the local station table.
1519e705c121SKalle Valo 	 */
1520e705c121SKalle Valo 	if (!sta) {
1521e705c121SKalle Valo 		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
1522e705c121SKalle Valo 						lockdep_is_held(&mvm->mutex));
1523e705c121SKalle Valo 		if (IS_ERR_OR_NULL(sta)) {
1524e705c121SKalle Valo 			IWL_ERR(mvm, "Invalid station id\n");
1525e705c121SKalle Valo 			return -EINVAL;
1526e705c121SKalle Valo 		}
1527e705c121SKalle Valo 	}
1528e705c121SKalle Valo 
1529e705c121SKalle Valo 	if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
1530e705c121SKalle Valo 		return -EINVAL;
1531e705c121SKalle Valo 
15324615fd15SEmmanuel Grumbach 	/* If the key_offset is not pre-assigned, we need to find a
15334615fd15SEmmanuel Grumbach 	 * new offset to use.  In normal cases, the offset is not
15344615fd15SEmmanuel Grumbach 	 * pre-assigned, but during HW_RESTART we want to reuse the
15354615fd15SEmmanuel Grumbach 	 * same indices, so we pass them when this function is called.
15364615fd15SEmmanuel Grumbach 	 *
15374615fd15SEmmanuel Grumbach 	 * In D3 entry, we need to hardcoded the indices (because the
15384615fd15SEmmanuel Grumbach 	 * firmware hardcodes the PTK offset to 0).  In this case, we
15394615fd15SEmmanuel Grumbach 	 * need to make sure we don't overwrite the hw_key_idx in the
15404615fd15SEmmanuel Grumbach 	 * keyconf structure, because otherwise we cannot configure
15414615fd15SEmmanuel Grumbach 	 * the original ones back when resuming.
1542e705c121SKalle Valo 	 */
15434615fd15SEmmanuel Grumbach 	if (key_offset == STA_KEY_IDX_INVALID) {
15444615fd15SEmmanuel Grumbach 		key_offset  = iwl_mvm_set_fw_key_idx(mvm);
15454615fd15SEmmanuel Grumbach 		if (key_offset == STA_KEY_IDX_INVALID)
1546e705c121SKalle Valo 			return -ENOSPC;
15474615fd15SEmmanuel Grumbach 		keyconf->hw_key_idx = key_offset;
1548e705c121SKalle Valo 	}
1549e705c121SKalle Valo 
15504615fd15SEmmanuel Grumbach 	ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, key_offset, mcast);
15519c3deeb5SLuca Coelho 	if (ret)
1552e705c121SKalle Valo 		goto end;
1553e705c121SKalle Valo 
1554e705c121SKalle Valo 	/*
1555e705c121SKalle Valo 	 * For WEP, the same key is used for multicast and unicast. Upload it
1556e705c121SKalle Valo 	 * again, using the same key offset, and now pointing the other one
1557e705c121SKalle Valo 	 * to the same key slot (offset).
1558e705c121SKalle Valo 	 * If this fails, remove the original as well.
1559e705c121SKalle Valo 	 */
1560e705c121SKalle Valo 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
1561e705c121SKalle Valo 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
15624615fd15SEmmanuel Grumbach 		ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf,
15634615fd15SEmmanuel Grumbach 					    key_offset, !mcast);
1564e705c121SKalle Valo 		if (ret) {
1565e705c121SKalle Valo 			__iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
15669c3deeb5SLuca Coelho 			goto end;
1567e705c121SKalle Valo 		}
1568e705c121SKalle Valo 	}
1569e705c121SKalle Valo 
15709c3deeb5SLuca Coelho 	__set_bit(key_offset, mvm->fw_key_table);
15719c3deeb5SLuca Coelho 
1572e705c121SKalle Valo end:
1573e705c121SKalle Valo 	IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
1574e705c121SKalle Valo 		      keyconf->cipher, keyconf->keylen, keyconf->keyidx,
1575e705c121SKalle Valo 		      sta ? sta->addr : zero_addr, ret);
1576e705c121SKalle Valo 	return ret;
1577e705c121SKalle Valo }
1578e705c121SKalle Valo 
1579e705c121SKalle Valo int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
1580e705c121SKalle Valo 			   struct ieee80211_vif *vif,
1581e705c121SKalle Valo 			   struct ieee80211_sta *sta,
1582e705c121SKalle Valo 			   struct ieee80211_key_conf *keyconf)
1583e705c121SKalle Valo {
1584e705c121SKalle Valo 	bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
15855f7a1847SJohannes Berg 	struct iwl_mvm_sta *mvm_sta;
15865f7a1847SJohannes Berg 	u8 sta_id = IWL_MVM_STATION_COUNT;
1587e705c121SKalle Valo 	int ret, i;
1588e705c121SKalle Valo 
1589e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
1590e705c121SKalle Valo 
15915f7a1847SJohannes Berg 	/* Get the station from the mvm local station table */
15925f7a1847SJohannes Berg 	mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta);
1593e705c121SKalle Valo 
1594e705c121SKalle Valo 	IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
1595e705c121SKalle Valo 		      keyconf->keyidx, sta_id);
1596e705c121SKalle Valo 
1597e705c121SKalle Valo 	if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
1598e705c121SKalle Valo 		return iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, true);
1599e705c121SKalle Valo 
1600e705c121SKalle Valo 	if (!__test_and_clear_bit(keyconf->hw_key_idx, mvm->fw_key_table)) {
1601e705c121SKalle Valo 		IWL_ERR(mvm, "offset %d not used in fw key table.\n",
1602e705c121SKalle Valo 			keyconf->hw_key_idx);
1603e705c121SKalle Valo 		return -ENOENT;
1604e705c121SKalle Valo 	}
1605e705c121SKalle Valo 
1606e705c121SKalle Valo 	/* track which key was deleted last */
1607e705c121SKalle Valo 	for (i = 0; i < STA_KEY_MAX_NUM; i++) {
1608e705c121SKalle Valo 		if (mvm->fw_key_deleted[i] < U8_MAX)
1609e705c121SKalle Valo 			mvm->fw_key_deleted[i]++;
1610e705c121SKalle Valo 	}
1611e705c121SKalle Valo 	mvm->fw_key_deleted[keyconf->hw_key_idx] = 0;
1612e705c121SKalle Valo 
16135f7a1847SJohannes Berg 	if (!mvm_sta) {
1614e705c121SKalle Valo 		IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n");
1615e705c121SKalle Valo 		return 0;
1616e705c121SKalle Valo 	}
1617e705c121SKalle Valo 
16185f7a1847SJohannes Berg 	sta_id = mvm_sta->sta_id;
16195f7a1847SJohannes Berg 
1620e705c121SKalle Valo 	ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
1621e705c121SKalle Valo 	if (ret)
1622e705c121SKalle Valo 		return ret;
1623e705c121SKalle Valo 
1624e705c121SKalle Valo 	/* delete WEP key twice to get rid of (now useless) offset */
1625e705c121SKalle Valo 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
1626e705c121SKalle Valo 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
1627e705c121SKalle Valo 		ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, !mcast);
1628e705c121SKalle Valo 
1629e705c121SKalle Valo 	return ret;
1630e705c121SKalle Valo }
1631e705c121SKalle Valo 
1632e705c121SKalle Valo void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
1633e705c121SKalle Valo 			     struct ieee80211_vif *vif,
1634e705c121SKalle Valo 			     struct ieee80211_key_conf *keyconf,
1635e705c121SKalle Valo 			     struct ieee80211_sta *sta, u32 iv32,
1636e705c121SKalle Valo 			     u16 *phase1key)
1637e705c121SKalle Valo {
1638e705c121SKalle Valo 	struct iwl_mvm_sta *mvm_sta;
1639e705c121SKalle Valo 	bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
1640e705c121SKalle Valo 
1641e705c121SKalle Valo 	rcu_read_lock();
1642e705c121SKalle Valo 
16435f7a1847SJohannes Berg 	mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta);
16445f7a1847SJohannes Berg 	if (WARN_ON_ONCE(!mvm_sta))
164512f17211SEmmanuel Grumbach 		goto unlock;
1646e705c121SKalle Valo 	iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
16474615fd15SEmmanuel Grumbach 			     iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx);
164812f17211SEmmanuel Grumbach 
164912f17211SEmmanuel Grumbach  unlock:
1650e705c121SKalle Valo 	rcu_read_unlock();
1651e705c121SKalle Valo }
1652e705c121SKalle Valo 
1653e705c121SKalle Valo void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
1654e705c121SKalle Valo 				struct ieee80211_sta *sta)
1655e705c121SKalle Valo {
1656e705c121SKalle Valo 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1657e705c121SKalle Valo 	struct iwl_mvm_add_sta_cmd cmd = {
1658e705c121SKalle Valo 		.add_modify = STA_MODE_MODIFY,
1659e705c121SKalle Valo 		.sta_id = mvmsta->sta_id,
1660e705c121SKalle Valo 		.station_flags_msk = cpu_to_le32(STA_FLG_PS),
1661e705c121SKalle Valo 		.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
1662e705c121SKalle Valo 	};
1663e705c121SKalle Valo 	int ret;
1664e705c121SKalle Valo 
1665854c5705SSara Sharon 	ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC,
1666854c5705SSara Sharon 				   iwl_mvm_add_sta_cmd_size(mvm), &cmd);
1667e705c121SKalle Valo 	if (ret)
1668e705c121SKalle Valo 		IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
1669e705c121SKalle Valo }
1670e705c121SKalle Valo 
1671e705c121SKalle Valo void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
1672e705c121SKalle Valo 				       struct ieee80211_sta *sta,
1673e705c121SKalle Valo 				       enum ieee80211_frame_release_type reason,
1674e705c121SKalle Valo 				       u16 cnt, u16 tids, bool more_data,
1675e705c121SKalle Valo 				       bool agg)
1676e705c121SKalle Valo {
1677e705c121SKalle Valo 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1678e705c121SKalle Valo 	struct iwl_mvm_add_sta_cmd cmd = {
1679e705c121SKalle Valo 		.add_modify = STA_MODE_MODIFY,
1680e705c121SKalle Valo 		.sta_id = mvmsta->sta_id,
1681e705c121SKalle Valo 		.modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT,
1682e705c121SKalle Valo 		.sleep_tx_count = cpu_to_le16(cnt),
1683e705c121SKalle Valo 		.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
1684e705c121SKalle Valo 	};
1685e705c121SKalle Valo 	int tid, ret;
1686e705c121SKalle Valo 	unsigned long _tids = tids;
1687e705c121SKalle Valo 
1688e705c121SKalle Valo 	/* convert TIDs to ACs - we don't support TSPEC so that's OK
1689e705c121SKalle Valo 	 * Note that this field is reserved and unused by firmware not
1690e705c121SKalle Valo 	 * supporting GO uAPSD, so it's safe to always do this.
1691e705c121SKalle Valo 	 */
1692e705c121SKalle Valo 	for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT)
1693e705c121SKalle Valo 		cmd.awake_acs |= BIT(tid_to_ucode_ac[tid]);
1694e705c121SKalle Valo 
1695e705c121SKalle Valo 	/* If we're releasing frames from aggregation queues then check if the
1696e705c121SKalle Valo 	 * all queues combined that we're releasing frames from have
1697e705c121SKalle Valo 	 *  - more frames than the service period, in which case more_data
1698e705c121SKalle Valo 	 *    needs to be set
1699e705c121SKalle Valo 	 *  - fewer than 'cnt' frames, in which case we need to adjust the
1700e705c121SKalle Valo 	 *    firmware command (but do that unconditionally)
1701e705c121SKalle Valo 	 */
1702e705c121SKalle Valo 	if (agg) {
1703e705c121SKalle Valo 		int remaining = cnt;
170436be0eb6SEmmanuel Grumbach 		int sleep_tx_count;
1705e705c121SKalle Valo 
1706e705c121SKalle Valo 		spin_lock_bh(&mvmsta->lock);
1707e705c121SKalle Valo 		for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) {
1708e705c121SKalle Valo 			struct iwl_mvm_tid_data *tid_data;
1709e705c121SKalle Valo 			u16 n_queued;
1710e705c121SKalle Valo 
1711e705c121SKalle Valo 			tid_data = &mvmsta->tid_data[tid];
1712e705c121SKalle Valo 			if (WARN(tid_data->state != IWL_AGG_ON &&
1713e705c121SKalle Valo 				 tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA,
1714e705c121SKalle Valo 				 "TID %d state is %d\n",
1715e705c121SKalle Valo 				 tid, tid_data->state)) {
1716e705c121SKalle Valo 				spin_unlock_bh(&mvmsta->lock);
1717e705c121SKalle Valo 				ieee80211_sta_eosp(sta);
1718e705c121SKalle Valo 				return;
1719e705c121SKalle Valo 			}
1720e705c121SKalle Valo 
1721e705c121SKalle Valo 			n_queued = iwl_mvm_tid_queued(tid_data);
1722e705c121SKalle Valo 			if (n_queued > remaining) {
1723e705c121SKalle Valo 				more_data = true;
1724e705c121SKalle Valo 				remaining = 0;
1725e705c121SKalle Valo 				break;
1726e705c121SKalle Valo 			}
1727e705c121SKalle Valo 			remaining -= n_queued;
1728e705c121SKalle Valo 		}
172936be0eb6SEmmanuel Grumbach 		sleep_tx_count = cnt - remaining;
173036be0eb6SEmmanuel Grumbach 		if (reason == IEEE80211_FRAME_RELEASE_UAPSD)
173136be0eb6SEmmanuel Grumbach 			mvmsta->sleep_tx_count = sleep_tx_count;
1732e705c121SKalle Valo 		spin_unlock_bh(&mvmsta->lock);
1733e705c121SKalle Valo 
173436be0eb6SEmmanuel Grumbach 		cmd.sleep_tx_count = cpu_to_le16(sleep_tx_count);
1735e705c121SKalle Valo 		if (WARN_ON(cnt - remaining == 0)) {
1736e705c121SKalle Valo 			ieee80211_sta_eosp(sta);
1737e705c121SKalle Valo 			return;
1738e705c121SKalle Valo 		}
1739e705c121SKalle Valo 	}
1740e705c121SKalle Valo 
1741e705c121SKalle Valo 	/* Note: this is ignored by firmware not supporting GO uAPSD */
1742e705c121SKalle Valo 	if (more_data)
1743e705c121SKalle Valo 		cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_MOREDATA);
1744e705c121SKalle Valo 
1745e705c121SKalle Valo 	if (reason == IEEE80211_FRAME_RELEASE_PSPOLL) {
1746e705c121SKalle Valo 		mvmsta->next_status_eosp = true;
1747e705c121SKalle Valo 		cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_PS_POLL);
1748e705c121SKalle Valo 	} else {
1749e705c121SKalle Valo 		cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_UAPSD);
1750e705c121SKalle Valo 	}
1751e705c121SKalle Valo 
1752156f92f2SEmmanuel Grumbach 	/* block the Tx queues until the FW updated the sleep Tx count */
1753156f92f2SEmmanuel Grumbach 	iwl_trans_block_txq_ptrs(mvm->trans, true);
1754156f92f2SEmmanuel Grumbach 
1755156f92f2SEmmanuel Grumbach 	ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA,
1756156f92f2SEmmanuel Grumbach 				   CMD_ASYNC | CMD_WANT_ASYNC_CALLBACK,
1757854c5705SSara Sharon 				   iwl_mvm_add_sta_cmd_size(mvm), &cmd);
1758e705c121SKalle Valo 	if (ret)
1759e705c121SKalle Valo 		IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
1760e705c121SKalle Valo }
1761e705c121SKalle Valo 
1762e705c121SKalle Valo void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
1763e705c121SKalle Valo 			   struct iwl_rx_cmd_buffer *rxb)
1764e705c121SKalle Valo {
1765e705c121SKalle Valo 	struct iwl_rx_packet *pkt = rxb_addr(rxb);
1766e705c121SKalle Valo 	struct iwl_mvm_eosp_notification *notif = (void *)pkt->data;
1767e705c121SKalle Valo 	struct ieee80211_sta *sta;
1768e705c121SKalle Valo 	u32 sta_id = le32_to_cpu(notif->sta_id);
1769e705c121SKalle Valo 
1770e705c121SKalle Valo 	if (WARN_ON_ONCE(sta_id >= IWL_MVM_STATION_COUNT))
1771e705c121SKalle Valo 		return;
1772e705c121SKalle Valo 
1773e705c121SKalle Valo 	rcu_read_lock();
1774e705c121SKalle Valo 	sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
1775e705c121SKalle Valo 	if (!IS_ERR_OR_NULL(sta))
1776e705c121SKalle Valo 		ieee80211_sta_eosp(sta);
1777e705c121SKalle Valo 	rcu_read_unlock();
1778e705c121SKalle Valo }
1779e705c121SKalle Valo 
1780e705c121SKalle Valo void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm,
1781e705c121SKalle Valo 				   struct iwl_mvm_sta *mvmsta, bool disable)
1782e705c121SKalle Valo {
1783e705c121SKalle Valo 	struct iwl_mvm_add_sta_cmd cmd = {
1784e705c121SKalle Valo 		.add_modify = STA_MODE_MODIFY,
1785e705c121SKalle Valo 		.sta_id = mvmsta->sta_id,
1786e705c121SKalle Valo 		.station_flags = disable ? cpu_to_le32(STA_FLG_DISABLE_TX) : 0,
1787e705c121SKalle Valo 		.station_flags_msk = cpu_to_le32(STA_FLG_DISABLE_TX),
1788e705c121SKalle Valo 		.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
1789e705c121SKalle Valo 	};
1790e705c121SKalle Valo 	int ret;
1791e705c121SKalle Valo 
1792854c5705SSara Sharon 	ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC,
1793854c5705SSara Sharon 				   iwl_mvm_add_sta_cmd_size(mvm), &cmd);
1794e705c121SKalle Valo 	if (ret)
1795e705c121SKalle Valo 		IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
1796e705c121SKalle Valo }
1797e705c121SKalle Valo 
1798e705c121SKalle Valo void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm,
1799e705c121SKalle Valo 				      struct ieee80211_sta *sta,
1800e705c121SKalle Valo 				      bool disable)
1801e705c121SKalle Valo {
1802e705c121SKalle Valo 	struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
1803e705c121SKalle Valo 
1804e705c121SKalle Valo 	spin_lock_bh(&mvm_sta->lock);
1805e705c121SKalle Valo 
1806e705c121SKalle Valo 	if (mvm_sta->disable_tx == disable) {
1807e705c121SKalle Valo 		spin_unlock_bh(&mvm_sta->lock);
1808e705c121SKalle Valo 		return;
1809e705c121SKalle Valo 	}
1810e705c121SKalle Valo 
1811e705c121SKalle Valo 	mvm_sta->disable_tx = disable;
1812e705c121SKalle Valo 
1813e705c121SKalle Valo 	/*
1814e705c121SKalle Valo 	 * Tell mac80211 to start/stop queuing tx for this station,
1815e705c121SKalle Valo 	 * but don't stop queuing if there are still pending frames
1816e705c121SKalle Valo 	 * for this station.
1817e705c121SKalle Valo 	 */
1818e705c121SKalle Valo 	if (disable || !atomic_read(&mvm->pending_frames[mvm_sta->sta_id]))
1819e705c121SKalle Valo 		ieee80211_sta_block_awake(mvm->hw, sta, disable);
1820e705c121SKalle Valo 
1821e705c121SKalle Valo 	iwl_mvm_sta_modify_disable_tx(mvm, mvm_sta, disable);
1822e705c121SKalle Valo 
1823e705c121SKalle Valo 	spin_unlock_bh(&mvm_sta->lock);
1824e705c121SKalle Valo }
1825e705c121SKalle Valo 
1826e705c121SKalle Valo void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
1827e705c121SKalle Valo 				       struct iwl_mvm_vif *mvmvif,
1828e705c121SKalle Valo 				       bool disable)
1829e705c121SKalle Valo {
1830e705c121SKalle Valo 	struct ieee80211_sta *sta;
1831e705c121SKalle Valo 	struct iwl_mvm_sta *mvm_sta;
1832e705c121SKalle Valo 	int i;
1833e705c121SKalle Valo 
1834e705c121SKalle Valo 	lockdep_assert_held(&mvm->mutex);
1835e705c121SKalle Valo 
1836e705c121SKalle Valo 	/* Block/unblock all the stations of the given mvmvif */
1837e705c121SKalle Valo 	for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
1838e705c121SKalle Valo 		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
1839e705c121SKalle Valo 						lockdep_is_held(&mvm->mutex));
1840e705c121SKalle Valo 		if (IS_ERR_OR_NULL(sta))
1841e705c121SKalle Valo 			continue;
1842e705c121SKalle Valo 
1843e705c121SKalle Valo 		mvm_sta = iwl_mvm_sta_from_mac80211(sta);
1844e705c121SKalle Valo 		if (mvm_sta->mac_id_n_color !=
1845e705c121SKalle Valo 		    FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color))
1846e705c121SKalle Valo 			continue;
1847e705c121SKalle Valo 
1848e705c121SKalle Valo 		iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, disable);
1849e705c121SKalle Valo 	}
1850e705c121SKalle Valo }
1851e705c121SKalle Valo 
1852e705c121SKalle Valo void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1853e705c121SKalle Valo {
1854e705c121SKalle Valo 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1855e705c121SKalle Valo 	struct iwl_mvm_sta *mvmsta;
1856e705c121SKalle Valo 
1857e705c121SKalle Valo 	rcu_read_lock();
1858e705c121SKalle Valo 
1859e705c121SKalle Valo 	mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, mvmvif->ap_sta_id);
1860e705c121SKalle Valo 
1861e705c121SKalle Valo 	if (!WARN_ON(!mvmsta))
1862e705c121SKalle Valo 		iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true);
1863e705c121SKalle Valo 
1864e705c121SKalle Valo 	rcu_read_unlock();
1865e705c121SKalle Valo }
1866