1fe8ee9adSChristian Lamparter /*
2fe8ee9adSChristian Lamparter  * Atheros CARL9170 driver
3fe8ee9adSChristian Lamparter  *
4fe8ee9adSChristian Lamparter  * mac80211 interaction code
5fe8ee9adSChristian Lamparter  *
6fe8ee9adSChristian Lamparter  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
7fe8ee9adSChristian Lamparter  * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com>
8fe8ee9adSChristian Lamparter  *
9fe8ee9adSChristian Lamparter  * This program is free software; you can redistribute it and/or modify
10fe8ee9adSChristian Lamparter  * it under the terms of the GNU General Public License as published by
11fe8ee9adSChristian Lamparter  * the Free Software Foundation; either version 2 of the License, or
12fe8ee9adSChristian Lamparter  * (at your option) any later version.
13fe8ee9adSChristian Lamparter  *
14fe8ee9adSChristian Lamparter  * This program is distributed in the hope that it will be useful,
15fe8ee9adSChristian Lamparter  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16fe8ee9adSChristian Lamparter  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17fe8ee9adSChristian Lamparter  * GNU General Public License for more details.
18fe8ee9adSChristian Lamparter  *
19fe8ee9adSChristian Lamparter  * You should have received a copy of the GNU General Public License
20fe8ee9adSChristian Lamparter  * along with this program; see the file COPYING.  If not, see
21fe8ee9adSChristian Lamparter  * http://www.gnu.org/licenses/.
22fe8ee9adSChristian Lamparter  *
23fe8ee9adSChristian Lamparter  * This file incorporates work covered by the following copyright and
24fe8ee9adSChristian Lamparter  * permission notice:
25fe8ee9adSChristian Lamparter  *    Copyright (c) 2007-2008 Atheros Communications, Inc.
26fe8ee9adSChristian Lamparter  *
27fe8ee9adSChristian Lamparter  *    Permission to use, copy, modify, and/or distribute this software for any
28fe8ee9adSChristian Lamparter  *    purpose with or without fee is hereby granted, provided that the above
29fe8ee9adSChristian Lamparter  *    copyright notice and this permission notice appear in all copies.
30fe8ee9adSChristian Lamparter  *
31fe8ee9adSChristian Lamparter  *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
32fe8ee9adSChristian Lamparter  *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
33fe8ee9adSChristian Lamparter  *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
34fe8ee9adSChristian Lamparter  *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
35fe8ee9adSChristian Lamparter  *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
36fe8ee9adSChristian Lamparter  *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
37fe8ee9adSChristian Lamparter  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
38fe8ee9adSChristian Lamparter  */
39fe8ee9adSChristian Lamparter 
40fe8ee9adSChristian Lamparter #include <linux/slab.h>
41fe8ee9adSChristian Lamparter #include <linux/module.h>
42fe8ee9adSChristian Lamparter #include <linux/etherdevice.h>
43fe8ee9adSChristian Lamparter #include <linux/random.h>
44fe8ee9adSChristian Lamparter #include <net/mac80211.h>
45fe8ee9adSChristian Lamparter #include <net/cfg80211.h>
46fe8ee9adSChristian Lamparter #include "hw.h"
47fe8ee9adSChristian Lamparter #include "carl9170.h"
48fe8ee9adSChristian Lamparter #include "cmd.h"
49fe8ee9adSChristian Lamparter 
50eb939922SRusty Russell static bool modparam_nohwcrypt;
512ef00c53SJoe Perches module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
52fe8ee9adSChristian Lamparter MODULE_PARM_DESC(nohwcrypt, "Disable hardware crypto offload.");
53fe8ee9adSChristian Lamparter 
54fe8ee9adSChristian Lamparter int modparam_noht;
552ef00c53SJoe Perches module_param_named(noht, modparam_noht, int, 0444);
56fe8ee9adSChristian Lamparter MODULE_PARM_DESC(noht, "Disable MPDU aggregation.");
57fe8ee9adSChristian Lamparter 
58fe8ee9adSChristian Lamparter #define RATE(_bitrate, _hw_rate, _txpidx, _flags) {	\
59fe8ee9adSChristian Lamparter 	.bitrate	= (_bitrate),			\
60fe8ee9adSChristian Lamparter 	.flags		= (_flags),			\
61fe8ee9adSChristian Lamparter 	.hw_value	= (_hw_rate) | (_txpidx) << 4,	\
62fe8ee9adSChristian Lamparter }
63fe8ee9adSChristian Lamparter 
64fe8ee9adSChristian Lamparter struct ieee80211_rate __carl9170_ratetable[] = {
65fe8ee9adSChristian Lamparter 	RATE(10, 0, 0, 0),
66fe8ee9adSChristian Lamparter 	RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE),
67fe8ee9adSChristian Lamparter 	RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE),
68fe8ee9adSChristian Lamparter 	RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE),
69fe8ee9adSChristian Lamparter 	RATE(60, 0xb, 0, 0),
70fe8ee9adSChristian Lamparter 	RATE(90, 0xf, 0, 0),
71fe8ee9adSChristian Lamparter 	RATE(120, 0xa, 0, 0),
72fe8ee9adSChristian Lamparter 	RATE(180, 0xe, 0, 0),
73fe8ee9adSChristian Lamparter 	RATE(240, 0x9, 0, 0),
74fe8ee9adSChristian Lamparter 	RATE(360, 0xd, 1, 0),
75fe8ee9adSChristian Lamparter 	RATE(480, 0x8, 2, 0),
76fe8ee9adSChristian Lamparter 	RATE(540, 0xc, 3, 0),
77fe8ee9adSChristian Lamparter };
78fe8ee9adSChristian Lamparter #undef RATE
79fe8ee9adSChristian Lamparter 
80fe8ee9adSChristian Lamparter #define carl9170_g_ratetable	(__carl9170_ratetable + 0)
81fe8ee9adSChristian Lamparter #define carl9170_g_ratetable_size	12
82fe8ee9adSChristian Lamparter #define carl9170_a_ratetable	(__carl9170_ratetable + 4)
83fe8ee9adSChristian Lamparter #define carl9170_a_ratetable_size	8
84fe8ee9adSChristian Lamparter 
85fe8ee9adSChristian Lamparter /*
86fe8ee9adSChristian Lamparter  * NB: The hw_value is used as an index into the carl9170_phy_freq_params
87fe8ee9adSChristian Lamparter  *     array in phy.c so that we don't have to do frequency lookups!
88fe8ee9adSChristian Lamparter  */
89fe8ee9adSChristian Lamparter #define CHAN(_freq, _idx) {		\
90fe8ee9adSChristian Lamparter 	.center_freq	= (_freq),	\
91fe8ee9adSChristian Lamparter 	.hw_value	= (_idx),	\
92fe8ee9adSChristian Lamparter 	.max_power	= 18, /* XXX */	\
93fe8ee9adSChristian Lamparter }
94fe8ee9adSChristian Lamparter 
95fe8ee9adSChristian Lamparter static struct ieee80211_channel carl9170_2ghz_chantable[] = {
96fe8ee9adSChristian Lamparter 	CHAN(2412,  0),
97fe8ee9adSChristian Lamparter 	CHAN(2417,  1),
98fe8ee9adSChristian Lamparter 	CHAN(2422,  2),
99fe8ee9adSChristian Lamparter 	CHAN(2427,  3),
100fe8ee9adSChristian Lamparter 	CHAN(2432,  4),
101fe8ee9adSChristian Lamparter 	CHAN(2437,  5),
102fe8ee9adSChristian Lamparter 	CHAN(2442,  6),
103fe8ee9adSChristian Lamparter 	CHAN(2447,  7),
104fe8ee9adSChristian Lamparter 	CHAN(2452,  8),
105fe8ee9adSChristian Lamparter 	CHAN(2457,  9),
106fe8ee9adSChristian Lamparter 	CHAN(2462, 10),
107fe8ee9adSChristian Lamparter 	CHAN(2467, 11),
108fe8ee9adSChristian Lamparter 	CHAN(2472, 12),
109fe8ee9adSChristian Lamparter 	CHAN(2484, 13),
110fe8ee9adSChristian Lamparter };
111fe8ee9adSChristian Lamparter 
112fe8ee9adSChristian Lamparter static struct ieee80211_channel carl9170_5ghz_chantable[] = {
113fe8ee9adSChristian Lamparter 	CHAN(4920, 14),
114fe8ee9adSChristian Lamparter 	CHAN(4940, 15),
115fe8ee9adSChristian Lamparter 	CHAN(4960, 16),
116fe8ee9adSChristian Lamparter 	CHAN(4980, 17),
117fe8ee9adSChristian Lamparter 	CHAN(5040, 18),
118fe8ee9adSChristian Lamparter 	CHAN(5060, 19),
119fe8ee9adSChristian Lamparter 	CHAN(5080, 20),
120fe8ee9adSChristian Lamparter 	CHAN(5180, 21),
121fe8ee9adSChristian Lamparter 	CHAN(5200, 22),
122fe8ee9adSChristian Lamparter 	CHAN(5220, 23),
123fe8ee9adSChristian Lamparter 	CHAN(5240, 24),
124fe8ee9adSChristian Lamparter 	CHAN(5260, 25),
125fe8ee9adSChristian Lamparter 	CHAN(5280, 26),
126fe8ee9adSChristian Lamparter 	CHAN(5300, 27),
127fe8ee9adSChristian Lamparter 	CHAN(5320, 28),
128fe8ee9adSChristian Lamparter 	CHAN(5500, 29),
129fe8ee9adSChristian Lamparter 	CHAN(5520, 30),
130fe8ee9adSChristian Lamparter 	CHAN(5540, 31),
131fe8ee9adSChristian Lamparter 	CHAN(5560, 32),
132fe8ee9adSChristian Lamparter 	CHAN(5580, 33),
133fe8ee9adSChristian Lamparter 	CHAN(5600, 34),
134fe8ee9adSChristian Lamparter 	CHAN(5620, 35),
135fe8ee9adSChristian Lamparter 	CHAN(5640, 36),
136fe8ee9adSChristian Lamparter 	CHAN(5660, 37),
137fe8ee9adSChristian Lamparter 	CHAN(5680, 38),
138fe8ee9adSChristian Lamparter 	CHAN(5700, 39),
139fe8ee9adSChristian Lamparter 	CHAN(5745, 40),
140fe8ee9adSChristian Lamparter 	CHAN(5765, 41),
141fe8ee9adSChristian Lamparter 	CHAN(5785, 42),
142fe8ee9adSChristian Lamparter 	CHAN(5805, 43),
143fe8ee9adSChristian Lamparter 	CHAN(5825, 44),
144fe8ee9adSChristian Lamparter 	CHAN(5170, 45),
145fe8ee9adSChristian Lamparter 	CHAN(5190, 46),
146fe8ee9adSChristian Lamparter 	CHAN(5210, 47),
147fe8ee9adSChristian Lamparter 	CHAN(5230, 48),
148fe8ee9adSChristian Lamparter };
149fe8ee9adSChristian Lamparter #undef CHAN
150fe8ee9adSChristian Lamparter 
151fe8ee9adSChristian Lamparter #define CARL9170_HT_CAP							\
152fe8ee9adSChristian Lamparter {									\
153fe8ee9adSChristian Lamparter 	.ht_supported	= true,						\
154fe8ee9adSChristian Lamparter 	.cap		= IEEE80211_HT_CAP_MAX_AMSDU |			\
155fe8ee9adSChristian Lamparter 			  IEEE80211_HT_CAP_SUP_WIDTH_20_40 |		\
156fe8ee9adSChristian Lamparter 			  IEEE80211_HT_CAP_SGI_40 |			\
157fe8ee9adSChristian Lamparter 			  IEEE80211_HT_CAP_DSSSCCK40 |			\
158fe8ee9adSChristian Lamparter 			  IEEE80211_HT_CAP_SM_PS,			\
159fe8ee9adSChristian Lamparter 	.ampdu_factor	= IEEE80211_HT_MAX_AMPDU_64K,			\
160fe8ee9adSChristian Lamparter 	.ampdu_density	= IEEE80211_HT_MPDU_DENSITY_8,			\
161fe8ee9adSChristian Lamparter 	.mcs		= {						\
162fe8ee9adSChristian Lamparter 		.rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, },	\
163fe8ee9adSChristian Lamparter 		.rx_highest = cpu_to_le16(300),				\
164fe8ee9adSChristian Lamparter 		.tx_params = IEEE80211_HT_MCS_TX_DEFINED,		\
165fe8ee9adSChristian Lamparter 	},								\
166fe8ee9adSChristian Lamparter }
167fe8ee9adSChristian Lamparter 
168fe8ee9adSChristian Lamparter static struct ieee80211_supported_band carl9170_band_2GHz = {
169fe8ee9adSChristian Lamparter 	.channels	= carl9170_2ghz_chantable,
170fe8ee9adSChristian Lamparter 	.n_channels	= ARRAY_SIZE(carl9170_2ghz_chantable),
171fe8ee9adSChristian Lamparter 	.bitrates	= carl9170_g_ratetable,
172fe8ee9adSChristian Lamparter 	.n_bitrates	= carl9170_g_ratetable_size,
173fe8ee9adSChristian Lamparter 	.ht_cap		= CARL9170_HT_CAP,
174fe8ee9adSChristian Lamparter };
175fe8ee9adSChristian Lamparter 
176fe8ee9adSChristian Lamparter static struct ieee80211_supported_band carl9170_band_5GHz = {
177fe8ee9adSChristian Lamparter 	.channels	= carl9170_5ghz_chantable,
178fe8ee9adSChristian Lamparter 	.n_channels	= ARRAY_SIZE(carl9170_5ghz_chantable),
179fe8ee9adSChristian Lamparter 	.bitrates	= carl9170_a_ratetable,
180fe8ee9adSChristian Lamparter 	.n_bitrates	= carl9170_a_ratetable_size,
181fe8ee9adSChristian Lamparter 	.ht_cap		= CARL9170_HT_CAP,
182fe8ee9adSChristian Lamparter };
183fe8ee9adSChristian Lamparter 
carl9170_ampdu_gc(struct ar9170 * ar)184fe8ee9adSChristian Lamparter static void carl9170_ampdu_gc(struct ar9170 *ar)
185fe8ee9adSChristian Lamparter {
186fe8ee9adSChristian Lamparter 	struct carl9170_sta_tid *tid_info;
187fe8ee9adSChristian Lamparter 	LIST_HEAD(tid_gc);
188fe8ee9adSChristian Lamparter 
189fe8ee9adSChristian Lamparter 	rcu_read_lock();
190fe8ee9adSChristian Lamparter 	list_for_each_entry_rcu(tid_info, &ar->tx_ampdu_list, list) {
191fe8ee9adSChristian Lamparter 		spin_lock_bh(&ar->tx_ampdu_list_lock);
192fe8ee9adSChristian Lamparter 		if (tid_info->state == CARL9170_TID_STATE_SHUTDOWN) {
193fe8ee9adSChristian Lamparter 			tid_info->state = CARL9170_TID_STATE_KILLED;
194fe8ee9adSChristian Lamparter 			list_del_rcu(&tid_info->list);
195fe8ee9adSChristian Lamparter 			ar->tx_ampdu_list_len--;
196fe8ee9adSChristian Lamparter 			list_add_tail(&tid_info->tmp_list, &tid_gc);
197fe8ee9adSChristian Lamparter 		}
198fe8ee9adSChristian Lamparter 		spin_unlock_bh(&ar->tx_ampdu_list_lock);
199fe8ee9adSChristian Lamparter 
200fe8ee9adSChristian Lamparter 	}
201fe8ee9adSChristian Lamparter 	rcu_assign_pointer(ar->tx_ampdu_iter, tid_info);
202fe8ee9adSChristian Lamparter 	rcu_read_unlock();
203fe8ee9adSChristian Lamparter 
204fe8ee9adSChristian Lamparter 	synchronize_rcu();
205fe8ee9adSChristian Lamparter 
206fe8ee9adSChristian Lamparter 	while (!list_empty(&tid_gc)) {
207fe8ee9adSChristian Lamparter 		struct sk_buff *skb;
208fe8ee9adSChristian Lamparter 		tid_info = list_first_entry(&tid_gc, struct carl9170_sta_tid,
209fe8ee9adSChristian Lamparter 					    tmp_list);
210fe8ee9adSChristian Lamparter 
211fe8ee9adSChristian Lamparter 		while ((skb = __skb_dequeue(&tid_info->queue)))
212fe8ee9adSChristian Lamparter 			carl9170_tx_status(ar, skb, false);
213fe8ee9adSChristian Lamparter 
214fe8ee9adSChristian Lamparter 		list_del_init(&tid_info->tmp_list);
215fe8ee9adSChristian Lamparter 		kfree(tid_info);
216fe8ee9adSChristian Lamparter 	}
217fe8ee9adSChristian Lamparter }
218fe8ee9adSChristian Lamparter 
carl9170_flush(struct ar9170 * ar,bool drop_queued)219fe8ee9adSChristian Lamparter static void carl9170_flush(struct ar9170 *ar, bool drop_queued)
220fe8ee9adSChristian Lamparter {
221fe8ee9adSChristian Lamparter 	if (drop_queued) {
222fe8ee9adSChristian Lamparter 		int i;
223fe8ee9adSChristian Lamparter 
224fe8ee9adSChristian Lamparter 		/*
225fe8ee9adSChristian Lamparter 		 * We can only drop frames which have not been uploaded
226fe8ee9adSChristian Lamparter 		 * to the device yet.
227fe8ee9adSChristian Lamparter 		 */
228fe8ee9adSChristian Lamparter 
229fe8ee9adSChristian Lamparter 		for (i = 0; i < ar->hw->queues; i++) {
230fe8ee9adSChristian Lamparter 			struct sk_buff *skb;
231fe8ee9adSChristian Lamparter 
232cb139eccSChristian Lamparter 			while ((skb = skb_dequeue(&ar->tx_pending[i]))) {
233cb139eccSChristian Lamparter 				struct ieee80211_tx_info *info;
234cb139eccSChristian Lamparter 
235cb139eccSChristian Lamparter 				info = IEEE80211_SKB_CB(skb);
236cb139eccSChristian Lamparter 				if (info->flags & IEEE80211_TX_CTL_AMPDU)
237cb139eccSChristian Lamparter 					atomic_dec(&ar->tx_ampdu_upload);
238cb139eccSChristian Lamparter 
239fe8ee9adSChristian Lamparter 				carl9170_tx_status(ar, skb, false);
240fe8ee9adSChristian Lamparter 			}
241fe8ee9adSChristian Lamparter 		}
242cb139eccSChristian Lamparter 	}
243fe8ee9adSChristian Lamparter 
244fe8ee9adSChristian Lamparter 	/* Wait for all other outstanding frames to timeout. */
245fe8ee9adSChristian Lamparter 	if (atomic_read(&ar->tx_total_queued))
246fe8ee9adSChristian Lamparter 		WARN_ON(wait_for_completion_timeout(&ar->tx_flush, HZ) == 0);
247fe8ee9adSChristian Lamparter }
248fe8ee9adSChristian Lamparter 
carl9170_flush_ba(struct ar9170 * ar)249fe8ee9adSChristian Lamparter static void carl9170_flush_ba(struct ar9170 *ar)
250fe8ee9adSChristian Lamparter {
251fe8ee9adSChristian Lamparter 	struct sk_buff_head free;
252fe8ee9adSChristian Lamparter 	struct carl9170_sta_tid *tid_info;
253fe8ee9adSChristian Lamparter 	struct sk_buff *skb;
254fe8ee9adSChristian Lamparter 
255fe8ee9adSChristian Lamparter 	__skb_queue_head_init(&free);
256fe8ee9adSChristian Lamparter 
257fe8ee9adSChristian Lamparter 	rcu_read_lock();
258fe8ee9adSChristian Lamparter 	spin_lock_bh(&ar->tx_ampdu_list_lock);
259fe8ee9adSChristian Lamparter 	list_for_each_entry_rcu(tid_info, &ar->tx_ampdu_list, list) {
260fe8ee9adSChristian Lamparter 		if (tid_info->state > CARL9170_TID_STATE_SUSPEND) {
261fe8ee9adSChristian Lamparter 			tid_info->state = CARL9170_TID_STATE_SUSPEND;
262fe8ee9adSChristian Lamparter 
263fe8ee9adSChristian Lamparter 			spin_lock(&tid_info->lock);
264fe8ee9adSChristian Lamparter 			while ((skb = __skb_dequeue(&tid_info->queue)))
265fe8ee9adSChristian Lamparter 				__skb_queue_tail(&free, skb);
266fe8ee9adSChristian Lamparter 			spin_unlock(&tid_info->lock);
267fe8ee9adSChristian Lamparter 		}
268fe8ee9adSChristian Lamparter 	}
269fe8ee9adSChristian Lamparter 	spin_unlock_bh(&ar->tx_ampdu_list_lock);
270fe8ee9adSChristian Lamparter 	rcu_read_unlock();
271fe8ee9adSChristian Lamparter 
272fe8ee9adSChristian Lamparter 	while ((skb = __skb_dequeue(&free)))
273fe8ee9adSChristian Lamparter 		carl9170_tx_status(ar, skb, false);
274fe8ee9adSChristian Lamparter }
275fe8ee9adSChristian Lamparter 
carl9170_zap_queues(struct ar9170 * ar)276fe8ee9adSChristian Lamparter static void carl9170_zap_queues(struct ar9170 *ar)
277fe8ee9adSChristian Lamparter {
278fe8ee9adSChristian Lamparter 	struct carl9170_vif_info *cvif;
279fe8ee9adSChristian Lamparter 	unsigned int i;
280fe8ee9adSChristian Lamparter 
281fe8ee9adSChristian Lamparter 	carl9170_ampdu_gc(ar);
282fe8ee9adSChristian Lamparter 
283fe8ee9adSChristian Lamparter 	carl9170_flush_ba(ar);
284fe8ee9adSChristian Lamparter 	carl9170_flush(ar, true);
285fe8ee9adSChristian Lamparter 
286fe8ee9adSChristian Lamparter 	for (i = 0; i < ar->hw->queues; i++) {
287fe8ee9adSChristian Lamparter 		spin_lock_bh(&ar->tx_status[i].lock);
288fe8ee9adSChristian Lamparter 		while (!skb_queue_empty(&ar->tx_status[i])) {
289fe8ee9adSChristian Lamparter 			struct sk_buff *skb;
290fe8ee9adSChristian Lamparter 
291fe8ee9adSChristian Lamparter 			skb = skb_peek(&ar->tx_status[i]);
292fe8ee9adSChristian Lamparter 			carl9170_tx_get_skb(skb);
293fe8ee9adSChristian Lamparter 			spin_unlock_bh(&ar->tx_status[i].lock);
294fe8ee9adSChristian Lamparter 			carl9170_tx_drop(ar, skb);
295fe8ee9adSChristian Lamparter 			spin_lock_bh(&ar->tx_status[i].lock);
296fe8ee9adSChristian Lamparter 			carl9170_tx_put_skb(skb);
297fe8ee9adSChristian Lamparter 		}
298fe8ee9adSChristian Lamparter 		spin_unlock_bh(&ar->tx_status[i].lock);
299fe8ee9adSChristian Lamparter 	}
300fe8ee9adSChristian Lamparter 
301fe8ee9adSChristian Lamparter 	BUILD_BUG_ON(CARL9170_NUM_TX_LIMIT_SOFT < 1);
302fe8ee9adSChristian Lamparter 	BUILD_BUG_ON(CARL9170_NUM_TX_LIMIT_HARD < CARL9170_NUM_TX_LIMIT_SOFT);
303fe8ee9adSChristian Lamparter 	BUILD_BUG_ON(CARL9170_NUM_TX_LIMIT_HARD >= CARL9170_BAW_BITS);
304fe8ee9adSChristian Lamparter 
305fe8ee9adSChristian Lamparter 	/* reinitialize queues statistics */
306fe8ee9adSChristian Lamparter 	memset(&ar->tx_stats, 0, sizeof(ar->tx_stats));
307fe8ee9adSChristian Lamparter 	for (i = 0; i < ar->hw->queues; i++)
308fe8ee9adSChristian Lamparter 		ar->tx_stats[i].limit = CARL9170_NUM_TX_LIMIT_HARD;
309fe8ee9adSChristian Lamparter 
3106273c972SChristophe JAILLET 	bitmap_zero(ar->mem_bitmap, ar->fw.mem_blocks);
311fe8ee9adSChristian Lamparter 
312fe8ee9adSChristian Lamparter 	rcu_read_lock();
313fe8ee9adSChristian Lamparter 	list_for_each_entry_rcu(cvif, &ar->vif_list, list) {
314fe8ee9adSChristian Lamparter 		spin_lock_bh(&ar->beacon_lock);
315fe8ee9adSChristian Lamparter 		dev_kfree_skb_any(cvif->beacon);
316fe8ee9adSChristian Lamparter 		cvif->beacon = NULL;
317fe8ee9adSChristian Lamparter 		spin_unlock_bh(&ar->beacon_lock);
318fe8ee9adSChristian Lamparter 	}
319fe8ee9adSChristian Lamparter 	rcu_read_unlock();
320fe8ee9adSChristian Lamparter 
321fe8ee9adSChristian Lamparter 	atomic_set(&ar->tx_ampdu_upload, 0);
322fe8ee9adSChristian Lamparter 	atomic_set(&ar->tx_ampdu_scheduler, 0);
323fe8ee9adSChristian Lamparter 	atomic_set(&ar->tx_total_pending, 0);
324fe8ee9adSChristian Lamparter 	atomic_set(&ar->tx_total_queued, 0);
325fe8ee9adSChristian Lamparter 	atomic_set(&ar->mem_free_blocks, ar->fw.mem_blocks);
326fe8ee9adSChristian Lamparter }
327fe8ee9adSChristian Lamparter 
328fe8ee9adSChristian Lamparter #define CARL9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop)		\
329fe8ee9adSChristian Lamparter do {									\
330fe8ee9adSChristian Lamparter 	queue.aifs = ai_fs;						\
331fe8ee9adSChristian Lamparter 	queue.cw_min = cwmin;						\
332fe8ee9adSChristian Lamparter 	queue.cw_max = cwmax;						\
333fe8ee9adSChristian Lamparter 	queue.txop = _txop;						\
334fe8ee9adSChristian Lamparter } while (0)
335fe8ee9adSChristian Lamparter 
carl9170_op_start(struct ieee80211_hw * hw)336fe8ee9adSChristian Lamparter static int carl9170_op_start(struct ieee80211_hw *hw)
337fe8ee9adSChristian Lamparter {
338fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
339fe8ee9adSChristian Lamparter 	int err, i;
340fe8ee9adSChristian Lamparter 
341fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
342fe8ee9adSChristian Lamparter 
343fe8ee9adSChristian Lamparter 	carl9170_zap_queues(ar);
344fe8ee9adSChristian Lamparter 
345fe8ee9adSChristian Lamparter 	/* reset QoS defaults */
346c2a7965fSChristian Lamparter 	CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_VO], 2, 3,     7, 47);
347c2a7965fSChristian Lamparter 	CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_VI], 2, 7,    15, 94);
348c2a7965fSChristian Lamparter 	CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_BE], 3, 15, 1023,  0);
349c2a7965fSChristian Lamparter 	CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_BK], 7, 15, 1023,  0);
350c2a7965fSChristian Lamparter 	CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_SPECIAL], 2, 3, 7, 0);
351fe8ee9adSChristian Lamparter 
352fe8ee9adSChristian Lamparter 	ar->current_factor = ar->current_density = -1;
353fe8ee9adSChristian Lamparter 	/* "The first key is unique." */
354fe8ee9adSChristian Lamparter 	ar->usedkeys = 1;
355fe8ee9adSChristian Lamparter 	ar->filter_state = 0;
356fe8ee9adSChristian Lamparter 	ar->ps.last_action = jiffies;
357fe8ee9adSChristian Lamparter 	ar->ps.last_slept = jiffies;
358fe8ee9adSChristian Lamparter 	ar->erp_mode = CARL9170_ERP_AUTO;
3597a5c7307SChristian Lamparter 
3607a5c7307SChristian Lamparter 	/* Set "disable hw crypto offload" whenever the module parameter
3617a5c7307SChristian Lamparter 	 * nohwcrypt is true or if the firmware does not support it.
3627a5c7307SChristian Lamparter 	 */
3637a5c7307SChristian Lamparter 	ar->disable_offload = modparam_nohwcrypt |
3647a5c7307SChristian Lamparter 		ar->fw.disable_offload_fw;
3657a5c7307SChristian Lamparter 	ar->rx_software_decryption = ar->disable_offload;
366fe8ee9adSChristian Lamparter 
367fe8ee9adSChristian Lamparter 	for (i = 0; i < ar->hw->queues; i++) {
368fe8ee9adSChristian Lamparter 		ar->queue_stop_timeout[i] = jiffies;
369fe8ee9adSChristian Lamparter 		ar->max_queue_stop_timeout[i] = 0;
370fe8ee9adSChristian Lamparter 	}
371fe8ee9adSChristian Lamparter 
372fe8ee9adSChristian Lamparter 	atomic_set(&ar->mem_allocs, 0);
373fe8ee9adSChristian Lamparter 
374fe8ee9adSChristian Lamparter 	err = carl9170_usb_open(ar);
375fe8ee9adSChristian Lamparter 	if (err)
376fe8ee9adSChristian Lamparter 		goto out;
377fe8ee9adSChristian Lamparter 
378fe8ee9adSChristian Lamparter 	err = carl9170_init_mac(ar);
379fe8ee9adSChristian Lamparter 	if (err)
380fe8ee9adSChristian Lamparter 		goto out;
381fe8ee9adSChristian Lamparter 
382fe8ee9adSChristian Lamparter 	err = carl9170_set_qos(ar);
383fe8ee9adSChristian Lamparter 	if (err)
384fe8ee9adSChristian Lamparter 		goto out;
385fe8ee9adSChristian Lamparter 
3865c895691SChristian Lamparter 	if (ar->fw.rx_filter) {
3875c895691SChristian Lamparter 		err = carl9170_rx_filter(ar, CARL9170_RX_FILTER_OTHER_RA |
3885c895691SChristian Lamparter 			CARL9170_RX_FILTER_CTL_OTHER | CARL9170_RX_FILTER_BAD);
3895c895691SChristian Lamparter 		if (err)
3905c895691SChristian Lamparter 			goto out;
3915c895691SChristian Lamparter 	}
3925c895691SChristian Lamparter 
393fe8ee9adSChristian Lamparter 	err = carl9170_write_reg(ar, AR9170_MAC_REG_DMA_TRIGGER,
394fe8ee9adSChristian Lamparter 				 AR9170_DMA_TRIGGER_RXQ);
395fe8ee9adSChristian Lamparter 	if (err)
396fe8ee9adSChristian Lamparter 		goto out;
397fe8ee9adSChristian Lamparter 
398fe8ee9adSChristian Lamparter 	/* Clear key-cache */
399fe8ee9adSChristian Lamparter 	for (i = 0; i < AR9170_CAM_MAX_USER + 4; i++) {
400fe8ee9adSChristian Lamparter 		err = carl9170_upload_key(ar, i, NULL, AR9170_ENC_ALG_NONE,
401fe8ee9adSChristian Lamparter 					  0, NULL, 0);
402fe8ee9adSChristian Lamparter 		if (err)
403fe8ee9adSChristian Lamparter 			goto out;
404fe8ee9adSChristian Lamparter 
405fe8ee9adSChristian Lamparter 		err = carl9170_upload_key(ar, i, NULL, AR9170_ENC_ALG_NONE,
406fe8ee9adSChristian Lamparter 					  1, NULL, 0);
407fe8ee9adSChristian Lamparter 		if (err)
408fe8ee9adSChristian Lamparter 			goto out;
409fe8ee9adSChristian Lamparter 
410fe8ee9adSChristian Lamparter 		if (i < AR9170_CAM_MAX_USER) {
411fe8ee9adSChristian Lamparter 			err = carl9170_disable_key(ar, i);
412fe8ee9adSChristian Lamparter 			if (err)
413fe8ee9adSChristian Lamparter 				goto out;
414fe8ee9adSChristian Lamparter 		}
415fe8ee9adSChristian Lamparter 	}
416fe8ee9adSChristian Lamparter 
417fe8ee9adSChristian Lamparter 	carl9170_set_state_when(ar, CARL9170_IDLE, CARL9170_STARTED);
418fe8ee9adSChristian Lamparter 
419acf17712SChristian Lamparter 	ieee80211_queue_delayed_work(ar->hw, &ar->stat_work,
420acf17712SChristian Lamparter 		round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK)));
421acf17712SChristian Lamparter 
422fe8ee9adSChristian Lamparter 	ieee80211_wake_queues(ar->hw);
423fe8ee9adSChristian Lamparter 	err = 0;
424fe8ee9adSChristian Lamparter 
425fe8ee9adSChristian Lamparter out:
426fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
427fe8ee9adSChristian Lamparter 	return err;
428fe8ee9adSChristian Lamparter }
429fe8ee9adSChristian Lamparter 
carl9170_cancel_worker(struct ar9170 * ar)430fe8ee9adSChristian Lamparter static void carl9170_cancel_worker(struct ar9170 *ar)
431fe8ee9adSChristian Lamparter {
432acf17712SChristian Lamparter 	cancel_delayed_work_sync(&ar->stat_work);
433fe8ee9adSChristian Lamparter 	cancel_delayed_work_sync(&ar->tx_janitor);
434fe8ee9adSChristian Lamparter #ifdef CONFIG_CARL9170_LEDS
435fe8ee9adSChristian Lamparter 	cancel_delayed_work_sync(&ar->led_work);
436fe8ee9adSChristian Lamparter #endif /* CONFIG_CARL9170_LEDS */
437fe8ee9adSChristian Lamparter 	cancel_work_sync(&ar->ps_work);
438e4a668c5SChristian Lamparter 	cancel_work_sync(&ar->ping_work);
439fe8ee9adSChristian Lamparter 	cancel_work_sync(&ar->ampdu_work);
440fe8ee9adSChristian Lamparter }
441fe8ee9adSChristian Lamparter 
carl9170_op_stop(struct ieee80211_hw * hw)442fe8ee9adSChristian Lamparter static void carl9170_op_stop(struct ieee80211_hw *hw)
443fe8ee9adSChristian Lamparter {
444fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
445fe8ee9adSChristian Lamparter 
446fe8ee9adSChristian Lamparter 	carl9170_set_state_when(ar, CARL9170_STARTED, CARL9170_IDLE);
447fe8ee9adSChristian Lamparter 
448fe8ee9adSChristian Lamparter 	ieee80211_stop_queues(ar->hw);
449fe8ee9adSChristian Lamparter 
450fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
451fe8ee9adSChristian Lamparter 	if (IS_ACCEPTING_CMD(ar)) {
4522cfa5a04SEric Dumazet 		RCU_INIT_POINTER(ar->beacon_iter, NULL);
453fe8ee9adSChristian Lamparter 
454fe8ee9adSChristian Lamparter 		carl9170_led_set_state(ar, 0);
455fe8ee9adSChristian Lamparter 
456fe8ee9adSChristian Lamparter 		/* stop DMA */
457fe8ee9adSChristian Lamparter 		carl9170_write_reg(ar, AR9170_MAC_REG_DMA_TRIGGER, 0);
458fe8ee9adSChristian Lamparter 		carl9170_usb_stop(ar);
459fe8ee9adSChristian Lamparter 	}
460fe8ee9adSChristian Lamparter 
461fe8ee9adSChristian Lamparter 	carl9170_zap_queues(ar);
462fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
463fe8ee9adSChristian Lamparter 
464fe8ee9adSChristian Lamparter 	carl9170_cancel_worker(ar);
465fe8ee9adSChristian Lamparter }
466fe8ee9adSChristian Lamparter 
carl9170_restart_work(struct work_struct * work)467fe8ee9adSChristian Lamparter static void carl9170_restart_work(struct work_struct *work)
468fe8ee9adSChristian Lamparter {
469fe8ee9adSChristian Lamparter 	struct ar9170 *ar = container_of(work, struct ar9170,
470fe8ee9adSChristian Lamparter 					 restart_work);
4715bcbc3fcSRonald Wahl 	int err = -EIO;
472fe8ee9adSChristian Lamparter 
473fe8ee9adSChristian Lamparter 	ar->usedkeys = 0;
474fe8ee9adSChristian Lamparter 	ar->filter_state = 0;
475fe8ee9adSChristian Lamparter 	carl9170_cancel_worker(ar);
476fe8ee9adSChristian Lamparter 
477fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
4785bcbc3fcSRonald Wahl 	if (!ar->force_usb_reset) {
479fe8ee9adSChristian Lamparter 		err = carl9170_usb_restart(ar);
480fe8ee9adSChristian Lamparter 		if (net_ratelimit()) {
4815bcbc3fcSRonald Wahl 			if (err)
4825bcbc3fcSRonald Wahl 				dev_err(&ar->udev->dev, "Failed to restart device (%d).\n", err);
4835bcbc3fcSRonald Wahl 			else
4845bcbc3fcSRonald Wahl 				dev_info(&ar->udev->dev, "device restarted successfully.\n");
485fe8ee9adSChristian Lamparter 		}
486fe8ee9adSChristian Lamparter 	}
487fe8ee9adSChristian Lamparter 	carl9170_zap_queues(ar);
488fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
4895bcbc3fcSRonald Wahl 
4905bcbc3fcSRonald Wahl 	if (!err && !ar->force_usb_reset) {
491fe8ee9adSChristian Lamparter 		ar->restart_counter++;
492fe8ee9adSChristian Lamparter 		atomic_set(&ar->pending_restarts, 0);
493fe8ee9adSChristian Lamparter 
494fe8ee9adSChristian Lamparter 		ieee80211_restart_hw(ar->hw);
495fe8ee9adSChristian Lamparter 	} else {
496fe8ee9adSChristian Lamparter 		/*
497fe8ee9adSChristian Lamparter 		 * The reset was unsuccessful and the device seems to
498fe8ee9adSChristian Lamparter 		 * be dead. But there's still one option: a low-level
499fe8ee9adSChristian Lamparter 		 * usb subsystem reset...
500fe8ee9adSChristian Lamparter 		 */
501fe8ee9adSChristian Lamparter 
502fe8ee9adSChristian Lamparter 		carl9170_usb_reset(ar);
503fe8ee9adSChristian Lamparter 	}
504fe8ee9adSChristian Lamparter }
505fe8ee9adSChristian Lamparter 
carl9170_restart(struct ar9170 * ar,const enum carl9170_restart_reasons r)506fe8ee9adSChristian Lamparter void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
507fe8ee9adSChristian Lamparter {
508fe8ee9adSChristian Lamparter 	carl9170_set_state_when(ar, CARL9170_STARTED, CARL9170_IDLE);
509fe8ee9adSChristian Lamparter 
510fe8ee9adSChristian Lamparter 	/*
511fe8ee9adSChristian Lamparter 	 * Sometimes, an error can trigger several different reset events.
512fe8ee9adSChristian Lamparter 	 * By ignoring these *surplus* reset events, the device won't be
513fe8ee9adSChristian Lamparter 	 * killed again, right after it has recovered.
514fe8ee9adSChristian Lamparter 	 */
515fe8ee9adSChristian Lamparter 	if (atomic_inc_return(&ar->pending_restarts) > 1) {
516fe8ee9adSChristian Lamparter 		dev_dbg(&ar->udev->dev, "ignoring restart (%d)\n", r);
517fe8ee9adSChristian Lamparter 		return;
518fe8ee9adSChristian Lamparter 	}
519fe8ee9adSChristian Lamparter 
520fe8ee9adSChristian Lamparter 	ieee80211_stop_queues(ar->hw);
521fe8ee9adSChristian Lamparter 
522fe8ee9adSChristian Lamparter 	dev_err(&ar->udev->dev, "restart device (%d)\n", r);
523fe8ee9adSChristian Lamparter 
524fe8ee9adSChristian Lamparter 	if (!WARN_ON(r == CARL9170_RR_NO_REASON) ||
525fe8ee9adSChristian Lamparter 	    !WARN_ON(r >= __CARL9170_RR_LAST))
526fe8ee9adSChristian Lamparter 		ar->last_reason = r;
527fe8ee9adSChristian Lamparter 
528fe8ee9adSChristian Lamparter 	if (!ar->registered)
529fe8ee9adSChristian Lamparter 		return;
530fe8ee9adSChristian Lamparter 
5315bcbc3fcSRonald Wahl 	if (!IS_ACCEPTING_CMD(ar) || ar->needs_full_reset)
5325bcbc3fcSRonald Wahl 		ar->force_usb_reset = true;
5335bcbc3fcSRonald Wahl 
534fe8ee9adSChristian Lamparter 	ieee80211_queue_work(ar->hw, &ar->restart_work);
535fe8ee9adSChristian Lamparter 
536fe8ee9adSChristian Lamparter 	/*
537fe8ee9adSChristian Lamparter 	 * At this point, the device instance might have vanished/disabled.
538fe8ee9adSChristian Lamparter 	 * So, don't put any code which access the ar9170 struct
539fe8ee9adSChristian Lamparter 	 * without proper protection.
540fe8ee9adSChristian Lamparter 	 */
541fe8ee9adSChristian Lamparter }
542fe8ee9adSChristian Lamparter 
carl9170_ping_work(struct work_struct * work)543e4a668c5SChristian Lamparter static void carl9170_ping_work(struct work_struct *work)
544e4a668c5SChristian Lamparter {
545e4a668c5SChristian Lamparter 	struct ar9170 *ar = container_of(work, struct ar9170, ping_work);
546e4a668c5SChristian Lamparter 	int err;
547e4a668c5SChristian Lamparter 
548e4a668c5SChristian Lamparter 	if (!IS_STARTED(ar))
549e4a668c5SChristian Lamparter 		return;
550e4a668c5SChristian Lamparter 
551e4a668c5SChristian Lamparter 	mutex_lock(&ar->mutex);
552e4a668c5SChristian Lamparter 	err = carl9170_echo_test(ar, 0xdeadbeef);
553e4a668c5SChristian Lamparter 	if (err)
554e4a668c5SChristian Lamparter 		carl9170_restart(ar, CARL9170_RR_UNRESPONSIVE_DEVICE);
555e4a668c5SChristian Lamparter 	mutex_unlock(&ar->mutex);
556e4a668c5SChristian Lamparter }
557e4a668c5SChristian Lamparter 
carl9170_init_interface(struct ar9170 * ar,struct ieee80211_vif * vif)558fe8ee9adSChristian Lamparter static int carl9170_init_interface(struct ar9170 *ar,
559fe8ee9adSChristian Lamparter 				   struct ieee80211_vif *vif)
560fe8ee9adSChristian Lamparter {
561fe8ee9adSChristian Lamparter 	struct ath_common *common = &ar->common;
562fe8ee9adSChristian Lamparter 	int err;
563fe8ee9adSChristian Lamparter 
564fe8ee9adSChristian Lamparter 	if (!vif) {
565fe8ee9adSChristian Lamparter 		WARN_ON_ONCE(IS_STARTED(ar));
566fe8ee9adSChristian Lamparter 		return 0;
567fe8ee9adSChristian Lamparter 	}
568fe8ee9adSChristian Lamparter 
569fe8ee9adSChristian Lamparter 	memcpy(common->macaddr, vif->addr, ETH_ALEN);
570fe8ee9adSChristian Lamparter 
5717a5c7307SChristian Lamparter 	/* We have to fall back to software crypto, whenever
5727a5c7307SChristian Lamparter 	 * the user choose to participates in an IBSS. HW
5737a5c7307SChristian Lamparter 	 * offload for IBSS RSN is not supported by this driver.
5747a5c7307SChristian Lamparter 	 *
5757a5c7307SChristian Lamparter 	 * NOTE: If the previous main interface has already
5767a5c7307SChristian Lamparter 	 * disabled hw crypto offload, we have to keep this
5777a5c7307SChristian Lamparter 	 * previous disable_offload setting as it was.
5787a5c7307SChristian Lamparter 	 * Altough ideally, we should notify mac80211 and tell
5797a5c7307SChristian Lamparter 	 * it to forget about any HW crypto offload for now.
5807a5c7307SChristian Lamparter 	 */
5817a5c7307SChristian Lamparter 	ar->disable_offload |= ((vif->type != NL80211_IFTYPE_STATION) &&
5827a5c7307SChristian Lamparter 	    (vif->type != NL80211_IFTYPE_AP));
5837a5c7307SChristian Lamparter 
584b14fba7eSChristian Lamparter 	/* The driver used to have P2P GO+CLIENT support,
585b14fba7eSChristian Lamparter 	 * but since this was dropped and we don't know if
586b14fba7eSChristian Lamparter 	 * there are any gremlins lurking in the shadows,
587b14fba7eSChristian Lamparter 	 * so best we keep HW offload disabled for P2P.
58855fa645eSChristian Lamparter 	 */
58955fa645eSChristian Lamparter 	ar->disable_offload |= vif->p2p;
59055fa645eSChristian Lamparter 
5917a5c7307SChristian Lamparter 	ar->rx_software_decryption = ar->disable_offload;
592fe8ee9adSChristian Lamparter 
593fe8ee9adSChristian Lamparter 	err = carl9170_set_operating_mode(ar);
594fe8ee9adSChristian Lamparter 	return err;
595fe8ee9adSChristian Lamparter }
596fe8ee9adSChristian Lamparter 
carl9170_op_add_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)597fe8ee9adSChristian Lamparter static int carl9170_op_add_interface(struct ieee80211_hw *hw,
598fe8ee9adSChristian Lamparter 				     struct ieee80211_vif *vif)
599fe8ee9adSChristian Lamparter {
600fe8ee9adSChristian Lamparter 	struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv;
6017f878b0dSChristian Lamparter 	struct ieee80211_vif *main_vif, *old_main = NULL;
602fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
603fe8ee9adSChristian Lamparter 	int vif_id = -1, err = 0;
604fe8ee9adSChristian Lamparter 
605fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
606fe8ee9adSChristian Lamparter 	rcu_read_lock();
607fe8ee9adSChristian Lamparter 	if (vif_priv->active) {
608fe8ee9adSChristian Lamparter 		/*
609fe8ee9adSChristian Lamparter 		 * Skip the interface structure initialization,
610fe8ee9adSChristian Lamparter 		 * if the vif survived the _restart call.
611fe8ee9adSChristian Lamparter 		 */
612fe8ee9adSChristian Lamparter 		vif_id = vif_priv->id;
613fe8ee9adSChristian Lamparter 		vif_priv->enable_beacon = false;
614fe8ee9adSChristian Lamparter 
615fe8ee9adSChristian Lamparter 		spin_lock_bh(&ar->beacon_lock);
616fe8ee9adSChristian Lamparter 		dev_kfree_skb_any(vif_priv->beacon);
617fe8ee9adSChristian Lamparter 		vif_priv->beacon = NULL;
618fe8ee9adSChristian Lamparter 		spin_unlock_bh(&ar->beacon_lock);
619fe8ee9adSChristian Lamparter 
620fe8ee9adSChristian Lamparter 		goto init;
621fe8ee9adSChristian Lamparter 	}
622fe8ee9adSChristian Lamparter 
6237f878b0dSChristian Lamparter 	/* Because the AR9170 HW's MAC doesn't provide full support for
6247f878b0dSChristian Lamparter 	 * multiple, independent interfaces [of different operation modes].
6257f878b0dSChristian Lamparter 	 * We have to select ONE main interface [main mode of HW], but we
6267f878b0dSChristian Lamparter 	 * can have multiple slaves [AKA: entry in the ACK-table].
6277f878b0dSChristian Lamparter 	 *
6287f878b0dSChristian Lamparter 	 * The first (from HEAD/TOP) interface in the ar->vif_list is
6297f878b0dSChristian Lamparter 	 * always the main intf. All following intfs in this list
6307f878b0dSChristian Lamparter 	 * are considered to be slave intfs.
6317f878b0dSChristian Lamparter 	 */
632fe8ee9adSChristian Lamparter 	main_vif = carl9170_get_main_vif(ar);
633fe8ee9adSChristian Lamparter 
634fe8ee9adSChristian Lamparter 	if (main_vif) {
635fe8ee9adSChristian Lamparter 		switch (main_vif->type) {
636fe8ee9adSChristian Lamparter 		case NL80211_IFTYPE_STATION:
637fe8ee9adSChristian Lamparter 			if (vif->type == NL80211_IFTYPE_STATION)
638fe8ee9adSChristian Lamparter 				break;
639fe8ee9adSChristian Lamparter 
640fe8ee9adSChristian Lamparter 			err = -EBUSY;
641fe8ee9adSChristian Lamparter 			rcu_read_unlock();
642fe8ee9adSChristian Lamparter 
643fe8ee9adSChristian Lamparter 			goto unlock;
644fe8ee9adSChristian Lamparter 
645da93c26dSJavier Lopez 		case NL80211_IFTYPE_MESH_POINT:
646fe8ee9adSChristian Lamparter 		case NL80211_IFTYPE_AP:
647fe8ee9adSChristian Lamparter 			if ((vif->type == NL80211_IFTYPE_STATION) ||
648da93c26dSJavier Lopez 			    (vif->type == NL80211_IFTYPE_AP) ||
649da93c26dSJavier Lopez 			    (vif->type == NL80211_IFTYPE_MESH_POINT))
650fe8ee9adSChristian Lamparter 				break;
651fe8ee9adSChristian Lamparter 
652fe8ee9adSChristian Lamparter 			err = -EBUSY;
653fe8ee9adSChristian Lamparter 			rcu_read_unlock();
654fe8ee9adSChristian Lamparter 			goto unlock;
655fe8ee9adSChristian Lamparter 
656fe8ee9adSChristian Lamparter 		default:
657fe8ee9adSChristian Lamparter 			rcu_read_unlock();
658fe8ee9adSChristian Lamparter 			goto unlock;
659fe8ee9adSChristian Lamparter 		}
660fe8ee9adSChristian Lamparter 	}
661fe8ee9adSChristian Lamparter 
662fe8ee9adSChristian Lamparter 	vif_id = bitmap_find_free_region(&ar->vif_bitmap, ar->fw.vif_num, 0);
663fe8ee9adSChristian Lamparter 
664fe8ee9adSChristian Lamparter 	if (vif_id < 0) {
665fe8ee9adSChristian Lamparter 		rcu_read_unlock();
666fe8ee9adSChristian Lamparter 
667fe8ee9adSChristian Lamparter 		err = -ENOSPC;
668fe8ee9adSChristian Lamparter 		goto unlock;
669fe8ee9adSChristian Lamparter 	}
670fe8ee9adSChristian Lamparter 
671fe8ee9adSChristian Lamparter 	BUG_ON(ar->vif_priv[vif_id].id != vif_id);
672fe8ee9adSChristian Lamparter 
673fe8ee9adSChristian Lamparter 	vif_priv->active = true;
674fe8ee9adSChristian Lamparter 	vif_priv->id = vif_id;
675fe8ee9adSChristian Lamparter 	vif_priv->enable_beacon = false;
676fe8ee9adSChristian Lamparter 	ar->vifs++;
6777f878b0dSChristian Lamparter 	if (old_main) {
6787f878b0dSChristian Lamparter 		/* We end up in here, if the main interface is being replaced.
6797f878b0dSChristian Lamparter 		 * Put the new main interface at the HEAD of the list and the
6807f878b0dSChristian Lamparter 		 * previous inteface will automatically become second in line.
6817f878b0dSChristian Lamparter 		 */
6827f878b0dSChristian Lamparter 		list_add_rcu(&vif_priv->list, &ar->vif_list);
6837f878b0dSChristian Lamparter 	} else {
6847f878b0dSChristian Lamparter 		/* Add new inteface. If the list is empty, it will become the
6857f878b0dSChristian Lamparter 		 * main inteface, otherwise it will be slave.
6867f878b0dSChristian Lamparter 		 */
687fe8ee9adSChristian Lamparter 		list_add_tail_rcu(&vif_priv->list, &ar->vif_list);
6887f878b0dSChristian Lamparter 	}
689fe8ee9adSChristian Lamparter 	rcu_assign_pointer(ar->vif_priv[vif_id].vif, vif);
690fe8ee9adSChristian Lamparter 
691fe8ee9adSChristian Lamparter init:
6927f878b0dSChristian Lamparter 	main_vif = carl9170_get_main_vif(ar);
6937f878b0dSChristian Lamparter 
6947f878b0dSChristian Lamparter 	if (main_vif == vif) {
695fe8ee9adSChristian Lamparter 		rcu_assign_pointer(ar->beacon_iter, vif_priv);
696fe8ee9adSChristian Lamparter 		rcu_read_unlock();
697fe8ee9adSChristian Lamparter 
6987f878b0dSChristian Lamparter 		if (old_main) {
6997f878b0dSChristian Lamparter 			struct carl9170_vif_info *old_main_priv =
7007f878b0dSChristian Lamparter 				(void *) old_main->drv_priv;
7017f878b0dSChristian Lamparter 			/* downgrade old main intf to slave intf.
7027f878b0dSChristian Lamparter 			 * NOTE: We are no longer under rcu_read_lock.
7037f878b0dSChristian Lamparter 			 * But we are still holding ar->mutex, so the
7047f878b0dSChristian Lamparter 			 * vif data [id, addr] is safe.
7057f878b0dSChristian Lamparter 			 */
7067f878b0dSChristian Lamparter 			err = carl9170_mod_virtual_mac(ar, old_main_priv->id,
7077f878b0dSChristian Lamparter 						       old_main->addr);
7087f878b0dSChristian Lamparter 			if (err)
7097f878b0dSChristian Lamparter 				goto unlock;
7107f878b0dSChristian Lamparter 		}
7117f878b0dSChristian Lamparter 
712fe8ee9adSChristian Lamparter 		err = carl9170_init_interface(ar, vif);
713fe8ee9adSChristian Lamparter 		if (err)
714fe8ee9adSChristian Lamparter 			goto unlock;
715fe8ee9adSChristian Lamparter 	} else {
716fe8ee9adSChristian Lamparter 		rcu_read_unlock();
717dafeac38SChristian Lamparter 		err = carl9170_mod_virtual_mac(ar, vif_id, vif->addr);
718fe8ee9adSChristian Lamparter 
719fe8ee9adSChristian Lamparter 		if (err)
720fe8ee9adSChristian Lamparter 			goto unlock;
721fe8ee9adSChristian Lamparter 	}
722fe8ee9adSChristian Lamparter 
723aa32452dSChristian Lamparter 	if (ar->fw.tx_seq_table) {
724aa32452dSChristian Lamparter 		err = carl9170_write_reg(ar, ar->fw.tx_seq_table + vif_id * 4,
725aa32452dSChristian Lamparter 					 0);
726aa32452dSChristian Lamparter 		if (err)
727aa32452dSChristian Lamparter 			goto unlock;
728aa32452dSChristian Lamparter 	}
729aa32452dSChristian Lamparter 
730fe8ee9adSChristian Lamparter unlock:
731b397492aSChristian Lamparter 	if (err && (vif_id >= 0)) {
732fe8ee9adSChristian Lamparter 		vif_priv->active = false;
733fe8ee9adSChristian Lamparter 		bitmap_release_region(&ar->vif_bitmap, vif_id, 0);
734fe8ee9adSChristian Lamparter 		ar->vifs--;
7352cfa5a04SEric Dumazet 		RCU_INIT_POINTER(ar->vif_priv[vif_id].vif, NULL);
736fe8ee9adSChristian Lamparter 		list_del_rcu(&vif_priv->list);
737fe8ee9adSChristian Lamparter 		mutex_unlock(&ar->mutex);
738fe8ee9adSChristian Lamparter 		synchronize_rcu();
739fe8ee9adSChristian Lamparter 	} else {
740fe8ee9adSChristian Lamparter 		if (ar->vifs > 1)
741fe8ee9adSChristian Lamparter 			ar->ps.off_override |= PS_OFF_VIF;
742fe8ee9adSChristian Lamparter 
743fe8ee9adSChristian Lamparter 		mutex_unlock(&ar->mutex);
744fe8ee9adSChristian Lamparter 	}
745fe8ee9adSChristian Lamparter 
746fe8ee9adSChristian Lamparter 	return err;
747fe8ee9adSChristian Lamparter }
748fe8ee9adSChristian Lamparter 
carl9170_op_remove_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)749fe8ee9adSChristian Lamparter static void carl9170_op_remove_interface(struct ieee80211_hw *hw,
750fe8ee9adSChristian Lamparter 					 struct ieee80211_vif *vif)
751fe8ee9adSChristian Lamparter {
752fe8ee9adSChristian Lamparter 	struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv;
753fe8ee9adSChristian Lamparter 	struct ieee80211_vif *main_vif;
754fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
755fe8ee9adSChristian Lamparter 	unsigned int id;
756fe8ee9adSChristian Lamparter 
757fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
758fe8ee9adSChristian Lamparter 
759fe8ee9adSChristian Lamparter 	if (WARN_ON_ONCE(!vif_priv->active))
760fe8ee9adSChristian Lamparter 		goto unlock;
761fe8ee9adSChristian Lamparter 
762fe8ee9adSChristian Lamparter 	ar->vifs--;
763fe8ee9adSChristian Lamparter 
764fe8ee9adSChristian Lamparter 	rcu_read_lock();
765fe8ee9adSChristian Lamparter 	main_vif = carl9170_get_main_vif(ar);
766fe8ee9adSChristian Lamparter 
767fe8ee9adSChristian Lamparter 	id = vif_priv->id;
768fe8ee9adSChristian Lamparter 
769fe8ee9adSChristian Lamparter 	vif_priv->active = false;
770fe8ee9adSChristian Lamparter 	WARN_ON(vif_priv->enable_beacon);
771fe8ee9adSChristian Lamparter 	vif_priv->enable_beacon = false;
772fe8ee9adSChristian Lamparter 	list_del_rcu(&vif_priv->list);
7732cfa5a04SEric Dumazet 	RCU_INIT_POINTER(ar->vif_priv[id].vif, NULL);
774fe8ee9adSChristian Lamparter 
775fe8ee9adSChristian Lamparter 	if (vif == main_vif) {
776fe8ee9adSChristian Lamparter 		rcu_read_unlock();
777fe8ee9adSChristian Lamparter 
778fe8ee9adSChristian Lamparter 		if (ar->vifs) {
779fe8ee9adSChristian Lamparter 			WARN_ON(carl9170_init_interface(ar,
780fe8ee9adSChristian Lamparter 					carl9170_get_main_vif(ar)));
781fe8ee9adSChristian Lamparter 		} else {
782fe8ee9adSChristian Lamparter 			carl9170_set_operating_mode(ar);
783fe8ee9adSChristian Lamparter 		}
784fe8ee9adSChristian Lamparter 	} else {
785fe8ee9adSChristian Lamparter 		rcu_read_unlock();
786fe8ee9adSChristian Lamparter 
787fe8ee9adSChristian Lamparter 		WARN_ON(carl9170_mod_virtual_mac(ar, id, NULL));
788fe8ee9adSChristian Lamparter 	}
789fe8ee9adSChristian Lamparter 
790fe8ee9adSChristian Lamparter 	carl9170_update_beacon(ar, false);
791fe8ee9adSChristian Lamparter 	carl9170_flush_cab(ar, id);
792fe8ee9adSChristian Lamparter 
793fe8ee9adSChristian Lamparter 	spin_lock_bh(&ar->beacon_lock);
794fe8ee9adSChristian Lamparter 	dev_kfree_skb_any(vif_priv->beacon);
795fe8ee9adSChristian Lamparter 	vif_priv->beacon = NULL;
796fe8ee9adSChristian Lamparter 	spin_unlock_bh(&ar->beacon_lock);
797fe8ee9adSChristian Lamparter 
798fe8ee9adSChristian Lamparter 	bitmap_release_region(&ar->vif_bitmap, id, 0);
799fe8ee9adSChristian Lamparter 
800fe8ee9adSChristian Lamparter 	carl9170_set_beacon_timers(ar);
801fe8ee9adSChristian Lamparter 
802fe8ee9adSChristian Lamparter 	if (ar->vifs == 1)
803fe8ee9adSChristian Lamparter 		ar->ps.off_override &= ~PS_OFF_VIF;
804fe8ee9adSChristian Lamparter 
805fe8ee9adSChristian Lamparter unlock:
806fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
807fe8ee9adSChristian Lamparter 
808fe8ee9adSChristian Lamparter 	synchronize_rcu();
809fe8ee9adSChristian Lamparter }
810fe8ee9adSChristian Lamparter 
carl9170_ps_check(struct ar9170 * ar)811fe8ee9adSChristian Lamparter void carl9170_ps_check(struct ar9170 *ar)
812fe8ee9adSChristian Lamparter {
813fe8ee9adSChristian Lamparter 	ieee80211_queue_work(ar->hw, &ar->ps_work);
814fe8ee9adSChristian Lamparter }
815fe8ee9adSChristian Lamparter 
816fe8ee9adSChristian Lamparter /* caller must hold ar->mutex */
carl9170_ps_update(struct ar9170 * ar)817fe8ee9adSChristian Lamparter static int carl9170_ps_update(struct ar9170 *ar)
818fe8ee9adSChristian Lamparter {
819fe8ee9adSChristian Lamparter 	bool ps = false;
820fe8ee9adSChristian Lamparter 	int err = 0;
821fe8ee9adSChristian Lamparter 
822fe8ee9adSChristian Lamparter 	if (!ar->ps.off_override)
823fe8ee9adSChristian Lamparter 		ps = (ar->hw->conf.flags & IEEE80211_CONF_PS);
824fe8ee9adSChristian Lamparter 
825fe8ee9adSChristian Lamparter 	if (ps != ar->ps.state) {
826fe8ee9adSChristian Lamparter 		err = carl9170_powersave(ar, ps);
827fe8ee9adSChristian Lamparter 		if (err)
828fe8ee9adSChristian Lamparter 			return err;
829fe8ee9adSChristian Lamparter 
830fe8ee9adSChristian Lamparter 		if (ar->ps.state && !ps) {
831fe8ee9adSChristian Lamparter 			ar->ps.sleep_ms = jiffies_to_msecs(jiffies -
832fe8ee9adSChristian Lamparter 				ar->ps.last_action);
833fe8ee9adSChristian Lamparter 		}
834fe8ee9adSChristian Lamparter 
835fe8ee9adSChristian Lamparter 		if (ps)
836fe8ee9adSChristian Lamparter 			ar->ps.last_slept = jiffies;
837fe8ee9adSChristian Lamparter 
838fe8ee9adSChristian Lamparter 		ar->ps.last_action = jiffies;
839fe8ee9adSChristian Lamparter 		ar->ps.state = ps;
840fe8ee9adSChristian Lamparter 	}
841fe8ee9adSChristian Lamparter 
842fe8ee9adSChristian Lamparter 	return 0;
843fe8ee9adSChristian Lamparter }
844fe8ee9adSChristian Lamparter 
carl9170_ps_work(struct work_struct * work)845fe8ee9adSChristian Lamparter static void carl9170_ps_work(struct work_struct *work)
846fe8ee9adSChristian Lamparter {
847fe8ee9adSChristian Lamparter 	struct ar9170 *ar = container_of(work, struct ar9170,
848fe8ee9adSChristian Lamparter 					 ps_work);
849fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
850fe8ee9adSChristian Lamparter 	if (IS_STARTED(ar))
851fe8ee9adSChristian Lamparter 		WARN_ON_ONCE(carl9170_ps_update(ar) != 0);
852fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
853fe8ee9adSChristian Lamparter }
854fe8ee9adSChristian Lamparter 
carl9170_update_survey(struct ar9170 * ar,bool flush,bool noise)855acf17712SChristian Lamparter static int carl9170_update_survey(struct ar9170 *ar, bool flush, bool noise)
856acf17712SChristian Lamparter {
857acf17712SChristian Lamparter 	int err;
858acf17712SChristian Lamparter 
859acf17712SChristian Lamparter 	if (noise) {
860acf17712SChristian Lamparter 		err = carl9170_get_noisefloor(ar);
861acf17712SChristian Lamparter 		if (err)
862acf17712SChristian Lamparter 			return err;
863acf17712SChristian Lamparter 	}
864acf17712SChristian Lamparter 
865acf17712SChristian Lamparter 	if (ar->fw.hw_counters) {
866acf17712SChristian Lamparter 		err = carl9170_collect_tally(ar);
867acf17712SChristian Lamparter 		if (err)
868acf17712SChristian Lamparter 			return err;
869acf17712SChristian Lamparter 	}
870acf17712SChristian Lamparter 
871acf17712SChristian Lamparter 	if (flush)
872acf17712SChristian Lamparter 		memset(&ar->tally, 0, sizeof(ar->tally));
873acf17712SChristian Lamparter 
874acf17712SChristian Lamparter 	return 0;
875acf17712SChristian Lamparter }
876acf17712SChristian Lamparter 
carl9170_stat_work(struct work_struct * work)877acf17712SChristian Lamparter static void carl9170_stat_work(struct work_struct *work)
878acf17712SChristian Lamparter {
879acf17712SChristian Lamparter 	struct ar9170 *ar = container_of(work, struct ar9170, stat_work.work);
880acf17712SChristian Lamparter 	int err;
881acf17712SChristian Lamparter 
882acf17712SChristian Lamparter 	mutex_lock(&ar->mutex);
883acf17712SChristian Lamparter 	err = carl9170_update_survey(ar, false, true);
884acf17712SChristian Lamparter 	mutex_unlock(&ar->mutex);
885acf17712SChristian Lamparter 
886acf17712SChristian Lamparter 	if (err)
887acf17712SChristian Lamparter 		return;
888acf17712SChristian Lamparter 
889acf17712SChristian Lamparter 	ieee80211_queue_delayed_work(ar->hw, &ar->stat_work,
890acf17712SChristian Lamparter 		round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK)));
891acf17712SChristian Lamparter }
892fe8ee9adSChristian Lamparter 
carl9170_op_config(struct ieee80211_hw * hw,u32 changed)893fe8ee9adSChristian Lamparter static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
894fe8ee9adSChristian Lamparter {
895fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
896fe8ee9adSChristian Lamparter 	int err = 0;
897fe8ee9adSChristian Lamparter 
898fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
899fe8ee9adSChristian Lamparter 	if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
900fe8ee9adSChristian Lamparter 		/* TODO */
901fe8ee9adSChristian Lamparter 		err = 0;
902fe8ee9adSChristian Lamparter 	}
903fe8ee9adSChristian Lamparter 
904fe8ee9adSChristian Lamparter 	if (changed & IEEE80211_CONF_CHANGE_PS) {
905fe8ee9adSChristian Lamparter 		err = carl9170_ps_update(ar);
906fe8ee9adSChristian Lamparter 		if (err)
907fe8ee9adSChristian Lamparter 			goto out;
908fe8ee9adSChristian Lamparter 	}
909fe8ee9adSChristian Lamparter 
910fe8ee9adSChristian Lamparter 	if (changed & IEEE80211_CONF_CHANGE_SMPS) {
911fe8ee9adSChristian Lamparter 		/* TODO */
912fe8ee9adSChristian Lamparter 		err = 0;
913fe8ee9adSChristian Lamparter 	}
914fe8ee9adSChristian Lamparter 
915fe8ee9adSChristian Lamparter 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
916675a0b04SKarl Beldan 		enum nl80211_channel_type channel_type =
917675a0b04SKarl Beldan 			cfg80211_get_chandef_type(&hw->conf.chandef);
918675a0b04SKarl Beldan 
919fe8ee9adSChristian Lamparter 		/* adjust slot time for 5 GHz */
920fe8ee9adSChristian Lamparter 		err = carl9170_set_slot_time(ar);
921fe8ee9adSChristian Lamparter 		if (err)
922fe8ee9adSChristian Lamparter 			goto out;
923fe8ee9adSChristian Lamparter 
924acf17712SChristian Lamparter 		err = carl9170_update_survey(ar, true, false);
925acf17712SChristian Lamparter 		if (err)
926acf17712SChristian Lamparter 			goto out;
927acf17712SChristian Lamparter 
928675a0b04SKarl Beldan 		err = carl9170_set_channel(ar, hw->conf.chandef.chan,
929655d8e23SJohn W. Linville 					   channel_type);
930fe8ee9adSChristian Lamparter 		if (err)
931fe8ee9adSChristian Lamparter 			goto out;
932fe8ee9adSChristian Lamparter 
933acf17712SChristian Lamparter 		err = carl9170_update_survey(ar, false, true);
934acf17712SChristian Lamparter 		if (err)
935acf17712SChristian Lamparter 			goto out;
936acf17712SChristian Lamparter 
937fe8ee9adSChristian Lamparter 		err = carl9170_set_dyn_sifs_ack(ar);
938fe8ee9adSChristian Lamparter 		if (err)
939fe8ee9adSChristian Lamparter 			goto out;
940fe8ee9adSChristian Lamparter 
941fe8ee9adSChristian Lamparter 		err = carl9170_set_rts_cts_rate(ar);
942fe8ee9adSChristian Lamparter 		if (err)
943fe8ee9adSChristian Lamparter 			goto out;
944fe8ee9adSChristian Lamparter 	}
945fe8ee9adSChristian Lamparter 
94667e43de6SChristian Lamparter 	if (changed & IEEE80211_CONF_CHANGE_POWER) {
947675a0b04SKarl Beldan 		err = carl9170_set_mac_tpc(ar, ar->hw->conf.chandef.chan);
94867e43de6SChristian Lamparter 		if (err)
94967e43de6SChristian Lamparter 			goto out;
95067e43de6SChristian Lamparter 	}
95167e43de6SChristian Lamparter 
952fe8ee9adSChristian Lamparter out:
953fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
954fe8ee9adSChristian Lamparter 	return err;
955fe8ee9adSChristian Lamparter }
956fe8ee9adSChristian Lamparter 
carl9170_op_prepare_multicast(struct ieee80211_hw * hw,struct netdev_hw_addr_list * mc_list)957fe8ee9adSChristian Lamparter static u64 carl9170_op_prepare_multicast(struct ieee80211_hw *hw,
958fe8ee9adSChristian Lamparter 					 struct netdev_hw_addr_list *mc_list)
959fe8ee9adSChristian Lamparter {
960fe8ee9adSChristian Lamparter 	struct netdev_hw_addr *ha;
961fe8ee9adSChristian Lamparter 	u64 mchash;
962fe8ee9adSChristian Lamparter 
963fe8ee9adSChristian Lamparter 	/* always get broadcast frames */
964fe8ee9adSChristian Lamparter 	mchash = 1ULL << (0xff >> 2);
965fe8ee9adSChristian Lamparter 
966fe8ee9adSChristian Lamparter 	netdev_hw_addr_list_for_each(ha, mc_list)
967fe8ee9adSChristian Lamparter 		mchash |= 1ULL << (ha->addr[5] >> 2);
968fe8ee9adSChristian Lamparter 
969fe8ee9adSChristian Lamparter 	return mchash;
970fe8ee9adSChristian Lamparter }
971fe8ee9adSChristian Lamparter 
carl9170_op_configure_filter(struct ieee80211_hw * hw,unsigned int changed_flags,unsigned int * new_flags,u64 multicast)972fe8ee9adSChristian Lamparter static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
973fe8ee9adSChristian Lamparter 					 unsigned int changed_flags,
974fe8ee9adSChristian Lamparter 					 unsigned int *new_flags,
975fe8ee9adSChristian Lamparter 					 u64 multicast)
976fe8ee9adSChristian Lamparter {
977fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
978fe8ee9adSChristian Lamparter 
979fe8ee9adSChristian Lamparter 	/* mask supported flags */
9805c895691SChristian Lamparter 	*new_flags &= FIF_ALLMULTI | ar->rx_filter_caps;
981fe8ee9adSChristian Lamparter 
982fe8ee9adSChristian Lamparter 	if (!IS_ACCEPTING_CMD(ar))
983fe8ee9adSChristian Lamparter 		return;
984fe8ee9adSChristian Lamparter 
985fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
986fe8ee9adSChristian Lamparter 
987fe8ee9adSChristian Lamparter 	ar->filter_state = *new_flags;
988fe8ee9adSChristian Lamparter 	/*
989fe8ee9adSChristian Lamparter 	 * We can support more by setting the sniffer bit and
990fe8ee9adSChristian Lamparter 	 * then checking the error flags, later.
991fe8ee9adSChristian Lamparter 	 */
992fe8ee9adSChristian Lamparter 
9938f7f3b2fSNicolas Cavallari 	if (*new_flags & FIF_ALLMULTI)
994fe8ee9adSChristian Lamparter 		multicast = ~0ULL;
995fe8ee9adSChristian Lamparter 
996fe8ee9adSChristian Lamparter 	if (multicast != ar->cur_mc_hash)
997fe8ee9adSChristian Lamparter 		WARN_ON(carl9170_update_multicast(ar, multicast));
998fe8ee9adSChristian Lamparter 
999df140465SJohannes Berg 	if (changed_flags & FIF_OTHER_BSS) {
1000df140465SJohannes Berg 		ar->sniffer_enabled = !!(*new_flags & FIF_OTHER_BSS);
1001fe8ee9adSChristian Lamparter 
1002fe8ee9adSChristian Lamparter 		WARN_ON(carl9170_set_operating_mode(ar));
1003fe8ee9adSChristian Lamparter 	}
1004fe8ee9adSChristian Lamparter 
10055c895691SChristian Lamparter 	if (ar->fw.rx_filter && changed_flags & ar->rx_filter_caps) {
10065c895691SChristian Lamparter 		u32 rx_filter = 0;
10075c895691SChristian Lamparter 
1008c9122c0dSChristian Lamparter 		if (!ar->fw.ba_filter)
1009c9122c0dSChristian Lamparter 			rx_filter |= CARL9170_RX_FILTER_CTL_OTHER;
1010c9122c0dSChristian Lamparter 
10115c895691SChristian Lamparter 		if (!(*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL)))
10125c895691SChristian Lamparter 			rx_filter |= CARL9170_RX_FILTER_BAD;
10135c895691SChristian Lamparter 
10145c895691SChristian Lamparter 		if (!(*new_flags & FIF_CONTROL))
10155c895691SChristian Lamparter 			rx_filter |= CARL9170_RX_FILTER_CTL_OTHER;
10165c895691SChristian Lamparter 
10175c895691SChristian Lamparter 		if (!(*new_flags & FIF_PSPOLL))
10185c895691SChristian Lamparter 			rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL;
10195c895691SChristian Lamparter 
1020df140465SJohannes Berg 		if (!(*new_flags & FIF_OTHER_BSS)) {
10215c895691SChristian Lamparter 			rx_filter |= CARL9170_RX_FILTER_OTHER_RA;
10225c895691SChristian Lamparter 			rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL;
10235c895691SChristian Lamparter 		}
10245c895691SChristian Lamparter 
10255c895691SChristian Lamparter 		WARN_ON(carl9170_rx_filter(ar, rx_filter));
10265c895691SChristian Lamparter 	}
10275c895691SChristian Lamparter 
1028fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
1029fe8ee9adSChristian Lamparter }
1030fe8ee9adSChristian Lamparter 
1031fe8ee9adSChristian Lamparter 
carl9170_op_bss_info_changed(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * bss_conf,u64 changed)1032fe8ee9adSChristian Lamparter static void carl9170_op_bss_info_changed(struct ieee80211_hw *hw,
1033fe8ee9adSChristian Lamparter 					 struct ieee80211_vif *vif,
1034fe8ee9adSChristian Lamparter 					 struct ieee80211_bss_conf *bss_conf,
10357b7090b4SJohannes Berg 					 u64 changed)
1036fe8ee9adSChristian Lamparter {
1037fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
1038fe8ee9adSChristian Lamparter 	struct ath_common *common = &ar->common;
1039fe8ee9adSChristian Lamparter 	int err = 0;
1040fe8ee9adSChristian Lamparter 	struct carl9170_vif_info *vif_priv;
1041fe8ee9adSChristian Lamparter 	struct ieee80211_vif *main_vif;
1042fe8ee9adSChristian Lamparter 
1043fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
1044fe8ee9adSChristian Lamparter 	vif_priv = (void *) vif->drv_priv;
1045fe8ee9adSChristian Lamparter 	main_vif = carl9170_get_main_vif(ar);
1046fe8ee9adSChristian Lamparter 	if (WARN_ON(!main_vif))
1047fe8ee9adSChristian Lamparter 		goto out;
1048fe8ee9adSChristian Lamparter 
1049fe8ee9adSChristian Lamparter 	if (changed & BSS_CHANGED_BEACON_ENABLED) {
1050fe8ee9adSChristian Lamparter 		struct carl9170_vif_info *iter;
1051fe8ee9adSChristian Lamparter 		int i = 0;
1052fe8ee9adSChristian Lamparter 
1053fe8ee9adSChristian Lamparter 		vif_priv->enable_beacon = bss_conf->enable_beacon;
1054fe8ee9adSChristian Lamparter 		rcu_read_lock();
1055fe8ee9adSChristian Lamparter 		list_for_each_entry_rcu(iter, &ar->vif_list, list) {
1056fe8ee9adSChristian Lamparter 			if (iter->active && iter->enable_beacon)
1057fe8ee9adSChristian Lamparter 				i++;
1058fe8ee9adSChristian Lamparter 
1059fe8ee9adSChristian Lamparter 		}
1060fe8ee9adSChristian Lamparter 		rcu_read_unlock();
1061fe8ee9adSChristian Lamparter 
1062fe8ee9adSChristian Lamparter 		ar->beacon_enabled = i;
1063fe8ee9adSChristian Lamparter 	}
1064fe8ee9adSChristian Lamparter 
1065fe8ee9adSChristian Lamparter 	if (changed & BSS_CHANGED_BEACON) {
1066fe8ee9adSChristian Lamparter 		err = carl9170_update_beacon(ar, false);
1067fe8ee9adSChristian Lamparter 		if (err)
1068fe8ee9adSChristian Lamparter 			goto out;
1069fe8ee9adSChristian Lamparter 	}
1070fe8ee9adSChristian Lamparter 
1071fe8ee9adSChristian Lamparter 	if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON |
1072fe8ee9adSChristian Lamparter 		       BSS_CHANGED_BEACON_INT)) {
1073fe8ee9adSChristian Lamparter 
1074fe8ee9adSChristian Lamparter 		if (main_vif != vif) {
1075fe8ee9adSChristian Lamparter 			bss_conf->beacon_int = main_vif->bss_conf.beacon_int;
1076fe8ee9adSChristian Lamparter 			bss_conf->dtim_period = main_vif->bss_conf.dtim_period;
1077fe8ee9adSChristian Lamparter 		}
1078fe8ee9adSChristian Lamparter 
1079fe8ee9adSChristian Lamparter 		/*
1080fe8ee9adSChristian Lamparter 		 * Therefore a hard limit for the broadcast traffic should
1081fe8ee9adSChristian Lamparter 		 * prevent false alarms.
1082fe8ee9adSChristian Lamparter 		 */
1083fe8ee9adSChristian Lamparter 		if (vif->type != NL80211_IFTYPE_STATION &&
1084fe8ee9adSChristian Lamparter 		    (bss_conf->beacon_int * bss_conf->dtim_period >=
1085fe8ee9adSChristian Lamparter 		     (CARL9170_QUEUE_STUCK_TIMEOUT / 2))) {
1086fe8ee9adSChristian Lamparter 			err = -EINVAL;
1087fe8ee9adSChristian Lamparter 			goto out;
1088fe8ee9adSChristian Lamparter 		}
1089fe8ee9adSChristian Lamparter 
1090fe8ee9adSChristian Lamparter 		err = carl9170_set_beacon_timers(ar);
1091fe8ee9adSChristian Lamparter 		if (err)
1092fe8ee9adSChristian Lamparter 			goto out;
1093fe8ee9adSChristian Lamparter 	}
1094fe8ee9adSChristian Lamparter 
1095fe8ee9adSChristian Lamparter 	if (changed & BSS_CHANGED_HT) {
1096fe8ee9adSChristian Lamparter 		/* TODO */
1097fe8ee9adSChristian Lamparter 		err = 0;
1098fe8ee9adSChristian Lamparter 		if (err)
1099fe8ee9adSChristian Lamparter 			goto out;
1100fe8ee9adSChristian Lamparter 	}
1101fe8ee9adSChristian Lamparter 
1102fe8ee9adSChristian Lamparter 	if (main_vif != vif)
1103fe8ee9adSChristian Lamparter 		goto out;
1104fe8ee9adSChristian Lamparter 
1105fe8ee9adSChristian Lamparter 	/*
1106fe8ee9adSChristian Lamparter 	 * The following settings can only be changed by the
1107fe8ee9adSChristian Lamparter 	 * master interface.
1108fe8ee9adSChristian Lamparter 	 */
1109fe8ee9adSChristian Lamparter 
1110fe8ee9adSChristian Lamparter 	if (changed & BSS_CHANGED_BSSID) {
1111fe8ee9adSChristian Lamparter 		memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1112fe8ee9adSChristian Lamparter 		err = carl9170_set_operating_mode(ar);
1113fe8ee9adSChristian Lamparter 		if (err)
1114fe8ee9adSChristian Lamparter 			goto out;
1115fe8ee9adSChristian Lamparter 	}
1116fe8ee9adSChristian Lamparter 
1117fe8ee9adSChristian Lamparter 	if (changed & BSS_CHANGED_ASSOC) {
1118f276e20bSJohannes Berg 		ar->common.curaid = vif->cfg.aid;
1119fe8ee9adSChristian Lamparter 		err = carl9170_set_beacon_timers(ar);
1120fe8ee9adSChristian Lamparter 		if (err)
1121fe8ee9adSChristian Lamparter 			goto out;
1122fe8ee9adSChristian Lamparter 	}
1123fe8ee9adSChristian Lamparter 
1124fe8ee9adSChristian Lamparter 	if (changed & BSS_CHANGED_ERP_SLOT) {
1125fe8ee9adSChristian Lamparter 		err = carl9170_set_slot_time(ar);
1126fe8ee9adSChristian Lamparter 		if (err)
1127fe8ee9adSChristian Lamparter 			goto out;
1128fe8ee9adSChristian Lamparter 	}
1129fe8ee9adSChristian Lamparter 
1130fe8ee9adSChristian Lamparter 	if (changed & BSS_CHANGED_BASIC_RATES) {
1131fe8ee9adSChristian Lamparter 		err = carl9170_set_mac_rates(ar);
1132fe8ee9adSChristian Lamparter 		if (err)
1133fe8ee9adSChristian Lamparter 			goto out;
1134fe8ee9adSChristian Lamparter 	}
1135fe8ee9adSChristian Lamparter 
1136fe8ee9adSChristian Lamparter out:
1137fe8ee9adSChristian Lamparter 	WARN_ON_ONCE(err && IS_STARTED(ar));
1138fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
1139fe8ee9adSChristian Lamparter }
1140fe8ee9adSChristian Lamparter 
carl9170_op_get_tsf(struct ieee80211_hw * hw,struct ieee80211_vif * vif)114137a41b4aSEliad Peller static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw,
114237a41b4aSEliad Peller 			       struct ieee80211_vif *vif)
1143fe8ee9adSChristian Lamparter {
1144fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
1145fe8ee9adSChristian Lamparter 	struct carl9170_tsf_rsp tsf;
1146fe8ee9adSChristian Lamparter 	int err;
1147fe8ee9adSChristian Lamparter 
1148fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
1149fe8ee9adSChristian Lamparter 	err = carl9170_exec_cmd(ar, CARL9170_CMD_READ_TSF,
1150fe8ee9adSChristian Lamparter 				0, NULL, sizeof(tsf), &tsf);
1151fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
1152fe8ee9adSChristian Lamparter 	if (WARN_ON(err))
1153fe8ee9adSChristian Lamparter 		return 0;
1154fe8ee9adSChristian Lamparter 
1155fe8ee9adSChristian Lamparter 	return le64_to_cpu(tsf.tsf_64);
1156fe8ee9adSChristian Lamparter }
1157fe8ee9adSChristian Lamparter 
carl9170_op_set_key(struct ieee80211_hw * hw,enum set_key_cmd cmd,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key)1158fe8ee9adSChristian Lamparter static int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1159fe8ee9adSChristian Lamparter 			       struct ieee80211_vif *vif,
1160fe8ee9adSChristian Lamparter 			       struct ieee80211_sta *sta,
1161fe8ee9adSChristian Lamparter 			       struct ieee80211_key_conf *key)
1162fe8ee9adSChristian Lamparter {
1163fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
1164fe8ee9adSChristian Lamparter 	int err = 0, i;
1165fe8ee9adSChristian Lamparter 	u8 ktype;
1166fe8ee9adSChristian Lamparter 
1167fe8ee9adSChristian Lamparter 	if (ar->disable_offload || !vif)
1168fe8ee9adSChristian Lamparter 		return -EOPNOTSUPP;
1169fe8ee9adSChristian Lamparter 
11707a5c7307SChristian Lamparter 	/* Fall back to software encryption whenever the driver is connected
1171fe8ee9adSChristian Lamparter 	 * to more than one network.
1172fe8ee9adSChristian Lamparter 	 *
1173fe8ee9adSChristian Lamparter 	 * This is very unfortunate, because some machines cannot handle
1174fe8ee9adSChristian Lamparter 	 * the high througput speed in 802.11n networks.
1175fe8ee9adSChristian Lamparter 	 */
1176fe8ee9adSChristian Lamparter 
117766cb54bdSAlexey Khoroshilov 	if (!is_main_vif(ar, vif)) {
117866cb54bdSAlexey Khoroshilov 		mutex_lock(&ar->mutex);
1179fe8ee9adSChristian Lamparter 		goto err_softw;
118066cb54bdSAlexey Khoroshilov 	}
1181fe8ee9adSChristian Lamparter 
1182fe8ee9adSChristian Lamparter 	/*
1183fe8ee9adSChristian Lamparter 	 * While the hardware supports *catch-all* key, for offloading
1184fe8ee9adSChristian Lamparter 	 * group-key en-/de-cryption. The way of how the hardware
1185fe8ee9adSChristian Lamparter 	 * decides which keyId maps to which key, remains a mystery...
1186fe8ee9adSChristian Lamparter 	 */
1187fe8ee9adSChristian Lamparter 	if ((vif->type != NL80211_IFTYPE_STATION &&
1188fe8ee9adSChristian Lamparter 	     vif->type != NL80211_IFTYPE_ADHOC) &&
1189fe8ee9adSChristian Lamparter 	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
1190fe8ee9adSChristian Lamparter 		return -EOPNOTSUPP;
1191fe8ee9adSChristian Lamparter 
1192fe8ee9adSChristian Lamparter 	switch (key->cipher) {
1193fe8ee9adSChristian Lamparter 	case WLAN_CIPHER_SUITE_WEP40:
1194fe8ee9adSChristian Lamparter 		ktype = AR9170_ENC_ALG_WEP64;
1195fe8ee9adSChristian Lamparter 		break;
1196fe8ee9adSChristian Lamparter 	case WLAN_CIPHER_SUITE_WEP104:
1197fe8ee9adSChristian Lamparter 		ktype = AR9170_ENC_ALG_WEP128;
1198fe8ee9adSChristian Lamparter 		break;
1199fe8ee9adSChristian Lamparter 	case WLAN_CIPHER_SUITE_TKIP:
1200fe8ee9adSChristian Lamparter 		ktype = AR9170_ENC_ALG_TKIP;
1201fe8ee9adSChristian Lamparter 		break;
1202fe8ee9adSChristian Lamparter 	case WLAN_CIPHER_SUITE_CCMP:
1203fe8ee9adSChristian Lamparter 		ktype = AR9170_ENC_ALG_AESCCMP;
1204e37b6741SChristian Lamparter 		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
1205fe8ee9adSChristian Lamparter 		break;
1206fe8ee9adSChristian Lamparter 	default:
1207fe8ee9adSChristian Lamparter 		return -EOPNOTSUPP;
1208fe8ee9adSChristian Lamparter 	}
1209fe8ee9adSChristian Lamparter 
1210fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
1211fe8ee9adSChristian Lamparter 	if (cmd == SET_KEY) {
1212fe8ee9adSChristian Lamparter 		if (!IS_STARTED(ar)) {
1213fe8ee9adSChristian Lamparter 			err = -EOPNOTSUPP;
1214fe8ee9adSChristian Lamparter 			goto out;
1215fe8ee9adSChristian Lamparter 		}
1216fe8ee9adSChristian Lamparter 
1217fe8ee9adSChristian Lamparter 		if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
1218fe8ee9adSChristian Lamparter 			sta = NULL;
1219fe8ee9adSChristian Lamparter 
1220fe8ee9adSChristian Lamparter 			i = 64 + key->keyidx;
1221fe8ee9adSChristian Lamparter 		} else {
1222fe8ee9adSChristian Lamparter 			for (i = 0; i < 64; i++)
1223fe8ee9adSChristian Lamparter 				if (!(ar->usedkeys & BIT(i)))
1224fe8ee9adSChristian Lamparter 					break;
1225fe8ee9adSChristian Lamparter 			if (i == 64)
1226fe8ee9adSChristian Lamparter 				goto err_softw;
1227fe8ee9adSChristian Lamparter 		}
1228fe8ee9adSChristian Lamparter 
1229fe8ee9adSChristian Lamparter 		key->hw_key_idx = i;
1230fe8ee9adSChristian Lamparter 
1231fe8ee9adSChristian Lamparter 		err = carl9170_upload_key(ar, i, sta ? sta->addr : NULL,
1232fe8ee9adSChristian Lamparter 					  ktype, 0, key->key,
1233fe8ee9adSChristian Lamparter 					  min_t(u8, 16, key->keylen));
1234fe8ee9adSChristian Lamparter 		if (err)
1235fe8ee9adSChristian Lamparter 			goto out;
1236fe8ee9adSChristian Lamparter 
1237fe8ee9adSChristian Lamparter 		if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
1238fe8ee9adSChristian Lamparter 			err = carl9170_upload_key(ar, i, sta ? sta->addr :
1239fe8ee9adSChristian Lamparter 						  NULL, ktype, 1,
1240fe8ee9adSChristian Lamparter 						  key->key + 16, 16);
1241fe8ee9adSChristian Lamparter 			if (err)
1242fe8ee9adSChristian Lamparter 				goto out;
1243fe8ee9adSChristian Lamparter 
1244fe8ee9adSChristian Lamparter 			/*
1245fe8ee9adSChristian Lamparter 			 * hardware is not capable generating MMIC
1246fe8ee9adSChristian Lamparter 			 * of fragmented frames!
1247fe8ee9adSChristian Lamparter 			 */
1248fe8ee9adSChristian Lamparter 			key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
1249fe8ee9adSChristian Lamparter 		}
1250fe8ee9adSChristian Lamparter 
1251fe8ee9adSChristian Lamparter 		if (i < 64)
1252fe8ee9adSChristian Lamparter 			ar->usedkeys |= BIT(i);
1253fe8ee9adSChristian Lamparter 
1254fe8ee9adSChristian Lamparter 		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1255fe8ee9adSChristian Lamparter 	} else {
1256fe8ee9adSChristian Lamparter 		if (!IS_STARTED(ar)) {
1257fe8ee9adSChristian Lamparter 			/* The device is gone... together with the key ;-) */
1258fe8ee9adSChristian Lamparter 			err = 0;
1259fe8ee9adSChristian Lamparter 			goto out;
1260fe8ee9adSChristian Lamparter 		}
1261fe8ee9adSChristian Lamparter 
1262fe8ee9adSChristian Lamparter 		if (key->hw_key_idx < 64) {
1263fe8ee9adSChristian Lamparter 			ar->usedkeys &= ~BIT(key->hw_key_idx);
1264fe8ee9adSChristian Lamparter 		} else {
1265fe8ee9adSChristian Lamparter 			err = carl9170_upload_key(ar, key->hw_key_idx, NULL,
1266fe8ee9adSChristian Lamparter 						  AR9170_ENC_ALG_NONE, 0,
1267fe8ee9adSChristian Lamparter 						  NULL, 0);
1268fe8ee9adSChristian Lamparter 			if (err)
1269fe8ee9adSChristian Lamparter 				goto out;
1270fe8ee9adSChristian Lamparter 
1271fe8ee9adSChristian Lamparter 			if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
1272fe8ee9adSChristian Lamparter 				err = carl9170_upload_key(ar, key->hw_key_idx,
1273fe8ee9adSChristian Lamparter 							  NULL,
1274fe8ee9adSChristian Lamparter 							  AR9170_ENC_ALG_NONE,
1275fe8ee9adSChristian Lamparter 							  1, NULL, 0);
1276fe8ee9adSChristian Lamparter 				if (err)
1277fe8ee9adSChristian Lamparter 					goto out;
1278fe8ee9adSChristian Lamparter 			}
1279fe8ee9adSChristian Lamparter 
1280fe8ee9adSChristian Lamparter 		}
1281fe8ee9adSChristian Lamparter 
1282fe8ee9adSChristian Lamparter 		err = carl9170_disable_key(ar, key->hw_key_idx);
1283fe8ee9adSChristian Lamparter 		if (err)
1284fe8ee9adSChristian Lamparter 			goto out;
1285fe8ee9adSChristian Lamparter 	}
1286fe8ee9adSChristian Lamparter 
1287fe8ee9adSChristian Lamparter out:
1288fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
1289fe8ee9adSChristian Lamparter 	return err;
1290fe8ee9adSChristian Lamparter 
1291fe8ee9adSChristian Lamparter err_softw:
1292fe8ee9adSChristian Lamparter 	if (!ar->rx_software_decryption) {
1293fe8ee9adSChristian Lamparter 		ar->rx_software_decryption = true;
1294fe8ee9adSChristian Lamparter 		carl9170_set_operating_mode(ar);
1295fe8ee9adSChristian Lamparter 	}
1296fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
1297fe8ee9adSChristian Lamparter 	return -ENOSPC;
1298fe8ee9adSChristian Lamparter }
1299fe8ee9adSChristian Lamparter 
carl9170_op_sta_add(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1300fe8ee9adSChristian Lamparter static int carl9170_op_sta_add(struct ieee80211_hw *hw,
1301fe8ee9adSChristian Lamparter 			       struct ieee80211_vif *vif,
1302fe8ee9adSChristian Lamparter 			       struct ieee80211_sta *sta)
1303fe8ee9adSChristian Lamparter {
1304fe8ee9adSChristian Lamparter 	struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
1305fe8ee9adSChristian Lamparter 	unsigned int i;
1306fe8ee9adSChristian Lamparter 
1307caf1eae2SChristian Lamparter 	atomic_set(&sta_info->pending_frames, 0);
1308caf1eae2SChristian Lamparter 
1309046d2e7cSSriram R 	if (sta->deflink.ht_cap.ht_supported) {
1310046d2e7cSSriram R 		if (sta->deflink.ht_cap.ampdu_density > 6) {
1311fe8ee9adSChristian Lamparter 			/*
1312fe8ee9adSChristian Lamparter 			 * HW does support 16us AMPDU density.
1313fe8ee9adSChristian Lamparter 			 * No HT-Xmit for station.
1314fe8ee9adSChristian Lamparter 			 */
1315fe8ee9adSChristian Lamparter 
1316fe8ee9adSChristian Lamparter 			return 0;
1317fe8ee9adSChristian Lamparter 		}
1318fe8ee9adSChristian Lamparter 
1319558925f3SChristian Lamparter 		for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++)
13202cfa5a04SEric Dumazet 			RCU_INIT_POINTER(sta_info->agg[i], NULL);
1321fe8ee9adSChristian Lamparter 
1322046d2e7cSSriram R 		sta_info->ampdu_max_len = 1 << (3 + sta->deflink.ht_cap.ampdu_factor);
1323fe8ee9adSChristian Lamparter 		sta_info->ht_sta = true;
1324fe8ee9adSChristian Lamparter 	}
1325fe8ee9adSChristian Lamparter 
1326fe8ee9adSChristian Lamparter 	return 0;
1327fe8ee9adSChristian Lamparter }
1328fe8ee9adSChristian Lamparter 
carl9170_op_sta_remove(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1329fe8ee9adSChristian Lamparter static int carl9170_op_sta_remove(struct ieee80211_hw *hw,
1330fe8ee9adSChristian Lamparter 				struct ieee80211_vif *vif,
1331fe8ee9adSChristian Lamparter 				struct ieee80211_sta *sta)
1332fe8ee9adSChristian Lamparter {
1333fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
1334fe8ee9adSChristian Lamparter 	struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
1335fe8ee9adSChristian Lamparter 	unsigned int i;
1336fe8ee9adSChristian Lamparter 	bool cleanup = false;
1337fe8ee9adSChristian Lamparter 
1338046d2e7cSSriram R 	if (sta->deflink.ht_cap.ht_supported) {
1339fe8ee9adSChristian Lamparter 
1340fe8ee9adSChristian Lamparter 		sta_info->ht_sta = false;
1341fe8ee9adSChristian Lamparter 
1342fe8ee9adSChristian Lamparter 		rcu_read_lock();
1343558925f3SChristian Lamparter 		for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++) {
1344fe8ee9adSChristian Lamparter 			struct carl9170_sta_tid *tid_info;
1345fe8ee9adSChristian Lamparter 
1346fe8ee9adSChristian Lamparter 			tid_info = rcu_dereference(sta_info->agg[i]);
13472cfa5a04SEric Dumazet 			RCU_INIT_POINTER(sta_info->agg[i], NULL);
1348fe8ee9adSChristian Lamparter 
1349fe8ee9adSChristian Lamparter 			if (!tid_info)
1350fe8ee9adSChristian Lamparter 				continue;
1351fe8ee9adSChristian Lamparter 
1352fe8ee9adSChristian Lamparter 			spin_lock_bh(&ar->tx_ampdu_list_lock);
1353fe8ee9adSChristian Lamparter 			if (tid_info->state > CARL9170_TID_STATE_SHUTDOWN)
1354fe8ee9adSChristian Lamparter 				tid_info->state = CARL9170_TID_STATE_SHUTDOWN;
1355fe8ee9adSChristian Lamparter 			spin_unlock_bh(&ar->tx_ampdu_list_lock);
1356fe8ee9adSChristian Lamparter 			cleanup = true;
1357fe8ee9adSChristian Lamparter 		}
1358fe8ee9adSChristian Lamparter 		rcu_read_unlock();
1359fe8ee9adSChristian Lamparter 
1360fe8ee9adSChristian Lamparter 		if (cleanup)
1361fe8ee9adSChristian Lamparter 			carl9170_ampdu_gc(ar);
1362fe8ee9adSChristian Lamparter 	}
1363fe8ee9adSChristian Lamparter 
1364fe8ee9adSChristian Lamparter 	return 0;
1365fe8ee9adSChristian Lamparter }
1366fe8ee9adSChristian Lamparter 
carl9170_op_conf_tx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,unsigned int link_id,u16 queue,const struct ieee80211_tx_queue_params * param)13678a3a3c85SEliad Peller static int carl9170_op_conf_tx(struct ieee80211_hw *hw,
1368b3e2130bSJohannes Berg 			       struct ieee80211_vif *vif,
1369b3e2130bSJohannes Berg 			       unsigned int link_id, u16 queue,
1370fe8ee9adSChristian Lamparter 			       const struct ieee80211_tx_queue_params *param)
1371fe8ee9adSChristian Lamparter {
1372fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
1373fe8ee9adSChristian Lamparter 	int ret;
1374fe8ee9adSChristian Lamparter 
1375fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
1376859228a3SLee Jones 	memcpy(&ar->edcf[ar9170_qmap(queue)], param, sizeof(*param));
1377fe8ee9adSChristian Lamparter 	ret = carl9170_set_qos(ar);
1378fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
1379fe8ee9adSChristian Lamparter 	return ret;
1380fe8ee9adSChristian Lamparter }
1381fe8ee9adSChristian Lamparter 
carl9170_ampdu_work(struct work_struct * work)1382fe8ee9adSChristian Lamparter static void carl9170_ampdu_work(struct work_struct *work)
1383fe8ee9adSChristian Lamparter {
1384fe8ee9adSChristian Lamparter 	struct ar9170 *ar = container_of(work, struct ar9170,
1385fe8ee9adSChristian Lamparter 					 ampdu_work);
1386fe8ee9adSChristian Lamparter 
1387fe8ee9adSChristian Lamparter 	if (!IS_STARTED(ar))
1388fe8ee9adSChristian Lamparter 		return;
1389fe8ee9adSChristian Lamparter 
1390fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
1391fe8ee9adSChristian Lamparter 	carl9170_ampdu_gc(ar);
1392fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
1393fe8ee9adSChristian Lamparter }
1394fe8ee9adSChristian Lamparter 
carl9170_op_ampdu_action(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_ampdu_params * params)1395fe8ee9adSChristian Lamparter static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
1396fe8ee9adSChristian Lamparter 				    struct ieee80211_vif *vif,
139750ea05efSSara Sharon 				    struct ieee80211_ampdu_params *params)
1398fe8ee9adSChristian Lamparter {
139950ea05efSSara Sharon 	struct ieee80211_sta *sta = params->sta;
140050ea05efSSara Sharon 	enum ieee80211_ampdu_mlme_action action = params->action;
140150ea05efSSara Sharon 	u16 tid = params->tid;
140250ea05efSSara Sharon 	u16 *ssn = &params->ssn;
1403fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
1404fe8ee9adSChristian Lamparter 	struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
1405fe8ee9adSChristian Lamparter 	struct carl9170_sta_tid *tid_info;
1406fe8ee9adSChristian Lamparter 
1407fe8ee9adSChristian Lamparter 	if (modparam_noht)
1408fe8ee9adSChristian Lamparter 		return -EOPNOTSUPP;
1409fe8ee9adSChristian Lamparter 
1410fe8ee9adSChristian Lamparter 	switch (action) {
1411fe8ee9adSChristian Lamparter 	case IEEE80211_AMPDU_TX_START:
14129c655c8bSChristian Lamparter 		if (!sta_info->ht_sta)
1413fe8ee9adSChristian Lamparter 			return -EOPNOTSUPP;
1414fe8ee9adSChristian Lamparter 
1415fe8ee9adSChristian Lamparter 		tid_info = kzalloc(sizeof(struct carl9170_sta_tid),
1416e42fe43aSChristian Lamparter 				   GFP_KERNEL);
141769e2a771SAndreea-Cristina Bernat 		if (!tid_info)
1418fe8ee9adSChristian Lamparter 			return -ENOMEM;
1419fe8ee9adSChristian Lamparter 
1420fe8ee9adSChristian Lamparter 		tid_info->hsn = tid_info->bsn = tid_info->snx = (*ssn);
1421fe8ee9adSChristian Lamparter 		tid_info->state = CARL9170_TID_STATE_PROGRESS;
1422fe8ee9adSChristian Lamparter 		tid_info->tid = tid;
1423fe8ee9adSChristian Lamparter 		tid_info->max = sta_info->ampdu_max_len;
14249ad86ed3SChristian Lamparter 		tid_info->sta = sta;
14259ad86ed3SChristian Lamparter 		tid_info->vif = vif;
1426fe8ee9adSChristian Lamparter 
1427fe8ee9adSChristian Lamparter 		INIT_LIST_HEAD(&tid_info->list);
1428fe8ee9adSChristian Lamparter 		INIT_LIST_HEAD(&tid_info->tmp_list);
1429fe8ee9adSChristian Lamparter 		skb_queue_head_init(&tid_info->queue);
1430fe8ee9adSChristian Lamparter 		spin_lock_init(&tid_info->lock);
1431fe8ee9adSChristian Lamparter 
1432fe8ee9adSChristian Lamparter 		spin_lock_bh(&ar->tx_ampdu_list_lock);
1433fe8ee9adSChristian Lamparter 		ar->tx_ampdu_list_len++;
1434fe8ee9adSChristian Lamparter 		list_add_tail_rcu(&tid_info->list, &ar->tx_ampdu_list);
1435fe8ee9adSChristian Lamparter 		rcu_assign_pointer(sta_info->agg[tid], tid_info);
1436fe8ee9adSChristian Lamparter 		spin_unlock_bh(&ar->tx_ampdu_list_lock);
1437fe8ee9adSChristian Lamparter 
14382ce113deSJohannes Berg 		return IEEE80211_AMPDU_TX_START_IMMEDIATE;
1439fe8ee9adSChristian Lamparter 
144018b559d5SJohannes Berg 	case IEEE80211_AMPDU_TX_STOP_CONT:
144118b559d5SJohannes Berg 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
144218b559d5SJohannes Berg 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
1443fe8ee9adSChristian Lamparter 		rcu_read_lock();
1444fe8ee9adSChristian Lamparter 		tid_info = rcu_dereference(sta_info->agg[tid]);
1445fe8ee9adSChristian Lamparter 		if (tid_info) {
1446fe8ee9adSChristian Lamparter 			spin_lock_bh(&ar->tx_ampdu_list_lock);
1447fe8ee9adSChristian Lamparter 			if (tid_info->state > CARL9170_TID_STATE_SHUTDOWN)
1448fe8ee9adSChristian Lamparter 				tid_info->state = CARL9170_TID_STATE_SHUTDOWN;
1449fe8ee9adSChristian Lamparter 			spin_unlock_bh(&ar->tx_ampdu_list_lock);
1450fe8ee9adSChristian Lamparter 		}
1451fe8ee9adSChristian Lamparter 
14522cfa5a04SEric Dumazet 		RCU_INIT_POINTER(sta_info->agg[tid], NULL);
1453fe8ee9adSChristian Lamparter 		rcu_read_unlock();
1454fe8ee9adSChristian Lamparter 
1455fe8ee9adSChristian Lamparter 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1456fe8ee9adSChristian Lamparter 		ieee80211_queue_work(ar->hw, &ar->ampdu_work);
1457fe8ee9adSChristian Lamparter 		break;
1458fe8ee9adSChristian Lamparter 
1459fe8ee9adSChristian Lamparter 	case IEEE80211_AMPDU_TX_OPERATIONAL:
1460fe8ee9adSChristian Lamparter 		rcu_read_lock();
1461fe8ee9adSChristian Lamparter 		tid_info = rcu_dereference(sta_info->agg[tid]);
1462fe8ee9adSChristian Lamparter 
1463fe8ee9adSChristian Lamparter 		sta_info->stats[tid].clear = true;
146424047e2cSChristian Lamparter 		sta_info->stats[tid].req = false;
1465fe8ee9adSChristian Lamparter 
1466fe8ee9adSChristian Lamparter 		if (tid_info) {
1467fe8ee9adSChristian Lamparter 			bitmap_zero(tid_info->bitmap, CARL9170_BAW_SIZE);
1468fe8ee9adSChristian Lamparter 			tid_info->state = CARL9170_TID_STATE_IDLE;
1469fe8ee9adSChristian Lamparter 		}
1470fe8ee9adSChristian Lamparter 		rcu_read_unlock();
1471fe8ee9adSChristian Lamparter 
1472fe8ee9adSChristian Lamparter 		if (WARN_ON_ONCE(!tid_info))
1473fe8ee9adSChristian Lamparter 			return -EFAULT;
1474fe8ee9adSChristian Lamparter 
1475fe8ee9adSChristian Lamparter 		break;
1476fe8ee9adSChristian Lamparter 
1477fe8ee9adSChristian Lamparter 	case IEEE80211_AMPDU_RX_START:
1478fe8ee9adSChristian Lamparter 	case IEEE80211_AMPDU_RX_STOP:
1479fe8ee9adSChristian Lamparter 		/* Handled by hardware */
1480fe8ee9adSChristian Lamparter 		break;
1481fe8ee9adSChristian Lamparter 
1482fe8ee9adSChristian Lamparter 	default:
1483fe8ee9adSChristian Lamparter 		return -EOPNOTSUPP;
1484fe8ee9adSChristian Lamparter 	}
1485fe8ee9adSChristian Lamparter 
1486fe8ee9adSChristian Lamparter 	return 0;
1487fe8ee9adSChristian Lamparter }
1488fe8ee9adSChristian Lamparter 
1489fe8ee9adSChristian Lamparter #ifdef CONFIG_CARL9170_WPC
carl9170_register_wps_button(struct ar9170 * ar)1490fe8ee9adSChristian Lamparter static int carl9170_register_wps_button(struct ar9170 *ar)
1491fe8ee9adSChristian Lamparter {
1492fe8ee9adSChristian Lamparter 	struct input_dev *input;
1493fe8ee9adSChristian Lamparter 	int err;
1494fe8ee9adSChristian Lamparter 
1495fe8ee9adSChristian Lamparter 	if (!(ar->features & CARL9170_WPS_BUTTON))
1496fe8ee9adSChristian Lamparter 		return 0;
1497fe8ee9adSChristian Lamparter 
149887ddb2fcSChristian Lamparter 	input = devm_input_allocate_device(&ar->udev->dev);
1499fe8ee9adSChristian Lamparter 	if (!input)
1500fe8ee9adSChristian Lamparter 		return -ENOMEM;
1501fe8ee9adSChristian Lamparter 
1502fe8ee9adSChristian Lamparter 	snprintf(ar->wps.name, sizeof(ar->wps.name), "%s WPS Button",
1503fe8ee9adSChristian Lamparter 		 wiphy_name(ar->hw->wiphy));
1504fe8ee9adSChristian Lamparter 
1505fe8ee9adSChristian Lamparter 	snprintf(ar->wps.phys, sizeof(ar->wps.phys),
1506fe8ee9adSChristian Lamparter 		 "ieee80211/%s/input0", wiphy_name(ar->hw->wiphy));
1507fe8ee9adSChristian Lamparter 
1508fe8ee9adSChristian Lamparter 	input->name = ar->wps.name;
1509fe8ee9adSChristian Lamparter 	input->phys = ar->wps.phys;
1510fe8ee9adSChristian Lamparter 	input->id.bustype = BUS_USB;
1511fe8ee9adSChristian Lamparter 	input->dev.parent = &ar->hw->wiphy->dev;
1512fe8ee9adSChristian Lamparter 
1513fe8ee9adSChristian Lamparter 	input_set_capability(input, EV_KEY, KEY_WPS_BUTTON);
1514fe8ee9adSChristian Lamparter 
1515fe8ee9adSChristian Lamparter 	err = input_register_device(input);
151687ddb2fcSChristian Lamparter 	if (err)
1517fe8ee9adSChristian Lamparter 		return err;
1518fe8ee9adSChristian Lamparter 
1519fe8ee9adSChristian Lamparter 	ar->wps.pbc = input;
1520fe8ee9adSChristian Lamparter 	return 0;
1521fe8ee9adSChristian Lamparter }
1522fe8ee9adSChristian Lamparter #endif /* CONFIG_CARL9170_WPC */
1523fe8ee9adSChristian Lamparter 
152400044f17SChristian Lamparter #ifdef CONFIG_CARL9170_HWRNG
carl9170_rng_get(struct ar9170 * ar)152500044f17SChristian Lamparter static int carl9170_rng_get(struct ar9170 *ar)
152600044f17SChristian Lamparter {
152700044f17SChristian Lamparter 
152800044f17SChristian Lamparter #define RW	(CARL9170_MAX_CMD_PAYLOAD_LEN / sizeof(u32))
152900044f17SChristian Lamparter #define RB	(CARL9170_MAX_CMD_PAYLOAD_LEN)
153000044f17SChristian Lamparter 
153100044f17SChristian Lamparter 	static const __le32 rng_load[RW] = {
153200044f17SChristian Lamparter 		[0 ... (RW - 1)] = cpu_to_le32(AR9170_RAND_REG_NUM)};
153300044f17SChristian Lamparter 
153400044f17SChristian Lamparter 	u32 buf[RW];
153500044f17SChristian Lamparter 
153600044f17SChristian Lamparter 	unsigned int i, off = 0, transfer, count;
153700044f17SChristian Lamparter 	int err;
153800044f17SChristian Lamparter 
153900044f17SChristian Lamparter 	BUILD_BUG_ON(RB > CARL9170_MAX_CMD_PAYLOAD_LEN);
154000044f17SChristian Lamparter 
154123de0fa0SChristian Lamparter 	if (!IS_ACCEPTING_CMD(ar))
154200044f17SChristian Lamparter 		return -EAGAIN;
154300044f17SChristian Lamparter 
154400044f17SChristian Lamparter 	count = ARRAY_SIZE(ar->rng.cache);
154500044f17SChristian Lamparter 	while (count) {
154600044f17SChristian Lamparter 		err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG,
154700044f17SChristian Lamparter 					RB, (u8 *) rng_load,
154800044f17SChristian Lamparter 					RB, (u8 *) buf);
154900044f17SChristian Lamparter 		if (err)
155000044f17SChristian Lamparter 			return err;
155100044f17SChristian Lamparter 
155200044f17SChristian Lamparter 		transfer = min_t(unsigned int, count, RW);
155300044f17SChristian Lamparter 		for (i = 0; i < transfer; i++)
155400044f17SChristian Lamparter 			ar->rng.cache[off + i] = buf[i];
155500044f17SChristian Lamparter 
155600044f17SChristian Lamparter 		off += transfer;
155700044f17SChristian Lamparter 		count -= transfer;
155800044f17SChristian Lamparter 	}
155900044f17SChristian Lamparter 
156000044f17SChristian Lamparter 	ar->rng.cache_idx = 0;
156100044f17SChristian Lamparter 
156200044f17SChristian Lamparter #undef RW
156300044f17SChristian Lamparter #undef RB
156400044f17SChristian Lamparter 	return 0;
156500044f17SChristian Lamparter }
156600044f17SChristian Lamparter 
carl9170_rng_read(struct hwrng * rng,u32 * data)156700044f17SChristian Lamparter static int carl9170_rng_read(struct hwrng *rng, u32 *data)
156800044f17SChristian Lamparter {
156900044f17SChristian Lamparter 	struct ar9170 *ar = (struct ar9170 *)rng->priv;
157000044f17SChristian Lamparter 	int ret = -EIO;
157100044f17SChristian Lamparter 
157200044f17SChristian Lamparter 	mutex_lock(&ar->mutex);
157300044f17SChristian Lamparter 	if (ar->rng.cache_idx >= ARRAY_SIZE(ar->rng.cache)) {
157400044f17SChristian Lamparter 		ret = carl9170_rng_get(ar);
157500044f17SChristian Lamparter 		if (ret) {
157600044f17SChristian Lamparter 			mutex_unlock(&ar->mutex);
157700044f17SChristian Lamparter 			return ret;
157800044f17SChristian Lamparter 		}
157900044f17SChristian Lamparter 	}
158000044f17SChristian Lamparter 
158100044f17SChristian Lamparter 	*data = ar->rng.cache[ar->rng.cache_idx++];
158200044f17SChristian Lamparter 	mutex_unlock(&ar->mutex);
158300044f17SChristian Lamparter 
158400044f17SChristian Lamparter 	return sizeof(u16);
158500044f17SChristian Lamparter }
158600044f17SChristian Lamparter 
carl9170_register_hwrng(struct ar9170 * ar)158700044f17SChristian Lamparter static int carl9170_register_hwrng(struct ar9170 *ar)
158800044f17SChristian Lamparter {
158900044f17SChristian Lamparter 	int err;
159000044f17SChristian Lamparter 
159100044f17SChristian Lamparter 	snprintf(ar->rng.name, ARRAY_SIZE(ar->rng.name),
159200044f17SChristian Lamparter 		 "%s_%s", KBUILD_MODNAME, wiphy_name(ar->hw->wiphy));
159300044f17SChristian Lamparter 	ar->rng.rng.name = ar->rng.name;
159400044f17SChristian Lamparter 	ar->rng.rng.data_read = carl9170_rng_read;
159500044f17SChristian Lamparter 	ar->rng.rng.priv = (unsigned long)ar;
159600044f17SChristian Lamparter 
159723de0fa0SChristian Lamparter 	err = devm_hwrng_register(&ar->udev->dev, &ar->rng.rng);
159800044f17SChristian Lamparter 	if (err) {
159900044f17SChristian Lamparter 		dev_err(&ar->udev->dev, "Failed to register the random "
160000044f17SChristian Lamparter 			"number generator (%d)\n", err);
160100044f17SChristian Lamparter 		return err;
160200044f17SChristian Lamparter 	}
160300044f17SChristian Lamparter 
160423de0fa0SChristian Lamparter 	return carl9170_rng_get(ar);
160500044f17SChristian Lamparter }
160600044f17SChristian Lamparter #endif /* CONFIG_CARL9170_HWRNG */
160700044f17SChristian Lamparter 
carl9170_op_get_survey(struct ieee80211_hw * hw,int idx,struct survey_info * survey)1608fe8ee9adSChristian Lamparter static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx,
1609fe8ee9adSChristian Lamparter 				struct survey_info *survey)
1610fe8ee9adSChristian Lamparter {
1611fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
1612acf17712SChristian Lamparter 	struct ieee80211_channel *chan;
1613acf17712SChristian Lamparter 	struct ieee80211_supported_band *band;
1614acf17712SChristian Lamparter 	int err, b, i;
1615fe8ee9adSChristian Lamparter 
1616acf17712SChristian Lamparter 	chan = ar->channel;
1617acf17712SChristian Lamparter 	if (!chan)
1618acf17712SChristian Lamparter 		return -ENODEV;
1619fe8ee9adSChristian Lamparter 
1620acf17712SChristian Lamparter 	if (idx == chan->hw_value) {
1621fe8ee9adSChristian Lamparter 		mutex_lock(&ar->mutex);
1622acf17712SChristian Lamparter 		err = carl9170_update_survey(ar, false, true);
1623fe8ee9adSChristian Lamparter 		mutex_unlock(&ar->mutex);
1624fe8ee9adSChristian Lamparter 		if (err)
1625fe8ee9adSChristian Lamparter 			return err;
1626acf17712SChristian Lamparter 	}
1627fe8ee9adSChristian Lamparter 
162857fbcce3SJohannes Berg 	for (b = 0; b < NUM_NL80211_BANDS; b++) {
1629acf17712SChristian Lamparter 		band = ar->hw->wiphy->bands[b];
1630acf17712SChristian Lamparter 
1631acf17712SChristian Lamparter 		if (!band)
1632acf17712SChristian Lamparter 			continue;
1633acf17712SChristian Lamparter 
1634acf17712SChristian Lamparter 		for (i = 0; i < band->n_channels; i++) {
1635acf17712SChristian Lamparter 			if (band->channels[i].hw_value == idx) {
1636acf17712SChristian Lamparter 				chan = &band->channels[i];
1637acf17712SChristian Lamparter 				goto found;
1638acf17712SChristian Lamparter 			}
1639acf17712SChristian Lamparter 		}
1640acf17712SChristian Lamparter 	}
1641acf17712SChristian Lamparter 	return -ENOENT;
1642acf17712SChristian Lamparter 
1643acf17712SChristian Lamparter found:
1644acf17712SChristian Lamparter 	memcpy(survey, &ar->survey[idx], sizeof(*survey));
1645acf17712SChristian Lamparter 
1646acf17712SChristian Lamparter 	survey->channel = chan;
1647fe8ee9adSChristian Lamparter 	survey->filled = SURVEY_INFO_NOISE_DBM;
1648acf17712SChristian Lamparter 
1649acf17712SChristian Lamparter 	if (ar->channel == chan)
1650acf17712SChristian Lamparter 		survey->filled |= SURVEY_INFO_IN_USE;
1651acf17712SChristian Lamparter 
1652acf17712SChristian Lamparter 	if (ar->fw.hw_counters) {
16534ed20bebSJohannes Berg 		survey->filled |= SURVEY_INFO_TIME |
16544ed20bebSJohannes Berg 				  SURVEY_INFO_TIME_BUSY |
16554ed20bebSJohannes Berg 				  SURVEY_INFO_TIME_TX;
1656acf17712SChristian Lamparter 	}
1657acf17712SChristian Lamparter 
1658fe8ee9adSChristian Lamparter 	return 0;
1659fe8ee9adSChristian Lamparter }
1660fe8ee9adSChristian Lamparter 
carl9170_op_flush(struct ieee80211_hw * hw,struct ieee80211_vif * vif,u32 queues,bool drop)166177be2c54SEmmanuel Grumbach static void carl9170_op_flush(struct ieee80211_hw *hw,
166277be2c54SEmmanuel Grumbach 			      struct ieee80211_vif *vif,
166377be2c54SEmmanuel Grumbach 			      u32 queues, bool drop)
1664fe8ee9adSChristian Lamparter {
1665fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
1666fe8ee9adSChristian Lamparter 	unsigned int vid;
1667fe8ee9adSChristian Lamparter 
1668fe8ee9adSChristian Lamparter 	mutex_lock(&ar->mutex);
1669fe8ee9adSChristian Lamparter 	for_each_set_bit(vid, &ar->vif_bitmap, ar->fw.vif_num)
1670fe8ee9adSChristian Lamparter 		carl9170_flush_cab(ar, vid);
1671fe8ee9adSChristian Lamparter 
1672fe8ee9adSChristian Lamparter 	carl9170_flush(ar, drop);
1673fe8ee9adSChristian Lamparter 	mutex_unlock(&ar->mutex);
1674fe8ee9adSChristian Lamparter }
1675fe8ee9adSChristian Lamparter 
carl9170_op_get_stats(struct ieee80211_hw * hw,struct ieee80211_low_level_stats * stats)1676fe8ee9adSChristian Lamparter static int carl9170_op_get_stats(struct ieee80211_hw *hw,
1677fe8ee9adSChristian Lamparter 				 struct ieee80211_low_level_stats *stats)
1678fe8ee9adSChristian Lamparter {
1679fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
1680fe8ee9adSChristian Lamparter 
1681fe8ee9adSChristian Lamparter 	memset(stats, 0, sizeof(*stats));
1682fe8ee9adSChristian Lamparter 	stats->dot11ACKFailureCount = ar->tx_ack_failures;
1683fe8ee9adSChristian Lamparter 	stats->dot11FCSErrorCount = ar->tx_fcs_errors;
1684fe8ee9adSChristian Lamparter 	return 0;
1685fe8ee9adSChristian Lamparter }
1686fe8ee9adSChristian Lamparter 
carl9170_op_sta_notify(struct ieee80211_hw * hw,struct ieee80211_vif * vif,enum sta_notify_cmd cmd,struct ieee80211_sta * sta)1687fe8ee9adSChristian Lamparter static void carl9170_op_sta_notify(struct ieee80211_hw *hw,
1688fe8ee9adSChristian Lamparter 				   struct ieee80211_vif *vif,
1689fe8ee9adSChristian Lamparter 				   enum sta_notify_cmd cmd,
1690fe8ee9adSChristian Lamparter 				   struct ieee80211_sta *sta)
1691fe8ee9adSChristian Lamparter {
1692fe8ee9adSChristian Lamparter 	struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
1693fe8ee9adSChristian Lamparter 
1694fe8ee9adSChristian Lamparter 	switch (cmd) {
1695fe8ee9adSChristian Lamparter 	case STA_NOTIFY_SLEEP:
1696caf1eae2SChristian Lamparter 		sta_info->sleeping = true;
1697caf1eae2SChristian Lamparter 		if (atomic_read(&sta_info->pending_frames))
1698caf1eae2SChristian Lamparter 			ieee80211_sta_block_awake(hw, sta, true);
1699fe8ee9adSChristian Lamparter 		break;
1700fe8ee9adSChristian Lamparter 
1701fe8ee9adSChristian Lamparter 	case STA_NOTIFY_AWAKE:
1702caf1eae2SChristian Lamparter 		sta_info->sleeping = false;
1703fe8ee9adSChristian Lamparter 		break;
1704fe8ee9adSChristian Lamparter 	}
1705fe8ee9adSChristian Lamparter }
1706fe8ee9adSChristian Lamparter 
carl9170_tx_frames_pending(struct ieee80211_hw * hw)170769f7235fSChristian Lamparter static bool carl9170_tx_frames_pending(struct ieee80211_hw *hw)
170869f7235fSChristian Lamparter {
170969f7235fSChristian Lamparter 	struct ar9170 *ar = hw->priv;
171069f7235fSChristian Lamparter 
171169f7235fSChristian Lamparter 	return !!atomic_read(&ar->tx_total_queued);
171269f7235fSChristian Lamparter }
171369f7235fSChristian Lamparter 
1714fe8ee9adSChristian Lamparter static const struct ieee80211_ops carl9170_ops = {
1715fe8ee9adSChristian Lamparter 	.start			= carl9170_op_start,
1716fe8ee9adSChristian Lamparter 	.stop			= carl9170_op_stop,
1717fe8ee9adSChristian Lamparter 	.tx			= carl9170_op_tx,
1718*a790cc3aSAlexander Wetzel 	.wake_tx_queue		= ieee80211_handle_wake_tx_queue,
1719fe8ee9adSChristian Lamparter 	.flush			= carl9170_op_flush,
1720fe8ee9adSChristian Lamparter 	.add_interface		= carl9170_op_add_interface,
1721fe8ee9adSChristian Lamparter 	.remove_interface	= carl9170_op_remove_interface,
1722fe8ee9adSChristian Lamparter 	.config			= carl9170_op_config,
1723fe8ee9adSChristian Lamparter 	.prepare_multicast	= carl9170_op_prepare_multicast,
1724fe8ee9adSChristian Lamparter 	.configure_filter	= carl9170_op_configure_filter,
1725fe8ee9adSChristian Lamparter 	.conf_tx		= carl9170_op_conf_tx,
1726fe8ee9adSChristian Lamparter 	.bss_info_changed	= carl9170_op_bss_info_changed,
1727fe8ee9adSChristian Lamparter 	.get_tsf		= carl9170_op_get_tsf,
1728fe8ee9adSChristian Lamparter 	.set_key		= carl9170_op_set_key,
1729fe8ee9adSChristian Lamparter 	.sta_add		= carl9170_op_sta_add,
1730fe8ee9adSChristian Lamparter 	.sta_remove		= carl9170_op_sta_remove,
1731fe8ee9adSChristian Lamparter 	.sta_notify		= carl9170_op_sta_notify,
1732fe8ee9adSChristian Lamparter 	.get_survey		= carl9170_op_get_survey,
1733fe8ee9adSChristian Lamparter 	.get_stats		= carl9170_op_get_stats,
1734fe8ee9adSChristian Lamparter 	.ampdu_action		= carl9170_op_ampdu_action,
173569f7235fSChristian Lamparter 	.tx_frames_pending	= carl9170_tx_frames_pending,
1736fe8ee9adSChristian Lamparter };
1737fe8ee9adSChristian Lamparter 
carl9170_alloc(size_t priv_size)1738fe8ee9adSChristian Lamparter void *carl9170_alloc(size_t priv_size)
1739fe8ee9adSChristian Lamparter {
1740fe8ee9adSChristian Lamparter 	struct ieee80211_hw *hw;
1741fe8ee9adSChristian Lamparter 	struct ar9170 *ar;
1742fe8ee9adSChristian Lamparter 	struct sk_buff *skb;
1743fe8ee9adSChristian Lamparter 	int i;
1744fe8ee9adSChristian Lamparter 
1745fe8ee9adSChristian Lamparter 	/*
1746fe8ee9adSChristian Lamparter 	 * this buffer is used for rx stream reconstruction.
1747fe8ee9adSChristian Lamparter 	 * Under heavy load this device (or the transport layer?)
1748fe8ee9adSChristian Lamparter 	 * tends to split the streams into separate rx descriptors.
1749fe8ee9adSChristian Lamparter 	 */
1750fe8ee9adSChristian Lamparter 
1751fe8ee9adSChristian Lamparter 	skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL);
1752fe8ee9adSChristian Lamparter 	if (!skb)
1753fe8ee9adSChristian Lamparter 		goto err_nomem;
1754fe8ee9adSChristian Lamparter 
1755fe8ee9adSChristian Lamparter 	hw = ieee80211_alloc_hw(priv_size, &carl9170_ops);
1756fe8ee9adSChristian Lamparter 	if (!hw)
1757fe8ee9adSChristian Lamparter 		goto err_nomem;
1758fe8ee9adSChristian Lamparter 
1759fe8ee9adSChristian Lamparter 	ar = hw->priv;
1760fe8ee9adSChristian Lamparter 	ar->hw = hw;
1761fe8ee9adSChristian Lamparter 	ar->rx_failover = skb;
1762fe8ee9adSChristian Lamparter 
1763fe8ee9adSChristian Lamparter 	memset(&ar->rx_plcp, 0, sizeof(struct ar9170_rx_head));
1764fe8ee9adSChristian Lamparter 	ar->rx_has_plcp = false;
1765fe8ee9adSChristian Lamparter 
1766fe8ee9adSChristian Lamparter 	/*
1767fe8ee9adSChristian Lamparter 	 * Here's a hidden pitfall!
1768fe8ee9adSChristian Lamparter 	 *
1769fe8ee9adSChristian Lamparter 	 * All 4 AC queues work perfectly well under _legacy_ operation.
1770fe8ee9adSChristian Lamparter 	 * However as soon as aggregation is enabled, the traffic flow
1771fe8ee9adSChristian Lamparter 	 * gets very bumpy. Therefore we have to _switch_ to a
1772fe8ee9adSChristian Lamparter 	 * software AC with a single HW queue.
1773fe8ee9adSChristian Lamparter 	 */
1774fe8ee9adSChristian Lamparter 	hw->queues = __AR9170_NUM_TXQ;
1775fe8ee9adSChristian Lamparter 
1776fe8ee9adSChristian Lamparter 	mutex_init(&ar->mutex);
1777fe8ee9adSChristian Lamparter 	spin_lock_init(&ar->beacon_lock);
1778fe8ee9adSChristian Lamparter 	spin_lock_init(&ar->cmd_lock);
1779fe8ee9adSChristian Lamparter 	spin_lock_init(&ar->tx_stats_lock);
1780fe8ee9adSChristian Lamparter 	spin_lock_init(&ar->tx_ampdu_list_lock);
1781fe8ee9adSChristian Lamparter 	spin_lock_init(&ar->mem_lock);
1782fe8ee9adSChristian Lamparter 	spin_lock_init(&ar->state_lock);
1783fe8ee9adSChristian Lamparter 	atomic_set(&ar->pending_restarts, 0);
1784fe8ee9adSChristian Lamparter 	ar->vifs = 0;
1785fe8ee9adSChristian Lamparter 	for (i = 0; i < ar->hw->queues; i++) {
1786fe8ee9adSChristian Lamparter 		skb_queue_head_init(&ar->tx_status[i]);
1787fe8ee9adSChristian Lamparter 		skb_queue_head_init(&ar->tx_pending[i]);
1788c9122c0dSChristian Lamparter 
1789c9122c0dSChristian Lamparter 		INIT_LIST_HEAD(&ar->bar_list[i]);
1790c9122c0dSChristian Lamparter 		spin_lock_init(&ar->bar_list_lock[i]);
1791fe8ee9adSChristian Lamparter 	}
1792fe8ee9adSChristian Lamparter 	INIT_WORK(&ar->ps_work, carl9170_ps_work);
1793e4a668c5SChristian Lamparter 	INIT_WORK(&ar->ping_work, carl9170_ping_work);
1794fe8ee9adSChristian Lamparter 	INIT_WORK(&ar->restart_work, carl9170_restart_work);
1795fe8ee9adSChristian Lamparter 	INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work);
1796acf17712SChristian Lamparter 	INIT_DELAYED_WORK(&ar->stat_work, carl9170_stat_work);
1797fe8ee9adSChristian Lamparter 	INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor);
1798fe8ee9adSChristian Lamparter 	INIT_LIST_HEAD(&ar->tx_ampdu_list);
1799fe8ee9adSChristian Lamparter 	rcu_assign_pointer(ar->tx_ampdu_iter,
1800fe8ee9adSChristian Lamparter 			   (struct carl9170_sta_tid *) &ar->tx_ampdu_list);
1801fe8ee9adSChristian Lamparter 
1802fe8ee9adSChristian Lamparter 	bitmap_zero(&ar->vif_bitmap, ar->fw.vif_num);
1803fe8ee9adSChristian Lamparter 	INIT_LIST_HEAD(&ar->vif_list);
1804fe8ee9adSChristian Lamparter 	init_completion(&ar->tx_flush);
1805fe8ee9adSChristian Lamparter 
1806df64962fSChristian Lamparter 	/* firmware decides which modes we support */
1807df64962fSChristian Lamparter 	hw->wiphy->interface_modes = 0;
1808fe8ee9adSChristian Lamparter 
180930686bf7SJohannes Berg 	ieee80211_hw_set(hw, RX_INCLUDES_FCS);
181030686bf7SJohannes Berg 	ieee80211_hw_set(hw, MFP_CAPABLE);
181130686bf7SJohannes Berg 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
181230686bf7SJohannes Berg 	ieee80211_hw_set(hw, SUPPORTS_PS);
181330686bf7SJohannes Berg 	ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
181430686bf7SJohannes Berg 	ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC);
181530686bf7SJohannes Berg 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
181630686bf7SJohannes Berg 	ieee80211_hw_set(hw, SIGNAL_DBM);
181730686bf7SJohannes Berg 	ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
1818fe8ee9adSChristian Lamparter 
1819fe8ee9adSChristian Lamparter 	if (!modparam_noht) {
1820fe8ee9adSChristian Lamparter 		/*
1821fe8ee9adSChristian Lamparter 		 * see the comment above, why we allow the user
1822fe8ee9adSChristian Lamparter 		 * to disable HT by a module parameter.
1823fe8ee9adSChristian Lamparter 		 */
182430686bf7SJohannes Berg 		ieee80211_hw_set(hw, AMPDU_AGGREGATION);
1825fe8ee9adSChristian Lamparter 	}
1826fe8ee9adSChristian Lamparter 
1827fe8ee9adSChristian Lamparter 	hw->extra_tx_headroom = sizeof(struct _carl9170_tx_superframe);
1828fe8ee9adSChristian Lamparter 	hw->sta_data_size = sizeof(struct carl9170_sta_info);
1829fe8ee9adSChristian Lamparter 	hw->vif_data_size = sizeof(struct carl9170_vif_info);
1830fe8ee9adSChristian Lamparter 
1831fe8ee9adSChristian Lamparter 	hw->max_rates = CARL9170_TX_MAX_RATES;
1832fe8ee9adSChristian Lamparter 	hw->max_rate_tries = CARL9170_TX_USER_RATE_TRIES;
1833fe8ee9adSChristian Lamparter 
1834fe8ee9adSChristian Lamparter 	for (i = 0; i < ARRAY_SIZE(ar->noise); i++)
1835fe8ee9adSChristian Lamparter 		ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
1836fe8ee9adSChristian Lamparter 
1837ae44b502SAndrew Zaborowski 	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
1838ae44b502SAndrew Zaborowski 
1839fe8ee9adSChristian Lamparter 	return ar;
1840fe8ee9adSChristian Lamparter 
1841fe8ee9adSChristian Lamparter err_nomem:
1842fe8ee9adSChristian Lamparter 	kfree_skb(skb);
1843fe8ee9adSChristian Lamparter 	return ERR_PTR(-ENOMEM);
1844fe8ee9adSChristian Lamparter }
1845fe8ee9adSChristian Lamparter 
carl9170_read_eeprom(struct ar9170 * ar)1846fe8ee9adSChristian Lamparter static int carl9170_read_eeprom(struct ar9170 *ar)
1847fe8ee9adSChristian Lamparter {
1848fe8ee9adSChristian Lamparter #define RW	8	/* number of words to read at once */
1849fe8ee9adSChristian Lamparter #define RB	(sizeof(u32) * RW)
1850fe8ee9adSChristian Lamparter 	u8 *eeprom = (void *)&ar->eeprom;
1851fe8ee9adSChristian Lamparter 	__le32 offsets[RW];
1852fe8ee9adSChristian Lamparter 	int i, j, err;
1853fe8ee9adSChristian Lamparter 
1854fe8ee9adSChristian Lamparter 	BUILD_BUG_ON(sizeof(ar->eeprom) & 3);
1855fe8ee9adSChristian Lamparter 
1856fe8ee9adSChristian Lamparter 	BUILD_BUG_ON(RB > CARL9170_MAX_CMD_LEN - 4);
1857fe8ee9adSChristian Lamparter #ifndef __CHECKER__
1858fe8ee9adSChristian Lamparter 	/* don't want to handle trailing remains */
1859fe8ee9adSChristian Lamparter 	BUILD_BUG_ON(sizeof(ar->eeprom) % RB);
1860fe8ee9adSChristian Lamparter #endif
1861fe8ee9adSChristian Lamparter 
1862fe8ee9adSChristian Lamparter 	for (i = 0; i < sizeof(ar->eeprom) / RB; i++) {
1863fe8ee9adSChristian Lamparter 		for (j = 0; j < RW; j++)
1864fe8ee9adSChristian Lamparter 			offsets[j] = cpu_to_le32(AR9170_EEPROM_START +
1865fe8ee9adSChristian Lamparter 						 RB * i + 4 * j);
1866fe8ee9adSChristian Lamparter 
1867fe8ee9adSChristian Lamparter 		err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG,
1868fe8ee9adSChristian Lamparter 					RB, (u8 *) &offsets,
1869fe8ee9adSChristian Lamparter 					RB, eeprom + RB * i);
1870fe8ee9adSChristian Lamparter 		if (err)
1871fe8ee9adSChristian Lamparter 			return err;
1872fe8ee9adSChristian Lamparter 	}
1873fe8ee9adSChristian Lamparter 
1874fe8ee9adSChristian Lamparter #undef RW
1875fe8ee9adSChristian Lamparter #undef RB
1876fe8ee9adSChristian Lamparter 	return 0;
1877fe8ee9adSChristian Lamparter }
1878fe8ee9adSChristian Lamparter 
carl9170_parse_eeprom(struct ar9170 * ar)1879fe8ee9adSChristian Lamparter static int carl9170_parse_eeprom(struct ar9170 *ar)
1880fe8ee9adSChristian Lamparter {
1881fe8ee9adSChristian Lamparter 	struct ath_regulatory *regulatory = &ar->common.regulatory;
1882fe8ee9adSChristian Lamparter 	unsigned int rx_streams, tx_streams, tx_params = 0;
1883fe8ee9adSChristian Lamparter 	int bands = 0;
1884acf17712SChristian Lamparter 	int chans = 0;
1885fe8ee9adSChristian Lamparter 
1886fe8ee9adSChristian Lamparter 	if (ar->eeprom.length == cpu_to_le16(0xffff))
1887fe8ee9adSChristian Lamparter 		return -ENODATA;
1888fe8ee9adSChristian Lamparter 
1889fe8ee9adSChristian Lamparter 	rx_streams = hweight8(ar->eeprom.rx_mask);
1890fe8ee9adSChristian Lamparter 	tx_streams = hweight8(ar->eeprom.tx_mask);
1891fe8ee9adSChristian Lamparter 
1892fe8ee9adSChristian Lamparter 	if (rx_streams != tx_streams) {
1893fe8ee9adSChristian Lamparter 		tx_params = IEEE80211_HT_MCS_TX_RX_DIFF;
1894fe8ee9adSChristian Lamparter 
1895fe8ee9adSChristian Lamparter 		WARN_ON(!(tx_streams >= 1 && tx_streams <=
1896fe8ee9adSChristian Lamparter 			IEEE80211_HT_MCS_TX_MAX_STREAMS));
1897fe8ee9adSChristian Lamparter 
189802a95374SColin Ian King 		tx_params |= (tx_streams - 1) <<
1899fe8ee9adSChristian Lamparter 			    IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
1900fe8ee9adSChristian Lamparter 
1901fe8ee9adSChristian Lamparter 		carl9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params;
1902fe8ee9adSChristian Lamparter 		carl9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params;
1903fe8ee9adSChristian Lamparter 	}
1904fe8ee9adSChristian Lamparter 
1905fe8ee9adSChristian Lamparter 	if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) {
190657fbcce3SJohannes Berg 		ar->hw->wiphy->bands[NL80211_BAND_2GHZ] =
1907fe8ee9adSChristian Lamparter 			&carl9170_band_2GHz;
1908acf17712SChristian Lamparter 		chans += carl9170_band_2GHz.n_channels;
1909fe8ee9adSChristian Lamparter 		bands++;
1910fe8ee9adSChristian Lamparter 	}
1911fe8ee9adSChristian Lamparter 	if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) {
191257fbcce3SJohannes Berg 		ar->hw->wiphy->bands[NL80211_BAND_5GHZ] =
1913fe8ee9adSChristian Lamparter 			&carl9170_band_5GHz;
1914acf17712SChristian Lamparter 		chans += carl9170_band_5GHz.n_channels;
1915fe8ee9adSChristian Lamparter 		bands++;
1916fe8ee9adSChristian Lamparter 	}
1917fe8ee9adSChristian Lamparter 
1918acf17712SChristian Lamparter 	if (!bands)
1919acf17712SChristian Lamparter 		return -EINVAL;
1920acf17712SChristian Lamparter 
192183fe43abSChristian Lamparter 	ar->survey = devm_kcalloc(&ar->udev->dev, chans,
192283fe43abSChristian Lamparter 				  sizeof(struct survey_info), GFP_KERNEL);
1923acf17712SChristian Lamparter 	if (!ar->survey)
1924acf17712SChristian Lamparter 		return -ENOMEM;
1925acf17712SChristian Lamparter 	ar->num_channels = chans;
1926acf17712SChristian Lamparter 
1927fe8ee9adSChristian Lamparter 	regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
1928fe8ee9adSChristian Lamparter 
1929fe8ee9adSChristian Lamparter 	/* second part of wiphy init */
1930fe8ee9adSChristian Lamparter 	SET_IEEE80211_PERM_ADDR(ar->hw, ar->eeprom.mac_address);
1931fe8ee9adSChristian Lamparter 
1932acf17712SChristian Lamparter 	return 0;
1933fe8ee9adSChristian Lamparter }
1934fe8ee9adSChristian Lamparter 
carl9170_reg_notifier(struct wiphy * wiphy,struct regulatory_request * request)19350c0280bdSLuis R. Rodriguez static void carl9170_reg_notifier(struct wiphy *wiphy,
1936fe8ee9adSChristian Lamparter 				  struct regulatory_request *request)
1937fe8ee9adSChristian Lamparter {
1938fe8ee9adSChristian Lamparter 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
1939fe8ee9adSChristian Lamparter 	struct ar9170 *ar = hw->priv;
1940fe8ee9adSChristian Lamparter 
19410c0280bdSLuis R. Rodriguez 	ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
1942fe8ee9adSChristian Lamparter }
1943fe8ee9adSChristian Lamparter 
carl9170_register(struct ar9170 * ar)1944fe8ee9adSChristian Lamparter int carl9170_register(struct ar9170 *ar)
1945fe8ee9adSChristian Lamparter {
1946fe8ee9adSChristian Lamparter 	struct ath_regulatory *regulatory = &ar->common.regulatory;
1947fe8ee9adSChristian Lamparter 	int err = 0, i;
1948fe8ee9adSChristian Lamparter 
1949a8da65f9SChristian Lamparter 	ar->mem_bitmap = devm_bitmap_zalloc(&ar->udev->dev, ar->fw.mem_blocks, GFP_KERNEL);
1950fe8ee9adSChristian Lamparter 	if (!ar->mem_bitmap)
1951fe8ee9adSChristian Lamparter 		return -ENOMEM;
1952fe8ee9adSChristian Lamparter 
1953fe8ee9adSChristian Lamparter 	/* try to read EEPROM, init MAC addr */
1954fe8ee9adSChristian Lamparter 	err = carl9170_read_eeprom(ar);
1955fe8ee9adSChristian Lamparter 	if (err)
1956fe8ee9adSChristian Lamparter 		return err;
1957fe8ee9adSChristian Lamparter 
1958fe8ee9adSChristian Lamparter 	err = carl9170_parse_eeprom(ar);
1959fe8ee9adSChristian Lamparter 	if (err)
1960fe8ee9adSChristian Lamparter 		return err;
1961fe8ee9adSChristian Lamparter 
1962fe8ee9adSChristian Lamparter 	err = ath_regd_init(regulatory, ar->hw->wiphy,
1963fe8ee9adSChristian Lamparter 			    carl9170_reg_notifier);
1964fe8ee9adSChristian Lamparter 	if (err)
1965fe8ee9adSChristian Lamparter 		return err;
1966fe8ee9adSChristian Lamparter 
1967fe8ee9adSChristian Lamparter 	if (modparam_noht) {
1968fe8ee9adSChristian Lamparter 		carl9170_band_2GHz.ht_cap.ht_supported = false;
1969fe8ee9adSChristian Lamparter 		carl9170_band_5GHz.ht_cap.ht_supported = false;
1970fe8ee9adSChristian Lamparter 	}
1971fe8ee9adSChristian Lamparter 
1972fe8ee9adSChristian Lamparter 	for (i = 0; i < ar->fw.vif_num; i++) {
1973fe8ee9adSChristian Lamparter 		ar->vif_priv[i].id = i;
1974fe8ee9adSChristian Lamparter 		ar->vif_priv[i].vif = NULL;
1975fe8ee9adSChristian Lamparter 	}
1976fe8ee9adSChristian Lamparter 
1977fe8ee9adSChristian Lamparter 	err = ieee80211_register_hw(ar->hw);
1978fe8ee9adSChristian Lamparter 	if (err)
1979fe8ee9adSChristian Lamparter 		return err;
1980fe8ee9adSChristian Lamparter 
1981fe8ee9adSChristian Lamparter 	/* mac80211 interface is now registered */
1982fe8ee9adSChristian Lamparter 	ar->registered = true;
1983fe8ee9adSChristian Lamparter 
1984fe8ee9adSChristian Lamparter 	if (!ath_is_world_regd(regulatory))
1985fe8ee9adSChristian Lamparter 		regulatory_hint(ar->hw->wiphy, regulatory->alpha2);
1986fe8ee9adSChristian Lamparter 
1987fe8ee9adSChristian Lamparter #ifdef CONFIG_CARL9170_DEBUGFS
1988fe8ee9adSChristian Lamparter 	carl9170_debugfs_register(ar);
1989fe8ee9adSChristian Lamparter #endif /* CONFIG_CARL9170_DEBUGFS */
1990fe8ee9adSChristian Lamparter 
1991fe8ee9adSChristian Lamparter 	err = carl9170_led_init(ar);
1992fe8ee9adSChristian Lamparter 	if (err)
1993fe8ee9adSChristian Lamparter 		goto err_unreg;
1994fe8ee9adSChristian Lamparter 
1995fe8ee9adSChristian Lamparter #ifdef CONFIG_CARL9170_LEDS
1996fe8ee9adSChristian Lamparter 	err = carl9170_led_register(ar);
1997fe8ee9adSChristian Lamparter 	if (err)
1998fe8ee9adSChristian Lamparter 		goto err_unreg;
19998e7ce893SHauke Mehrtens #endif /* CONFIG_CARL9170_LEDS */
2000fe8ee9adSChristian Lamparter 
2001fe8ee9adSChristian Lamparter #ifdef CONFIG_CARL9170_WPC
2002fe8ee9adSChristian Lamparter 	err = carl9170_register_wps_button(ar);
2003fe8ee9adSChristian Lamparter 	if (err)
2004fe8ee9adSChristian Lamparter 		goto err_unreg;
2005fe8ee9adSChristian Lamparter #endif /* CONFIG_CARL9170_WPC */
2006fe8ee9adSChristian Lamparter 
200700044f17SChristian Lamparter #ifdef CONFIG_CARL9170_HWRNG
200800044f17SChristian Lamparter 	err = carl9170_register_hwrng(ar);
200900044f17SChristian Lamparter 	if (err)
201000044f17SChristian Lamparter 		goto err_unreg;
201100044f17SChristian Lamparter #endif /* CONFIG_CARL9170_HWRNG */
201200044f17SChristian Lamparter 
2013fe8ee9adSChristian Lamparter 	dev_info(&ar->udev->dev, "Atheros AR9170 is registered as '%s'\n",
2014fe8ee9adSChristian Lamparter 		 wiphy_name(ar->hw->wiphy));
2015fe8ee9adSChristian Lamparter 
2016fe8ee9adSChristian Lamparter 	return 0;
2017fe8ee9adSChristian Lamparter 
2018fe8ee9adSChristian Lamparter err_unreg:
2019fe8ee9adSChristian Lamparter 	carl9170_unregister(ar);
2020fe8ee9adSChristian Lamparter 	return err;
2021fe8ee9adSChristian Lamparter }
2022fe8ee9adSChristian Lamparter 
carl9170_unregister(struct ar9170 * ar)2023fe8ee9adSChristian Lamparter void carl9170_unregister(struct ar9170 *ar)
2024fe8ee9adSChristian Lamparter {
2025fe8ee9adSChristian Lamparter 	if (!ar->registered)
2026fe8ee9adSChristian Lamparter 		return;
2027fe8ee9adSChristian Lamparter 
2028fe8ee9adSChristian Lamparter 	ar->registered = false;
2029fe8ee9adSChristian Lamparter 
2030fe8ee9adSChristian Lamparter #ifdef CONFIG_CARL9170_LEDS
2031fe8ee9adSChristian Lamparter 	carl9170_led_unregister(ar);
2032fe8ee9adSChristian Lamparter #endif /* CONFIG_CARL9170_LEDS */
2033fe8ee9adSChristian Lamparter 
2034fe8ee9adSChristian Lamparter #ifdef CONFIG_CARL9170_DEBUGFS
2035fe8ee9adSChristian Lamparter 	carl9170_debugfs_unregister(ar);
2036fe8ee9adSChristian Lamparter #endif /* CONFIG_CARL9170_DEBUGFS */
2037fe8ee9adSChristian Lamparter 
2038fe8ee9adSChristian Lamparter 	carl9170_cancel_worker(ar);
2039fe8ee9adSChristian Lamparter 	cancel_work_sync(&ar->restart_work);
2040fe8ee9adSChristian Lamparter 
2041fe8ee9adSChristian Lamparter 	ieee80211_unregister_hw(ar->hw);
2042fe8ee9adSChristian Lamparter }
2043fe8ee9adSChristian Lamparter 
carl9170_free(struct ar9170 * ar)2044fe8ee9adSChristian Lamparter void carl9170_free(struct ar9170 *ar)
2045fe8ee9adSChristian Lamparter {
2046fe8ee9adSChristian Lamparter 	WARN_ON(ar->registered);
2047fe8ee9adSChristian Lamparter 	WARN_ON(IS_INITIALIZED(ar));
2048fe8ee9adSChristian Lamparter 
2049fe8ee9adSChristian Lamparter 	kfree_skb(ar->rx_failover);
2050fe8ee9adSChristian Lamparter 	ar->rx_failover = NULL;
2051fe8ee9adSChristian Lamparter 
2052fe8ee9adSChristian Lamparter 	mutex_destroy(&ar->mutex);
2053fe8ee9adSChristian Lamparter 
2054fe8ee9adSChristian Lamparter 	ieee80211_free_hw(ar->hw);
2055fe8ee9adSChristian Lamparter }
2056