aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwmc3200wifi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi')
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Kconfig39
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Makefile10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/bus.h57
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c882
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.h31
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c1002
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h509
-rw-r--r--drivers/net/wireless/iwmc3200wifi/debug.h123
-rw-r--r--drivers/net/wireless/iwmc3200wifi/debugfs.c488
-rw-r--r--drivers/net/wireless/iwmc3200wifi/eeprom.c234
-rw-r--r--drivers/net/wireless/iwmc3200wifi/eeprom.h127
-rw-r--r--drivers/net/wireless/iwmc3200wifi/fw.c416
-rw-r--r--drivers/net/wireless/iwmc3200wifi/fw.h100
-rw-r--r--drivers/net/wireless/iwmc3200wifi/hal.c470
-rw-r--r--drivers/net/wireless/iwmc3200wifi/hal.h237
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h367
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h484
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c847
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c191
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c1701
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.h60
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.c509
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.h64
-rw-r--r--drivers/net/wireless/iwmc3200wifi/trace.c3
-rw-r--r--drivers/net/wireless/iwmc3200wifi/trace.h283
-rw-r--r--drivers/net/wireless/iwmc3200wifi/tx.c529
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h789
27 files changed, 0 insertions, 10552 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig
deleted file mode 100644
index 7107ce53d4d4..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/Kconfig
+++ /dev/null
@@ -1,39 +0,0 @@
1config IWM
2 tristate "Intel Wireless Multicomm 3200 WiFi driver (EXPERIMENTAL)"
3 depends on MMC && EXPERIMENTAL
4 depends on CFG80211
5 select FW_LOADER
6 select IWMC3200TOP
7 help
8 The Intel Wireless Multicomm 3200 hardware is a combo
9 card with GPS, Bluetooth, WiMax and 802.11 radios. It
10 runs over SDIO and is typically found on Moorestown
11 based platform. This driver takes care of the 802.11
12 part, which is a fullmac one.
13
14 If you choose to build it as a module, it'll be called
15 iwmc3200wifi.ko.
16
17config IWM_DEBUG
18 bool "Enable full debugging output in iwmc3200wifi"
19 depends on IWM && DEBUG_FS
20 help
21 This option will enable debug tracing and setting for iwm
22
23 You can set the debug level and module through debugfs. By
24 default all modules are set to the IWL_DL_ERR level.
25 To see the list of debug modules and levels, see iwm/debug.h
26
27 For example, if you want the full MLME debug output:
28 echo 0xff > /sys/kernel/debug/iwm/phyN/debug/mlme
29
30 Or, if you want the full debug, for all modules:
31 echo 0xff > /sys/kernel/debug/iwm/phyN/debug/level
32 echo 0xff > /sys/kernel/debug/iwm/phyN/debug/modules
33
34config IWM_TRACING
35 bool "Enable event tracing for iwmc3200wifi"
36 depends on IWM && EVENT_TRACING
37 help
38 Say Y here to trace all the commands and responses between
39 the driver and firmware (including TX/RX frames) with ftrace.
diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile
deleted file mode 100644
index cdc7e07ba113..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
1obj-$(CONFIG_IWM) := iwmc3200wifi.o
2iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o
3iwmc3200wifi-objs += commands.o cfg80211.o eeprom.o
4
5iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o
6iwmc3200wifi-$(CONFIG_IWM_TRACING) += trace.o
7
8CFLAGS_trace.o := -I$(src)
9
10ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/iwmc3200wifi/bus.h b/drivers/net/wireless/iwmc3200wifi/bus.h
deleted file mode 100644
index 62edd5888a7b..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/bus.h
+++ /dev/null
@@ -1,57 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5 * Samuel Ortiz <samuel.ortiz@intel.com>
6 * Zhu Yi <yi.zhu@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 */
23
24#ifndef __IWM_BUS_H__
25#define __IWM_BUS_H__
26
27#include "iwm.h"
28
29struct iwm_if_ops {
30 int (*enable)(struct iwm_priv *iwm);
31 int (*disable)(struct iwm_priv *iwm);
32 int (*send_chunk)(struct iwm_priv *iwm, u8* buf, int count);
33
34 void (*debugfs_init)(struct iwm_priv *iwm, struct dentry *parent_dir);
35 void (*debugfs_exit)(struct iwm_priv *iwm);
36
37 const char *umac_name;
38 const char *calib_lmac_name;
39 const char *lmac_name;
40};
41
42static inline int iwm_bus_send_chunk(struct iwm_priv *iwm, u8 *buf, int count)
43{
44 return iwm->bus_ops->send_chunk(iwm, buf, count);
45}
46
47static inline int iwm_bus_enable(struct iwm_priv *iwm)
48{
49 return iwm->bus_ops->enable(iwm);
50}
51
52static inline int iwm_bus_disable(struct iwm_priv *iwm)
53{
54 return iwm->bus_ops->disable(iwm);
55}
56
57#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
deleted file mode 100644
index 48e8218fd23b..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ /dev/null
@@ -1,882 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5 * Samuel Ortiz <samuel.ortiz@intel.com>
6 * Zhu Yi <yi.zhu@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 */
23
24#include <linux/kernel.h>
25#include <linux/netdevice.h>
26#include <linux/sched.h>
27#include <linux/etherdevice.h>
28#include <linux/wireless.h>
29#include <linux/ieee80211.h>
30#include <linux/slab.h>
31#include <net/cfg80211.h>
32
33#include "iwm.h"
34#include "commands.h"
35#include "cfg80211.h"
36#include "debug.h"
37
38#define RATETAB_ENT(_rate, _rateid, _flags) \
39 { \
40 .bitrate = (_rate), \
41 .hw_value = (_rateid), \
42 .flags = (_flags), \
43 }
44
45#define CHAN2G(_channel, _freq, _flags) { \
46 .band = IEEE80211_BAND_2GHZ, \
47 .center_freq = (_freq), \
48 .hw_value = (_channel), \
49 .flags = (_flags), \
50 .max_antenna_gain = 0, \
51 .max_power = 30, \
52}
53
54#define CHAN5G(_channel, _flags) { \
55 .band = IEEE80211_BAND_5GHZ, \
56 .center_freq = 5000 + (5 * (_channel)), \
57 .hw_value = (_channel), \
58 .flags = (_flags), \
59 .max_antenna_gain = 0, \
60 .max_power = 30, \
61}
62
63static struct ieee80211_rate iwm_rates[] = {
64 RATETAB_ENT(10, 0x1, 0),
65 RATETAB_ENT(20, 0x2, 0),
66 RATETAB_ENT(55, 0x4, 0),
67 RATETAB_ENT(110, 0x8, 0),
68 RATETAB_ENT(60, 0x10, 0),
69 RATETAB_ENT(90, 0x20, 0),
70 RATETAB_ENT(120, 0x40, 0),
71 RATETAB_ENT(180, 0x80, 0),
72 RATETAB_ENT(240, 0x100, 0),
73 RATETAB_ENT(360, 0x200, 0),
74 RATETAB_ENT(480, 0x400, 0),
75 RATETAB_ENT(540, 0x800, 0),
76};
77
78#define iwm_a_rates (iwm_rates + 4)
79#define iwm_a_rates_size 8
80#define iwm_g_rates (iwm_rates + 0)
81#define iwm_g_rates_size 12
82
83static struct ieee80211_channel iwm_2ghz_channels[] = {
84 CHAN2G(1, 2412, 0),
85 CHAN2G(2, 2417, 0),
86 CHAN2G(3, 2422, 0),
87 CHAN2G(4, 2427, 0),
88 CHAN2G(5, 2432, 0),
89 CHAN2G(6, 2437, 0),
90 CHAN2G(7, 2442, 0),
91 CHAN2G(8, 2447, 0),
92 CHAN2G(9, 2452, 0),
93 CHAN2G(10, 2457, 0),
94 CHAN2G(11, 2462, 0),
95 CHAN2G(12, 2467, 0),
96 CHAN2G(13, 2472, 0),
97 CHAN2G(14, 2484, 0),
98};
99
100static struct ieee80211_channel iwm_5ghz_a_channels[] = {
101 CHAN5G(34, 0), CHAN5G(36, 0),
102 CHAN5G(38, 0), CHAN5G(40, 0),
103 CHAN5G(42, 0), CHAN5G(44, 0),
104 CHAN5G(46, 0), CHAN5G(48, 0),
105 CHAN5G(52, 0), CHAN5G(56, 0),
106 CHAN5G(60, 0), CHAN5G(64, 0),
107 CHAN5G(100, 0), CHAN5G(104, 0),
108 CHAN5G(108, 0), CHAN5G(112, 0),
109 CHAN5G(116, 0), CHAN5G(120, 0),
110 CHAN5G(124, 0), CHAN5G(128, 0),
111 CHAN5G(132, 0), CHAN5G(136, 0),
112 CHAN5G(140, 0), CHAN5G(149, 0),
113 CHAN5G(153, 0), CHAN5G(157, 0),
114 CHAN5G(161, 0), CHAN5G(165, 0),
115 CHAN5G(184, 0), CHAN5G(188, 0),
116 CHAN5G(192, 0), CHAN5G(196, 0),
117 CHAN5G(200, 0), CHAN5G(204, 0),
118 CHAN5G(208, 0), CHAN5G(212, 0),
119 CHAN5G(216, 0),
120};
121
122static struct ieee80211_supported_band iwm_band_2ghz = {
123 .channels = iwm_2ghz_channels,
124 .n_channels = ARRAY_SIZE(iwm_2ghz_channels),
125 .bitrates = iwm_g_rates,
126 .n_bitrates = iwm_g_rates_size,
127};
128
129static struct ieee80211_supported_band iwm_band_5ghz = {
130 .channels = iwm_5ghz_a_channels,
131 .n_channels = ARRAY_SIZE(iwm_5ghz_a_channels),
132 .bitrates = iwm_a_rates,
133 .n_bitrates = iwm_a_rates_size,
134};
135
136static int iwm_key_init(struct iwm_key *key, u8 key_index,
137 const u8 *mac_addr, struct key_params *params)
138{
139 key->hdr.key_idx = key_index;
140 if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
141 key->hdr.multicast = 1;
142 memset(key->hdr.mac, 0xff, ETH_ALEN);
143 } else {
144 key->hdr.multicast = 0;
145 memcpy(key->hdr.mac, mac_addr, ETH_ALEN);
146 }
147
148 if (params) {
149 if (params->key_len > WLAN_MAX_KEY_LEN ||
150 params->seq_len > IW_ENCODE_SEQ_MAX_SIZE)
151 return -EINVAL;
152
153 key->cipher = params->cipher;
154 key->key_len = params->key_len;
155 key->seq_len = params->seq_len;
156 memcpy(key->key, params->key, key->key_len);
157 memcpy(key->seq, params->seq, key->seq_len);
158 }
159
160 return 0;
161}
162
163static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
164 u8 key_index, bool pairwise, const u8 *mac_addr,
165 struct key_params *params)
166{
167 struct iwm_priv *iwm = ndev_to_iwm(ndev);
168 struct iwm_key *key;
169 int ret;
170
171 IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
172
173 if (key_index >= IWM_NUM_KEYS)
174 return -ENOENT;
175
176 key = &iwm->keys[key_index];
177 memset(key, 0, sizeof(struct iwm_key));
178 ret = iwm_key_init(key, key_index, mac_addr, params);
179 if (ret < 0) {
180 IWM_ERR(iwm, "Invalid key_params\n");
181 return ret;
182 }
183
184 return iwm_set_key(iwm, 0, key);
185}
186
187static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
188 u8 key_index, bool pairwise, const u8 *mac_addr,
189 void *cookie,
190 void (*callback)(void *cookie,
191 struct key_params*))
192{
193 struct iwm_priv *iwm = ndev_to_iwm(ndev);
194 struct iwm_key *key;
195 struct key_params params;
196
197 IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);
198
199 if (key_index >= IWM_NUM_KEYS)
200 return -ENOENT;
201
202 memset(&params, 0, sizeof(params));
203
204 key = &iwm->keys[key_index];
205 params.cipher = key->cipher;
206 params.key_len = key->key_len;
207 params.seq_len = key->seq_len;
208 params.seq = key->seq;
209 params.key = key->key;
210
211 callback(cookie, &params);
212
213 return key->key_len ? 0 : -ENOENT;
214}
215
216
217static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
218 u8 key_index, bool pairwise, const u8 *mac_addr)
219{
220 struct iwm_priv *iwm = ndev_to_iwm(ndev);
221 struct iwm_key *key;
222
223 if (key_index >= IWM_NUM_KEYS)
224 return -ENOENT;
225
226 key = &iwm->keys[key_index];
227 if (!iwm->keys[key_index].key_len) {
228 IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
229 return 0;
230 }
231
232 if (key_index == iwm->default_key)
233 iwm->default_key = -1;
234
235 return iwm_set_key(iwm, 1, key);
236}
237
238static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
239 struct net_device *ndev,
240 u8 key_index, bool unicast,
241 bool multicast)
242{
243 struct iwm_priv *iwm = ndev_to_iwm(ndev);
244
245 IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
246
247 if (key_index >= IWM_NUM_KEYS)
248 return -ENOENT;
249
250 if (!iwm->keys[key_index].key_len) {
251 IWM_ERR(iwm, "Key %d not used\n", key_index);
252 return -EINVAL;
253 }
254
255 iwm->default_key = key_index;
256
257 return iwm_set_tx_key(iwm, key_index);
258}
259
260static int iwm_cfg80211_get_station(struct wiphy *wiphy,
261 struct net_device *ndev,
262 u8 *mac, struct station_info *sinfo)
263{
264 struct iwm_priv *iwm = ndev_to_iwm(ndev);
265
266 if (memcmp(mac, iwm->bssid, ETH_ALEN))
267 return -ENOENT;
268
269 sinfo->filled |= STATION_INFO_TX_BITRATE;
270 sinfo->txrate.legacy = iwm->rate * 10;
271
272 if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
273 sinfo->filled |= STATION_INFO_SIGNAL;
274 sinfo->signal = iwm->wstats.qual.level;
275 }
276
277 return 0;
278}
279
280
281int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
282{
283 struct wiphy *wiphy = iwm_to_wiphy(iwm);
284 struct iwm_bss_info *bss;
285 struct iwm_umac_notif_bss_info *umac_bss;
286 struct ieee80211_mgmt *mgmt;
287 struct ieee80211_channel *channel;
288 struct ieee80211_supported_band *band;
289 s32 signal;
290 int freq;
291
292 list_for_each_entry(bss, &iwm->bss_list, node) {
293 umac_bss = bss->bss;
294 mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf);
295
296 if (umac_bss->band == UMAC_BAND_2GHZ)
297 band = wiphy->bands[IEEE80211_BAND_2GHZ];
298 else if (umac_bss->band == UMAC_BAND_5GHZ)
299 band = wiphy->bands[IEEE80211_BAND_5GHZ];
300 else {
301 IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band);
302 return -EINVAL;
303 }
304
305 freq = ieee80211_channel_to_frequency(umac_bss->channel,
306 band->band);
307 channel = ieee80211_get_channel(wiphy, freq);
308 signal = umac_bss->rssi * 100;
309
310 if (!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
311 le16_to_cpu(umac_bss->frame_len),
312 signal, GFP_KERNEL))
313 return -EINVAL;
314 }
315
316 return 0;
317}
318
319static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
320 struct net_device *ndev,
321 enum nl80211_iftype type, u32 *flags,
322 struct vif_params *params)
323{
324 struct wireless_dev *wdev;
325 struct iwm_priv *iwm;
326 u32 old_mode;
327
328 wdev = ndev->ieee80211_ptr;
329 iwm = ndev_to_iwm(ndev);
330 old_mode = iwm->conf.mode;
331
332 switch (type) {
333 case NL80211_IFTYPE_STATION:
334 iwm->conf.mode = UMAC_MODE_BSS;
335 break;
336 case NL80211_IFTYPE_ADHOC:
337 iwm->conf.mode = UMAC_MODE_IBSS;
338 break;
339 default:
340 return -EOPNOTSUPP;
341 }
342
343 wdev->iftype = type;
344
345 if ((old_mode == iwm->conf.mode) || !iwm->umac_profile)
346 return 0;
347
348 iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode);
349
350 if (iwm->umac_profile_active)
351 iwm_invalidate_mlme_profile(iwm);
352
353 return 0;
354}
355
356static int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
357 struct cfg80211_scan_request *request)
358{
359 struct iwm_priv *iwm = ndev_to_iwm(ndev);
360 int ret;
361
362 if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
363 IWM_ERR(iwm, "Scan while device is not ready\n");
364 return -EIO;
365 }
366
367 if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) {
368 IWM_ERR(iwm, "Scanning already\n");
369 return -EAGAIN;
370 }
371
372 if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) {
373 IWM_ERR(iwm, "Scanning being aborted\n");
374 return -EAGAIN;
375 }
376
377 set_bit(IWM_STATUS_SCANNING, &iwm->status);
378
379 ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids);
380 if (ret) {
381 clear_bit(IWM_STATUS_SCANNING, &iwm->status);
382 return ret;
383 }
384
385 iwm->scan_request = request;
386 return 0;
387}
388
389static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
390{
391 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
392
393 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
394 (iwm->conf.rts_threshold != wiphy->rts_threshold)) {
395 int ret;
396
397 iwm->conf.rts_threshold = wiphy->rts_threshold;
398
399 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
400 CFG_RTS_THRESHOLD,
401 iwm->conf.rts_threshold);
402 if (ret < 0)
403 return ret;
404 }
405
406 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
407 (iwm->conf.frag_threshold != wiphy->frag_threshold)) {
408 int ret;
409
410 iwm->conf.frag_threshold = wiphy->frag_threshold;
411
412 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX,
413 CFG_FRAG_THRESHOLD,
414 iwm->conf.frag_threshold);
415 if (ret < 0)
416 return ret;
417 }
418
419 return 0;
420}
421
422static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
423 struct cfg80211_ibss_params *params)
424{
425 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
426 struct ieee80211_channel *chan = params->channel;
427
428 if (!test_bit(IWM_STATUS_READY, &iwm->status))
429 return -EIO;
430
431 /* UMAC doesn't support creating or joining an IBSS network
432 * with specified bssid. */
433 if (params->bssid)
434 return -EOPNOTSUPP;
435
436 iwm->channel = ieee80211_frequency_to_channel(chan->center_freq);
437 iwm->umac_profile->ibss.band = chan->band;
438 iwm->umac_profile->ibss.channel = iwm->channel;
439 iwm->umac_profile->ssid.ssid_len = params->ssid_len;
440 memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len);
441
442 return iwm_send_mlme_profile(iwm);
443}
444
445static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
446{
447 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
448
449 if (iwm->umac_profile_active)
450 return iwm_invalidate_mlme_profile(iwm);
451
452 return 0;
453}
454
455static int iwm_set_auth_type(struct iwm_priv *iwm,
456 enum nl80211_auth_type sme_auth_type)
457{
458 u8 *auth_type = &iwm->umac_profile->sec.auth_type;
459
460 switch (sme_auth_type) {
461 case NL80211_AUTHTYPE_AUTOMATIC:
462 case NL80211_AUTHTYPE_OPEN_SYSTEM:
463 IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
464 *auth_type = UMAC_AUTH_TYPE_OPEN;
465 break;
466 case NL80211_AUTHTYPE_SHARED_KEY:
467 if (iwm->umac_profile->sec.flags &
468 (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
469 IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
470 *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
471 } else {
472 IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
473 *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
474 }
475
476 break;
477 default:
478 IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
479 return -ENOTSUPP;
480 }
481
482 return 0;
483}
484
485static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
486{
487 IWM_DBG_WEXT(iwm, DBG, "wpa_version: %d\n", wpa_version);
488
489 if (!wpa_version) {
490 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
491 return 0;
492 }
493
494 if (wpa_version & NL80211_WPA_VERSION_1)
495 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
496
497 if (wpa_version & NL80211_WPA_VERSION_2)
498 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
499
500 return 0;
501}
502
503static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
504{
505 u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
506 &iwm->umac_profile->sec.mcast_cipher;
507
508 if (!cipher) {
509 *profile_cipher = UMAC_CIPHER_TYPE_NONE;
510 return 0;
511 }
512
513 IWM_DBG_WEXT(iwm, DBG, "%ccast cipher is 0x%x\n", ucast ? 'u' : 'm',
514 cipher);
515
516 switch (cipher) {
517 case IW_AUTH_CIPHER_NONE:
518 *profile_cipher = UMAC_CIPHER_TYPE_NONE;
519 break;
520 case WLAN_CIPHER_SUITE_WEP40:
521 *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
522 break;
523 case WLAN_CIPHER_SUITE_WEP104:
524 *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
525 break;
526 case WLAN_CIPHER_SUITE_TKIP:
527 *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
528 break;
529 case WLAN_CIPHER_SUITE_CCMP:
530 *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
531 break;
532 default:
533 IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
534 return -ENOTSUPP;
535 }
536
537 return 0;
538}
539
540static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
541{
542 u8 *auth_type = &iwm->umac_profile->sec.auth_type;
543
544 IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
545
546 if (key_mgt == WLAN_AKM_SUITE_8021X)
547 *auth_type = UMAC_AUTH_TYPE_8021X;
548 else if (key_mgt == WLAN_AKM_SUITE_PSK) {
549 if (iwm->umac_profile->sec.flags &
550 (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
551 *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
552 else
553 *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
554 } else {
555 IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
556 return -EINVAL;
557 }
558
559 return 0;
560}
561
562
563static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
564 struct cfg80211_connect_params *sme)
565{
566 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
567 struct ieee80211_channel *chan = sme->channel;
568 struct key_params key_param;
569 int ret;
570
571 if (!test_bit(IWM_STATUS_READY, &iwm->status))
572 return -EIO;
573
574 if (!sme->ssid)
575 return -EINVAL;
576
577 if (iwm->umac_profile_active) {
578 ret = iwm_invalidate_mlme_profile(iwm);
579 if (ret) {
580 IWM_ERR(iwm, "Couldn't invalidate profile\n");
581 return ret;
582 }
583 }
584
585 if (chan)
586 iwm->channel =
587 ieee80211_frequency_to_channel(chan->center_freq);
588
589 iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
590 memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
591
592 if (sme->bssid) {
593 IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
594 memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
595 iwm->umac_profile->bss_num = 1;
596 } else {
597 memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
598 iwm->umac_profile->bss_num = 0;
599 }
600
601 ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
602 if (ret < 0)
603 return ret;
604
605 ret = iwm_set_auth_type(iwm, sme->auth_type);
606 if (ret < 0)
607 return ret;
608
609 if (sme->crypto.n_ciphers_pairwise) {
610 ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
611 true);
612 if (ret < 0)
613 return ret;
614 }
615
616 ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
617 if (ret < 0)
618 return ret;
619
620 if (sme->crypto.n_akm_suites) {
621 ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
622 if (ret < 0)
623 return ret;
624 }
625
626 /*
627 * We save the WEP key in case we want to do shared authentication.
628 * We have to do it so because UMAC will assert whenever it gets a
629 * key before a profile.
630 */
631 if (sme->key) {
632 key_param.key = kmemdup(sme->key, sme->key_len, GFP_KERNEL);
633 if (key_param.key == NULL)
634 return -ENOMEM;
635 key_param.key_len = sme->key_len;
636 key_param.seq_len = 0;
637 key_param.cipher = sme->crypto.ciphers_pairwise[0];
638
639 ret = iwm_key_init(&iwm->keys[sme->key_idx], sme->key_idx,
640 NULL, &key_param);
641 kfree(key_param.key);
642 if (ret < 0) {
643 IWM_ERR(iwm, "Invalid key_params\n");
644 return ret;
645 }
646
647 iwm->default_key = sme->key_idx;
648 }
649
650 /* WPA and open AUTH type from wpa_s means WPS (a.k.a. WSC) */
651 if ((iwm->umac_profile->sec.flags &
652 (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) &&
653 iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN) {
654 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WSC_ON_MSK;
655 }
656
657 ret = iwm_send_mlme_profile(iwm);
658
659 if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK ||
660 sme->key == NULL)
661 return ret;
662
663 /*
664 * We want to do shared auth.
665 * We need to actually set the key we previously cached,
666 * and then tell the UMAC it's the default one.
667 * That will trigger the auth+assoc UMAC machinery, and again,
668 * this must be done after setting the profile.
669 */
670 ret = iwm_set_key(iwm, 0, &iwm->keys[sme->key_idx]);
671 if (ret < 0)
672 return ret;
673
674 return iwm_set_tx_key(iwm, iwm->default_key);
675}
676
677static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
678 u16 reason_code)
679{
680 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
681
682 IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
683
684 if (iwm->umac_profile_active)
685 iwm_invalidate_mlme_profile(iwm);
686
687 return 0;
688}
689
690static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
691 enum nl80211_tx_power_setting type, int mbm)
692{
693 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
694 int ret;
695
696 switch (type) {
697 case NL80211_TX_POWER_AUTOMATIC:
698 return 0;
699 case NL80211_TX_POWER_FIXED:
700 if (mbm < 0 || (mbm % 100))
701 return -EOPNOTSUPP;
702
703 if (!test_bit(IWM_STATUS_READY, &iwm->status))
704 return 0;
705
706 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
707 CFG_TX_PWR_LIMIT_USR,
708 MBM_TO_DBM(mbm) * 2);
709 if (ret < 0)
710 return ret;
711
712 return iwm_tx_power_trigger(iwm);
713 default:
714 IWM_ERR(iwm, "Unsupported power type: %d\n", type);
715 return -EOPNOTSUPP;
716 }
717
718 return 0;
719}
720
721static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
722{
723 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
724
725 *dbm = iwm->txpower >> 1;
726
727 return 0;
728}
729
730static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
731 struct net_device *dev,
732 bool enabled, int timeout)
733{
734 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
735 u32 power_index;
736
737 if (enabled)
738 power_index = IWM_POWER_INDEX_DEFAULT;
739 else
740 power_index = IWM_POWER_INDEX_MIN;
741
742 if (power_index == iwm->conf.power_index)
743 return 0;
744
745 iwm->conf.power_index = power_index;
746
747 return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
748 CFG_POWER_INDEX, iwm->conf.power_index);
749}
750
751static int iwm_cfg80211_set_pmksa(struct wiphy *wiphy,
752 struct net_device *netdev,
753 struct cfg80211_pmksa *pmksa)
754{
755 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
756
757 return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_ADD);
758}
759
760static int iwm_cfg80211_del_pmksa(struct wiphy *wiphy,
761 struct net_device *netdev,
762 struct cfg80211_pmksa *pmksa)
763{
764 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
765
766 return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_DEL);
767}
768
769static int iwm_cfg80211_flush_pmksa(struct wiphy *wiphy,
770 struct net_device *netdev)
771{
772 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
773 struct cfg80211_pmksa pmksa;
774
775 memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
776
777 return iwm_send_pmkid_update(iwm, &pmksa, IWM_CMD_PMKID_FLUSH);
778}
779
780
781static struct cfg80211_ops iwm_cfg80211_ops = {
782 .change_virtual_intf = iwm_cfg80211_change_iface,
783 .add_key = iwm_cfg80211_add_key,
784 .get_key = iwm_cfg80211_get_key,
785 .del_key = iwm_cfg80211_del_key,
786 .set_default_key = iwm_cfg80211_set_default_key,
787 .get_station = iwm_cfg80211_get_station,
788 .scan = iwm_cfg80211_scan,
789 .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
790 .connect = iwm_cfg80211_connect,
791 .disconnect = iwm_cfg80211_disconnect,
792 .join_ibss = iwm_cfg80211_join_ibss,
793 .leave_ibss = iwm_cfg80211_leave_ibss,
794 .set_tx_power = iwm_cfg80211_set_txpower,
795 .get_tx_power = iwm_cfg80211_get_txpower,
796 .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
797 .set_pmksa = iwm_cfg80211_set_pmksa,
798 .del_pmksa = iwm_cfg80211_del_pmksa,
799 .flush_pmksa = iwm_cfg80211_flush_pmksa,
800};
801
802static const u32 cipher_suites[] = {
803 WLAN_CIPHER_SUITE_WEP40,
804 WLAN_CIPHER_SUITE_WEP104,
805 WLAN_CIPHER_SUITE_TKIP,
806 WLAN_CIPHER_SUITE_CCMP,
807};
808
809struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
810{
811 int ret = 0;
812 struct wireless_dev *wdev;
813
814 /*
815 * We're trying to have the following memory
816 * layout:
817 *
818 * +-------------------------+
819 * | struct wiphy |
820 * +-------------------------+
821 * | struct iwm_priv |
822 * +-------------------------+
823 * | bus private data |
824 * | (e.g. iwm_priv_sdio) |
825 * +-------------------------+
826 *
827 */
828
829 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
830 if (!wdev) {
831 dev_err(dev, "Couldn't allocate wireless device\n");
832 return ERR_PTR(-ENOMEM);
833 }
834
835 wdev->wiphy = wiphy_new(&iwm_cfg80211_ops,
836 sizeof(struct iwm_priv) + sizeof_bus);
837 if (!wdev->wiphy) {
838 dev_err(dev, "Couldn't allocate wiphy device\n");
839 ret = -ENOMEM;
840 goto out_err_new;
841 }
842
843 set_wiphy_dev(wdev->wiphy, dev);
844 wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX;
845 wdev->wiphy->max_num_pmkids = UMAC_MAX_NUM_PMKIDS;
846 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
847 BIT(NL80211_IFTYPE_ADHOC);
848 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz;
849 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
850 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
851
852 wdev->wiphy->cipher_suites = cipher_suites;
853 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
854
855 ret = wiphy_register(wdev->wiphy);
856 if (ret < 0) {
857 dev_err(dev, "Couldn't register wiphy device\n");
858 goto out_err_register;
859 }
860
861 return wdev;
862
863 out_err_register:
864 wiphy_free(wdev->wiphy);
865
866 out_err_new:
867 kfree(wdev);
868
869 return ERR_PTR(ret);
870}
871
872void iwm_wdev_free(struct iwm_priv *iwm)
873{
874 struct wireless_dev *wdev = iwm_to_wdev(iwm);
875
876 if (!wdev)
877 return;
878
879 wiphy_unregister(wdev->wiphy);
880 wiphy_free(wdev->wiphy);
881 kfree(wdev);
882}
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.h b/drivers/net/wireless/iwmc3200wifi/cfg80211.h
deleted file mode 100644
index 56a34145acbf..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.h
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5 * Samuel Ortiz <samuel.ortiz@intel.com>
6 * Zhu Yi <yi.zhu@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 */
23
24#ifndef __IWM_CFG80211_H__
25#define __IWM_CFG80211_H__
26
27int iwm_cfg80211_inform_bss(struct iwm_priv *iwm);
28struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev);
29void iwm_wdev_free(struct iwm_priv *iwm);
30
31#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
deleted file mode 100644
index bd75078c454b..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ /dev/null
@@ -1,1002 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#include <linux/kernel.h>
40#include <linux/wireless.h>
41#include <linux/etherdevice.h>
42#include <linux/ieee80211.h>
43#include <linux/sched.h>
44#include <linux/slab.h>
45#include <linux/moduleparam.h>
46
47#include "iwm.h"
48#include "bus.h"
49#include "hal.h"
50#include "umac.h"
51#include "commands.h"
52#include "debug.h"
53
54static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm,
55 u8 lmac_cmd_id,
56 const void *lmac_payload,
57 u16 lmac_payload_size,
58 u8 resp)
59{
60 struct iwm_udma_wifi_cmd udma_cmd = UDMA_LMAC_INIT;
61 struct iwm_umac_cmd umac_cmd;
62 struct iwm_lmac_cmd lmac_cmd;
63
64 lmac_cmd.id = lmac_cmd_id;
65
66 umac_cmd.id = UMAC_CMD_OPCODE_WIFI_PASS_THROUGH;
67 umac_cmd.resp = resp;
68
69 return iwm_hal_send_host_cmd(iwm, &udma_cmd, &umac_cmd, &lmac_cmd,
70 lmac_payload, lmac_payload_size);
71}
72
73int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
74 bool resp)
75{
76 struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload;
77 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
78 struct iwm_umac_cmd umac_cmd;
79 int ret;
80 u8 oid = hdr->oid;
81
82 if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
83 IWM_ERR(iwm, "Interface is not ready yet");
84 return -EAGAIN;
85 }
86
87 umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
88 umac_cmd.resp = resp;
89
90 ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
91 payload, payload_size);
92
93 if (resp) {
94 ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue,
95 test_and_clear_bit(oid, &iwm->wifi_ntfy[0]),
96 3 * HZ);
97
98 return ret ? 0 : -EBUSY;
99 }
100
101 return ret;
102}
103
104static int modparam_wiwi = COEX_MODE_CM;
105module_param_named(wiwi, modparam_wiwi, int, 0644);
106MODULE_PARM_DESC(wiwi, "Wifi-WiMAX coexistence: 1=SA, 2=XOR, 3=CM (default)");
107
108static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
109{
110 {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS},
111 {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
112 {4, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
113 {4, 3, 0, COEX_CALIBRATION_FLAGS},
114 {4, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
115 {4, 3, 0, COEX_CONNECTION_ESTAB_FLAGS},
116 {4, 3, 0, COEX_ASSOCIATED_IDLE_FLAGS},
117 {4, 3, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
118 {4, 3, 0, COEX_ASSOC_AUTO_SCAN_FLAGS},
119 {4, 3, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS},
120 {6, 3, 0, COEX_XOR_RF_ON_FLAGS},
121 {4, 3, 0, COEX_RF_OFF_FLAGS},
122 {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS},
123 {4, 3, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS},
124 {4, 3, 0, COEX_RSRVD1_FLAGS},
125 {4, 3, 0, COEX_RSRVD2_FLAGS}
126};
127
128static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] =
129{
130 {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS},
131 {4, 4, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
132 {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
133 {6, 6, 0, COEX_CALIBRATION_FLAGS},
134 {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
135 {6, 5, 0, COEX_CONNECTION_ESTAB_FLAGS},
136 {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS},
137 {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
138 {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS},
139 {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS},
140 {1, 1, 0, COEX_RF_ON_FLAGS},
141 {1, 1, 0, COEX_RF_OFF_FLAGS},
142 {7, 7, 0, COEX_STAND_ALONE_DEBUG_FLAGS},
143 {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS},
144 {1, 1, 0, COEX_RSRVD1_FLAGS},
145 {1, 1, 0, COEX_RSRVD2_FLAGS}
146};
147
148int iwm_send_prio_table(struct iwm_priv *iwm)
149{
150 struct iwm_coex_prio_table_cmd coex_table_cmd;
151 u32 coex_enabled, mode_enabled;
152
153 memset(&coex_table_cmd, 0, sizeof(struct iwm_coex_prio_table_cmd));
154
155 coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK;
156
157 switch (modparam_wiwi) {
158 case COEX_MODE_XOR:
159 case COEX_MODE_CM:
160 coex_enabled = 1;
161 break;
162 default:
163 coex_enabled = 0;
164 break;
165 }
166
167 switch (iwm->conf.mode) {
168 case UMAC_MODE_BSS:
169 case UMAC_MODE_IBSS:
170 mode_enabled = 1;
171 break;
172 default:
173 mode_enabled = 0;
174 break;
175 }
176
177 if (coex_enabled && mode_enabled) {
178 coex_table_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK |
179 COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK |
180 COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK;
181
182 switch (modparam_wiwi) {
183 case COEX_MODE_XOR:
184 memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl,
185 sizeof(iwm_sta_xor_prio_tbl));
186 break;
187 case COEX_MODE_CM:
188 memcpy(coex_table_cmd.sta_prio, iwm_sta_cm_prio_tbl,
189 sizeof(iwm_sta_cm_prio_tbl));
190 break;
191 default:
192 IWM_ERR(iwm, "Invalid coex_mode 0x%x\n",
193 modparam_wiwi);
194 break;
195 }
196 } else
197 IWM_WARN(iwm, "coexistense disabled\n");
198
199 return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD,
200 &coex_table_cmd,
201 sizeof(struct iwm_coex_prio_table_cmd), 0);
202}
203
204int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested)
205{
206 struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd;
207
208 memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd));
209
210 cal_cfg_cmd.ucode_cfg.init.enable = cpu_to_le32(calib_requested);
211 cal_cfg_cmd.ucode_cfg.init.start = cpu_to_le32(calib_requested);
212 cal_cfg_cmd.ucode_cfg.init.send_res = cpu_to_le32(calib_requested);
213 cal_cfg_cmd.ucode_cfg.flags =
214 cpu_to_le32(CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK);
215
216 return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd,
217 sizeof(struct iwm_lmac_cal_cfg_cmd), 1);
218}
219
220int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested)
221{
222 struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd;
223
224 memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd));
225
226 cal_cfg_cmd.ucode_cfg.periodic.enable = cpu_to_le32(calib_requested);
227 cal_cfg_cmd.ucode_cfg.periodic.start = cpu_to_le32(calib_requested);
228
229 return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd,
230 sizeof(struct iwm_lmac_cal_cfg_cmd), 0);
231}
232
233int iwm_store_rxiq_calib_result(struct iwm_priv *iwm)
234{
235 struct iwm_calib_rxiq *rxiq;
236 u8 *eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ);
237 int grplen = sizeof(struct iwm_calib_rxiq_group);
238
239 rxiq = kzalloc(sizeof(struct iwm_calib_rxiq), GFP_KERNEL);
240 if (!rxiq) {
241 IWM_ERR(iwm, "Couldn't alloc memory for RX IQ\n");
242 return -ENOMEM;
243 }
244
245 eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ);
246 if (IS_ERR(eeprom_rxiq)) {
247 IWM_ERR(iwm, "Couldn't access EEPROM RX IQ entry\n");
248 kfree(rxiq);
249 return PTR_ERR(eeprom_rxiq);
250 }
251
252 iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].buf = (u8 *)rxiq;
253 iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].size = sizeof(*rxiq);
254
255 rxiq->hdr.opcode = SHILOH_PHY_CALIBRATE_RX_IQ_CMD;
256 rxiq->hdr.first_grp = 0;
257 rxiq->hdr.grp_num = 1;
258 rxiq->hdr.all_data_valid = 1;
259
260 memcpy(&rxiq->group[0], eeprom_rxiq, 4 * grplen);
261 memcpy(&rxiq->group[4], eeprom_rxiq + 6 * grplen, grplen);
262
263 return 0;
264}
265
266int iwm_send_calib_results(struct iwm_priv *iwm)
267{
268 int i, ret = 0;
269
270 for (i = PHY_CALIBRATE_OPCODES_NUM; i < CALIBRATION_CMD_NUM; i++) {
271 if (test_bit(i - PHY_CALIBRATE_OPCODES_NUM,
272 &iwm->calib_done_map)) {
273 IWM_DBG_CMD(iwm, DBG,
274 "Send calibration %d result\n", i);
275 ret |= iwm_send_lmac_ptrough_cmd(iwm,
276 REPLY_PHY_CALIBRATION_CMD,
277 iwm->calib_res[i].buf,
278 iwm->calib_res[i].size, 0);
279
280 kfree(iwm->calib_res[i].buf);
281 iwm->calib_res[i].buf = NULL;
282 iwm->calib_res[i].size = 0;
283 }
284 }
285
286 return ret;
287}
288
289int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit)
290{
291 struct iwm_ct_kill_cfg_cmd cmd;
292
293 cmd.entry_threshold = entry;
294 cmd.exit_threshold = exit;
295
296 return iwm_send_lmac_ptrough_cmd(iwm, REPLY_CT_KILL_CONFIG_CMD, &cmd,
297 sizeof(struct iwm_ct_kill_cfg_cmd), 0);
298}
299
300int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp)
301{
302 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
303 struct iwm_umac_cmd umac_cmd;
304 struct iwm_umac_cmd_reset reset;
305
306 reset.flags = reset_flags;
307
308 umac_cmd.id = UMAC_CMD_OPCODE_RESET;
309 umac_cmd.resp = resp;
310
311 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &reset,
312 sizeof(struct iwm_umac_cmd_reset));
313}
314
315int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value)
316{
317 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
318 struct iwm_umac_cmd umac_cmd;
319 struct iwm_umac_cmd_set_param_fix param;
320
321 if ((tbl != UMAC_PARAM_TBL_CFG_FIX) &&
322 (tbl != UMAC_PARAM_TBL_FA_CFG_FIX))
323 return -EINVAL;
324
325 umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_FIX;
326 umac_cmd.resp = 0;
327
328 param.tbl = cpu_to_le16(tbl);
329 param.key = cpu_to_le16(key);
330 param.value = cpu_to_le32(value);
331
332 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &param,
333 sizeof(struct iwm_umac_cmd_set_param_fix));
334}
335
336int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
337 void *payload, u16 payload_size)
338{
339 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
340 struct iwm_umac_cmd umac_cmd;
341 struct iwm_umac_cmd_set_param_var *param_hdr;
342 u8 *param;
343 int ret;
344
345 param = kzalloc(payload_size +
346 sizeof(struct iwm_umac_cmd_set_param_var), GFP_KERNEL);
347 if (!param) {
348 IWM_ERR(iwm, "Couldn't allocate param\n");
349 return -ENOMEM;
350 }
351
352 param_hdr = (struct iwm_umac_cmd_set_param_var *)param;
353
354 umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_VAR;
355 umac_cmd.resp = 0;
356
357 param_hdr->tbl = cpu_to_le16(UMAC_PARAM_TBL_CFG_VAR);
358 param_hdr->key = cpu_to_le16(key);
359 param_hdr->len = cpu_to_le16(payload_size);
360 memcpy(param + sizeof(struct iwm_umac_cmd_set_param_var),
361 payload, payload_size);
362
363 ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, param,
364 sizeof(struct iwm_umac_cmd_set_param_var) +
365 payload_size);
366 kfree(param);
367
368 return ret;
369}
370
371int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags)
372{
373 int ret;
374
375 /* Use UMAC default values */
376 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
377 CFG_POWER_INDEX, iwm->conf.power_index);
378 if (ret < 0)
379 return ret;
380
381 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX,
382 CFG_FRAG_THRESHOLD,
383 iwm->conf.frag_threshold);
384 if (ret < 0)
385 return ret;
386
387 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
388 CFG_RTS_THRESHOLD,
389 iwm->conf.rts_threshold);
390 if (ret < 0)
391 return ret;
392
393 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
394 CFG_CTS_TO_SELF, iwm->conf.cts_to_self);
395 if (ret < 0)
396 return ret;
397
398 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
399 CFG_WIRELESS_MODE,
400 iwm->conf.wireless_mode);
401 if (ret < 0)
402 return ret;
403
404 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
405 CFG_COEX_MODE, modparam_wiwi);
406 if (ret < 0)
407 return ret;
408
409 /*
410 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
411 CFG_ASSOCIATION_TIMEOUT,
412 iwm->conf.assoc_timeout);
413 if (ret < 0)
414 return ret;
415
416 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
417 CFG_ROAM_TIMEOUT,
418 iwm->conf.roam_timeout);
419 if (ret < 0)
420 return ret;
421
422 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
423 CFG_WIRELESS_MODE,
424 WIRELESS_MODE_11A | WIRELESS_MODE_11G);
425 if (ret < 0)
426 return ret;
427 */
428
429 ret = iwm_umac_set_config_var(iwm, CFG_NET_ADDR,
430 iwm_to_ndev(iwm)->dev_addr, ETH_ALEN);
431 if (ret < 0)
432 return ret;
433
434 /* UMAC PM static configurations */
435 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
436 CFG_PM_LEGACY_RX_TIMEOUT, 0x12C);
437 if (ret < 0)
438 return ret;
439
440 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
441 CFG_PM_LEGACY_TX_TIMEOUT, 0x15E);
442 if (ret < 0)
443 return ret;
444
445 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
446 CFG_PM_CTRL_FLAGS, 0x1);
447 if (ret < 0)
448 return ret;
449
450 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
451 CFG_PM_KEEP_ALIVE_IN_BEACONS, 0x80);
452 if (ret < 0)
453 return ret;
454
455 /* reset UMAC */
456 ret = iwm_send_umac_reset(iwm, reset_flags, 1);
457 if (ret < 0)
458 return ret;
459
460 ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC,
461 WAIT_NOTIF_TIMEOUT);
462 if (ret) {
463 IWM_ERR(iwm, "Wait for UMAC RESET timeout\n");
464 return ret;
465 }
466
467 return ret;
468}
469
470int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id)
471{
472 struct iwm_udma_wifi_cmd udma_cmd;
473 struct iwm_umac_cmd umac_cmd;
474 struct iwm_tx_info *tx_info = skb_to_tx_info(skb);
475
476 udma_cmd.eop = 1; /* always set eop for non-concatenated Tx */
477 udma_cmd.credit_group = pool_id;
478 udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid;
479 udma_cmd.lmac_offset = 0;
480
481 umac_cmd.id = REPLY_TX;
482 umac_cmd.color = tx_info->color;
483 umac_cmd.resp = 0;
484
485 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
486 skb->data, skb->len);
487}
488
489static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
490 u8 *response, u32 resp_size)
491{
492 struct iwm_udma_nonwifi_cmd target_cmd;
493 struct iwm_nonwifi_cmd *cmd;
494 u16 seq_num;
495 int ret = 0;
496
497 target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ;
498 target_cmd.addr = address;
499 target_cmd.op1_sz = cpu_to_le32(resp_size);
500 target_cmd.op2 = 0;
501 target_cmd.handle_by_hw = 0;
502 target_cmd.resp = 1;
503 target_cmd.eop = 1;
504
505 ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
506 if (ret < 0) {
507 IWM_ERR(iwm, "Couldn't send READ command\n");
508 return ret;
509 }
510
511 /* When succeeding, the send_target routine returns the seq number */
512 seq_num = ret;
513
514 ret = wait_event_interruptible_timeout(iwm->nonwifi_queue,
515 (cmd = iwm_get_pending_nonwifi_cmd(iwm, seq_num,
516 UMAC_HDI_OUT_OPCODE_READ)) != NULL,
517 2 * HZ);
518
519 if (!ret) {
520 IWM_ERR(iwm, "Didn't receive a target READ answer\n");
521 return ret;
522 }
523
524 memcpy(response, cmd->buf.hdr + sizeof(struct iwm_udma_in_hdr),
525 resp_size);
526
527 kfree(cmd);
528
529 return 0;
530}
531
532int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
533{
534 int ret;
535 u8 mac_align[ALIGN(ETH_ALEN, 8)];
536
537 ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR),
538 mac_align, sizeof(mac_align));
539 if (ret)
540 return ret;
541
542 if (is_valid_ether_addr(mac_align))
543 memcpy(mac, mac_align, ETH_ALEN);
544 else {
545 IWM_ERR(iwm, "Invalid EEPROM MAC\n");
546 memcpy(mac, iwm->conf.mac_addr, ETH_ALEN);
547 get_random_bytes(&mac[3], 3);
548 }
549
550 return 0;
551}
552
553static int iwm_check_profile(struct iwm_priv *iwm)
554{
555 if (!iwm->umac_profile_active)
556 return -EAGAIN;
557
558 if (iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 &&
559 iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104 &&
560 iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_TKIP &&
561 iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_CCMP) {
562 IWM_ERR(iwm, "Wrong unicast cipher: 0x%x\n",
563 iwm->umac_profile->sec.ucast_cipher);
564 return -EAGAIN;
565 }
566
567 if (iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_40 &&
568 iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_104 &&
569 iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_TKIP &&
570 iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_CCMP) {
571 IWM_ERR(iwm, "Wrong multicast cipher: 0x%x\n",
572 iwm->umac_profile->sec.mcast_cipher);
573 return -EAGAIN;
574 }
575
576 if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 ||
577 iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) &&
578 (iwm->umac_profile->sec.ucast_cipher !=
579 iwm->umac_profile->sec.mcast_cipher)) {
580 IWM_ERR(iwm, "Unicast and multicast ciphers differ for WEP\n");
581 }
582
583 return 0;
584}
585
586int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
587{
588 struct iwm_umac_tx_key_id tx_key_id;
589 int ret;
590
591 ret = iwm_check_profile(iwm);
592 if (ret < 0)
593 return ret;
594
595 /* UMAC only allows to set default key for WEP and auth type is
596 * NOT 802.1X or RSNA. */
597 if ((iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 &&
598 iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104) ||
599 iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_8021X ||
600 iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_RSNA_PSK)
601 return 0;
602
603 tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
604 tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
605 sizeof(struct iwm_umac_wifi_if));
606
607 tx_key_id.key_idx = key_idx;
608
609 return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1);
610}
611
612int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
613{
614 int ret = 0;
615 u8 cmd[64], *sta_addr, *key_data, key_len;
616 s8 key_idx;
617 u16 cmd_size = 0;
618 struct iwm_umac_key_hdr *key_hdr = &key->hdr;
619 struct iwm_umac_key_wep40 *wep40 = (struct iwm_umac_key_wep40 *)cmd;
620 struct iwm_umac_key_wep104 *wep104 = (struct iwm_umac_key_wep104 *)cmd;
621 struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
622 struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;
623
624 if (!remove) {
625 ret = iwm_check_profile(iwm);
626 if (ret < 0)
627 return ret;
628 }
629
630 sta_addr = key->hdr.mac;
631 key_data = key->key;
632 key_len = key->key_len;
633 key_idx = key->hdr.key_idx;
634
635 if (!remove) {
636 u8 auth_type = iwm->umac_profile->sec.auth_type;
637
638 IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx);
639 IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len);
640 IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n",
641 key_hdr->mac, key_hdr->key_idx, key_hdr->multicast);
642
643 IWM_DBG_WEXT(iwm, DBG, "profile: mcast:0x%x, ucast:0x%x\n",
644 iwm->umac_profile->sec.mcast_cipher,
645 iwm->umac_profile->sec.ucast_cipher);
646 IWM_DBG_WEXT(iwm, DBG, "profile: auth_type:0x%x, flags:0x%x\n",
647 iwm->umac_profile->sec.auth_type,
648 iwm->umac_profile->sec.flags);
649
650 switch (key->cipher) {
651 case WLAN_CIPHER_SUITE_WEP40:
652 wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY;
653 wep40->hdr.buf_size =
654 cpu_to_le16(sizeof(struct iwm_umac_key_wep40) -
655 sizeof(struct iwm_umac_wifi_if));
656
657 memcpy(&wep40->key_hdr, key_hdr,
658 sizeof(struct iwm_umac_key_hdr));
659 memcpy(wep40->key, key_data, key_len);
660 wep40->static_key =
661 !!((auth_type != UMAC_AUTH_TYPE_8021X) &&
662 (auth_type != UMAC_AUTH_TYPE_RSNA_PSK));
663
664 cmd_size = sizeof(struct iwm_umac_key_wep40);
665 break;
666
667 case WLAN_CIPHER_SUITE_WEP104:
668 wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY;
669 wep104->hdr.buf_size =
670 cpu_to_le16(sizeof(struct iwm_umac_key_wep104) -
671 sizeof(struct iwm_umac_wifi_if));
672
673 memcpy(&wep104->key_hdr, key_hdr,
674 sizeof(struct iwm_umac_key_hdr));
675 memcpy(wep104->key, key_data, key_len);
676 wep104->static_key =
677 !!((auth_type != UMAC_AUTH_TYPE_8021X) &&
678 (auth_type != UMAC_AUTH_TYPE_RSNA_PSK));
679
680 cmd_size = sizeof(struct iwm_umac_key_wep104);
681 break;
682
683 case WLAN_CIPHER_SUITE_CCMP:
684 key_hdr->key_idx++;
685 ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY;
686 ccmp->hdr.buf_size =
687 cpu_to_le16(sizeof(struct iwm_umac_key_ccmp) -
688 sizeof(struct iwm_umac_wifi_if));
689
690 memcpy(&ccmp->key_hdr, key_hdr,
691 sizeof(struct iwm_umac_key_hdr));
692
693 memcpy(ccmp->key, key_data, key_len);
694
695 if (key->seq_len)
696 memcpy(ccmp->iv_count, key->seq, key->seq_len);
697
698 cmd_size = sizeof(struct iwm_umac_key_ccmp);
699 break;
700
701 case WLAN_CIPHER_SUITE_TKIP:
702 key_hdr->key_idx++;
703 tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY;
704 tkip->hdr.buf_size =
705 cpu_to_le16(sizeof(struct iwm_umac_key_tkip) -
706 sizeof(struct iwm_umac_wifi_if));
707
708 memcpy(&tkip->key_hdr, key_hdr,
709 sizeof(struct iwm_umac_key_hdr));
710
711 memcpy(tkip->tkip_key, key_data, IWM_TKIP_KEY_SIZE);
712 memcpy(tkip->mic_tx_key, key_data + IWM_TKIP_KEY_SIZE,
713 IWM_TKIP_MIC_SIZE);
714 memcpy(tkip->mic_rx_key,
715 key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE,
716 IWM_TKIP_MIC_SIZE);
717
718 if (key->seq_len)
719 memcpy(ccmp->iv_count, key->seq, key->seq_len);
720
721 cmd_size = sizeof(struct iwm_umac_key_tkip);
722 break;
723
724 default:
725 return -ENOTSUPP;
726 }
727
728 if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) ||
729 (key->cipher == WLAN_CIPHER_SUITE_CCMP))
730 /*
731 * UGLY_UGLY_UGLY
732 * Copied HACK from the MWG driver.
733 * Without it, the key is set before the second
734 * EAPOL frame is sent, and the latter is thus
735 * encrypted.
736 */
737 schedule_timeout_interruptible(usecs_to_jiffies(300));
738
739 ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1);
740 } else {
741 struct iwm_umac_key_remove key_remove;
742
743 IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx);
744
745 key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY;
746 key_remove.hdr.buf_size =
747 cpu_to_le16(sizeof(struct iwm_umac_key_remove) -
748 sizeof(struct iwm_umac_wifi_if));
749 memcpy(&key_remove.key_hdr, key_hdr,
750 sizeof(struct iwm_umac_key_hdr));
751
752 ret = iwm_send_wifi_if_cmd(iwm, &key_remove,
753 sizeof(struct iwm_umac_key_remove),
754 1);
755 if (ret)
756 return ret;
757
758 iwm->keys[key_idx].key_len = 0;
759 }
760
761 return ret;
762}
763
764
765int iwm_send_mlme_profile(struct iwm_priv *iwm)
766{
767 int ret;
768 struct iwm_umac_profile profile;
769
770 memcpy(&profile, iwm->umac_profile, sizeof(profile));
771
772 profile.hdr.oid = UMAC_WIFI_IF_CMD_SET_PROFILE;
773 profile.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_profile) -
774 sizeof(struct iwm_umac_wifi_if));
775
776 ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1);
777 if (ret) {
778 IWM_ERR(iwm, "Send profile command failed\n");
779 return ret;
780 }
781
782 set_bit(IWM_STATUS_SME_CONNECTING, &iwm->status);
783 return 0;
784}
785
786int __iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
787{
788 struct iwm_umac_invalidate_profile invalid;
789
790 invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE;
791 invalid.hdr.buf_size =
792 cpu_to_le16(sizeof(struct iwm_umac_invalidate_profile) -
793 sizeof(struct iwm_umac_wifi_if));
794
795 invalid.reason = WLAN_REASON_UNSPECIFIED;
796
797 return iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
798}
799
800int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
801{
802 int ret;
803
804 ret = __iwm_invalidate_mlme_profile(iwm);
805 if (ret)
806 return ret;
807
808 ret = wait_event_interruptible_timeout(iwm->mlme_queue,
809 (iwm->umac_profile_active == 0), 5 * HZ);
810
811 return ret ? 0 : -EBUSY;
812}
813
814int iwm_tx_power_trigger(struct iwm_priv *iwm)
815{
816 struct iwm_umac_pwr_trigger pwr_trigger;
817
818 pwr_trigger.hdr.oid = UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER;
819 pwr_trigger.hdr.buf_size =
820 cpu_to_le16(sizeof(struct iwm_umac_pwr_trigger) -
821 sizeof(struct iwm_umac_wifi_if));
822
823
824 return iwm_send_wifi_if_cmd(iwm, &pwr_trigger, sizeof(pwr_trigger), 1);
825}
826
827int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
828{
829 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
830 struct iwm_umac_cmd umac_cmd;
831 struct iwm_umac_cmd_stats_req stats_req;
832
833 stats_req.flags = cpu_to_le32(flags);
834
835 umac_cmd.id = UMAC_CMD_OPCODE_STATISTIC_REQUEST;
836 umac_cmd.resp = 0;
837
838 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stats_req,
839 sizeof(struct iwm_umac_cmd_stats_req));
840}
841
842int iwm_send_umac_channel_list(struct iwm_priv *iwm)
843{
844 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
845 struct iwm_umac_cmd umac_cmd;
846 struct iwm_umac_cmd_get_channel_list *ch_list;
847 int size = sizeof(struct iwm_umac_cmd_get_channel_list) +
848 sizeof(struct iwm_umac_channel_info) * 4;
849 int ret;
850
851 ch_list = kzalloc(size, GFP_KERNEL);
852 if (!ch_list) {
853 IWM_ERR(iwm, "Couldn't allocate channel list cmd\n");
854 return -ENOMEM;
855 }
856
857 ch_list->ch[0].band = UMAC_BAND_2GHZ;
858 ch_list->ch[0].type = UMAC_CHANNEL_WIDTH_20MHZ;
859 ch_list->ch[0].flags = UMAC_CHANNEL_FLAG_VALID;
860
861 ch_list->ch[1].band = UMAC_BAND_5GHZ;
862 ch_list->ch[1].type = UMAC_CHANNEL_WIDTH_20MHZ;
863 ch_list->ch[1].flags = UMAC_CHANNEL_FLAG_VALID;
864
865 ch_list->ch[2].band = UMAC_BAND_2GHZ;
866 ch_list->ch[2].type = UMAC_CHANNEL_WIDTH_20MHZ;
867 ch_list->ch[2].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS;
868
869 ch_list->ch[3].band = UMAC_BAND_5GHZ;
870 ch_list->ch[3].type = UMAC_CHANNEL_WIDTH_20MHZ;
871 ch_list->ch[3].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS;
872
873 ch_list->count = cpu_to_le16(4);
874
875 umac_cmd.id = UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST;
876 umac_cmd.resp = 1;
877
878 ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ch_list, size);
879
880 kfree(ch_list);
881
882 return ret;
883}
884
885int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
886 int ssid_num)
887{
888 struct iwm_umac_cmd_scan_request req;
889 int i, ret;
890
891 memset(&req, 0, sizeof(struct iwm_umac_cmd_scan_request));
892
893 req.hdr.oid = UMAC_WIFI_IF_CMD_SCAN_REQUEST;
894 req.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_cmd_scan_request)
895 - sizeof(struct iwm_umac_wifi_if));
896 req.type = UMAC_WIFI_IF_SCAN_TYPE_USER;
897 req.timeout = 2;
898 req.seq_num = iwm->scan_id;
899 req.ssid_num = min(ssid_num, UMAC_WIFI_IF_PROBE_OPTION_MAX);
900
901 for (i = 0; i < req.ssid_num; i++) {
902 memcpy(req.ssids[i].ssid, ssids[i].ssid, ssids[i].ssid_len);
903 req.ssids[i].ssid_len = ssids[i].ssid_len;
904 }
905
906 ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0);
907 if (ret) {
908 IWM_ERR(iwm, "Couldn't send scan request\n");
909 return ret;
910 }
911
912 iwm->scan_id = (iwm->scan_id + 1) % IWM_SCAN_ID_MAX;
913
914 return 0;
915}
916
917int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len)
918{
919 struct cfg80211_ssid one_ssid;
920
921 if (test_and_set_bit(IWM_STATUS_SCANNING, &iwm->status))
922 return 0;
923
924 one_ssid.ssid_len = min(ssid_len, IEEE80211_MAX_SSID_LEN);
925 memcpy(&one_ssid.ssid, ssid, one_ssid.ssid_len);
926
927 return iwm_scan_ssids(iwm, &one_ssid, 1);
928}
929
930int iwm_target_reset(struct iwm_priv *iwm)
931{
932 struct iwm_udma_nonwifi_cmd target_cmd;
933
934 target_cmd.opcode = UMAC_HDI_OUT_OPCODE_REBOOT;
935 target_cmd.addr = 0;
936 target_cmd.op1_sz = 0;
937 target_cmd.op2 = 0;
938 target_cmd.handle_by_hw = 0;
939 target_cmd.resp = 0;
940 target_cmd.eop = 1;
941
942 return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
943}
944
945int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm,
946 struct iwm_umac_notif_stop_resume_tx *ntf)
947{
948 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
949 struct iwm_umac_cmd umac_cmd;
950 struct iwm_umac_cmd_stop_resume_tx stp_res_cmd;
951 struct iwm_sta_info *sta_info;
952 u8 sta_id = STA_ID_N_COLOR_ID(ntf->sta_id);
953 int i;
954
955 sta_info = &iwm->sta_table[sta_id];
956 if (!sta_info->valid) {
957 IWM_ERR(iwm, "Invalid STA: %d\n", sta_id);
958 return -EINVAL;
959 }
960
961 umac_cmd.id = UMAC_CMD_OPCODE_STOP_RESUME_STA_TX;
962 umac_cmd.resp = 0;
963
964 stp_res_cmd.flags = ntf->flags;
965 stp_res_cmd.sta_id = ntf->sta_id;
966 stp_res_cmd.stop_resume_tid_msk = ntf->stop_resume_tid_msk;
967 for (i = 0; i < IWM_UMAC_TID_NR; i++)
968 stp_res_cmd.last_seq_num[i] =
969 sta_info->tid_info[i].last_seq_num;
970
971 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stp_res_cmd,
972 sizeof(struct iwm_umac_cmd_stop_resume_tx));
973
974}
975
976int iwm_send_pmkid_update(struct iwm_priv *iwm,
977 struct cfg80211_pmksa *pmksa, u32 command)
978{
979 struct iwm_umac_pmkid_update update;
980 int ret;
981
982 memset(&update, 0, sizeof(struct iwm_umac_pmkid_update));
983
984 update.hdr.oid = UMAC_WIFI_IF_CMD_PMKID_UPDATE;
985 update.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_pmkid_update) -
986 sizeof(struct iwm_umac_wifi_if));
987
988 update.command = cpu_to_le32(command);
989 if (pmksa->bssid)
990 memcpy(&update.bssid, pmksa->bssid, ETH_ALEN);
991 if (pmksa->pmkid)
992 memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
993
994 ret = iwm_send_wifi_if_cmd(iwm, &update,
995 sizeof(struct iwm_umac_pmkid_update), 0);
996 if (ret) {
997 IWM_ERR(iwm, "PMKID update command failed\n");
998 return ret;
999 }
1000
1001 return 0;
1002}
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
deleted file mode 100644
index 6421689f5e8e..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ /dev/null
@@ -1,509 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#ifndef __IWM_COMMANDS_H__
40#define __IWM_COMMANDS_H__
41
42#include <linux/ieee80211.h>
43
44#define IWM_BARKER_REBOOT_NOTIFICATION 0xF
45#define IWM_ACK_BARKER_NOTIFICATION 0x10
46
47/* UMAC commands */
48#define UMAC_RST_CTRL_FLG_LARC_CLK_EN 0x0001
49#define UMAC_RST_CTRL_FLG_LARC_RESET 0x0002
50#define UMAC_RST_CTRL_FLG_FUNC_RESET 0x0004
51#define UMAC_RST_CTRL_FLG_DEV_RESET 0x0008
52#define UMAC_RST_CTRL_FLG_WIFI_CORE_EN 0x0010
53#define UMAC_RST_CTRL_FLG_WIFI_LINK_EN 0x0040
54#define UMAC_RST_CTRL_FLG_WIFI_MLME_EN 0x0080
55#define UMAC_RST_CTRL_FLG_NVM_RELOAD 0x0100
56
57struct iwm_umac_cmd_reset {
58 __le32 flags;
59} __packed;
60
61#define UMAC_PARAM_TBL_ORD_FIX 0x0
62#define UMAC_PARAM_TBL_ORD_VAR 0x1
63#define UMAC_PARAM_TBL_CFG_FIX 0x2
64#define UMAC_PARAM_TBL_CFG_VAR 0x3
65#define UMAC_PARAM_TBL_BSS_TRK 0x4
66#define UMAC_PARAM_TBL_FA_CFG_FIX 0x5
67#define UMAC_PARAM_TBL_STA 0x6
68#define UMAC_PARAM_TBL_CHN 0x7
69#define UMAC_PARAM_TBL_STATISTICS 0x8
70
71/* fast access table */
72enum {
73 CFG_FRAG_THRESHOLD = 0,
74 CFG_FRAME_RETRY_LIMIT,
75 CFG_OS_QUEUE_UTIL_TH,
76 CFG_RX_FILTER,
77 /* <-- LAST --> */
78 FAST_ACCESS_CFG_TBL_FIX_LAST
79};
80
81/* fixed size table */
82enum {
83 CFG_POWER_INDEX = 0,
84 CFG_PM_LEGACY_RX_TIMEOUT,
85 CFG_PM_LEGACY_TX_TIMEOUT,
86 CFG_PM_CTRL_FLAGS,
87 CFG_PM_KEEP_ALIVE_IN_BEACONS,
88 CFG_BT_ON_THRESHOLD,
89 CFG_RTS_THRESHOLD,
90 CFG_CTS_TO_SELF,
91 CFG_COEX_MODE,
92 CFG_WIRELESS_MODE,
93 CFG_ASSOCIATION_TIMEOUT,
94 CFG_ROAM_TIMEOUT,
95 CFG_CAPABILITY_SUPPORTED_RATES,
96 CFG_SCAN_ALLOWED_UNASSOC_FLAGS,
97 CFG_SCAN_ALLOWED_MAIN_ASSOC_FLAGS,
98 CFG_SCAN_ALLOWED_PAN_ASSOC_FLAGS,
99 CFG_SCAN_INTERNAL_PERIODIC_ENABLED,
100 CFG_SCAN_IMM_INTERNAL_PERIODIC_SCAN_ON_INIT,
101 CFG_SCAN_DEFAULT_PERIODIC_FREQ_SEC,
102 CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN,
103 CFG_TLC_SUPPORTED_TX_HT_RATES,
104 CFG_TLC_SUPPORTED_TX_RATES,
105 CFG_TLC_SPATIAL_STREAM_SUPPORTED,
106 CFG_TLC_RETRY_PER_RATE,
107 CFG_TLC_RETRY_PER_HT_RATE,
108 CFG_TLC_FIXED_MCS,
109 CFG_TLC_CONTROL_FLAGS,
110 CFG_TLC_SR_MIN_FAIL,
111 CFG_TLC_SR_MIN_PASS,
112 CFG_TLC_HT_STAY_IN_COL_PASS_THRESH,
113 CFG_TLC_HT_STAY_IN_COL_FAIL_THRESH,
114 CFG_TLC_LEGACY_STAY_IN_COL_PASS_THRESH,
115 CFG_TLC_LEGACY_STAY_IN_COL_FAIL_THRESH,
116 CFG_TLC_HT_FLUSH_STATS_PACKETS,
117 CFG_TLC_LEGACY_FLUSH_STATS_PACKETS,
118 CFG_TLC_LEGACY_FLUSH_STATS_MS,
119 CFG_TLC_HT_FLUSH_STATS_MS,
120 CFG_TLC_STAY_IN_COL_TIME_OUT,
121 CFG_TLC_AGG_SHORT_LIM,
122 CFG_TLC_AGG_LONG_LIM,
123 CFG_TLC_HT_SR_NO_DECREASE,
124 CFG_TLC_LEGACY_SR_NO_DECREASE,
125 CFG_TLC_SR_FORCE_DECREASE,
126 CFG_TLC_SR_ALLOW_INCREASE,
127 CFG_TLC_AGG_SET_LONG,
128 CFG_TLC_AUTO_AGGREGATION,
129 CFG_TLC_AGG_THRESHOLD,
130 CFG_TLC_TID_LOAD_THRESHOLD,
131 CFG_TLC_BLOCK_ACK_TIMEOUT,
132 CFG_TLC_NO_BA_COUNTED_AS_ONE,
133 CFG_TLC_NUM_BA_STREAMS_ALLOWED,
134 CFG_TLC_NUM_BA_STREAMS_PRESENT,
135 CFG_TLC_RENEW_ADDBA_DELAY,
136 CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD,
137 CFG_TLC_IS_STABLE_IN_HT,
138 CFG_TLC_SR_SIC_1ST_FAIL,
139 CFG_TLC_SR_SIC_1ST_PASS,
140 CFG_TLC_SR_SIC_TOTAL_FAIL,
141 CFG_TLC_SR_SIC_TOTAL_PASS,
142 CFG_RLC_CHAIN_CTRL,
143 CFG_TRK_TABLE_OP_MODE,
144 CFG_TRK_TABLE_RSSI_THRESHOLD,
145 CFG_TX_PWR_TARGET, /* Used By xVT */
146 CFG_TX_PWR_LIMIT_USR,
147 CFG_TX_PWR_LIMIT_BSS, /* 11d limit */
148 CFG_TX_PWR_LIMIT_BSS_CONSTRAINT, /* 11h constraint */
149 CFG_TX_PWR_MODE,
150 CFG_MLME_DBG_NOTIF_BLOCK,
151 CFG_BT_OFF_BECONS_INTERVALS,
152 CFG_BT_FRAG_DURATION,
153 CFG_ACTIVE_CHAINS,
154 CFG_CALIB_CTRL,
155 CFG_CAPABILITY_SUPPORTED_HT_RATES,
156 CFG_HT_MAC_PARAM_INFO,
157 CFG_MIMO_PS_MODE,
158 CFG_HT_DEFAULT_CAPABILIES_INFO,
159 CFG_LED_SC_RESOLUTION_FACTOR,
160 CFG_PTAM_ENERGY_CCK_DET_DEFAULT,
161 CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_DEFAULT,
162 CFG_PTAM_CORR40_4_TH_ADD_MIN_DEFAULT,
163 CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_DEFAULT,
164 CFG_PTAM_CORR32_4_TH_ADD_MIN_DEFAULT,
165 CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_DEFAULT,
166 CFG_PTAM_CORR32_1_TH_ADD_MIN_DEFAULT,
167 CFG_PTAM_ENERGY_CCK_DET_MIN_VAL,
168 CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MIN_VAL,
169 CFG_PTAM_CORR40_4_TH_ADD_MIN_MIN_VAL,
170 CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MIN_VAL,
171 CFG_PTAM_CORR32_4_TH_ADD_MIN_MIN_VAL,
172 CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MIN_VAL,
173 CFG_PTAM_CORR32_1_TH_ADD_MIN_MIN_VAL,
174 CFG_PTAM_ENERGY_CCK_DET_MAX_VAL,
175 CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MAX_VAL,
176 CFG_PTAM_CORR40_4_TH_ADD_MIN_MAX_VAL,
177 CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MAX_VAL,
178 CFG_PTAM_CORR32_4_TH_ADD_MIN_MAX_VAL,
179 CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MAX_VAL,
180 CFG_PTAM_CORR32_1_TH_ADD_MIN_MAX_VAL,
181 CFG_PTAM_ENERGY_CCK_DET_STEP_VAL,
182 CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_STEP_VAL,
183 CFG_PTAM_CORR40_4_TH_ADD_MIN_STEP_VAL,
184 CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_STEP_VAL,
185 CFG_PTAM_CORR32_4_TH_ADD_MIN_STEP_VAL,
186 CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_STEP_VAL,
187 CFG_PTAM_CORR32_1_TH_ADD_MIN_STEP_VAL,
188 CFG_PTAM_LINK_SENS_FA_OFDM_MAX,
189 CFG_PTAM_LINK_SENS_FA_OFDM_MIN,
190 CFG_PTAM_LINK_SENS_FA_CCK_MAX,
191 CFG_PTAM_LINK_SENS_FA_CCK_MIN,
192 CFG_PTAM_LINK_SENS_NRG_DIFF,
193 CFG_PTAM_LINK_SENS_NRG_MARGIN,
194 CFG_PTAM_LINK_SENS_MAX_NUMBER_OF_TIMES_IN_CCK_NO_FA,
195 CFG_PTAM_LINK_SENS_AUTO_CORR_MAX_TH_CCK,
196 CFG_AGG_MGG_TID_LOAD_ADDBA_THRESHOLD,
197 CFG_AGG_MGG_TID_LOAD_DELBA_THRESHOLD,
198 CFG_AGG_MGG_ADDBA_BUF_SIZE,
199 CFG_AGG_MGG_ADDBA_INACTIVE_TIMEOUT,
200 CFG_AGG_MGG_ADDBA_DEBUG_FLAGS,
201 CFG_SCAN_PERIODIC_RSSI_HIGH_THRESHOLD,
202 CFG_SCAN_PERIODIC_COEF_RSSI_HIGH,
203 CFG_11D_ENABLED,
204 CFG_11H_FEATURE_FLAGS,
205
206 /* <-- LAST --> */
207 CFG_TBL_FIX_LAST
208};
209
210/* variable size table */
211enum {
212 CFG_NET_ADDR = 0,
213 CFG_LED_PATTERN_TABLE,
214
215 /* <-- LAST --> */
216 CFG_TBL_VAR_LAST
217};
218
219struct iwm_umac_cmd_set_param_fix {
220 __le16 tbl;
221 __le16 key;
222 __le32 value;
223} __packed;
224
225struct iwm_umac_cmd_set_param_var {
226 __le16 tbl;
227 __le16 key;
228 __le16 len;
229 __le16 reserved;
230} __packed;
231
232struct iwm_umac_cmd_get_param {
233 __le16 tbl;
234 __le16 key;
235} __packed;
236
237struct iwm_umac_cmd_get_param_resp {
238 __le16 tbl;
239 __le16 key;
240 __le16 len;
241 __le16 reserved;
242} __packed;
243
244struct iwm_umac_cmd_eeprom_proxy_hdr {
245 __le32 type;
246 __le32 offset;
247 __le32 len;
248} __packed;
249
250struct iwm_umac_cmd_eeprom_proxy {
251 struct iwm_umac_cmd_eeprom_proxy_hdr hdr;
252 u8 buf[0];
253} __packed;
254
255#define IWM_UMAC_CMD_EEPROM_TYPE_READ 0x1
256#define IWM_UMAC_CMD_EEPROM_TYPE_WRITE 0x2
257
258#define UMAC_CHANNEL_FLAG_VALID BIT(0)
259#define UMAC_CHANNEL_FLAG_IBSS BIT(1)
260#define UMAC_CHANNEL_FLAG_ACTIVE BIT(3)
261#define UMAC_CHANNEL_FLAG_RADAR BIT(4)
262#define UMAC_CHANNEL_FLAG_DFS BIT(7)
263
264struct iwm_umac_channel_info {
265 u8 band;
266 u8 type;
267 u8 reserved;
268 u8 flags;
269 __le32 channels_mask;
270} __packed;
271
272struct iwm_umac_cmd_get_channel_list {
273 __le16 count;
274 __le16 reserved;
275 struct iwm_umac_channel_info ch[0];
276} __packed;
277
278
279/* UMAC WiFi interface commands */
280
281/* Coexistence mode */
282#define COEX_MODE_SA 0x1
283#define COEX_MODE_XOR 0x2
284#define COEX_MODE_CM 0x3
285#define COEX_MODE_MAX 0x4
286
287/* Wireless mode */
288#define WIRELESS_MODE_11A 0x1
289#define WIRELESS_MODE_11G 0x2
290#define WIRELESS_MODE_11N 0x4
291
292#define UMAC_PROFILE_EX_IE_REQUIRED 0x1
293#define UMAC_PROFILE_QOS_ALLOWED 0x2
294
295/* Scanning */
296#define UMAC_WIFI_IF_PROBE_OPTION_MAX 10
297
298#define UMAC_WIFI_IF_SCAN_TYPE_USER 0x0
299#define UMAC_WIFI_IF_SCAN_TYPE_UMAC_RESERVED 0x1
300#define UMAC_WIFI_IF_SCAN_TYPE_HOST_PERIODIC 0x2
301#define UMAC_WIFI_IF_SCAN_TYPE_MAX 0x3
302
303struct iwm_umac_ssid {
304 u8 ssid_len;
305 u8 ssid[IEEE80211_MAX_SSID_LEN];
306 u8 reserved[3];
307} __packed;
308
309struct iwm_umac_cmd_scan_request {
310 struct iwm_umac_wifi_if hdr;
311 __le32 type; /* UMAC_WIFI_IF_SCAN_TYPE_* */
312 u8 ssid_num;
313 u8 seq_num;
314 u8 timeout; /* In seconds */
315 u8 reserved;
316 struct iwm_umac_ssid ssids[UMAC_WIFI_IF_PROBE_OPTION_MAX];
317} __packed;
318
319#define UMAC_CIPHER_TYPE_NONE 0xFF
320#define UMAC_CIPHER_TYPE_USE_GROUPCAST 0x00
321#define UMAC_CIPHER_TYPE_WEP_40 0x01
322#define UMAC_CIPHER_TYPE_WEP_104 0x02
323#define UMAC_CIPHER_TYPE_TKIP 0x04
324#define UMAC_CIPHER_TYPE_CCMP 0x08
325
326/* Supported authentication types - bitmap */
327#define UMAC_AUTH_TYPE_OPEN 0x00
328#define UMAC_AUTH_TYPE_LEGACY_PSK 0x01
329#define UMAC_AUTH_TYPE_8021X 0x02
330#define UMAC_AUTH_TYPE_RSNA_PSK 0x04
331
332/* iwm_umac_security.flag is WPA supported -- bits[0:0] */
333#define UMAC_SEC_FLG_WPA_ON_POS 0
334#define UMAC_SEC_FLG_WPA_ON_SEED 1
335#define UMAC_SEC_FLG_WPA_ON_MSK (UMAC_SEC_FLG_WPA_ON_SEED << \
336 UMAC_SEC_FLG_WPA_ON_POS)
337
338/* iwm_umac_security.flag is WPA2 supported -- bits [1:1] */
339#define UMAC_SEC_FLG_RSNA_ON_POS 1
340#define UMAC_SEC_FLG_RSNA_ON_SEED 1
341#define UMAC_SEC_FLG_RSNA_ON_MSK (UMAC_SEC_FLG_RSNA_ON_SEED << \
342 UMAC_SEC_FLG_RSNA_ON_POS)
343
344/* iwm_umac_security.flag is WSC mode on -- bits [2:2] */
345#define UMAC_SEC_FLG_WSC_ON_POS 2
346#define UMAC_SEC_FLG_WSC_ON_SEED 1
347#define UMAC_SEC_FLG_WSC_ON_MSK (UMAC_SEC_FLG_WSC_ON_SEED << \
348 UMAC_SEC_FLG_WSC_ON_POS)
349
350
351/* Legacy profile can use only WEP40 and WEP104 for encryption and
352 * OPEN or PSK for authentication */
353#define UMAC_SEC_FLG_LEGACY_PROFILE 0
354
355struct iwm_umac_security {
356 u8 auth_type;
357 u8 ucast_cipher;
358 u8 mcast_cipher;
359 u8 flags;
360} __packed;
361
362struct iwm_umac_ibss {
363 u8 beacon_interval; /* in millisecond */
364 u8 atim; /* in millisecond */
365 s8 join_only;
366 u8 band;
367 u8 channel;
368 u8 reserved[3];
369} __packed;
370
371#define UMAC_MODE_BSS 0
372#define UMAC_MODE_IBSS 1
373
374#define UMAC_BSSID_MAX 4
375
376struct iwm_umac_profile {
377 struct iwm_umac_wifi_if hdr;
378 __le32 mode;
379 struct iwm_umac_ssid ssid;
380 u8 bssid[UMAC_BSSID_MAX][ETH_ALEN];
381 struct iwm_umac_security sec;
382 struct iwm_umac_ibss ibss;
383 __le32 channel_2ghz;
384 __le32 channel_5ghz;
385 __le16 flags;
386 u8 wireless_mode;
387 u8 bss_num;
388} __packed;
389
390struct iwm_umac_invalidate_profile {
391 struct iwm_umac_wifi_if hdr;
392 u8 reason;
393 u8 reserved[3];
394} __packed;
395
396/* Encryption key commands */
397struct iwm_umac_key_wep40 {
398 struct iwm_umac_wifi_if hdr;
399 struct iwm_umac_key_hdr key_hdr;
400 u8 key[WLAN_KEY_LEN_WEP40];
401 u8 static_key;
402 u8 reserved[2];
403} __packed;
404
405struct iwm_umac_key_wep104 {
406 struct iwm_umac_wifi_if hdr;
407 struct iwm_umac_key_hdr key_hdr;
408 u8 key[WLAN_KEY_LEN_WEP104];
409 u8 static_key;
410 u8 reserved[2];
411} __packed;
412
413#define IWM_TKIP_KEY_SIZE 16
414#define IWM_TKIP_MIC_SIZE 8
415struct iwm_umac_key_tkip {
416 struct iwm_umac_wifi_if hdr;
417 struct iwm_umac_key_hdr key_hdr;
418 u8 iv_count[6];
419 u8 reserved[2];
420 u8 tkip_key[IWM_TKIP_KEY_SIZE];
421 u8 mic_rx_key[IWM_TKIP_MIC_SIZE];
422 u8 mic_tx_key[IWM_TKIP_MIC_SIZE];
423} __packed;
424
425struct iwm_umac_key_ccmp {
426 struct iwm_umac_wifi_if hdr;
427 struct iwm_umac_key_hdr key_hdr;
428 u8 iv_count[6];
429 u8 reserved[2];
430 u8 key[WLAN_KEY_LEN_CCMP];
431} __packed;
432
433struct iwm_umac_key_remove {
434 struct iwm_umac_wifi_if hdr;
435 struct iwm_umac_key_hdr key_hdr;
436} __packed;
437
438struct iwm_umac_tx_key_id {
439 struct iwm_umac_wifi_if hdr;
440 u8 key_idx;
441 u8 reserved[3];
442} __packed;
443
444struct iwm_umac_pwr_trigger {
445 struct iwm_umac_wifi_if hdr;
446 __le32 reseved;
447} __packed;
448
449struct iwm_umac_cmd_stats_req {
450 __le32 flags;
451} __packed;
452
453struct iwm_umac_cmd_stop_resume_tx {
454 u8 flags;
455 u8 sta_id;
456 __le16 stop_resume_tid_msk;
457 __le16 last_seq_num[IWM_UMAC_TID_NR];
458 u16 reserved;
459} __packed;
460
461#define IWM_CMD_PMKID_ADD 1
462#define IWM_CMD_PMKID_DEL 2
463#define IWM_CMD_PMKID_FLUSH 3
464
465struct iwm_umac_pmkid_update {
466 struct iwm_umac_wifi_if hdr;
467 __le32 command;
468 u8 bssid[ETH_ALEN];
469 __le16 reserved;
470 u8 pmkid[WLAN_PMKID_LEN];
471} __packed;
472
473/* LMAC commands */
474int iwm_read_mac(struct iwm_priv *iwm, u8 *mac);
475int iwm_send_prio_table(struct iwm_priv *iwm);
476int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
477int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
478int iwm_send_calib_results(struct iwm_priv *iwm);
479int iwm_store_rxiq_calib_result(struct iwm_priv *iwm);
480int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit);
481
482/* UMAC commands */
483int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
484 bool resp);
485int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp);
486int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value);
487int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
488 void *payload, u16 payload_size);
489int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags);
490int iwm_send_mlme_profile(struct iwm_priv *iwm);
491int __iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
492int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
493int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
494int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
495int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
496int iwm_tx_power_trigger(struct iwm_priv *iwm);
497int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
498int iwm_send_umac_channel_list(struct iwm_priv *iwm);
499int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
500 int ssid_num);
501int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len);
502int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm,
503 struct iwm_umac_notif_stop_resume_tx *ntf);
504int iwm_send_pmkid_update(struct iwm_priv *iwm,
505 struct cfg80211_pmksa *pmksa, u32 command);
506
507/* UDMA commands */
508int iwm_target_reset(struct iwm_priv *iwm);
509#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/debug.h b/drivers/net/wireless/iwmc3200wifi/debug.h
deleted file mode 100644
index a0c13a49ab3c..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/debug.h
+++ /dev/null
@@ -1,123 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5 * Samuel Ortiz <samuel.ortiz@intel.com>
6 * Zhu Yi <yi.zhu@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 */
23
24#ifndef __IWM_DEBUG_H__
25#define __IWM_DEBUG_H__
26
27#define IWM_ERR(p, f, a...) dev_err(iwm_to_dev(p), f, ## a)
28#define IWM_WARN(p, f, a...) dev_warn(iwm_to_dev(p), f, ## a)
29#define IWM_INFO(p, f, a...) dev_info(iwm_to_dev(p), f, ## a)
30#define IWM_CRIT(p, f, a...) dev_crit(iwm_to_dev(p), f, ## a)
31
32#ifdef CONFIG_IWM_DEBUG
33
34#define IWM_DEBUG_MODULE(i, level, module, f, a...) \
35do { \
36 if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\
37 dev_printk(KERN_INFO, (iwm_to_dev(i)), \
38 "%s " f, __func__ , ## a); \
39} while (0)
40
41#define IWM_HEXDUMP(i, level, module, pref, buf, len) \
42do { \
43 if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\
44 print_hex_dump(KERN_INFO, pref, DUMP_PREFIX_OFFSET, \
45 16, 1, buf, len, 1); \
46} while (0)
47
48#else
49
50#define IWM_DEBUG_MODULE(i, level, module, f, a...)
51#define IWM_HEXDUMP(i, level, module, pref, buf, len)
52
53#endif /* CONFIG_IWM_DEBUG */
54
55/* Debug modules */
56enum iwm_debug_module_id {
57 IWM_DM_BOOT = 0,
58 IWM_DM_FW,
59 IWM_DM_SDIO,
60 IWM_DM_NTF,
61 IWM_DM_RX,
62 IWM_DM_TX,
63 IWM_DM_MLME,
64 IWM_DM_CMD,
65 IWM_DM_WEXT,
66 __IWM_DM_NR,
67};
68#define IWM_DM_DEFAULT 0
69
70#define IWM_DBG_BOOT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, BOOT, f, ## a)
71#define IWM_DBG_FW(i, l, f, a...) IWM_DEBUG_MODULE(i, l, FW, f, ## a)
72#define IWM_DBG_SDIO(i, l, f, a...) IWM_DEBUG_MODULE(i, l, SDIO, f, ## a)
73#define IWM_DBG_NTF(i, l, f, a...) IWM_DEBUG_MODULE(i, l, NTF, f, ## a)
74#define IWM_DBG_RX(i, l, f, a...) IWM_DEBUG_MODULE(i, l, RX, f, ## a)
75#define IWM_DBG_TX(i, l, f, a...) IWM_DEBUG_MODULE(i, l, TX, f, ## a)
76#define IWM_DBG_MLME(i, l, f, a...) IWM_DEBUG_MODULE(i, l, MLME, f, ## a)
77#define IWM_DBG_CMD(i, l, f, a...) IWM_DEBUG_MODULE(i, l, CMD, f, ## a)
78#define IWM_DBG_WEXT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, WEXT, f, ## a)
79
80/* Debug levels */
81enum iwm_debug_level {
82 IWM_DL_NONE = 0,
83 IWM_DL_ERR,
84 IWM_DL_WARN,
85 IWM_DL_INFO,
86 IWM_DL_DBG,
87};
88#define IWM_DL_DEFAULT IWM_DL_ERR
89
90struct iwm_debugfs {
91 struct iwm_priv *iwm;
92 struct dentry *rootdir;
93 struct dentry *devdir;
94 struct dentry *dbgdir;
95 struct dentry *txdir;
96 struct dentry *rxdir;
97 struct dentry *busdir;
98
99 u32 dbg_level;
100 struct dentry *dbg_level_dentry;
101
102 unsigned long dbg_modules;
103 struct dentry *dbg_modules_dentry;
104
105 u8 dbg_module[__IWM_DM_NR];
106 struct dentry *dbg_module_dentries[__IWM_DM_NR];
107
108 struct dentry *txq_dentry;
109 struct dentry *tx_credit_dentry;
110 struct dentry *rx_ticket_dentry;
111
112 struct dentry *fw_err_dentry;
113};
114
115#ifdef CONFIG_IWM_DEBUG
116void iwm_debugfs_init(struct iwm_priv *iwm);
117void iwm_debugfs_exit(struct iwm_priv *iwm);
118#else
119static inline void iwm_debugfs_init(struct iwm_priv *iwm) {}
120static inline void iwm_debugfs_exit(struct iwm_priv *iwm) {}
121#endif
122
123#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c
deleted file mode 100644
index b6199d124bb9..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/debugfs.c
+++ /dev/null
@@ -1,488 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5 * Samuel Ortiz <samuel.ortiz@intel.com>
6 * Zhu Yi <yi.zhu@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 */
23
24#include <linux/slab.h>
25#include <linux/kernel.h>
26#include <linux/bitops.h>
27#include <linux/debugfs.h>
28#include <linux/export.h>
29
30#include "iwm.h"
31#include "bus.h"
32#include "rx.h"
33#include "debug.h"
34
35static struct {
36 u8 id;
37 char *name;
38} iwm_debug_module[__IWM_DM_NR] = {
39 {IWM_DM_BOOT, "boot"},
40 {IWM_DM_FW, "fw"},
41 {IWM_DM_SDIO, "sdio"},
42 {IWM_DM_NTF, "ntf"},
43 {IWM_DM_RX, "rx"},
44 {IWM_DM_TX, "tx"},
45 {IWM_DM_MLME, "mlme"},
46 {IWM_DM_CMD, "cmd"},
47 {IWM_DM_WEXT, "wext"},
48};
49
50#define add_dbg_module(dbg, name, id, initlevel) \
51do { \
52 dbg.dbg_module[id] = (initlevel); \
53 dbg.dbg_module_dentries[id] = \
54 debugfs_create_x8(name, 0600, \
55 dbg.dbgdir, \
56 &(dbg.dbg_module[id])); \
57} while (0)
58
59static int iwm_debugfs_u32_read(void *data, u64 *val)
60{
61 struct iwm_priv *iwm = data;
62
63 *val = iwm->dbg.dbg_level;
64 return 0;
65}
66
67static int iwm_debugfs_dbg_level_write(void *data, u64 val)
68{
69 struct iwm_priv *iwm = data;
70 int i;
71
72 iwm->dbg.dbg_level = val;
73
74 for (i = 0; i < __IWM_DM_NR; i++)
75 iwm->dbg.dbg_module[i] = val;
76
77 return 0;
78}
79DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_level,
80 iwm_debugfs_u32_read, iwm_debugfs_dbg_level_write,
81 "%llu\n");
82
83static int iwm_debugfs_dbg_modules_write(void *data, u64 val)
84{
85 struct iwm_priv *iwm = data;
86 int i, bit;
87
88 iwm->dbg.dbg_modules = val;
89
90 for (i = 0; i < __IWM_DM_NR; i++)
91 iwm->dbg.dbg_module[i] = 0;
92
93 for_each_set_bit(bit, &iwm->dbg.dbg_modules, __IWM_DM_NR)
94 iwm->dbg.dbg_module[bit] = iwm->dbg.dbg_level;
95
96 return 0;
97}
98DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules,
99 iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write,
100 "%llu\n");
101
102
103static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer,
104 size_t count, loff_t *ppos)
105{
106 struct iwm_priv *iwm = filp->private_data;
107 char *buf;
108 int i, buf_len = 4096;
109 size_t len = 0;
110 ssize_t ret;
111
112 if (*ppos != 0)
113 return 0;
114 if (count < sizeof(buf))
115 return -ENOSPC;
116
117 buf = kzalloc(buf_len, GFP_KERNEL);
118 if (!buf)
119 return -ENOMEM;
120
121 for (i = 0; i < IWM_TX_QUEUES; i++) {
122 struct iwm_tx_queue *txq = &iwm->txq[i];
123 struct sk_buff *skb;
124 int j;
125 unsigned long flags;
126
127 spin_lock_irqsave(&txq->queue.lock, flags);
128
129 skb = (struct sk_buff *)&txq->queue;
130
131 len += snprintf(buf + len, buf_len - len, "TXQ #%d\n", i);
132 len += snprintf(buf + len, buf_len - len, "\tStopped: %d\n",
133 __netif_subqueue_stopped(iwm_to_ndev(iwm),
134 txq->id));
135 len += snprintf(buf + len, buf_len - len, "\tConcat count:%d\n",
136 txq->concat_count);
137 len += snprintf(buf + len, buf_len - len, "\tQueue len: %d\n",
138 skb_queue_len(&txq->queue));
139 for (j = 0; j < skb_queue_len(&txq->queue); j++) {
140 struct iwm_tx_info *tx_info;
141
142 skb = skb->next;
143 tx_info = skb_to_tx_info(skb);
144
145 len += snprintf(buf + len, buf_len - len,
146 "\tSKB #%d\n", j);
147 len += snprintf(buf + len, buf_len - len,
148 "\t\tsta: %d\n", tx_info->sta);
149 len += snprintf(buf + len, buf_len - len,
150 "\t\tcolor: %d\n", tx_info->color);
151 len += snprintf(buf + len, buf_len - len,
152 "\t\ttid: %d\n", tx_info->tid);
153 }
154
155 spin_unlock_irqrestore(&txq->queue.lock, flags);
156
157 spin_lock_irqsave(&txq->stopped_queue.lock, flags);
158
159 len += snprintf(buf + len, buf_len - len,
160 "\tStopped Queue len: %d\n",
161 skb_queue_len(&txq->stopped_queue));
162 for (j = 0; j < skb_queue_len(&txq->stopped_queue); j++) {
163 struct iwm_tx_info *tx_info;
164
165 skb = skb->next;
166 tx_info = skb_to_tx_info(skb);
167
168 len += snprintf(buf + len, buf_len - len,
169 "\tSKB #%d\n", j);
170 len += snprintf(buf + len, buf_len - len,
171 "\t\tsta: %d\n", tx_info->sta);
172 len += snprintf(buf + len, buf_len - len,
173 "\t\tcolor: %d\n", tx_info->color);
174 len += snprintf(buf + len, buf_len - len,
175 "\t\ttid: %d\n", tx_info->tid);
176 }
177
178 spin_unlock_irqrestore(&txq->stopped_queue.lock, flags);
179 }
180
181 ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
182 kfree(buf);
183
184 return ret;
185}
186
187static ssize_t iwm_debugfs_tx_credit_read(struct file *filp,
188 char __user *buffer,
189 size_t count, loff_t *ppos)
190{
191 struct iwm_priv *iwm = filp->private_data;
192 struct iwm_tx_credit *credit = &iwm->tx_credit;
193 char *buf;
194 int i, buf_len = 4096;
195 size_t len = 0;
196 ssize_t ret;
197
198 if (*ppos != 0)
199 return 0;
200 if (count < sizeof(buf))
201 return -ENOSPC;
202
203 buf = kzalloc(buf_len, GFP_KERNEL);
204 if (!buf)
205 return -ENOMEM;
206
207 len += snprintf(buf + len, buf_len - len,
208 "NR pools: %d\n", credit->pool_nr);
209 len += snprintf(buf + len, buf_len - len,
210 "pools map: 0x%lx\n", credit->full_pools_map);
211
212 len += snprintf(buf + len, buf_len - len, "\n### POOLS ###\n");
213 for (i = 0; i < IWM_MACS_OUT_GROUPS; i++) {
214 len += snprintf(buf + len, buf_len - len,
215 "pools entry #%d\n", i);
216 len += snprintf(buf + len, buf_len - len,
217 "\tid: %d\n",
218 credit->pools[i].id);
219 len += snprintf(buf + len, buf_len - len,
220 "\tsid: %d\n",
221 credit->pools[i].sid);
222 len += snprintf(buf + len, buf_len - len,
223 "\tmin_pages: %d\n",
224 credit->pools[i].min_pages);
225 len += snprintf(buf + len, buf_len - len,
226 "\tmax_pages: %d\n",
227 credit->pools[i].max_pages);
228 len += snprintf(buf + len, buf_len - len,
229 "\talloc_pages: %d\n",
230 credit->pools[i].alloc_pages);
231 len += snprintf(buf + len, buf_len - len,
232 "\tfreed_pages: %d\n",
233 credit->pools[i].total_freed_pages);
234 }
235
236 len += snprintf(buf + len, buf_len - len, "\n### SPOOLS ###\n");
237 for (i = 0; i < IWM_MACS_OUT_SGROUPS; i++) {
238 len += snprintf(buf + len, buf_len - len,
239 "spools entry #%d\n", i);
240 len += snprintf(buf + len, buf_len - len,
241 "\tid: %d\n",
242 credit->spools[i].id);
243 len += snprintf(buf + len, buf_len - len,
244 "\tmax_pages: %d\n",
245 credit->spools[i].max_pages);
246 len += snprintf(buf + len, buf_len - len,
247 "\talloc_pages: %d\n",
248 credit->spools[i].alloc_pages);
249
250 }
251
252 ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
253 kfree(buf);
254
255 return ret;
256}
257
258static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp,
259 char __user *buffer,
260 size_t count, loff_t *ppos)
261{
262 struct iwm_priv *iwm = filp->private_data;
263 struct iwm_rx_ticket_node *ticket;
264 char *buf;
265 int buf_len = 4096, i;
266 size_t len = 0;
267 ssize_t ret;
268
269 if (*ppos != 0)
270 return 0;
271 if (count < sizeof(buf))
272 return -ENOSPC;
273
274 buf = kzalloc(buf_len, GFP_KERNEL);
275 if (!buf)
276 return -ENOMEM;
277
278 spin_lock(&iwm->ticket_lock);
279 list_for_each_entry(ticket, &iwm->rx_tickets, node) {
280 len += snprintf(buf + len, buf_len - len, "Ticket #%d\n",
281 ticket->ticket->id);
282 len += snprintf(buf + len, buf_len - len, "\taction: 0x%x\n",
283 ticket->ticket->action);
284 len += snprintf(buf + len, buf_len - len, "\tflags: 0x%x\n",
285 ticket->ticket->flags);
286 }
287 spin_unlock(&iwm->ticket_lock);
288
289 for (i = 0; i < IWM_RX_ID_HASH; i++) {
290 struct iwm_rx_packet *packet;
291 struct list_head *pkt_list = &iwm->rx_packets[i];
292
293 if (!list_empty(pkt_list)) {
294 len += snprintf(buf + len, buf_len - len,
295 "Packet hash #%d\n", i);
296 spin_lock(&iwm->packet_lock[i]);
297 list_for_each_entry(packet, pkt_list, node) {
298 len += snprintf(buf + len, buf_len - len,
299 "\tPacket id: %d\n",
300 packet->id);
301 len += snprintf(buf + len, buf_len - len,
302 "\tPacket length: %lu\n",
303 packet->pkt_size);
304 }
305 spin_unlock(&iwm->packet_lock[i]);
306 }
307 }
308
309 ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
310 kfree(buf);
311
312 return ret;
313}
314
315static ssize_t iwm_debugfs_fw_err_read(struct file *filp,
316 char __user *buffer,
317 size_t count, loff_t *ppos)
318{
319
320 struct iwm_priv *iwm = filp->private_data;
321 char buf[512];
322 int buf_len = 512;
323 size_t len = 0;
324
325 if (*ppos != 0)
326 return 0;
327 if (count < sizeof(buf))
328 return -ENOSPC;
329
330 if (!iwm->last_fw_err)
331 return -ENOMEM;
332
333 if (iwm->last_fw_err->line_num == 0)
334 goto out;
335
336 len += snprintf(buf + len, buf_len - len, "%cMAC FW ERROR:\n",
337 (le32_to_cpu(iwm->last_fw_err->category) == UMAC_SYS_ERR_CAT_LMAC)
338 ? 'L' : 'U');
339 len += snprintf(buf + len, buf_len - len,
340 "\tCategory: %d\n",
341 le32_to_cpu(iwm->last_fw_err->category));
342
343 len += snprintf(buf + len, buf_len - len,
344 "\tStatus: 0x%x\n",
345 le32_to_cpu(iwm->last_fw_err->status));
346
347 len += snprintf(buf + len, buf_len - len,
348 "\tPC: 0x%x\n",
349 le32_to_cpu(iwm->last_fw_err->pc));
350
351 len += snprintf(buf + len, buf_len - len,
352 "\tblink1: %d\n",
353 le32_to_cpu(iwm->last_fw_err->blink1));
354
355 len += snprintf(buf + len, buf_len - len,
356 "\tblink2: %d\n",
357 le32_to_cpu(iwm->last_fw_err->blink2));
358
359 len += snprintf(buf + len, buf_len - len,
360 "\tilink1: %d\n",
361 le32_to_cpu(iwm->last_fw_err->ilink1));
362
363 len += snprintf(buf + len, buf_len - len,
364 "\tilink2: %d\n",
365 le32_to_cpu(iwm->last_fw_err->ilink2));
366
367 len += snprintf(buf + len, buf_len - len,
368 "\tData1: 0x%x\n",
369 le32_to_cpu(iwm->last_fw_err->data1));
370
371 len += snprintf(buf + len, buf_len - len,
372 "\tData2: 0x%x\n",
373 le32_to_cpu(iwm->last_fw_err->data2));
374
375 len += snprintf(buf + len, buf_len - len,
376 "\tLine number: %d\n",
377 le32_to_cpu(iwm->last_fw_err->line_num));
378
379 len += snprintf(buf + len, buf_len - len,
380 "\tUMAC status: 0x%x\n",
381 le32_to_cpu(iwm->last_fw_err->umac_status));
382
383 len += snprintf(buf + len, buf_len - len,
384 "\tLMAC status: 0x%x\n",
385 le32_to_cpu(iwm->last_fw_err->lmac_status));
386
387 len += snprintf(buf + len, buf_len - len,
388 "\tSDIO status: 0x%x\n",
389 le32_to_cpu(iwm->last_fw_err->sdio_status));
390
391out:
392
393 return simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
394}
395
396static const struct file_operations iwm_debugfs_txq_fops = {
397 .owner = THIS_MODULE,
398 .open = simple_open,
399 .read = iwm_debugfs_txq_read,
400 .llseek = default_llseek,
401};
402
403static const struct file_operations iwm_debugfs_tx_credit_fops = {
404 .owner = THIS_MODULE,
405 .open = simple_open,
406 .read = iwm_debugfs_tx_credit_read,
407 .llseek = default_llseek,
408};
409
410static const struct file_operations iwm_debugfs_rx_ticket_fops = {
411 .owner = THIS_MODULE,
412 .open = simple_open,
413 .read = iwm_debugfs_rx_ticket_read,
414 .llseek = default_llseek,
415};
416
417static const struct file_operations iwm_debugfs_fw_err_fops = {
418 .owner = THIS_MODULE,
419 .open = simple_open,
420 .read = iwm_debugfs_fw_err_read,
421 .llseek = default_llseek,
422};
423
424void iwm_debugfs_init(struct iwm_priv *iwm)
425{
426 int i;
427
428 iwm->dbg.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
429 iwm->dbg.devdir = debugfs_create_dir(wiphy_name(iwm_to_wiphy(iwm)),
430 iwm->dbg.rootdir);
431 iwm->dbg.dbgdir = debugfs_create_dir("debug", iwm->dbg.devdir);
432 iwm->dbg.rxdir = debugfs_create_dir("rx", iwm->dbg.devdir);
433 iwm->dbg.txdir = debugfs_create_dir("tx", iwm->dbg.devdir);
434 iwm->dbg.busdir = debugfs_create_dir("bus", iwm->dbg.devdir);
435 if (iwm->bus_ops->debugfs_init)
436 iwm->bus_ops->debugfs_init(iwm, iwm->dbg.busdir);
437
438 iwm->dbg.dbg_level = IWM_DL_NONE;
439 iwm->dbg.dbg_level_dentry =
440 debugfs_create_file("level", 0200, iwm->dbg.dbgdir, iwm,
441 &fops_iwm_dbg_level);
442
443 iwm->dbg.dbg_modules = IWM_DM_DEFAULT;
444 iwm->dbg.dbg_modules_dentry =
445 debugfs_create_file("modules", 0200, iwm->dbg.dbgdir, iwm,
446 &fops_iwm_dbg_modules);
447
448 for (i = 0; i < __IWM_DM_NR; i++)
449 add_dbg_module(iwm->dbg, iwm_debug_module[i].name,
450 iwm_debug_module[i].id, IWM_DL_DEFAULT);
451
452 iwm->dbg.txq_dentry = debugfs_create_file("queues", 0200,
453 iwm->dbg.txdir, iwm,
454 &iwm_debugfs_txq_fops);
455 iwm->dbg.tx_credit_dentry = debugfs_create_file("credits", 0200,
456 iwm->dbg.txdir, iwm,
457 &iwm_debugfs_tx_credit_fops);
458 iwm->dbg.rx_ticket_dentry = debugfs_create_file("tickets", 0200,
459 iwm->dbg.rxdir, iwm,
460 &iwm_debugfs_rx_ticket_fops);
461 iwm->dbg.fw_err_dentry = debugfs_create_file("last_fw_err", 0200,
462 iwm->dbg.dbgdir, iwm,
463 &iwm_debugfs_fw_err_fops);
464}
465
466void iwm_debugfs_exit(struct iwm_priv *iwm)
467{
468 int i;
469
470 for (i = 0; i < __IWM_DM_NR; i++)
471 debugfs_remove(iwm->dbg.dbg_module_dentries[i]);
472
473 debugfs_remove(iwm->dbg.dbg_modules_dentry);
474 debugfs_remove(iwm->dbg.dbg_level_dentry);
475 debugfs_remove(iwm->dbg.txq_dentry);
476 debugfs_remove(iwm->dbg.tx_credit_dentry);
477 debugfs_remove(iwm->dbg.rx_ticket_dentry);
478 debugfs_remove(iwm->dbg.fw_err_dentry);
479 if (iwm->bus_ops->debugfs_exit)
480 iwm->bus_ops->debugfs_exit(iwm);
481
482 debugfs_remove(iwm->dbg.busdir);
483 debugfs_remove(iwm->dbg.dbgdir);
484 debugfs_remove(iwm->dbg.txdir);
485 debugfs_remove(iwm->dbg.rxdir);
486 debugfs_remove(iwm->dbg.devdir);
487 debugfs_remove(iwm->dbg.rootdir);
488}
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c
deleted file mode 100644
index e80e776b74f7..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/eeprom.c
+++ /dev/null
@@ -1,234 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#include <linux/kernel.h>
40#include <linux/slab.h>
41
42#include "iwm.h"
43#include "umac.h"
44#include "commands.h"
45#include "eeprom.h"
46
47static struct iwm_eeprom_entry eeprom_map[] = {
48 [IWM_EEPROM_SIG] =
49 {"Signature", IWM_EEPROM_SIG_OFF, IWM_EEPROM_SIG_LEN},
50
51 [IWM_EEPROM_VERSION] =
52 {"Version", IWM_EEPROM_VERSION_OFF, IWM_EEPROM_VERSION_LEN},
53
54 [IWM_EEPROM_OEM_HW_VERSION] =
55 {"OEM HW version", IWM_EEPROM_OEM_HW_VERSION_OFF,
56 IWM_EEPROM_OEM_HW_VERSION_LEN},
57
58 [IWM_EEPROM_MAC_VERSION] =
59 {"MAC version", IWM_EEPROM_MAC_VERSION_OFF, IWM_EEPROM_MAC_VERSION_LEN},
60
61 [IWM_EEPROM_CARD_ID] =
62 {"Card ID", IWM_EEPROM_CARD_ID_OFF, IWM_EEPROM_CARD_ID_LEN},
63
64 [IWM_EEPROM_RADIO_CONF] =
65 {"Radio config", IWM_EEPROM_RADIO_CONF_OFF, IWM_EEPROM_RADIO_CONF_LEN},
66
67 [IWM_EEPROM_SKU_CAP] =
68 {"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN},
69
70 [IWM_EEPROM_FAT_CHANNELS_CAP] =
71 {"HT channels capabilities", IWM_EEPROM_FAT_CHANNELS_CAP_OFF,
72 IWM_EEPROM_FAT_CHANNELS_CAP_LEN},
73
74 [IWM_EEPROM_CALIB_RXIQ_OFFSET] =
75 {"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN},
76
77 [IWM_EEPROM_CALIB_RXIQ] =
78 {"Calib RX IQ", 0, IWM_EEPROM_CALIB_RXIQ_LEN},
79};
80
81
82static int iwm_eeprom_read(struct iwm_priv *iwm, u8 eeprom_id)
83{
84 int ret;
85 u32 entry_size, chunk_size, data_offset = 0, addr_offset = 0;
86 u32 addr;
87 struct iwm_udma_wifi_cmd udma_cmd;
88 struct iwm_umac_cmd umac_cmd;
89 struct iwm_umac_cmd_eeprom_proxy eeprom_cmd;
90
91 if (eeprom_id > (IWM_EEPROM_LAST - 1))
92 return -EINVAL;
93
94 entry_size = eeprom_map[eeprom_id].length;
95
96 if (eeprom_id >= IWM_EEPROM_INDIRECT_DATA) {
97 /* indirect data */
98 u32 off_id = eeprom_id - IWM_EEPROM_INDIRECT_DATA +
99 IWM_EEPROM_INDIRECT_OFFSET;
100
101 eeprom_map[eeprom_id].offset =
102 *(u16 *)(iwm->eeprom + eeprom_map[off_id].offset) << 1;
103 }
104
105 addr = eeprom_map[eeprom_id].offset;
106
107 udma_cmd.eop = 1;
108 udma_cmd.credit_group = 0x4;
109 udma_cmd.ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD;
110 udma_cmd.lmac_offset = 0;
111
112 umac_cmd.id = UMAC_CMD_OPCODE_EEPROM_PROXY;
113 umac_cmd.resp = 1;
114
115 while (entry_size > 0) {
116 chunk_size = min_t(u32, entry_size, IWM_MAX_EEPROM_DATA_LEN);
117
118 eeprom_cmd.hdr.type =
119 cpu_to_le32(IWM_UMAC_CMD_EEPROM_TYPE_READ);
120 eeprom_cmd.hdr.offset = cpu_to_le32(addr + addr_offset);
121 eeprom_cmd.hdr.len = cpu_to_le32(chunk_size);
122
123 ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd,
124 &umac_cmd, &eeprom_cmd,
125 sizeof(struct iwm_umac_cmd_eeprom_proxy));
126 if (ret < 0) {
127 IWM_ERR(iwm, "Couldn't read eeprom\n");
128 return ret;
129 }
130
131 ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_EEPROM_PROXY,
132 IWM_SRC_UMAC, 2*HZ);
133 if (ret < 0) {
134 IWM_ERR(iwm, "Did not get any eeprom answer\n");
135 return ret;
136 }
137
138 data_offset += chunk_size;
139 addr_offset += chunk_size;
140 entry_size -= chunk_size;
141 }
142
143 return 0;
144}
145
146u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id)
147{
148 if (!iwm->eeprom)
149 return ERR_PTR(-ENODEV);
150
151 return iwm->eeprom + eeprom_map[eeprom_id].offset;
152}
153
154int iwm_eeprom_fat_channels(struct iwm_priv *iwm)
155{
156 struct wiphy *wiphy = iwm_to_wiphy(iwm);
157 struct ieee80211_supported_band *band;
158 u16 *channels, i;
159
160 channels = (u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_FAT_CHANNELS_CAP);
161 if (IS_ERR(channels))
162 return PTR_ERR(channels);
163
164 band = wiphy->bands[IEEE80211_BAND_2GHZ];
165 band->ht_cap.ht_supported = true;
166
167 for (i = 0; i < IWM_EEPROM_FAT_CHANNELS_24; i++)
168 if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED))
169 band->ht_cap.ht_supported = false;
170
171 band = wiphy->bands[IEEE80211_BAND_5GHZ];
172 band->ht_cap.ht_supported = true;
173 for (i = IWM_EEPROM_FAT_CHANNELS_24; i < IWM_EEPROM_FAT_CHANNELS; i++)
174 if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED))
175 band->ht_cap.ht_supported = false;
176
177 return 0;
178}
179
180u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm)
181{
182 u16 sku_cap;
183 u32 wireless_mode = 0;
184
185 sku_cap = *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP));
186
187 if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_24GHZ)
188 wireless_mode |= WIRELESS_MODE_11G;
189
190 if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_52GHZ)
191 wireless_mode |= WIRELESS_MODE_11A;
192
193 if (sku_cap & IWM_EEPROM_SKU_CAP_11N_ENABLE)
194 wireless_mode |= WIRELESS_MODE_11N;
195
196 return wireless_mode;
197}
198
199
200int iwm_eeprom_init(struct iwm_priv *iwm)
201{
202 int i, ret = 0;
203 char name[32];
204
205 iwm->eeprom = kzalloc(IWM_EEPROM_LEN, GFP_KERNEL);
206 if (!iwm->eeprom)
207 return -ENOMEM;
208
209 for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) {
210 ret = iwm_eeprom_read(iwm, i);
211 if (ret < 0) {
212 IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n",
213 i, eeprom_map[i].name);
214 break;
215 }
216 }
217
218 IWM_DBG_BOOT(iwm, DBG, "EEPROM dump:\n");
219 for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) {
220 memset(name, 0, 32);
221 sprintf(name, "%s: ", eeprom_map[i].name);
222
223 IWM_HEXDUMP(iwm, DBG, BOOT, name,
224 iwm->eeprom + eeprom_map[i].offset,
225 eeprom_map[i].length);
226 }
227
228 return ret;
229}
230
231void iwm_eeprom_exit(struct iwm_priv *iwm)
232{
233 kfree(iwm->eeprom);
234}
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.h b/drivers/net/wireless/iwmc3200wifi/eeprom.h
deleted file mode 100644
index 4e3a3fdab0d3..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/eeprom.h
+++ /dev/null
@@ -1,127 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#ifndef __IWM_EEPROM_H__
40#define __IWM_EEPROM_H__
41
42enum {
43 IWM_EEPROM_SIG = 0,
44 IWM_EEPROM_FIRST = IWM_EEPROM_SIG,
45 IWM_EEPROM_VERSION,
46 IWM_EEPROM_OEM_HW_VERSION,
47 IWM_EEPROM_MAC_VERSION,
48 IWM_EEPROM_CARD_ID,
49 IWM_EEPROM_RADIO_CONF,
50 IWM_EEPROM_SKU_CAP,
51 IWM_EEPROM_FAT_CHANNELS_CAP,
52
53 IWM_EEPROM_INDIRECT_OFFSET,
54 IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET,
55
56 IWM_EEPROM_INDIRECT_DATA,
57 IWM_EEPROM_CALIB_RXIQ = IWM_EEPROM_INDIRECT_DATA,
58
59 IWM_EEPROM_LAST,
60};
61
62#define IWM_EEPROM_SIG_OFF 0x00
63#define IWM_EEPROM_VERSION_OFF (0x54 << 1)
64#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1)
65#define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1)
66#define IWM_EEPROM_CARD_ID_OFF (0x5d << 1)
67#define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1)
68#define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1)
69#define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1)
70#define IWM_EEPROM_FAT_CHANNELS_CAP_OFF (0xde << 1)
71
72#define IWM_EEPROM_SIG_LEN 4
73#define IWM_EEPROM_VERSION_LEN 2
74#define IWM_EEPROM_OEM_HW_VERSION_LEN 2
75#define IWM_EEPROM_MAC_VERSION_LEN 1
76#define IWM_EEPROM_CARD_ID_LEN 2
77#define IWM_EEPROM_RADIO_CONF_LEN 2
78#define IWM_EEPROM_SKU_CAP_LEN 2
79#define IWM_EEPROM_FAT_CHANNELS_CAP_LEN 40
80#define IWM_EEPROM_INDIRECT_LEN 2
81
82#define IWM_MAX_EEPROM_DATA_LEN 240
83#define IWM_EEPROM_LEN 0x800
84
85#define IWM_EEPROM_MIN_ALLOWED_VERSION 0x0610
86#define IWM_EEPROM_MAX_ALLOWED_VERSION 0x0700
87#define IWM_EEPROM_CURRENT_VERSION 0x0612
88
89#define IWM_EEPROM_SKU_CAP_BAND_24GHZ (1 << 4)
90#define IWM_EEPROM_SKU_CAP_BAND_52GHZ (1 << 5)
91#define IWM_EEPROM_SKU_CAP_11N_ENABLE (1 << 6)
92
93#define IWM_EEPROM_FAT_CHANNELS 20
94/* 2.4 gHz FAT primary channels: 1, 2, 3, 4, 5, 6, 7, 8, 9 */
95#define IWM_EEPROM_FAT_CHANNELS_24 9
96/* 5.2 gHz FAT primary channels: 36,44,52,60,100,108,116,124,132,149,157 */
97#define IWM_EEPROM_FAT_CHANNELS_52 11
98
99#define IWM_EEPROM_FAT_CHANNEL_ENABLED (1 << 0)
100
101enum {
102 IWM_EEPROM_CALIB_CAL_HDR,
103 IWM_EEPROM_CALIB_TX_POWER,
104 IWM_EEPROM_CALIB_XTAL,
105 IWM_EEPROM_CALIB_TEMPERATURE,
106 IWM_EEPROM_CALIB_RX_BB_FILTER,
107 IWM_EEPROM_CALIB_RX_IQ,
108 IWM_EEPROM_CALIB_MAX,
109};
110
111#define IWM_EEPROM_CALIB_RXIQ_OFF (IWM_EEPROM_CALIB_CONFIG_OFF + \
112 (IWM_EEPROM_CALIB_RX_IQ << 1))
113#define IWM_EEPROM_CALIB_RXIQ_LEN sizeof(struct iwm_lmac_calib_rxiq)
114
115struct iwm_eeprom_entry {
116 char *name;
117 u32 offset;
118 u32 length;
119};
120
121int iwm_eeprom_init(struct iwm_priv *iwm);
122void iwm_eeprom_exit(struct iwm_priv *iwm);
123u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id);
124int iwm_eeprom_fat_channels(struct iwm_priv *iwm);
125u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm);
126
127#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c
deleted file mode 100644
index 6f1afe6bbc8c..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/fw.c
+++ /dev/null
@@ -1,416 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#include <linux/kernel.h>
40#include <linux/firmware.h>
41
42#include "iwm.h"
43#include "bus.h"
44#include "hal.h"
45#include "umac.h"
46#include "debug.h"
47#include "fw.h"
48#include "commands.h"
49
50static const char fw_barker[] = "*WESTOPFORNOONE*";
51
52/*
53 * @op_code: Op code we're looking for.
54 * @index: There can be several instances of the same opcode within
55 * the firmware. Index specifies which one we're looking for.
56 */
57static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw,
58 u16 op_code, u32 index)
59{
60 int offset = -EINVAL, fw_offset;
61 u32 op_index = 0;
62 const u8 *fw_ptr;
63 struct iwm_fw_hdr_rec *rec;
64
65 fw_offset = 0;
66 fw_ptr = fw->data;
67
68 /* We first need to look for the firmware barker */
69 if (memcmp(fw_ptr, fw_barker, IWM_HDR_BARKER_LEN)) {
70 IWM_ERR(iwm, "No barker string in this FW\n");
71 return -EINVAL;
72 }
73
74 if (fw->size < IWM_HDR_LEN) {
75 IWM_ERR(iwm, "FW is too small (%zu)\n", fw->size);
76 return -EINVAL;
77 }
78
79 fw_offset += IWM_HDR_BARKER_LEN;
80
81 while (fw_offset < fw->size) {
82 rec = (struct iwm_fw_hdr_rec *)(fw_ptr + fw_offset);
83
84 IWM_DBG_FW(iwm, DBG, "FW: op_code: 0x%x, len: %d @ 0x%x\n",
85 rec->op_code, rec->len, fw_offset);
86
87 if (rec->op_code == IWM_HDR_REC_OP_INVALID) {
88 IWM_DBG_FW(iwm, DBG, "Reached INVALID op code\n");
89 break;
90 }
91
92 if (rec->op_code == op_code) {
93 if (op_index == index) {
94 fw_offset += sizeof(struct iwm_fw_hdr_rec);
95 offset = fw_offset;
96 goto out;
97 }
98 op_index++;
99 }
100
101 fw_offset += sizeof(struct iwm_fw_hdr_rec) + rec->len;
102 }
103
104 out:
105 return offset;
106}
107
108static int iwm_load_firmware_chunk(struct iwm_priv *iwm,
109 const struct firmware *fw,
110 struct iwm_fw_img_desc *img_desc)
111{
112 struct iwm_udma_nonwifi_cmd target_cmd;
113 u32 chunk_size;
114 const u8 *chunk_ptr;
115 int ret = 0;
116
117 IWM_DBG_FW(iwm, INFO, "Loading FW chunk: %d bytes @ 0x%x\n",
118 img_desc->length, img_desc->address);
119
120 target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE;
121 target_cmd.handle_by_hw = 1;
122 target_cmd.op2 = 0;
123 target_cmd.resp = 0;
124 target_cmd.eop = 1;
125
126 chunk_size = img_desc->length;
127 chunk_ptr = fw->data + img_desc->offset;
128
129 while (chunk_size > 0) {
130 u32 tmp_chunk_size;
131
132 tmp_chunk_size = min_t(u32, chunk_size,
133 IWM_MAX_NONWIFI_CMD_BUFF_SIZE);
134
135 target_cmd.addr = cpu_to_le32(img_desc->address +
136 (chunk_ptr - fw->data - img_desc->offset));
137 target_cmd.op1_sz = cpu_to_le32(tmp_chunk_size);
138
139 IWM_DBG_FW(iwm, DBG, "\t%d bytes @ 0x%x\n",
140 tmp_chunk_size, target_cmd.addr);
141
142 ret = iwm_hal_send_target_cmd(iwm, &target_cmd, chunk_ptr);
143 if (ret < 0) {
144 IWM_ERR(iwm, "Couldn't load FW chunk\n");
145 break;
146 }
147
148 chunk_size -= tmp_chunk_size;
149 chunk_ptr += tmp_chunk_size;
150 }
151
152 return ret;
153}
154/*
155 * To load a fw image to the target, we basically go through the
156 * fw, looking for OP_MEM_DESC records. Once we found one, we
157 * pass it to iwm_load_firmware_chunk().
158 * The OP_MEM_DESC records contain the actuall memory chunk to be
159 * sent, but also the destination address.
160 */
161static int iwm_load_img(struct iwm_priv *iwm, const char *img_name)
162{
163 const struct firmware *fw;
164 struct iwm_fw_img_desc *img_desc;
165 struct iwm_fw_img_ver *ver;
166 int ret = 0, fw_offset;
167 u32 opcode_idx = 0, build_date;
168 char *build_tag;
169
170 ret = request_firmware(&fw, img_name, iwm_to_dev(iwm));
171 if (ret) {
172 IWM_ERR(iwm, "Request firmware failed");
173 return ret;
174 }
175
176 IWM_DBG_FW(iwm, INFO, "Start to load FW %s\n", img_name);
177
178 while (1) {
179 fw_offset = iwm_fw_op_offset(iwm, fw,
180 IWM_HDR_REC_OP_MEM_DESC,
181 opcode_idx);
182 if (fw_offset < 0)
183 break;
184
185 img_desc = (struct iwm_fw_img_desc *)(fw->data + fw_offset);
186 ret = iwm_load_firmware_chunk(iwm, fw, img_desc);
187 if (ret < 0)
188 goto err_release_fw;
189 opcode_idx++;
190 }
191
192 /* Read firmware version */
193 fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_SW_VER, 0);
194 if (fw_offset < 0)
195 goto err_release_fw;
196
197 ver = (struct iwm_fw_img_ver *)(fw->data + fw_offset);
198
199 /* Read build tag */
200 fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_TAG, 0);
201 if (fw_offset < 0)
202 goto err_release_fw;
203
204 build_tag = (char *)(fw->data + fw_offset);
205
206 /* Read build date */
207 fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_DATE, 0);
208 if (fw_offset < 0)
209 goto err_release_fw;
210
211 build_date = *(u32 *)(fw->data + fw_offset);
212
213 IWM_INFO(iwm, "%s:\n", img_name);
214 IWM_INFO(iwm, "\tVersion: %02X.%02X\n", ver->major, ver->minor);
215 IWM_INFO(iwm, "\tBuild tag: %s\n", build_tag);
216 IWM_INFO(iwm, "\tBuild date: %x-%x-%x\n",
217 IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date),
218 IWM_BUILD_DAY(build_date));
219
220 if (!strcmp(img_name, iwm->bus_ops->umac_name))
221 sprintf(iwm->umac_version, "%02X.%02X",
222 ver->major, ver->minor);
223
224 if (!strcmp(img_name, iwm->bus_ops->lmac_name))
225 sprintf(iwm->lmac_version, "%02X.%02X",
226 ver->major, ver->minor);
227
228 err_release_fw:
229 release_firmware(fw);
230
231 return ret;
232}
233
234static int iwm_load_umac(struct iwm_priv *iwm)
235{
236 struct iwm_udma_nonwifi_cmd target_cmd;
237 int ret;
238
239 ret = iwm_load_img(iwm, iwm->bus_ops->umac_name);
240 if (ret < 0)
241 return ret;
242
243 /* We've loaded the UMAC, we can tell the target to jump there */
244 target_cmd.opcode = UMAC_HDI_OUT_OPCODE_JUMP;
245 target_cmd.addr = cpu_to_le32(UMAC_MU_FW_INST_DATA_12_ADDR);
246 target_cmd.op1_sz = 0;
247 target_cmd.op2 = 0;
248 target_cmd.handle_by_hw = 0;
249 target_cmd.resp = 1 ;
250 target_cmd.eop = 1;
251
252 ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
253 if (ret < 0)
254 IWM_ERR(iwm, "Couldn't send JMP command\n");
255
256 return ret;
257}
258
259static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name)
260{
261 int ret;
262
263 ret = iwm_load_img(iwm, img_name);
264 if (ret < 0)
265 return ret;
266
267 return iwm_send_umac_reset(iwm,
268 cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_CLK_EN), 0);
269}
270
271static int iwm_init_calib(struct iwm_priv *iwm, unsigned long cfg_bitmap,
272 unsigned long expected_bitmap, u8 rx_iq_cmd)
273{
274 /* Read RX IQ calibration result from EEPROM */
275 if (test_bit(rx_iq_cmd, &cfg_bitmap)) {
276 iwm_store_rxiq_calib_result(iwm);
277 set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map);
278 }
279
280 iwm_send_prio_table(iwm);
281 iwm_send_init_calib_cfg(iwm, cfg_bitmap);
282
283 while (iwm->calib_done_map != expected_bitmap) {
284 if (iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION,
285 IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT)) {
286 IWM_DBG_FW(iwm, DBG, "Initial calibration timeout\n");
287 return -ETIMEDOUT;
288 }
289
290 IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: "
291 "0x%lx, expected calibrations: 0x%lx\n",
292 iwm->calib_done_map, expected_bitmap);
293 }
294
295 return 0;
296}
297
298/*
299 * We currently have to load 3 FWs:
300 * 1) The UMAC (Upper MAC).
301 * 2) The calibration LMAC (Lower MAC).
302 * We then send the calibration init command, so that the device can
303 * run a first calibration round.
304 * 3) The operational LMAC, which replaces the calibration one when it's
305 * done with the first calibration round.
306 *
307 * Once those 3 FWs have been loaded, we send the periodic calibration
308 * command, and then the device is available for regular 802.11 operations.
309 */
310int iwm_load_fw(struct iwm_priv *iwm)
311{
312 unsigned long init_calib_map, periodic_calib_map;
313 unsigned long expected_calib_map;
314 int ret;
315
316 /* We first start downloading the UMAC */
317 ret = iwm_load_umac(iwm);
318 if (ret < 0) {
319 IWM_ERR(iwm, "UMAC loading failed\n");
320 return ret;
321 }
322
323 /* Handle UMAC_ALIVE notification */
324 ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_ALIVE, IWM_SRC_UMAC,
325 WAIT_NOTIF_TIMEOUT);
326 if (ret) {
327 IWM_ERR(iwm, "Handle UMAC_ALIVE failed: %d\n", ret);
328 return ret;
329 }
330
331 /* UMAC is alive, we can download the calibration LMAC */
332 ret = iwm_load_lmac(iwm, iwm->bus_ops->calib_lmac_name);
333 if (ret) {
334 IWM_ERR(iwm, "Calibration LMAC loading failed\n");
335 return ret;
336 }
337
338 /* Handle UMAC_INIT_COMPLETE notification */
339 ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE,
340 IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT);
341 if (ret) {
342 IWM_ERR(iwm, "Handle INIT_COMPLETE failed for calibration "
343 "LMAC: %d\n", ret);
344 return ret;
345 }
346
347 /* Read EEPROM data */
348 ret = iwm_eeprom_init(iwm);
349 if (ret < 0) {
350 IWM_ERR(iwm, "Couldn't init eeprom array\n");
351 return ret;
352 }
353
354 init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK;
355 expected_calib_map = iwm->conf.expected_calib_map &
356 IWM_CALIB_MAP_INIT_MSK;
357 periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map);
358
359 ret = iwm_init_calib(iwm, init_calib_map, expected_calib_map,
360 CALIB_CFG_RX_IQ_IDX);
361 if (ret < 0) {
362 /* Let's try the old way */
363 ret = iwm_init_calib(iwm, expected_calib_map,
364 expected_calib_map,
365 PHY_CALIBRATE_RX_IQ_CMD);
366 if (ret < 0) {
367 IWM_ERR(iwm, "Calibration result timeout\n");
368 goto out;
369 }
370 }
371
372 /* Handle LMAC CALIBRATION_COMPLETE notification */
373 ret = iwm_notif_handle(iwm, CALIBRATION_COMPLETE_NOTIFICATION,
374 IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT);
375 if (ret) {
376 IWM_ERR(iwm, "Wait for CALIBRATION_COMPLETE timeout\n");
377 goto out;
378 }
379
380 IWM_INFO(iwm, "LMAC calibration done: 0x%lx\n", iwm->calib_done_map);
381
382 iwm_send_umac_reset(iwm, cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_RESET), 1);
383
384 ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC,
385 WAIT_NOTIF_TIMEOUT);
386 if (ret) {
387 IWM_ERR(iwm, "Wait for UMAC RESET timeout\n");
388 goto out;
389 }
390
391 /* Download the operational LMAC */
392 ret = iwm_load_lmac(iwm, iwm->bus_ops->lmac_name);
393 if (ret) {
394 IWM_ERR(iwm, "LMAC loading failed\n");
395 goto out;
396 }
397
398 ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE,
399 IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT);
400 if (ret) {
401 IWM_ERR(iwm, "Handle INIT_COMPLETE failed for LMAC: %d\n", ret);
402 goto out;
403 }
404
405 iwm_send_prio_table(iwm);
406 iwm_send_calib_results(iwm);
407 iwm_send_periodic_calib_cfg(iwm, periodic_calib_map);
408 iwm_send_ct_kill_cfg(iwm, iwm->conf.ct_kill_entry,
409 iwm->conf.ct_kill_exit);
410
411 return 0;
412
413 out:
414 iwm_eeprom_exit(iwm);
415 return ret;
416}
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.h b/drivers/net/wireless/iwmc3200wifi/fw.h
deleted file mode 100644
index c70a3b40dad3..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/fw.h
+++ /dev/null
@@ -1,100 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#ifndef __IWM_FW_H__
40#define __IWM_FW_H__
41
42/**
43 * struct iwm_fw_hdr_rec - An iwm firmware image is a
44 * concatenation of various records. Each of them is
45 * defined by an ID (aka op code), a length, and the
46 * actual data.
47 * @op_code: The record ID, see IWM_HDR_REC_OP_*
48 *
49 * @len: The record payload length
50 *
51 * @buf: The record payload
52 */
53struct iwm_fw_hdr_rec {
54 u16 op_code;
55 u16 len;
56 u8 buf[0];
57};
58
59/* Header's definitions */
60#define IWM_HDR_LEN (512)
61#define IWM_HDR_BARKER_LEN (16)
62
63/* Header's opcodes */
64#define IWM_HDR_REC_OP_INVALID (0x00)
65#define IWM_HDR_REC_OP_BUILD_DATE (0x01)
66#define IWM_HDR_REC_OP_BUILD_TAG (0x02)
67#define IWM_HDR_REC_OP_SW_VER (0x03)
68#define IWM_HDR_REC_OP_HW_SKU (0x04)
69#define IWM_HDR_REC_OP_BUILD_OPT (0x05)
70#define IWM_HDR_REC_OP_MEM_DESC (0x06)
71#define IWM_HDR_REC_USERDEFS (0x07)
72
73/* Header's records length (in bytes) */
74#define IWM_HDR_REC_LEN_BUILD_DATE (4)
75#define IWM_HDR_REC_LEN_BUILD_TAG (64)
76#define IWM_HDR_REC_LEN_SW_VER (4)
77#define IWM_HDR_REC_LEN_HW_SKU (4)
78#define IWM_HDR_REC_LEN_BUILD_OPT (4)
79#define IWM_HDR_REC_LEN_MEM_DESC (12)
80#define IWM_HDR_REC_LEN_USERDEF (64)
81
82#define IWM_BUILD_YEAR(date) ((date >> 16) & 0xffff)
83#define IWM_BUILD_MONTH(date) ((date >> 8) & 0xff)
84#define IWM_BUILD_DAY(date) (date & 0xff)
85
86struct iwm_fw_img_desc {
87 u32 offset;
88 u32 address;
89 u32 length;
90};
91
92struct iwm_fw_img_ver {
93 u8 minor;
94 u8 major;
95 u16 reserved;
96};
97
98int iwm_load_fw(struct iwm_priv *iwm);
99
100#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c
deleted file mode 100644
index 1cabcb39643f..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/hal.c
+++ /dev/null
@@ -1,470 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39/*
40 * Hardware Abstraction Layer for iwm.
41 *
42 * This file mostly defines an abstraction API for
43 * sending various commands to the target.
44 *
45 * We have 2 types of commands: wifi and non-wifi ones.
46 *
47 * - wifi commands:
48 * They are used for sending LMAC and UMAC commands,
49 * and thus are the most commonly used ones.
50 * There are 2 different wifi command types, the regular
51 * one and the LMAC one. The former is used to send
52 * UMAC commands (see UMAC_CMD_OPCODE_* from umac.h)
53 * while the latter is used for sending commands to the
54 * LMAC. If you look at LMAC commands you'll se that they
55 * are actually regular iwlwifi target commands encapsulated
56 * into a special UMAC command called UMAC passthrough.
57 * This is due to the fact the host talks exclusively
58 * to the UMAC and so there needs to be a special UMAC
59 * command for talking to the LMAC.
60 * This is how a wifi command is laid out:
61 * ------------------------
62 * | iwm_udma_out_wifi_hdr |
63 * ------------------------
64 * | SW meta_data (32 bits) |
65 * ------------------------
66 * | iwm_dev_cmd_hdr |
67 * ------------------------
68 * | payload |
69 * | .... |
70 *
71 * - non-wifi, or general commands:
72 * Those commands are handled by the device's bootrom,
73 * and are typically sent when the UMAC and the LMAC
74 * are not yet available.
75 * * This is how a non-wifi command is laid out:
76 * ---------------------------
77 * | iwm_udma_out_nonwifi_hdr |
78 * ---------------------------
79 * | payload |
80 * | .... |
81
82 *
83 * All the commands start with a UDMA header, which is
84 * basically a 32 bits field. The 4 LSB there define
85 * an opcode that allows the target to differentiate
86 * between wifi (opcode is 0xf) and non-wifi commands
87 * (opcode is [0..0xe]).
88 *
89 * When a command (wifi or non-wifi) is supposed to receive
90 * an answer, we queue the command buffer. When we do receive
91 * a command response from the UMAC, we go through the list
92 * of pending command, and pass both the command and the answer
93 * to the rx handler. Each command is sent with a unique
94 * sequence id, and the answer is sent with the same one. This
95 * is how we're supposed to match an answer with its command.
96 * See rx.c:iwm_rx_handle_[non]wifi() and iwm_get_pending_[non]wifi()
97 * for the implementation details.
98 */
99#include <linux/kernel.h>
100#include <linux/netdevice.h>
101#include <linux/slab.h>
102
103#include "iwm.h"
104#include "bus.h"
105#include "hal.h"
106#include "umac.h"
107#include "debug.h"
108#include "trace.h"
109
110static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
111 struct iwm_nonwifi_cmd *cmd,
112 struct iwm_udma_nonwifi_cmd *udma_cmd)
113{
114 INIT_LIST_HEAD(&cmd->pending);
115
116 spin_lock(&iwm->cmd_lock);
117
118 cmd->resp_received = 0;
119
120 cmd->seq_num = iwm->nonwifi_seq_num;
121 udma_cmd->seq_num = cpu_to_le16(cmd->seq_num);
122
123 iwm->nonwifi_seq_num++;
124 iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX;
125
126 if (udma_cmd->resp)
127 list_add_tail(&cmd->pending, &iwm->nonwifi_pending_cmd);
128
129 spin_unlock(&iwm->cmd_lock);
130
131 cmd->buf.start = cmd->buf.payload;
132 cmd->buf.len = 0;
133
134 memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
135
136 return cmd->seq_num;
137}
138
139u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm)
140{
141 u16 seq_num = iwm->wifi_seq_num;
142
143 iwm->wifi_seq_num++;
144 iwm->wifi_seq_num %= UMAC_WIFI_SEQ_NUM_MAX;
145
146 return seq_num;
147}
148
149static void iwm_wifi_cmd_init(struct iwm_priv *iwm,
150 struct iwm_wifi_cmd *cmd,
151 struct iwm_udma_wifi_cmd *udma_cmd,
152 struct iwm_umac_cmd *umac_cmd,
153 struct iwm_lmac_cmd *lmac_cmd,
154 u16 payload_size)
155{
156 INIT_LIST_HEAD(&cmd->pending);
157
158 spin_lock(&iwm->cmd_lock);
159
160 cmd->seq_num = iwm_alloc_wifi_cmd_seq(iwm);
161 umac_cmd->seq_num = cpu_to_le16(cmd->seq_num);
162
163 if (umac_cmd->resp)
164 list_add_tail(&cmd->pending, &iwm->wifi_pending_cmd);
165
166 spin_unlock(&iwm->cmd_lock);
167
168 cmd->buf.start = cmd->buf.payload;
169 cmd->buf.len = 0;
170
171 if (lmac_cmd) {
172 cmd->buf.start -= sizeof(struct iwm_lmac_hdr);
173
174 lmac_cmd->seq_num = cpu_to_le16(cmd->seq_num);
175 lmac_cmd->count = cpu_to_le16(payload_size);
176
177 memcpy(&cmd->lmac_cmd, lmac_cmd, sizeof(*lmac_cmd));
178
179 umac_cmd->count = cpu_to_le16(sizeof(struct iwm_lmac_hdr));
180 } else
181 umac_cmd->count = 0;
182
183 umac_cmd->count = cpu_to_le16(payload_size +
184 le16_to_cpu(umac_cmd->count));
185 udma_cmd->count = cpu_to_le16(sizeof(struct iwm_umac_fw_cmd_hdr) +
186 le16_to_cpu(umac_cmd->count));
187
188 memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
189 memcpy(&cmd->umac_cmd, umac_cmd, sizeof(*umac_cmd));
190}
191
192void iwm_cmd_flush(struct iwm_priv *iwm)
193{
194 struct iwm_wifi_cmd *wcmd, *wnext;
195 struct iwm_nonwifi_cmd *nwcmd, *nwnext;
196
197 list_for_each_entry_safe(wcmd, wnext, &iwm->wifi_pending_cmd, pending) {
198 list_del(&wcmd->pending);
199 kfree(wcmd);
200 }
201
202 list_for_each_entry_safe(nwcmd, nwnext, &iwm->nonwifi_pending_cmd,
203 pending) {
204 list_del(&nwcmd->pending);
205 kfree(nwcmd);
206 }
207}
208
209struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, u16 seq_num)
210{
211 struct iwm_wifi_cmd *cmd;
212
213 list_for_each_entry(cmd, &iwm->wifi_pending_cmd, pending)
214 if (cmd->seq_num == seq_num) {
215 list_del(&cmd->pending);
216 return cmd;
217 }
218
219 return NULL;
220}
221
222struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm,
223 u8 seq_num, u8 cmd_opcode)
224{
225 struct iwm_nonwifi_cmd *cmd;
226
227 list_for_each_entry(cmd, &iwm->nonwifi_pending_cmd, pending)
228 if ((cmd->seq_num == seq_num) &&
229 (cmd->udma_cmd.opcode == cmd_opcode) &&
230 (cmd->resp_received)) {
231 list_del(&cmd->pending);
232 return cmd;
233 }
234
235 return NULL;
236}
237
238static void iwm_build_udma_nonwifi_hdr(struct iwm_priv *iwm,
239 struct iwm_udma_out_nonwifi_hdr *hdr,
240 struct iwm_udma_nonwifi_cmd *cmd)
241{
242 memset(hdr, 0, sizeof(*hdr));
243
244 SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, cmd->opcode);
245 SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP, cmd->resp);
246 SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, 1);
247 SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW,
248 cmd->handle_by_hw);
249 SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE);
250 SET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM,
251 le16_to_cpu(cmd->seq_num));
252
253 hdr->addr = cmd->addr;
254 hdr->op1_sz = cmd->op1_sz;
255 hdr->op2 = cmd->op2;
256}
257
258static int iwm_send_udma_nonwifi_cmd(struct iwm_priv *iwm,
259 struct iwm_nonwifi_cmd *cmd)
260{
261 struct iwm_udma_out_nonwifi_hdr *udma_hdr;
262 struct iwm_nonwifi_cmd_buff *buf;
263 struct iwm_udma_nonwifi_cmd *udma_cmd = &cmd->udma_cmd;
264
265 buf = &cmd->buf;
266
267 buf->start -= sizeof(struct iwm_umac_nonwifi_out_hdr);
268 buf->len += sizeof(struct iwm_umac_nonwifi_out_hdr);
269
270 udma_hdr = (struct iwm_udma_out_nonwifi_hdr *)(buf->start);
271
272 iwm_build_udma_nonwifi_hdr(iwm, udma_hdr, udma_cmd);
273
274 IWM_DBG_CMD(iwm, DBG,
275 "Send UDMA nonwifi cmd: opcode = 0x%x, resp = 0x%x, "
276 "hw = 0x%x, seqnum = %d, addr = 0x%x, op1_sz = 0x%x, "
277 "op2 = 0x%x\n", udma_cmd->opcode, udma_cmd->resp,
278 udma_cmd->handle_by_hw, cmd->seq_num, udma_cmd->addr,
279 udma_cmd->op1_sz, udma_cmd->op2);
280
281 trace_iwm_tx_nonwifi_cmd(iwm, udma_hdr);
282 return iwm_bus_send_chunk(iwm, buf->start, buf->len);
283}
284
285void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop)
286{
287 struct iwm_udma_out_wifi_hdr *hdr = (struct iwm_udma_out_wifi_hdr *)buf;
288
289 SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, eop);
290}
291
292void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm,
293 struct iwm_udma_out_wifi_hdr *hdr,
294 struct iwm_udma_wifi_cmd *cmd)
295{
296 memset(hdr, 0, sizeof(*hdr));
297
298 SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, UMAC_HDI_OUT_OPCODE_WIFI);
299 SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, cmd->eop);
300 SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE);
301
302 SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_BYTE_COUNT,
303 le16_to_cpu(cmd->count));
304 SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_CREDIT_GRP, cmd->credit_group);
305 SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_RATID, cmd->ra_tid);
306 SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_LMAC_OFFSET, cmd->lmac_offset);
307}
308
309void iwm_build_umac_hdr(struct iwm_priv *iwm,
310 struct iwm_umac_fw_cmd_hdr *hdr,
311 struct iwm_umac_cmd *cmd)
312{
313 memset(hdr, 0, sizeof(*hdr));
314
315 SET_VAL32(hdr->meta_data, UMAC_FW_CMD_BYTE_COUNT,
316 le16_to_cpu(cmd->count));
317 SET_VAL32(hdr->meta_data, UMAC_FW_CMD_TX_STA_COLOR, cmd->color);
318 SET_VAL8(hdr->cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ, cmd->resp);
319
320 hdr->cmd.cmd = cmd->id;
321 hdr->cmd.seq_num = cmd->seq_num;
322}
323
324static int iwm_send_udma_wifi_cmd(struct iwm_priv *iwm,
325 struct iwm_wifi_cmd *cmd)
326{
327 struct iwm_umac_wifi_out_hdr *umac_hdr;
328 struct iwm_wifi_cmd_buff *buf;
329 struct iwm_udma_wifi_cmd *udma_cmd = &cmd->udma_cmd;
330 struct iwm_umac_cmd *umac_cmd = &cmd->umac_cmd;
331 int ret;
332
333 buf = &cmd->buf;
334
335 buf->start -= sizeof(struct iwm_umac_wifi_out_hdr);
336 buf->len += sizeof(struct iwm_umac_wifi_out_hdr);
337
338 umac_hdr = (struct iwm_umac_wifi_out_hdr *)(buf->start);
339
340 iwm_build_udma_wifi_hdr(iwm, &umac_hdr->hw_hdr, udma_cmd);
341 iwm_build_umac_hdr(iwm, &umac_hdr->sw_hdr, umac_cmd);
342
343 IWM_DBG_CMD(iwm, DBG,
344 "Send UDMA wifi cmd: opcode = 0x%x, UMAC opcode = 0x%x, "
345 "eop = 0x%x, count = 0x%x, credit_group = 0x%x, "
346 "ra_tid = 0x%x, lmac_offset = 0x%x, seqnum = %d\n",
347 UMAC_HDI_OUT_OPCODE_WIFI, umac_cmd->id,
348 udma_cmd->eop, udma_cmd->count, udma_cmd->credit_group,
349 udma_cmd->ra_tid, udma_cmd->lmac_offset, cmd->seq_num);
350
351 if (umac_cmd->id == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH)
352 IWM_DBG_CMD(iwm, DBG, "\tLMAC opcode: 0x%x\n",
353 cmd->lmac_cmd.id);
354
355 ret = iwm_tx_credit_alloc(iwm, udma_cmd->credit_group, buf->len);
356
357 /* We keep sending UMAC reset regardless of the command credits.
358 * The UMAC is supposed to be reset anyway and the Tx credits are
359 * reinitialized afterwards. If we are lucky, the reset could
360 * still be done even though we have run out of credits for the
361 * command pool at this moment.*/
362 if (ret && (umac_cmd->id != UMAC_CMD_OPCODE_RESET)) {
363 IWM_DBG_TX(iwm, DBG, "Failed to alloc tx credit for cmd %d\n",
364 umac_cmd->id);
365 return ret;
366 }
367
368 trace_iwm_tx_wifi_cmd(iwm, umac_hdr);
369 return iwm_bus_send_chunk(iwm, buf->start, buf->len);
370}
371
372/* target_cmd a.k.a udma_nonwifi_cmd can be sent when UMAC is not available */
373int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
374 struct iwm_udma_nonwifi_cmd *udma_cmd,
375 const void *payload)
376{
377 struct iwm_nonwifi_cmd *cmd;
378 int ret, seq_num;
379
380 cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL);
381 if (!cmd) {
382 IWM_ERR(iwm, "Couldn't alloc memory for hal cmd\n");
383 return -ENOMEM;
384 }
385
386 seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
387
388 if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE ||
389 cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) {
390 cmd->buf.len = le32_to_cpu(cmd->udma_cmd.op1_sz);
391 memcpy(&cmd->buf.payload, payload, cmd->buf.len);
392 }
393
394 ret = iwm_send_udma_nonwifi_cmd(iwm, cmd);
395
396 if (!udma_cmd->resp)
397 kfree(cmd);
398
399 if (ret < 0)
400 return ret;
401
402 return seq_num;
403}
404
405static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,
406 struct iwm_lmac_cmd *cmd)
407{
408 memset(hdr, 0, sizeof(*hdr));
409
410 hdr->id = cmd->id;
411 hdr->flags = 0; /* Is this ever used? */
412 hdr->seq_num = cmd->seq_num;
413}
414
415/*
416 * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC.
417 * Sending command to the LMAC is equivalent to sending a
418 * regular UMAC command with the LMAC passthrough or the LMAC
419 * wrapper UMAC command IDs.
420 */
421int iwm_hal_send_host_cmd(struct iwm_priv *iwm,
422 struct iwm_udma_wifi_cmd *udma_cmd,
423 struct iwm_umac_cmd *umac_cmd,
424 struct iwm_lmac_cmd *lmac_cmd,
425 const void *payload, u16 payload_size)
426{
427 struct iwm_wifi_cmd *cmd;
428 struct iwm_lmac_hdr *hdr;
429 int lmac_hdr_len = 0;
430 int ret;
431
432 cmd = kzalloc(sizeof(struct iwm_wifi_cmd), GFP_KERNEL);
433 if (!cmd) {
434 IWM_ERR(iwm, "Couldn't alloc memory for wifi hal cmd\n");
435 return -ENOMEM;
436 }
437
438 iwm_wifi_cmd_init(iwm, cmd, udma_cmd, umac_cmd, lmac_cmd, payload_size);
439
440 if (lmac_cmd) {
441 hdr = (struct iwm_lmac_hdr *)(cmd->buf.start);
442
443 iwm_build_lmac_hdr(iwm, hdr, &cmd->lmac_cmd);
444 lmac_hdr_len = sizeof(struct iwm_lmac_hdr);
445 }
446
447 memcpy(cmd->buf.payload, payload, payload_size);
448 cmd->buf.len = le16_to_cpu(umac_cmd->count);
449
450 ret = iwm_send_udma_wifi_cmd(iwm, cmd);
451
452 /* We free the cmd if we're not expecting any response */
453 if (!umac_cmd->resp)
454 kfree(cmd);
455 return ret;
456}
457
458/*
459 * iwm_hal_send_umac_cmd(): This is a special case for
460 * iwm_hal_send_host_cmd() to send direct UMAC cmd (without
461 * LMAC involved).
462 */
463int iwm_hal_send_umac_cmd(struct iwm_priv *iwm,
464 struct iwm_udma_wifi_cmd *udma_cmd,
465 struct iwm_umac_cmd *umac_cmd,
466 const void *payload, u16 payload_size)
467{
468 return iwm_hal_send_host_cmd(iwm, udma_cmd, umac_cmd, NULL,
469 payload, payload_size);
470}
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.h b/drivers/net/wireless/iwmc3200wifi/hal.h
deleted file mode 100644
index c20936d9b6b7..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/hal.h
+++ /dev/null
@@ -1,237 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#ifndef _IWM_HAL_H_
40#define _IWM_HAL_H_
41
42#include "umac.h"
43
44#define GET_VAL8(s, name) ((s >> name##_POS) & name##_SEED)
45#define GET_VAL16(s, name) ((le16_to_cpu(s) >> name##_POS) & name##_SEED)
46#define GET_VAL32(s, name) ((le32_to_cpu(s) >> name##_POS) & name##_SEED)
47
48#define SET_VAL8(s, name, val) \
49do { \
50 s = (s & ~(name##_SEED << name##_POS)) | \
51 ((val & name##_SEED) << name##_POS); \
52} while (0)
53
54#define SET_VAL16(s, name, val) \
55do { \
56 s = cpu_to_le16((le16_to_cpu(s) & ~(name##_SEED << name##_POS)) | \
57 ((val & name##_SEED) << name##_POS)); \
58} while (0)
59
60#define SET_VAL32(s, name, val) \
61do { \
62 s = cpu_to_le32((le32_to_cpu(s) & ~(name##_SEED << name##_POS)) | \
63 ((val & name##_SEED) << name##_POS)); \
64} while (0)
65
66
67#define UDMA_UMAC_INIT { .eop = 1, \
68 .credit_group = 0x4, \
69 .ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD, \
70 .lmac_offset = 0 }
71#define UDMA_LMAC_INIT { .eop = 1, \
72 .credit_group = 0x4, \
73 .ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD, \
74 .lmac_offset = 4 }
75
76
77/* UDMA IN OP CODE -- cmd bits [3:0] */
78#define UDMA_HDI_IN_NW_CMD_OPCODE_POS 0
79#define UDMA_HDI_IN_NW_CMD_OPCODE_SEED 0xF
80
81#define UDMA_IN_OPCODE_GENERAL_RESP 0x0
82#define UDMA_IN_OPCODE_READ_RESP 0x1
83#define UDMA_IN_OPCODE_WRITE_RESP 0x2
84#define UDMA_IN_OPCODE_PERS_WRITE_RESP 0x5
85#define UDMA_IN_OPCODE_PERS_READ_RESP 0x6
86#define UDMA_IN_OPCODE_RD_MDFY_WR_RESP 0x7
87#define UDMA_IN_OPCODE_EP_MNGMT_MSG 0x8
88#define UDMA_IN_OPCODE_CRDT_CHNG_MSG 0x9
89#define UDMA_IN_OPCODE_CNTRL_DATABASE_MSG 0xA
90#define UDMA_IN_OPCODE_SW_MSG 0xB
91#define UDMA_IN_OPCODE_WIFI 0xF
92#define UDMA_IN_OPCODE_WIFI_LMAC 0x1F
93#define UDMA_IN_OPCODE_WIFI_UMAC 0x2F
94
95/* HW API: udma_hdi_nonwifi API (OUT and IN) */
96
97/* iwm_udma_nonwifi_cmd request response -- bits [9:9] */
98#define UDMA_HDI_OUT_NW_CMD_RESP_POS 9
99#define UDMA_HDI_OUT_NW_CMD_RESP_SEED 0x1
100
101/* iwm_udma_nonwifi_cmd handle by HW -- bits [11:11] */
102#define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_POS 11
103#define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_SEED 0x1
104
105/* iwm_udma_nonwifi_cmd sequence-number -- bits [12:15] */
106#define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_POS 12
107#define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_SEED 0xF
108
109/* UDMA IN Non-WIFI HW sequence number -- bits [12:15] */
110#define UDMA_IN_NW_HW_SEQ_NUM_POS 12
111#define UDMA_IN_NW_HW_SEQ_NUM_SEED 0xF
112
113/* UDMA IN Non-WIFI HW signature -- bits [16:31] */
114#define UDMA_IN_NW_HW_SIG_POS 16
115#define UDMA_IN_NW_HW_SIG_SEED 0xFFFF
116
117/* fixed signature */
118#define UDMA_IN_NW_HW_SIG 0xCBBC
119
120/* UDMA IN Non-WIFI HW block length -- bits [32:35] */
121#define UDMA_IN_NW_HW_LENGTH_SEED 0xF
122#define UDMA_IN_NW_HW_LENGTH_POS 32
123
124/* End of HW API: udma_hdi_nonwifi API (OUT and IN) */
125
126#define IWM_SDIO_FW_MAX_CHUNK_SIZE 2032
127#define IWM_MAX_WIFI_HEADERS_SIZE 32
128#define IWM_MAX_NONWIFI_HEADERS_SIZE 16
129#define IWM_MAX_NONWIFI_CMD_BUFF_SIZE (IWM_SDIO_FW_MAX_CHUNK_SIZE - \
130 IWM_MAX_NONWIFI_HEADERS_SIZE)
131#define IWM_MAX_WIFI_CMD_BUFF_SIZE (IWM_SDIO_FW_MAX_CHUNK_SIZE - \
132 IWM_MAX_WIFI_HEADERS_SIZE)
133
134#define IWM_HAL_CONCATENATE_BUF_SIZE (32 * 1024)
135
136struct iwm_wifi_cmd_buff {
137 u16 len;
138 u8 *start;
139 u8 hdr[IWM_MAX_WIFI_HEADERS_SIZE];
140 u8 payload[IWM_MAX_WIFI_CMD_BUFF_SIZE];
141};
142
143struct iwm_nonwifi_cmd_buff {
144 u16 len;
145 u8 *start;
146 u8 hdr[IWM_MAX_NONWIFI_HEADERS_SIZE];
147 u8 payload[IWM_MAX_NONWIFI_CMD_BUFF_SIZE];
148};
149
150struct iwm_udma_nonwifi_cmd {
151 u8 opcode;
152 u8 eop;
153 u8 resp;
154 u8 handle_by_hw;
155 __le32 addr;
156 __le32 op1_sz;
157 __le32 op2;
158 __le16 seq_num;
159};
160
161struct iwm_udma_wifi_cmd {
162 __le16 count;
163 u8 eop;
164 u8 credit_group;
165 u8 ra_tid;
166 u8 lmac_offset;
167};
168
169struct iwm_umac_cmd {
170 u8 id;
171 __le16 count;
172 u8 resp;
173 __le16 seq_num;
174 u8 color;
175};
176
177struct iwm_lmac_cmd {
178 u8 id;
179 __le16 count;
180 u8 resp;
181 __le16 seq_num;
182};
183
184struct iwm_nonwifi_cmd {
185 u16 seq_num;
186 bool resp_received;
187 struct list_head pending;
188 struct iwm_udma_nonwifi_cmd udma_cmd;
189 struct iwm_umac_cmd umac_cmd;
190 struct iwm_lmac_cmd lmac_cmd;
191 struct iwm_nonwifi_cmd_buff buf;
192 u32 flags;
193};
194
195struct iwm_wifi_cmd {
196 u16 seq_num;
197 struct list_head pending;
198 struct iwm_udma_wifi_cmd udma_cmd;
199 struct iwm_umac_cmd umac_cmd;
200 struct iwm_lmac_cmd lmac_cmd;
201 struct iwm_wifi_cmd_buff buf;
202 u32 flags;
203};
204
205void iwm_cmd_flush(struct iwm_priv *iwm);
206
207struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm,
208 u16 seq_num);
209struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm,
210 u8 seq_num, u8 cmd_opcode);
211
212
213int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
214 struct iwm_udma_nonwifi_cmd *ucmd,
215 const void *payload);
216
217int iwm_hal_send_host_cmd(struct iwm_priv *iwm,
218 struct iwm_udma_wifi_cmd *udma_cmd,
219 struct iwm_umac_cmd *umac_cmd,
220 struct iwm_lmac_cmd *lmac_cmd,
221 const void *payload, u16 payload_size);
222
223int iwm_hal_send_umac_cmd(struct iwm_priv *iwm,
224 struct iwm_udma_wifi_cmd *udma_cmd,
225 struct iwm_umac_cmd *umac_cmd,
226 const void *payload, u16 payload_size);
227
228u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm);
229
230void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop);
231void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm,
232 struct iwm_udma_out_wifi_hdr *hdr,
233 struct iwm_udma_wifi_cmd *cmd);
234void iwm_build_umac_hdr(struct iwm_priv *iwm,
235 struct iwm_umac_fw_cmd_hdr *hdr,
236 struct iwm_umac_cmd *cmd);
237#endif /* _IWM_HAL_H_ */
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
deleted file mode 100644
index 51d7efa15ae6..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ /dev/null
@@ -1,367 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#ifndef __IWM_H__
40#define __IWM_H__
41
42#include <linux/netdevice.h>
43#include <linux/wireless.h>
44#include <net/cfg80211.h>
45
46#include "debug.h"
47#include "hal.h"
48#include "umac.h"
49#include "lmac.h"
50#include "eeprom.h"
51#include "trace.h"
52
53#define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation"
54#define IWM_AUTHOR "<ilw@linux.intel.com>"
55
56#define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX
57#define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA
58#define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW
59#define IWM_SRC_NUM 3
60
61#define IWM_POWER_INDEX_MIN 0
62#define IWM_POWER_INDEX_MAX 5
63#define IWM_POWER_INDEX_DEFAULT 3
64
65struct iwm_conf {
66 u32 sdio_ior_timeout;
67 unsigned long calib_map;
68 unsigned long expected_calib_map;
69 u8 ct_kill_entry;
70 u8 ct_kill_exit;
71 bool reset_on_fatal_err;
72 bool auto_connect;
73 bool wimax_not_present;
74 bool enable_qos;
75 u32 mode;
76
77 u32 power_index;
78 u32 frag_threshold;
79 u32 rts_threshold;
80 bool cts_to_self;
81
82 u32 assoc_timeout;
83 u32 roam_timeout;
84 u32 wireless_mode;
85
86 u8 ibss_band;
87 u8 ibss_channel;
88
89 u8 mac_addr[ETH_ALEN];
90};
91
92enum {
93 COEX_MODE_SA = 1,
94 COEX_MODE_XOR,
95 COEX_MODE_CM,
96 COEX_MODE_MAX,
97};
98
99struct iwm_if_ops;
100struct iwm_wifi_cmd;
101
102struct pool_entry {
103 int id; /* group id */
104 int sid; /* super group id */
105 int min_pages; /* min capacity in pages */
106 int max_pages; /* max capacity in pages */
107 int alloc_pages; /* allocated # of pages. incresed by driver */
108 int total_freed_pages; /* total freed # of pages. incresed by UMAC */
109};
110
111struct spool_entry {
112 int id;
113 int max_pages;
114 int alloc_pages;
115};
116
117struct iwm_tx_credit {
118 spinlock_t lock;
119 int pool_nr;
120 unsigned long full_pools_map; /* bitmap for # of filled tx pools */
121 struct pool_entry pools[IWM_MACS_OUT_GROUPS];
122 struct spool_entry spools[IWM_MACS_OUT_SGROUPS];
123};
124
125struct iwm_notif {
126 struct list_head pending;
127 u32 cmd_id;
128 void *cmd;
129 u8 src;
130 void *buf;
131 unsigned long buf_size;
132};
133
134struct iwm_tid_info {
135 __le16 last_seq_num;
136 bool stopped;
137 struct mutex mutex;
138};
139
140struct iwm_sta_info {
141 u8 addr[ETH_ALEN];
142 bool valid;
143 bool qos;
144 u8 color;
145 struct iwm_tid_info tid_info[IWM_UMAC_TID_NR];
146};
147
148struct iwm_tx_info {
149 u8 sta;
150 u8 color;
151 u8 tid;
152};
153
154struct iwm_rx_info {
155 unsigned long rx_size;
156 unsigned long rx_buf_size;
157};
158
159#define IWM_NUM_KEYS 4
160
161struct iwm_umac_key_hdr {
162 u8 mac[ETH_ALEN];
163 u8 key_idx;
164 u8 multicast; /* BCast encrypt & BCast decrypt of frames FROM mac */
165} __packed;
166
167struct iwm_key {
168 struct iwm_umac_key_hdr hdr;
169 u32 cipher;
170 u8 key[WLAN_MAX_KEY_LEN];
171 u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
172 int key_len;
173 int seq_len;
174};
175
176#define IWM_RX_ID_HASH 0xff
177#define IWM_RX_ID_GET_HASH(id) ((id) % IWM_RX_ID_HASH)
178
179#define IWM_STA_TABLE_NUM 16
180#define IWM_TX_LIST_SIZE 64
181#define IWM_RX_LIST_SIZE 256
182
183#define IWM_SCAN_ID_MAX 0xff
184
185#define IWM_STATUS_READY 0
186#define IWM_STATUS_SCANNING 1
187#define IWM_STATUS_SCAN_ABORTING 2
188#define IWM_STATUS_SME_CONNECTING 3
189#define IWM_STATUS_ASSOCIATED 4
190#define IWM_STATUS_RESETTING 5
191
192struct iwm_tx_queue {
193 int id;
194 struct sk_buff_head queue;
195 struct sk_buff_head stopped_queue;
196 spinlock_t lock;
197 struct workqueue_struct *wq;
198 struct work_struct worker;
199 u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE];
200 int concat_count;
201 u8 *concat_ptr;
202};
203
204/* Queues 0 ~ 3 for AC data, 5 for iPAN */
205#define IWM_TX_QUEUES 5
206#define IWM_TX_DATA_QUEUES 4
207#define IWM_TX_CMD_QUEUE 4
208
209struct iwm_bss_info {
210 struct list_head node;
211 struct cfg80211_bss *cfg_bss;
212 struct iwm_umac_notif_bss_info *bss;
213};
214
215typedef int (*iwm_handler)(struct iwm_priv *priv, u8 *buf,
216 unsigned long buf_size, struct iwm_wifi_cmd *cmd);
217
218#define IWM_WATCHDOG_PERIOD (6 * HZ)
219
220struct iwm_priv {
221 struct wireless_dev *wdev;
222 struct iwm_if_ops *bus_ops;
223
224 struct iwm_conf conf;
225
226 unsigned long status;
227
228 struct list_head pending_notif;
229 wait_queue_head_t notif_queue;
230
231 wait_queue_head_t nonwifi_queue;
232
233 unsigned long calib_done_map;
234 struct {
235 u8 *buf;
236 u32 size;
237 } calib_res[CALIBRATION_CMD_NUM];
238
239 struct iwm_umac_profile *umac_profile;
240 bool umac_profile_active;
241
242 u8 bssid[ETH_ALEN];
243 u8 channel;
244 u16 rate;
245 u32 txpower;
246
247 struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM];
248 struct list_head bss_list;
249
250 void (*nonwifi_rx_handlers[UMAC_HDI_IN_OPCODE_NONWIFI_MAX])
251 (struct iwm_priv *priv, u8 *buf, unsigned long buf_size);
252
253 const iwm_handler *umac_handlers;
254 const iwm_handler *lmac_handlers;
255 DECLARE_BITMAP(lmac_handler_map, LMAC_COMMAND_ID_NUM);
256 DECLARE_BITMAP(umac_handler_map, LMAC_COMMAND_ID_NUM);
257 DECLARE_BITMAP(udma_handler_map, LMAC_COMMAND_ID_NUM);
258
259 struct list_head wifi_pending_cmd;
260 struct list_head nonwifi_pending_cmd;
261 u16 wifi_seq_num;
262 u8 nonwifi_seq_num;
263 spinlock_t cmd_lock;
264
265 u32 core_enabled;
266
267 u8 scan_id;
268 struct cfg80211_scan_request *scan_request;
269
270 struct sk_buff_head rx_list;
271 struct list_head rx_tickets;
272 spinlock_t ticket_lock;
273 struct list_head rx_packets[IWM_RX_ID_HASH];
274 spinlock_t packet_lock[IWM_RX_ID_HASH];
275 struct workqueue_struct *rx_wq;
276 struct work_struct rx_worker;
277
278 struct iwm_tx_credit tx_credit;
279 struct iwm_tx_queue txq[IWM_TX_QUEUES];
280
281 struct iwm_key keys[IWM_NUM_KEYS];
282 s8 default_key;
283
284 DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX);
285 wait_queue_head_t wifi_ntfy_queue;
286
287 wait_queue_head_t mlme_queue;
288
289 struct iw_statistics wstats;
290 struct delayed_work stats_request;
291 struct delayed_work disconnect;
292 struct delayed_work ct_kill_delay;
293
294 struct iwm_debugfs dbg;
295
296 u8 *eeprom;
297 struct timer_list watchdog;
298 struct work_struct reset_worker;
299 struct work_struct auth_retry_worker;
300 struct mutex mutex;
301
302 u8 *req_ie;
303 int req_ie_len;
304 u8 *resp_ie;
305 int resp_ie_len;
306
307 struct iwm_fw_error_hdr *last_fw_err;
308 char umac_version[8];
309 char lmac_version[8];
310
311 char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
312};
313
314static inline void *iwm_private(struct iwm_priv *iwm)
315{
316 BUG_ON(!iwm);
317 return &iwm->private;
318}
319
320#define hw_to_iwm(h) (h->iwm)
321#define iwm_to_dev(i) (wiphy_dev(i->wdev->wiphy))
322#define iwm_to_wiphy(i) (i->wdev->wiphy)
323#define wiphy_to_iwm(w) (struct iwm_priv *)(wiphy_priv(w))
324#define iwm_to_wdev(i) (i->wdev)
325#define wdev_to_iwm(w) (struct iwm_priv *)(wdev_priv(w))
326#define iwm_to_ndev(i) (i->wdev->netdev)
327#define ndev_to_iwm(n) (wdev_to_iwm(n->ieee80211_ptr))
328#define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb))
329#define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb)
330
331void *iwm_if_alloc(int sizeof_bus, struct device *dev,
332 struct iwm_if_ops *if_ops);
333void iwm_if_free(struct iwm_priv *iwm);
334int iwm_if_add(struct iwm_priv *iwm);
335void iwm_if_remove(struct iwm_priv *iwm);
336int iwm_mode_to_nl80211_iftype(int mode);
337int iwm_priv_init(struct iwm_priv *iwm);
338void iwm_priv_deinit(struct iwm_priv *iwm);
339void iwm_reset(struct iwm_priv *iwm);
340void iwm_resetting(struct iwm_priv *iwm);
341void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
342 struct iwm_umac_notif_alive *alive);
343int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb);
344int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd,
345 u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size);
346int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout);
347void iwm_init_default_profile(struct iwm_priv *iwm,
348 struct iwm_umac_profile *profile);
349void iwm_link_on(struct iwm_priv *iwm);
350void iwm_link_off(struct iwm_priv *iwm);
351int iwm_up(struct iwm_priv *iwm);
352int iwm_down(struct iwm_priv *iwm);
353
354/* TX API */
355int iwm_tid_to_queue(u16 tid);
356void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages);
357void iwm_tx_worker(struct work_struct *work);
358int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
359
360/* RX API */
361void iwm_rx_setup_handlers(struct iwm_priv *iwm);
362int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size);
363int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size,
364 struct iwm_wifi_cmd *cmd);
365void iwm_rx_free(struct iwm_priv *iwm);
366
367#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
deleted file mode 100644
index 5ddcdf8c70c0..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ /dev/null
@@ -1,484 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#ifndef __IWM_LMAC_H__
40#define __IWM_LMAC_H__
41
42struct iwm_lmac_hdr {
43 u8 id;
44 u8 flags;
45 __le16 seq_num;
46} __packed;
47
48/* LMAC commands */
49#define CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK 0x1
50
51struct iwm_lmac_cal_cfg_elt {
52 __le32 enable; /* 1 means LMAC needs to do something */
53 __le32 start; /* 1 to start calibration, 0 to stop */
54 __le32 send_res; /* 1 for sending back results */
55 __le32 apply_res; /* 1 for applying calibration results to HW */
56 __le32 reserved;
57} __packed;
58
59struct iwm_lmac_cal_cfg_status {
60 struct iwm_lmac_cal_cfg_elt init;
61 struct iwm_lmac_cal_cfg_elt periodic;
62 __le32 flags; /* CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK */
63} __packed;
64
65struct iwm_lmac_cal_cfg_cmd {
66 struct iwm_lmac_cal_cfg_status ucode_cfg;
67 struct iwm_lmac_cal_cfg_status driver_cfg;
68 __le32 reserved;
69} __packed;
70
71struct iwm_lmac_cal_cfg_resp {
72 __le32 status;
73} __packed;
74
75#define IWM_CARD_STATE_SW_HW_ENABLED 0x00
76#define IWM_CARD_STATE_HW_DISABLED 0x01
77#define IWM_CARD_STATE_SW_DISABLED 0x02
78#define IWM_CARD_STATE_CTKILL_DISABLED 0x04
79#define IWM_CARD_STATE_IS_RXON 0x10
80
81struct iwm_lmac_card_state {
82 __le32 flags;
83} __packed;
84
85/**
86 * COEX_PRIORITY_TABLE_CMD
87 *
88 * Priority entry for each state
89 * Will keep two tables, for STA and WIPAN
90 */
91enum {
92 /* UN-ASSOCIATION PART */
93 COEX_UNASSOC_IDLE = 0,
94 COEX_UNASSOC_MANUAL_SCAN,
95 COEX_UNASSOC_AUTO_SCAN,
96
97 /* CALIBRATION */
98 COEX_CALIBRATION,
99 COEX_PERIODIC_CALIBRATION,
100
101 /* CONNECTION */
102 COEX_CONNECTION_ESTAB,
103
104 /* ASSOCIATION PART */
105 COEX_ASSOCIATED_IDLE,
106 COEX_ASSOC_MANUAL_SCAN,
107 COEX_ASSOC_AUTO_SCAN,
108 COEX_ASSOC_ACTIVE_LEVEL,
109
110 /* RF ON/OFF */
111 COEX_RF_ON,
112 COEX_RF_OFF,
113 COEX_STAND_ALONE_DEBUG,
114
115 /* IPNN */
116 COEX_IPAN_ASSOC_LEVEL,
117
118 /* RESERVED */
119 COEX_RSRVD1,
120 COEX_RSRVD2,
121
122 COEX_EVENTS_NUM
123};
124
125#define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK 0x1
126#define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK 0x2
127#define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK 0x4
128
129struct coex_event {
130 u8 req_prio;
131 u8 win_med_prio;
132 u8 reserved;
133 u8 flags;
134} __packed;
135
136#define COEX_FLAGS_STA_TABLE_VALID_MSK 0x1
137#define COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK 0x4
138#define COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK 0x8
139#define COEX_FLAGS_COEX_ENABLE_MSK 0x80
140
141struct iwm_coex_prio_table_cmd {
142 u8 flags;
143 u8 reserved[3];
144 struct coex_event sta_prio[COEX_EVENTS_NUM];
145} __packed;
146
147/* Coexistence definitions
148 *
149 * Constants to fill in the Priorities' Tables
150 * RP - Requested Priority
151 * WP - Win Medium Priority: priority assigned when the contention has been won
152 * FLAGS - Combination of COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK and
153 * COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK
154 */
155
156#define COEX_UNASSOC_IDLE_FLAGS 0
157#define COEX_UNASSOC_MANUAL_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
158 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK)
159#define COEX_UNASSOC_AUTO_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
160 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK)
161#define COEX_CALIBRATION_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
162 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK)
163#define COEX_PERIODIC_CALIBRATION_FLAGS 0
164/* COEX_CONNECTION_ESTAB: we need DELAY_MEDIUM_FREE_NTFY to let WiMAX
165 * disconnect from network. */
166#define COEX_CONNECTION_ESTAB_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
167 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \
168 COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK)
169#define COEX_ASSOCIATED_IDLE_FLAGS 0
170#define COEX_ASSOC_MANUAL_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
171 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK)
172#define COEX_ASSOC_AUTO_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
173 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK)
174#define COEX_ASSOC_ACTIVE_LEVEL_FLAGS 0
175#define COEX_RF_ON_FLAGS 0
176#define COEX_RF_OFF_FLAGS 0
177#define COEX_STAND_ALONE_DEBUG_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
178 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK)
179#define COEX_IPAN_ASSOC_LEVEL_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
180 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \
181 COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK)
182#define COEX_RSRVD1_FLAGS 0
183#define COEX_RSRVD2_FLAGS 0
184/* XOR_RF_ON is the event wrapping all radio ownership. We need
185 * DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network. */
186#define COEX_XOR_RF_ON_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \
187 COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \
188 COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK)
189
190/* CT kill config command */
191struct iwm_ct_kill_cfg_cmd {
192 u32 exit_threshold;
193 u32 reserved;
194 u32 entry_threshold;
195} __packed;
196
197
198/* LMAC OP CODES */
199#define REPLY_PAD 0x0
200#define REPLY_ALIVE 0x1
201#define REPLY_ERROR 0x2
202#define REPLY_ECHO 0x3
203#define REPLY_HALT 0x6
204
205/* RXON state commands */
206#define REPLY_RX_ON 0x10
207#define REPLY_RX_ON_ASSOC 0x11
208#define REPLY_RX_OFF 0x12
209#define REPLY_QOS_PARAM 0x13
210#define REPLY_RX_ON_TIMING 0x14
211#define REPLY_INTERNAL_QOS_PARAM 0x15
212#define REPLY_RX_INT_TIMEOUT_CNFG 0x16
213#define REPLY_NULL 0x17
214
215/* Multi-Station support */
216#define REPLY_ADD_STA 0x18
217#define REPLY_REMOVE_STA 0x19
218#define REPLY_RESET_ALL_STA 0x1a
219
220/* RX, TX */
221#define REPLY_ALM_RX 0x1b
222#define REPLY_TX 0x1c
223#define REPLY_TXFIFO_FLUSH 0x1e
224
225/* MISC commands */
226#define REPLY_MGMT_MCAST_KEY 0x1f
227#define REPLY_WEPKEY 0x20
228#define REPLY_INIT_IV 0x21
229#define REPLY_WRITE_MIB 0x22
230#define REPLY_READ_MIB 0x23
231#define REPLY_RADIO_FE 0x24
232#define REPLY_TXFIFO_CFG 0x25
233#define REPLY_WRITE_READ 0x26
234#define REPLY_INSTALL_SEC_KEY 0x27
235
236
237#define REPLY_RATE_SCALE 0x47
238#define REPLY_LEDS_CMD 0x48
239#define REPLY_TX_LINK_QUALITY_CMD 0x4e
240#define REPLY_ANA_MIB_OVERRIDE_CMD 0x4f
241#define REPLY_WRITE2REG_CMD 0x50
242
243/* winfi-wifi coexistence */
244#define COEX_PRIORITY_TABLE_CMD 0x5a
245#define COEX_MEDIUM_NOTIFICATION 0x5b
246#define COEX_EVENT_CMD 0x5c
247
248/* more Protocol and Protocol-test commands */
249#define REPLY_MAX_SLEEP_TIME_CMD 0x61
250#define CALIBRATION_CFG_CMD 0x65
251#define CALIBRATION_RES_NOTIFICATION 0x66
252#define CALIBRATION_COMPLETE_NOTIFICATION 0x67
253
254/* Measurements */
255#define REPLY_QUIET_CMD 0x71
256#define REPLY_CHANNEL_SWITCH 0x72
257#define CHANNEL_SWITCH_NOTIFICATION 0x73
258
259#define REPLY_SPECTRUM_MEASUREMENT_CMD 0x74
260#define SPECTRUM_MEASURE_NOTIFICATION 0x75
261#define REPLY_MEASUREMENT_ABORT_CMD 0x76
262
263/* Power Management */
264#define POWER_TABLE_CMD 0x77
265#define SAVE_RESTORE_ADDRESS_CMD 0x78
266#define REPLY_WATERMARK_CMD 0x79
267#define PM_DEBUG_STATISTIC_NOTIFIC 0x7B
268#define PD_FLUSH_N_NOTIFICATION 0x7C
269
270/* Scan commands and notifications */
271#define REPLY_SCAN_REQUEST_CMD 0x80
272#define REPLY_SCAN_ABORT_CMD 0x81
273#define SCAN_START_NOTIFICATION 0x82
274#define SCAN_RESULTS_NOTIFICATION 0x83
275#define SCAN_COMPLETE_NOTIFICATION 0x84
276
277/* Continuous TX commands */
278#define REPLY_CONT_TX_CMD 0x85
279#define END_OF_CONT_TX_NOTIFICATION 0x86
280
281/* Timer/Eeprom commands */
282#define TIMER_CMD 0x87
283#define EEPROM_WRITE_CMD 0x88
284
285/* PAPD commands */
286#define FEEDBACK_REQUEST_NOTIFICATION 0x8b
287#define REPLY_CW_CMD 0x8c
288
289/* IBSS/AP commands Continue */
290#define BEACON_NOTIFICATION 0x90
291#define REPLY_TX_BEACON 0x91
292#define REPLY_REQUEST_ATIM 0x93
293#define WHO_IS_AWAKE_NOTIFICATION 0x94
294#define TX_PWR_DBM_LIMIT_CMD 0x95
295#define QUIET_NOTIFICATION 0x96
296#define TX_PWR_TABLE_CMD 0x97
297#define TX_ANT_CONFIGURATION_CMD 0x98
298#define MEASURE_ABORT_NOTIFICATION 0x99
299#define REPLY_CALIBRATION_TUNE 0x9a
300
301/* bt config command */
302#define REPLY_BT_CONFIG 0x9b
303#define REPLY_STATISTICS_CMD 0x9c
304#define STATISTICS_NOTIFICATION 0x9d
305
306/* RF-KILL commands and notifications */
307#define REPLY_CARD_STATE_CMD 0xa0
308#define CARD_STATE_NOTIFICATION 0xa1
309
310/* Missed beacons notification */
311#define MISSED_BEACONS_NOTIFICATION 0xa2
312#define MISSED_BEACONS_NOTIFICATION_TH_CMD 0xa3
313
314#define REPLY_CT_KILL_CONFIG_CMD 0xa4
315
316/* HD commands and notifications */
317#define REPLY_HD_PARAMS_CMD 0xa6
318#define HD_PARAMS_NOTIFICATION 0xa7
319#define SENSITIVITY_CMD 0xa8
320#define U_APSD_PARAMS_CMD 0xa9
321#define NOISY_PLATFORM_CMD 0xaa
322#define ILLEGAL_CMD 0xac
323#define REPLY_PHY_CALIBRATION_CMD 0xb0
324#define REPLAY_RX_GAIN_CALIB_CMD 0xb1
325
326/* WiPAN commands */
327#define REPLY_WIPAN_PARAMS_CMD 0xb2
328#define REPLY_WIPAN_RX_ON_CMD 0xb3
329#define REPLY_WIPAN_RX_ON_TIMING 0xb4
330#define REPLY_WIPAN_TX_PWR_TABLE_CMD 0xb5
331#define REPLY_WIPAN_RXON_ASSOC_CMD 0xb6
332#define REPLY_WIPAN_QOS_PARAM 0xb7
333#define WIPAN_REPLY_WEPKEY 0xb8
334
335/* BeamForming commands */
336#define BEAMFORMER_CFG_CMD 0xba
337#define BEAMFORMEE_NOTIFICATION 0xbb
338
339/* TGn new Commands */
340#define REPLY_RX_PHY_CMD 0xc0
341#define REPLY_RX_MPDU_CMD 0xc1
342#define REPLY_MULTICAST_HASH 0xc2
343#define REPLY_KDR_RX 0xc3
344#define REPLY_RX_DSP_EXT_INFO 0xc4
345#define REPLY_COMPRESSED_BA 0xc5
346
347/* PNC commands */
348#define PNC_CONFIG_CMD 0xc8
349#define PNC_UPDATE_TABLE_CMD 0xc9
350#define XVT_GENERAL_CTRL_CMD 0xca
351#define REPLY_LEGACY_RADIO_FE 0xdd
352
353/* WoWLAN commands */
354#define WOWLAN_PATTERNS 0xe0
355#define WOWLAN_WAKEUP_FILTER 0xe1
356#define WOWLAN_TSC_RSC_PARAM 0xe2
357#define WOWLAN_TKIP_PARAM 0xe3
358#define WOWLAN_KEK_KCK_MATERIAL 0xe4
359#define WOWLAN_GET_STATUSES 0xe5
360#define WOWLAN_TX_POWER_PER_DB 0xe6
361#define REPLY_WOWLAN_GET_STATUSES WOWLAN_GET_STATUSES
362
363#define REPLY_DEBUG_CMD 0xf0
364#define REPLY_DSP_DEBUG_CMD 0xf1
365#define REPLY_DEBUG_MONITOR_CMD 0xf2
366#define REPLY_DEBUG_XVT_CMD 0xf3
367#define REPLY_DEBUG_DC_CALIB 0xf4
368#define REPLY_DYNAMIC_BP 0xf5
369
370/* General purpose Commands */
371#define REPLY_GP1_CMD 0xfa
372#define REPLY_GP2_CMD 0xfb
373#define REPLY_GP3_CMD 0xfc
374#define REPLY_GP4_CMD 0xfd
375#define REPLY_REPLAY_WRAPPER 0xfe
376#define REPLY_FRAME_DURATION_CALC_CMD 0xff
377
378#define LMAC_COMMAND_ID_MAX 0xff
379#define LMAC_COMMAND_ID_NUM (LMAC_COMMAND_ID_MAX + 1)
380
381
382/* Calibration */
383
384enum {
385 PHY_CALIBRATE_DC_CMD = 0,
386 PHY_CALIBRATE_LO_CMD = 1,
387 PHY_CALIBRATE_RX_BB_CMD = 2,
388 PHY_CALIBRATE_TX_IQ_CMD = 3,
389 PHY_CALIBRATE_RX_IQ_CMD = 4,
390 PHY_CALIBRATION_NOISE_CMD = 5,
391 PHY_CALIBRATE_AGC_TABLE_CMD = 6,
392 PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 7,
393 PHY_CALIBRATE_OPCODES_NUM,
394 SHILOH_PHY_CALIBRATE_DC_CMD = 8,
395 SHILOH_PHY_CALIBRATE_LO_CMD = 9,
396 SHILOH_PHY_CALIBRATE_RX_BB_CMD = 10,
397 SHILOH_PHY_CALIBRATE_TX_IQ_CMD = 11,
398 SHILOH_PHY_CALIBRATE_RX_IQ_CMD = 12,
399 SHILOH_PHY_CALIBRATION_NOISE_CMD = 13,
400 SHILOH_PHY_CALIBRATE_AGC_TABLE_CMD = 14,
401 SHILOH_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15,
402 SHILOH_PHY_CALIBRATE_BASE_BAND_CMD = 16,
403 SHILOH_PHY_CALIBRATE_TXIQ_PERIODIC_CMD = 17,
404 CALIBRATION_CMD_NUM,
405};
406
407enum {
408 CALIB_CFG_RX_BB_IDX = 0,
409 CALIB_CFG_DC_IDX = 1,
410 CALIB_CFG_LO_IDX = 2,
411 CALIB_CFG_TX_IQ_IDX = 3,
412 CALIB_CFG_RX_IQ_IDX = 4,
413 CALIB_CFG_NOISE_IDX = 5,
414 CALIB_CFG_CRYSTAL_IDX = 6,
415 CALIB_CFG_TEMPERATURE_IDX = 7,
416 CALIB_CFG_PAPD_IDX = 8,
417 CALIB_CFG_LAST_IDX = CALIB_CFG_PAPD_IDX,
418 CALIB_CFG_MODULE_NUM,
419};
420
421#define IWM_CALIB_MAP_INIT_MSK 0xFFFF
422#define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16)
423#define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24)
424#define IWM_CALIB_OPCODE_TO_INDEX(op) (op - PHY_CALIBRATE_OPCODES_NUM)
425
426struct iwm_lmac_calib_hdr {
427 u8 opcode;
428 u8 first_grp;
429 u8 grp_num;
430 u8 all_data_valid;
431} __packed;
432
433#define IWM_LMAC_CALIB_FREQ_GROUPS_NR 7
434#define IWM_CALIB_FREQ_GROUPS_NR 5
435#define IWM_CALIB_DC_MODES_NR 12
436
437struct iwm_calib_rxiq_entry {
438 u16 ptam_postdist_ars;
439 u16 ptam_postdist_arc;
440} __packed;
441
442struct iwm_calib_rxiq_group {
443 struct iwm_calib_rxiq_entry mode[IWM_CALIB_DC_MODES_NR];
444} __packed;
445
446struct iwm_lmac_calib_rxiq {
447 struct iwm_calib_rxiq_group group[IWM_LMAC_CALIB_FREQ_GROUPS_NR];
448} __packed;
449
450struct iwm_calib_rxiq {
451 struct iwm_lmac_calib_hdr hdr;
452 struct iwm_calib_rxiq_group group[IWM_CALIB_FREQ_GROUPS_NR];
453} __packed;
454
455#define LMAC_STA_ID_SEED 0x0f
456#define LMAC_STA_ID_POS 0
457
458#define LMAC_STA_COLOR_SEED 0x7
459#define LMAC_STA_COLOR_POS 4
460
461struct iwm_lmac_power_report {
462 u8 pa_status;
463 u8 pa_integ_res_A[3];
464 u8 pa_integ_res_B[3];
465 u8 pa_integ_res_C[3];
466} __packed;
467
468struct iwm_lmac_tx_resp {
469 u8 frame_cnt; /* 1-no aggregation, greater then 1 - aggregation */
470 u8 bt_kill_cnt;
471 __le16 retry_cnt;
472 __le32 initial_tx_rate;
473 __le16 wireless_media_time;
474 struct iwm_lmac_power_report power_report;
475 __le32 tfd_info;
476 __le16 seq_ctl;
477 __le16 byte_cnt;
478 u8 tlc_rate_info;
479 u8 ra_tid;
480 __le16 frame_ctl;
481 __le32 status;
482} __packed;
483
484#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
deleted file mode 100644
index 1f868b166d10..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ /dev/null
@@ -1,847 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#include <linux/kernel.h>
40#include <linux/netdevice.h>
41#include <linux/sched.h>
42#include <linux/ieee80211.h>
43#include <linux/wireless.h>
44#include <linux/slab.h>
45#include <linux/moduleparam.h>
46
47#include "iwm.h"
48#include "debug.h"
49#include "bus.h"
50#include "umac.h"
51#include "commands.h"
52#include "hal.h"
53#include "fw.h"
54#include "rx.h"
55
56static struct iwm_conf def_iwm_conf = {
57
58 .sdio_ior_timeout = 5000,
59 .calib_map = BIT(CALIB_CFG_DC_IDX) |
60 BIT(CALIB_CFG_LO_IDX) |
61 BIT(CALIB_CFG_TX_IQ_IDX) |
62 BIT(CALIB_CFG_RX_IQ_IDX) |
63 BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD),
64 .expected_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
65 BIT(PHY_CALIBRATE_LO_CMD) |
66 BIT(PHY_CALIBRATE_TX_IQ_CMD) |
67 BIT(PHY_CALIBRATE_RX_IQ_CMD) |
68 BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD),
69 .ct_kill_entry = 110,
70 .ct_kill_exit = 110,
71 .reset_on_fatal_err = 1,
72 .auto_connect = 1,
73 .enable_qos = 1,
74 .mode = UMAC_MODE_BSS,
75
76 /* UMAC configuration */
77 .power_index = 0,
78 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
79 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
80 .cts_to_self = 0,
81
82 .assoc_timeout = 2,
83 .roam_timeout = 10,
84 .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G |
85 WIRELESS_MODE_11N,
86
87 /* IBSS */
88 .ibss_band = UMAC_BAND_2GHZ,
89 .ibss_channel = 1,
90
91 .mac_addr = {0x00, 0x02, 0xb3, 0x01, 0x02, 0x03},
92};
93
94static bool modparam_reset;
95module_param_named(reset, modparam_reset, bool, 0644);
96MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])");
97
98static bool modparam_wimax_enable = true;
99module_param_named(wimax_enable, modparam_wimax_enable, bool, 0644);
100MODULE_PARM_DESC(wimax_enable, "Enable wimax core (default 1 [wimax enabled])");
101
102int iwm_mode_to_nl80211_iftype(int mode)
103{
104 switch (mode) {
105 case UMAC_MODE_BSS:
106 return NL80211_IFTYPE_STATION;
107 case UMAC_MODE_IBSS:
108 return NL80211_IFTYPE_ADHOC;
109 default:
110 return NL80211_IFTYPE_UNSPECIFIED;
111 }
112
113 return 0;
114}
115
116static void iwm_statistics_request(struct work_struct *work)
117{
118 struct iwm_priv *iwm =
119 container_of(work, struct iwm_priv, stats_request.work);
120
121 iwm_send_umac_stats_req(iwm, 0);
122}
123
124static void iwm_disconnect_work(struct work_struct *work)
125{
126 struct iwm_priv *iwm =
127 container_of(work, struct iwm_priv, disconnect.work);
128
129 if (iwm->umac_profile_active)
130 iwm_invalidate_mlme_profile(iwm);
131
132 clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
133 iwm->umac_profile_active = false;
134 memset(iwm->bssid, 0, ETH_ALEN);
135 iwm->channel = 0;
136
137 iwm_link_off(iwm);
138
139 wake_up_interruptible(&iwm->mlme_queue);
140
141 cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL);
142}
143
144static void iwm_ct_kill_work(struct work_struct *work)
145{
146 struct iwm_priv *iwm =
147 container_of(work, struct iwm_priv, ct_kill_delay.work);
148 struct wiphy *wiphy = iwm_to_wiphy(iwm);
149
150 IWM_INFO(iwm, "CT kill delay timeout\n");
151
152 wiphy_rfkill_set_hw_state(wiphy, false);
153}
154
155static int __iwm_up(struct iwm_priv *iwm);
156static int __iwm_down(struct iwm_priv *iwm);
157
158static void iwm_reset_worker(struct work_struct *work)
159{
160 struct iwm_priv *iwm;
161 struct iwm_umac_profile *profile = NULL;
162 int uninitialized_var(ret), retry = 0;
163
164 iwm = container_of(work, struct iwm_priv, reset_worker);
165
166 /*
167 * XXX: The iwm->mutex is introduced purely for this reset work,
168 * because the other users for iwm_up and iwm_down are only netdev
169 * ndo_open and ndo_stop which are already protected by rtnl.
170 * Please remove iwm->mutex together if iwm_reset_worker() is not
171 * required in the future.
172 */
173 if (!mutex_trylock(&iwm->mutex)) {
174 IWM_WARN(iwm, "We are in the middle of interface bringing "
175 "UP/DOWN. Skip driver resetting.\n");
176 return;
177 }
178
179 if (iwm->umac_profile_active) {
180 profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL);
181 if (profile)
182 memcpy(profile, iwm->umac_profile, sizeof(*profile));
183 else
184 IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
185 }
186
187 __iwm_down(iwm);
188
189 while (retry++ < 3) {
190 ret = __iwm_up(iwm);
191 if (!ret)
192 break;
193
194 schedule_timeout_uninterruptible(10 * HZ);
195 }
196
197 if (ret) {
198 IWM_WARN(iwm, "iwm_up() failed: %d\n", ret);
199
200 kfree(profile);
201 goto out;
202 }
203
204 if (profile) {
205 IWM_DBG_MLME(iwm, DBG, "Resend UMAC profile\n");
206 memcpy(iwm->umac_profile, profile, sizeof(*profile));
207 iwm_send_mlme_profile(iwm);
208 kfree(profile);
209 } else
210 clear_bit(IWM_STATUS_RESETTING, &iwm->status);
211
212 out:
213 mutex_unlock(&iwm->mutex);
214}
215
216static void iwm_auth_retry_worker(struct work_struct *work)
217{
218 struct iwm_priv *iwm;
219 int i, ret;
220
221 iwm = container_of(work, struct iwm_priv, auth_retry_worker);
222 if (iwm->umac_profile_active) {
223 ret = iwm_invalidate_mlme_profile(iwm);
224 if (ret < 0)
225 return;
226 }
227
228 iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
229
230 ret = iwm_send_mlme_profile(iwm);
231 if (ret < 0)
232 return;
233
234 for (i = 0; i < IWM_NUM_KEYS; i++)
235 if (iwm->keys[i].key_len)
236 iwm_set_key(iwm, 0, &iwm->keys[i]);
237
238 iwm_set_tx_key(iwm, iwm->default_key);
239}
240
241
242
243static void iwm_watchdog(unsigned long data)
244{
245 struct iwm_priv *iwm = (struct iwm_priv *)data;
246
247 IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n");
248
249 if (modparam_reset)
250 iwm_resetting(iwm);
251}
252
253int iwm_priv_init(struct iwm_priv *iwm)
254{
255 int i, j;
256 char name[32];
257
258 iwm->status = 0;
259 INIT_LIST_HEAD(&iwm->pending_notif);
260 init_waitqueue_head(&iwm->notif_queue);
261 init_waitqueue_head(&iwm->nonwifi_queue);
262 init_waitqueue_head(&iwm->wifi_ntfy_queue);
263 init_waitqueue_head(&iwm->mlme_queue);
264 memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf));
265 spin_lock_init(&iwm->tx_credit.lock);
266 INIT_LIST_HEAD(&iwm->wifi_pending_cmd);
267 INIT_LIST_HEAD(&iwm->nonwifi_pending_cmd);
268 iwm->wifi_seq_num = UMAC_WIFI_SEQ_NUM_BASE;
269 iwm->nonwifi_seq_num = UMAC_NONWIFI_SEQ_NUM_BASE;
270 spin_lock_init(&iwm->cmd_lock);
271 iwm->scan_id = 1;
272 INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
273 INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work);
274 INIT_DELAYED_WORK(&iwm->ct_kill_delay, iwm_ct_kill_work);
275 INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
276 INIT_WORK(&iwm->auth_retry_worker, iwm_auth_retry_worker);
277 INIT_LIST_HEAD(&iwm->bss_list);
278
279 skb_queue_head_init(&iwm->rx_list);
280 INIT_LIST_HEAD(&iwm->rx_tickets);
281 spin_lock_init(&iwm->ticket_lock);
282 for (i = 0; i < IWM_RX_ID_HASH; i++) {
283 INIT_LIST_HEAD(&iwm->rx_packets[i]);
284 spin_lock_init(&iwm->packet_lock[i]);
285 }
286
287 INIT_WORK(&iwm->rx_worker, iwm_rx_worker);
288
289 iwm->rx_wq = create_singlethread_workqueue(KBUILD_MODNAME "_rx");
290 if (!iwm->rx_wq)
291 return -EAGAIN;
292
293 for (i = 0; i < IWM_TX_QUEUES; i++) {
294 INIT_WORK(&iwm->txq[i].worker, iwm_tx_worker);
295 snprintf(name, 32, KBUILD_MODNAME "_tx_%d", i);
296 iwm->txq[i].id = i;
297 iwm->txq[i].wq = create_singlethread_workqueue(name);
298 if (!iwm->txq[i].wq)
299 return -EAGAIN;
300
301 skb_queue_head_init(&iwm->txq[i].queue);
302 skb_queue_head_init(&iwm->txq[i].stopped_queue);
303 spin_lock_init(&iwm->txq[i].lock);
304 }
305
306 for (i = 0; i < IWM_NUM_KEYS; i++)
307 memset(&iwm->keys[i], 0, sizeof(struct iwm_key));
308
309 iwm->default_key = -1;
310
311 for (i = 0; i < IWM_STA_TABLE_NUM; i++)
312 for (j = 0; j < IWM_UMAC_TID_NR; j++) {
313 mutex_init(&iwm->sta_table[i].tid_info[j].mutex);
314 iwm->sta_table[i].tid_info[j].stopped = false;
315 }
316
317 init_timer(&iwm->watchdog);
318 iwm->watchdog.function = iwm_watchdog;
319 iwm->watchdog.data = (unsigned long)iwm;
320 mutex_init(&iwm->mutex);
321
322 iwm->last_fw_err = kzalloc(sizeof(struct iwm_fw_error_hdr),
323 GFP_KERNEL);
324 if (iwm->last_fw_err == NULL)
325 return -ENOMEM;
326
327 return 0;
328}
329
330void iwm_priv_deinit(struct iwm_priv *iwm)
331{
332 int i;
333
334 for (i = 0; i < IWM_TX_QUEUES; i++)
335 destroy_workqueue(iwm->txq[i].wq);
336
337 destroy_workqueue(iwm->rx_wq);
338 kfree(iwm->last_fw_err);
339}
340
341/*
342 * We reset all the structures, and we reset the UMAC.
343 * After calling this routine, you're expected to reload
344 * the firmware.
345 */
346void iwm_reset(struct iwm_priv *iwm)
347{
348 struct iwm_notif *notif, *next;
349
350 if (test_bit(IWM_STATUS_READY, &iwm->status))
351 iwm_target_reset(iwm);
352
353 if (test_bit(IWM_STATUS_RESETTING, &iwm->status)) {
354 iwm->status = 0;
355 set_bit(IWM_STATUS_RESETTING, &iwm->status);
356 } else
357 iwm->status = 0;
358 iwm->scan_id = 1;
359
360 list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) {
361 list_del(&notif->pending);
362 kfree(notif->buf);
363 kfree(notif);
364 }
365
366 iwm_cmd_flush(iwm);
367
368 flush_workqueue(iwm->rx_wq);
369
370 iwm_link_off(iwm);
371}
372
373void iwm_resetting(struct iwm_priv *iwm)
374{
375 set_bit(IWM_STATUS_RESETTING, &iwm->status);
376
377 schedule_work(&iwm->reset_worker);
378}
379
380/*
381 * Notification code:
382 *
383 * We're faced with the following issue: Any host command can
384 * have an answer or not, and if there's an answer to expect,
385 * it can be treated synchronously or asynchronously.
386 * To work around the synchronous answer case, we implemented
387 * our notification mechanism.
388 * When a code path needs to wait for a command response
389 * synchronously, it calls notif_handle(), which waits for the
390 * right notification to show up, and then process it. Before
391 * starting to wait, it registered as a waiter for this specific
392 * answer (by toggling a bit in on of the handler_map), so that
393 * the rx code knows that it needs to send a notification to the
394 * waiting processes. It does so by calling iwm_notif_send(),
395 * which adds the notification to the pending notifications list,
396 * and then wakes the waiting processes up.
397 */
398int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd,
399 u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size)
400{
401 struct iwm_notif *notif;
402
403 notif = kzalloc(sizeof(struct iwm_notif), GFP_KERNEL);
404 if (!notif) {
405 IWM_ERR(iwm, "Couldn't alloc memory for notification\n");
406 return -ENOMEM;
407 }
408
409 INIT_LIST_HEAD(&notif->pending);
410 notif->cmd = cmd;
411 notif->cmd_id = cmd_id;
412 notif->src = source;
413 notif->buf = kzalloc(buf_size, GFP_KERNEL);
414 if (!notif->buf) {
415 IWM_ERR(iwm, "Couldn't alloc notification buffer\n");
416 kfree(notif);
417 return -ENOMEM;
418 }
419 notif->buf_size = buf_size;
420 memcpy(notif->buf, buf, buf_size);
421 list_add_tail(&notif->pending, &iwm->pending_notif);
422
423 wake_up_interruptible(&iwm->notif_queue);
424
425 return 0;
426}
427
428static struct iwm_notif *iwm_notif_find(struct iwm_priv *iwm, u32 cmd,
429 u8 source)
430{
431 struct iwm_notif *notif;
432
433 list_for_each_entry(notif, &iwm->pending_notif, pending) {
434 if ((notif->cmd_id == cmd) && (notif->src == source)) {
435 list_del(&notif->pending);
436 return notif;
437 }
438 }
439
440 return NULL;
441}
442
443static struct iwm_notif *iwm_notif_wait(struct iwm_priv *iwm, u32 cmd,
444 u8 source, long timeout)
445{
446 int ret;
447 struct iwm_notif *notif;
448 unsigned long *map = NULL;
449
450 switch (source) {
451 case IWM_SRC_LMAC:
452 map = &iwm->lmac_handler_map[0];
453 break;
454 case IWM_SRC_UMAC:
455 map = &iwm->umac_handler_map[0];
456 break;
457 case IWM_SRC_UDMA:
458 map = &iwm->udma_handler_map[0];
459 break;
460 }
461
462 set_bit(cmd, map);
463
464 ret = wait_event_interruptible_timeout(iwm->notif_queue,
465 ((notif = iwm_notif_find(iwm, cmd, source)) != NULL),
466 timeout);
467 clear_bit(cmd, map);
468
469 if (!ret)
470 return NULL;
471
472 return notif;
473}
474
475int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout)
476{
477 int ret;
478 struct iwm_notif *notif;
479
480 notif = iwm_notif_wait(iwm, cmd, source, timeout);
481 if (!notif)
482 return -ETIME;
483
484 ret = iwm_rx_handle_resp(iwm, notif->buf, notif->buf_size, notif->cmd);
485 kfree(notif->buf);
486 kfree(notif);
487
488 return ret;
489}
490
491static int iwm_config_boot_params(struct iwm_priv *iwm)
492{
493 struct iwm_udma_nonwifi_cmd target_cmd;
494 int ret;
495
496 /* check Wimax is off and config debug monitor */
497 if (!modparam_wimax_enable) {
498 u32 data1 = 0x1f;
499 u32 addr1 = 0x606BE258;
500
501 u32 data2_set = 0x0;
502 u32 data2_clr = 0x1;
503 u32 addr2 = 0x606BE100;
504
505 u32 data3 = 0x1;
506 u32 addr3 = 0x606BEC00;
507
508 target_cmd.resp = 0;
509 target_cmd.handle_by_hw = 0;
510 target_cmd.eop = 1;
511
512 target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE;
513 target_cmd.addr = cpu_to_le32(addr1);
514 target_cmd.op1_sz = cpu_to_le32(sizeof(u32));
515 target_cmd.op2 = 0;
516
517 ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1);
518 if (ret < 0) {
519 IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n");
520 return ret;
521 }
522
523 target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE;
524 target_cmd.addr = cpu_to_le32(addr2);
525 target_cmd.op1_sz = cpu_to_le32(data2_set);
526 target_cmd.op2 = cpu_to_le32(data2_clr);
527
528 ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1);
529 if (ret < 0) {
530 IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n");
531 return ret;
532 }
533
534 target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE;
535 target_cmd.addr = cpu_to_le32(addr3);
536 target_cmd.op1_sz = cpu_to_le32(sizeof(u32));
537 target_cmd.op2 = 0;
538
539 ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data3);
540 if (ret < 0) {
541 IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n");
542 return ret;
543 }
544 }
545
546 return 0;
547}
548
549void iwm_init_default_profile(struct iwm_priv *iwm,
550 struct iwm_umac_profile *profile)
551{
552 memset(profile, 0, sizeof(struct iwm_umac_profile));
553
554 profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
555 profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
556 profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_NONE;
557 profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_NONE;
558
559 if (iwm->conf.enable_qos)
560 profile->flags |= cpu_to_le16(UMAC_PROFILE_QOS_ALLOWED);
561
562 profile->wireless_mode = iwm->conf.wireless_mode;
563 profile->mode = cpu_to_le32(iwm->conf.mode);
564
565 profile->ibss.atim = 0;
566 profile->ibss.beacon_interval = 100;
567 profile->ibss.join_only = 0;
568 profile->ibss.band = iwm->conf.ibss_band;
569 profile->ibss.channel = iwm->conf.ibss_channel;
570}
571
572void iwm_link_on(struct iwm_priv *iwm)
573{
574 netif_carrier_on(iwm_to_ndev(iwm));
575 netif_tx_wake_all_queues(iwm_to_ndev(iwm));
576
577 iwm_send_umac_stats_req(iwm, 0);
578}
579
580void iwm_link_off(struct iwm_priv *iwm)
581{
582 struct iw_statistics *wstats = &iwm->wstats;
583 int i;
584
585 netif_tx_stop_all_queues(iwm_to_ndev(iwm));
586 netif_carrier_off(iwm_to_ndev(iwm));
587
588 for (i = 0; i < IWM_TX_QUEUES; i++) {
589 skb_queue_purge(&iwm->txq[i].queue);
590 skb_queue_purge(&iwm->txq[i].stopped_queue);
591
592 iwm->txq[i].concat_count = 0;
593 iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf;
594
595 flush_workqueue(iwm->txq[i].wq);
596 }
597
598 iwm_rx_free(iwm);
599
600 cancel_delayed_work_sync(&iwm->stats_request);
601 memset(wstats, 0, sizeof(struct iw_statistics));
602 wstats->qual.updated = IW_QUAL_ALL_INVALID;
603
604 kfree(iwm->req_ie);
605 iwm->req_ie = NULL;
606 iwm->req_ie_len = 0;
607 kfree(iwm->resp_ie);
608 iwm->resp_ie = NULL;
609 iwm->resp_ie_len = 0;
610
611 del_timer_sync(&iwm->watchdog);
612}
613
614static void iwm_bss_list_clean(struct iwm_priv *iwm)
615{
616 struct iwm_bss_info *bss, *next;
617
618 list_for_each_entry_safe(bss, next, &iwm->bss_list, node) {
619 list_del(&bss->node);
620 kfree(bss->bss);
621 kfree(bss);
622 }
623}
624
625static int iwm_channels_init(struct iwm_priv *iwm)
626{
627 int ret;
628
629 ret = iwm_send_umac_channel_list(iwm);
630 if (ret) {
631 IWM_ERR(iwm, "Send channel list failed\n");
632 return ret;
633 }
634
635 ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST,
636 IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT);
637 if (ret) {
638 IWM_ERR(iwm, "Didn't get a channel list notification\n");
639 return ret;
640 }
641
642 return 0;
643}
644
645static int __iwm_up(struct iwm_priv *iwm)
646{
647 int ret;
648 struct iwm_notif *notif_reboot, *notif_ack = NULL;
649 struct wiphy *wiphy = iwm_to_wiphy(iwm);
650 u32 wireless_mode;
651
652 ret = iwm_bus_enable(iwm);
653 if (ret) {
654 IWM_ERR(iwm, "Couldn't enable function\n");
655 return ret;
656 }
657
658 iwm_rx_setup_handlers(iwm);
659
660 /* Wait for initial BARKER_REBOOT from hardware */
661 notif_reboot = iwm_notif_wait(iwm, IWM_BARKER_REBOOT_NOTIFICATION,
662 IWM_SRC_UDMA, 2 * HZ);
663 if (!notif_reboot) {
664 IWM_ERR(iwm, "Wait for REBOOT_BARKER timeout\n");
665 goto err_disable;
666 }
667
668 /* We send the barker back */
669 ret = iwm_bus_send_chunk(iwm, notif_reboot->buf, 16);
670 if (ret) {
671 IWM_ERR(iwm, "REBOOT barker response failed\n");
672 kfree(notif_reboot);
673 goto err_disable;
674 }
675
676 kfree(notif_reboot->buf);
677 kfree(notif_reboot);
678
679 /* Wait for ACK_BARKER from hardware */
680 notif_ack = iwm_notif_wait(iwm, IWM_ACK_BARKER_NOTIFICATION,
681 IWM_SRC_UDMA, 2 * HZ);
682 if (!notif_ack) {
683 IWM_ERR(iwm, "Wait for ACK_BARKER timeout\n");
684 goto err_disable;
685 }
686
687 kfree(notif_ack->buf);
688 kfree(notif_ack);
689
690 /* We start to config static boot parameters */
691 ret = iwm_config_boot_params(iwm);
692 if (ret) {
693 IWM_ERR(iwm, "Config boot parameters failed\n");
694 goto err_disable;
695 }
696
697 ret = iwm_read_mac(iwm, iwm_to_ndev(iwm)->dev_addr);
698 if (ret) {
699 IWM_ERR(iwm, "MAC reading failed\n");
700 goto err_disable;
701 }
702 memcpy(iwm_to_ndev(iwm)->perm_addr, iwm_to_ndev(iwm)->dev_addr,
703 ETH_ALEN);
704
705 /* We can load the FWs */
706 ret = iwm_load_fw(iwm);
707 if (ret) {
708 IWM_ERR(iwm, "FW loading failed\n");
709 goto err_disable;
710 }
711
712 ret = iwm_eeprom_fat_channels(iwm);
713 if (ret) {
714 IWM_ERR(iwm, "Couldnt read HT channels EEPROM entries\n");
715 goto err_fw;
716 }
717
718 /*
719 * Read our SKU capabilities.
720 * If it's valid, we AND the configured wireless mode with the
721 * device EEPROM value as the current profile wireless mode.
722 */
723 wireless_mode = iwm_eeprom_wireless_mode(iwm);
724 if (wireless_mode) {
725 iwm->conf.wireless_mode &= wireless_mode;
726 if (iwm->umac_profile)
727 iwm->umac_profile->wireless_mode =
728 iwm->conf.wireless_mode;
729 } else
730 IWM_ERR(iwm, "Wrong SKU capabilities: 0x%x\n",
731 *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP)));
732
733 snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s",
734 iwm->lmac_version, iwm->umac_version);
735
736 /* We configure the UMAC and enable the wifi module */
737 ret = iwm_send_umac_config(iwm,
738 cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) |
739 cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_LINK_EN) |
740 cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_MLME_EN));
741 if (ret) {
742 IWM_ERR(iwm, "UMAC config failed\n");
743 goto err_fw;
744 }
745
746 ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS,
747 IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT);
748 if (ret) {
749 IWM_ERR(iwm, "Didn't get a wifi core status notification\n");
750 goto err_fw;
751 }
752
753 if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN |
754 UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) {
755 IWM_DBG_BOOT(iwm, DBG, "Not all cores enabled:0x%x\n",
756 iwm->core_enabled);
757 ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS,
758 IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT);
759 if (ret) {
760 IWM_ERR(iwm, "Didn't get a core status notification\n");
761 goto err_fw;
762 }
763
764 if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN |
765 UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) {
766 IWM_ERR(iwm, "Not all cores enabled: 0x%x\n",
767 iwm->core_enabled);
768 goto err_fw;
769 } else {
770 IWM_INFO(iwm, "All cores enabled\n");
771 }
772 }
773
774 ret = iwm_channels_init(iwm);
775 if (ret < 0) {
776 IWM_ERR(iwm, "Couldn't init channels\n");
777 goto err_fw;
778 }
779
780 /* Set the READY bit to indicate interface is brought up successfully */
781 set_bit(IWM_STATUS_READY, &iwm->status);
782
783 return 0;
784
785 err_fw:
786 iwm_eeprom_exit(iwm);
787
788 err_disable:
789 ret = iwm_bus_disable(iwm);
790 if (ret < 0)
791 IWM_ERR(iwm, "Couldn't disable function\n");
792
793 return -EIO;
794}
795
796int iwm_up(struct iwm_priv *iwm)
797{
798 int ret;
799
800 mutex_lock(&iwm->mutex);
801 ret = __iwm_up(iwm);
802 mutex_unlock(&iwm->mutex);
803
804 return ret;
805}
806
807static int __iwm_down(struct iwm_priv *iwm)
808{
809 int ret;
810
811 /* The interface is already down */
812 if (!test_bit(IWM_STATUS_READY, &iwm->status))
813 return 0;
814
815 if (iwm->scan_request) {
816 cfg80211_scan_done(iwm->scan_request, true);
817 iwm->scan_request = NULL;
818 }
819
820 clear_bit(IWM_STATUS_READY, &iwm->status);
821
822 iwm_eeprom_exit(iwm);
823 iwm_bss_list_clean(iwm);
824 iwm_init_default_profile(iwm, iwm->umac_profile);
825 iwm->umac_profile_active = false;
826 iwm->default_key = -1;
827 iwm->core_enabled = 0;
828
829 ret = iwm_bus_disable(iwm);
830 if (ret < 0) {
831 IWM_ERR(iwm, "Couldn't disable function\n");
832 return ret;
833 }
834
835 return 0;
836}
837
838int iwm_down(struct iwm_priv *iwm)
839{
840 int ret;
841
842 mutex_lock(&iwm->mutex);
843 ret = __iwm_down(iwm);
844 mutex_unlock(&iwm->mutex);
845
846 return ret;
847}
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
deleted file mode 100644
index 5091d77e02ce..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ /dev/null
@@ -1,191 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5 * Samuel Ortiz <samuel.ortiz@intel.com>
6 * Zhu Yi <yi.zhu@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 */
23
24/*
25 * This is the netdev related hooks for iwm.
26 *
27 * Some interesting code paths:
28 *
29 * iwm_open() (Called at netdev interface bringup time)
30 * -> iwm_up() (main.c)
31 * -> iwm_bus_enable()
32 * -> if_sdio_enable() (In case of an SDIO bus)
33 * -> sdio_enable_func()
34 * -> iwm_notif_wait(BARKER_REBOOT) (wait for reboot barker)
35 * -> iwm_notif_wait(ACK_BARKER) (wait for ACK barker)
36 * -> iwm_load_fw() (fw.c)
37 * -> iwm_load_umac()
38 * -> iwm_load_lmac() (Calibration LMAC)
39 * -> iwm_load_lmac() (Operational LMAC)
40 * -> iwm_send_umac_config()
41 *
42 * iwm_stop() (Called at netdev interface bringdown time)
43 * -> iwm_down()
44 * -> iwm_bus_disable()
45 * -> if_sdio_disable() (In case of an SDIO bus)
46 * -> sdio_disable_func()
47 */
48#include <linux/netdevice.h>
49#include <linux/slab.h>
50
51#include "iwm.h"
52#include "commands.h"
53#include "cfg80211.h"
54#include "debug.h"
55
56static int iwm_open(struct net_device *ndev)
57{
58 struct iwm_priv *iwm = ndev_to_iwm(ndev);
59
60 return iwm_up(iwm);
61}
62
63static int iwm_stop(struct net_device *ndev)
64{
65 struct iwm_priv *iwm = ndev_to_iwm(ndev);
66
67 return iwm_down(iwm);
68}
69
70/*
71 * iwm AC to queue mapping
72 *
73 * AC_VO -> queue 3
74 * AC_VI -> queue 2
75 * AC_BE -> queue 1
76 * AC_BK -> queue 0
77 */
78static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
79
80int iwm_tid_to_queue(u16 tid)
81{
82 if (tid > IWM_UMAC_TID_NR - 2)
83 return -EINVAL;
84
85 return iwm_1d_to_queue[tid];
86}
87
88static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb)
89{
90 skb->priority = cfg80211_classify8021d(skb);
91
92 return iwm_1d_to_queue[skb->priority];
93}
94
95static const struct net_device_ops iwm_netdev_ops = {
96 .ndo_open = iwm_open,
97 .ndo_stop = iwm_stop,
98 .ndo_start_xmit = iwm_xmit_frame,
99 .ndo_select_queue = iwm_select_queue,
100};
101
102void *iwm_if_alloc(int sizeof_bus, struct device *dev,
103 struct iwm_if_ops *if_ops)
104{
105 struct net_device *ndev;
106 struct wireless_dev *wdev;
107 struct iwm_priv *iwm;
108 int ret = 0;
109
110 wdev = iwm_wdev_alloc(sizeof_bus, dev);
111 if (IS_ERR(wdev))
112 return wdev;
113
114 iwm = wdev_to_iwm(wdev);
115 iwm->bus_ops = if_ops;
116 iwm->wdev = wdev;
117
118 ret = iwm_priv_init(iwm);
119 if (ret) {
120 dev_err(dev, "failed to init iwm_priv\n");
121 goto out_wdev;
122 }
123
124 wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode);
125
126 ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
127 if (!ndev) {
128 dev_err(dev, "no memory for network device instance\n");
129 ret = -ENOMEM;
130 goto out_priv;
131 }
132
133 ndev->netdev_ops = &iwm_netdev_ops;
134 ndev->ieee80211_ptr = wdev;
135 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
136 wdev->netdev = ndev;
137
138 iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
139 GFP_KERNEL);
140 if (!iwm->umac_profile) {
141 dev_err(dev, "Couldn't alloc memory for profile\n");
142 ret = -ENOMEM;
143 goto out_profile;
144 }
145
146 iwm_init_default_profile(iwm, iwm->umac_profile);
147
148 return iwm;
149
150 out_profile:
151 free_netdev(ndev);
152
153 out_priv:
154 iwm_priv_deinit(iwm);
155
156 out_wdev:
157 iwm_wdev_free(iwm);
158 return ERR_PTR(ret);
159}
160
161void iwm_if_free(struct iwm_priv *iwm)
162{
163 if (!iwm_to_ndev(iwm))
164 return;
165
166 cancel_delayed_work_sync(&iwm->ct_kill_delay);
167 free_netdev(iwm_to_ndev(iwm));
168 iwm_priv_deinit(iwm);
169 kfree(iwm->umac_profile);
170 iwm->umac_profile = NULL;
171 iwm_wdev_free(iwm);
172}
173
174int iwm_if_add(struct iwm_priv *iwm)
175{
176 struct net_device *ndev = iwm_to_ndev(iwm);
177 int ret;
178
179 ret = register_netdev(ndev);
180 if (ret < 0) {
181 dev_err(&ndev->dev, "Failed to register netdev: %d\n", ret);
182 return ret;
183 }
184
185 return 0;
186}
187
188void iwm_if_remove(struct iwm_priv *iwm)
189{
190 unregister_netdev(iwm_to_ndev(iwm));
191}
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
deleted file mode 100644
index 7d708f4395f3..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ /dev/null
@@ -1,1701 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#include <linux/kernel.h>
40#include <linux/netdevice.h>
41#include <linux/sched.h>
42#include <linux/etherdevice.h>
43#include <linux/wireless.h>
44#include <linux/ieee80211.h>
45#include <linux/if_arp.h>
46#include <linux/list.h>
47#include <linux/slab.h>
48#include <net/iw_handler.h>
49
50#include "iwm.h"
51#include "debug.h"
52#include "hal.h"
53#include "umac.h"
54#include "lmac.h"
55#include "commands.h"
56#include "rx.h"
57#include "cfg80211.h"
58#include "eeprom.h"
59
60static int iwm_rx_check_udma_hdr(struct iwm_udma_in_hdr *hdr)
61{
62 if ((le32_to_cpu(hdr->cmd) == UMAC_PAD_TERMINAL) ||
63 (le32_to_cpu(hdr->size) == UMAC_PAD_TERMINAL))
64 return -EINVAL;
65
66 return 0;
67}
68
69static inline int iwm_rx_resp_size(struct iwm_udma_in_hdr *hdr)
70{
71 return ALIGN(le32_to_cpu(hdr->size) + sizeof(struct iwm_udma_in_hdr),
72 16);
73}
74
75/*
76 * Notification handlers:
77 *
78 * For every possible notification we can receive from the
79 * target, we have a handler.
80 * When we get a target notification, and there is no one
81 * waiting for it, it's just processed through the rx code
82 * path:
83 *
84 * iwm_rx_handle()
85 * -> iwm_rx_handle_umac()
86 * -> iwm_rx_handle_wifi()
87 * -> iwm_rx_handle_resp()
88 * -> iwm_ntf_*()
89 *
90 * OR
91 *
92 * -> iwm_rx_handle_non_wifi()
93 *
94 * If there are processes waiting for this notification, then
95 * iwm_rx_handle_wifi() just wakes those processes up and they
96 * grab the pending notification.
97 */
98static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
99 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
100{
101 struct iwm_umac_notif_error *error;
102 struct iwm_fw_error_hdr *fw_err;
103
104 error = (struct iwm_umac_notif_error *)buf;
105 fw_err = &error->err;
106
107 memcpy(iwm->last_fw_err, fw_err, sizeof(struct iwm_fw_error_hdr));
108
109 IWM_ERR(iwm, "%cMAC FW ERROR:\n",
110 (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U');
111 IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category));
112 IWM_ERR(iwm, "\tStatus: 0x%x\n", le32_to_cpu(fw_err->status));
113 IWM_ERR(iwm, "\tPC: 0x%x\n", le32_to_cpu(fw_err->pc));
114 IWM_ERR(iwm, "\tblink1: %d\n", le32_to_cpu(fw_err->blink1));
115 IWM_ERR(iwm, "\tblink2: %d\n", le32_to_cpu(fw_err->blink2));
116 IWM_ERR(iwm, "\tilink1: %d\n", le32_to_cpu(fw_err->ilink1));
117 IWM_ERR(iwm, "\tilink2: %d\n", le32_to_cpu(fw_err->ilink2));
118 IWM_ERR(iwm, "\tData1: 0x%x\n", le32_to_cpu(fw_err->data1));
119 IWM_ERR(iwm, "\tData2: 0x%x\n", le32_to_cpu(fw_err->data2));
120 IWM_ERR(iwm, "\tLine number: %d\n", le32_to_cpu(fw_err->line_num));
121 IWM_ERR(iwm, "\tUMAC status: 0x%x\n", le32_to_cpu(fw_err->umac_status));
122 IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status));
123 IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status));
124
125 iwm_resetting(iwm);
126
127 return 0;
128}
129
130static int iwm_ntf_umac_alive(struct iwm_priv *iwm, u8 *buf,
131 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
132{
133 struct iwm_umac_notif_alive *alive_resp =
134 (struct iwm_umac_notif_alive *)(buf);
135 u16 status = le16_to_cpu(alive_resp->status);
136
137 if (status == UMAC_NTFY_ALIVE_STATUS_ERR) {
138 IWM_ERR(iwm, "Receive error UMAC_ALIVE\n");
139 return -EIO;
140 }
141
142 iwm_tx_credit_init_pools(iwm, alive_resp);
143
144 return 0;
145}
146
147static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf,
148 unsigned long buf_size,
149 struct iwm_wifi_cmd *cmd)
150{
151 struct wiphy *wiphy = iwm_to_wiphy(iwm);
152 struct iwm_umac_notif_init_complete *init_complete =
153 (struct iwm_umac_notif_init_complete *)(buf);
154 u16 status = le16_to_cpu(init_complete->status);
155 bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR);
156
157 if (blocked)
158 IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n");
159 else
160 IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n");
161
162 wiphy_rfkill_set_hw_state(wiphy, blocked);
163
164 return 0;
165}
166
167static int iwm_ntf_tx_credit_update(struct iwm_priv *iwm, u8 *buf,
168 unsigned long buf_size,
169 struct iwm_wifi_cmd *cmd)
170{
171 int pool_nr, total_freed_pages;
172 unsigned long pool_map;
173 int i, id;
174 struct iwm_umac_notif_page_dealloc *dealloc =
175 (struct iwm_umac_notif_page_dealloc *)buf;
176
177 pool_nr = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_CNT);
178 pool_map = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_MSK);
179
180 IWM_DBG_TX(iwm, DBG, "UMAC dealloc notification: pool nr %d, "
181 "update map 0x%lx\n", pool_nr, pool_map);
182
183 spin_lock(&iwm->tx_credit.lock);
184
185 for (i = 0; i < pool_nr; i++) {
186 id = GET_VAL32(dealloc->grp_info[i],
187 UMAC_DEALLOC_NTFY_GROUP_NUM);
188 if (test_bit(id, &pool_map)) {
189 total_freed_pages = GET_VAL32(dealloc->grp_info[i],
190 UMAC_DEALLOC_NTFY_PAGE_CNT);
191 iwm_tx_credit_inc(iwm, id, total_freed_pages);
192 }
193 }
194
195 spin_unlock(&iwm->tx_credit.lock);
196
197 return 0;
198}
199
200static int iwm_ntf_umac_reset(struct iwm_priv *iwm, u8 *buf,
201 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
202{
203 IWM_DBG_NTF(iwm, DBG, "UMAC RESET done\n");
204
205 return 0;
206}
207
208static int iwm_ntf_lmac_version(struct iwm_priv *iwm, u8 *buf,
209 unsigned long buf_size,
210 struct iwm_wifi_cmd *cmd)
211{
212 IWM_DBG_NTF(iwm, INFO, "LMAC Version: %x.%x\n", buf[9], buf[8]);
213
214 return 0;
215}
216
217static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf,
218 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
219{
220 struct iwm_lmac_tx_resp *tx_resp;
221 struct iwm_umac_wifi_in_hdr *hdr;
222
223 tx_resp = (struct iwm_lmac_tx_resp *)
224 (buf + sizeof(struct iwm_umac_wifi_in_hdr));
225 hdr = (struct iwm_umac_wifi_in_hdr *)buf;
226
227 IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
228
229 IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n",
230 le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
231 IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
232 IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n",
233 le16_to_cpu(tx_resp->retry_cnt));
234 IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
235 IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n",
236 le16_to_cpu(tx_resp->byte_cnt));
237 IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
238
239 return 0;
240}
241
242
243static int iwm_ntf_calib_res(struct iwm_priv *iwm, u8 *buf,
244 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
245{
246 u8 opcode;
247 u8 *calib_buf;
248 struct iwm_lmac_calib_hdr *hdr = (struct iwm_lmac_calib_hdr *)
249 (buf + sizeof(struct iwm_umac_wifi_in_hdr));
250
251 opcode = hdr->opcode;
252
253 BUG_ON(opcode >= CALIBRATION_CMD_NUM ||
254 opcode < PHY_CALIBRATE_OPCODES_NUM);
255
256 IWM_DBG_NTF(iwm, DBG, "Store calibration result for opcode: %d\n",
257 opcode);
258
259 buf_size -= sizeof(struct iwm_umac_wifi_in_hdr);
260 calib_buf = iwm->calib_res[opcode].buf;
261
262 if (!calib_buf || (iwm->calib_res[opcode].size < buf_size)) {
263 kfree(calib_buf);
264 calib_buf = kzalloc(buf_size, GFP_KERNEL);
265 if (!calib_buf) {
266 IWM_ERR(iwm, "Memory allocation failed: calib_res\n");
267 return -ENOMEM;
268 }
269 iwm->calib_res[opcode].buf = calib_buf;
270 iwm->calib_res[opcode].size = buf_size;
271 }
272
273 memcpy(calib_buf, hdr, buf_size);
274 set_bit(opcode - PHY_CALIBRATE_OPCODES_NUM, &iwm->calib_done_map);
275
276 return 0;
277}
278
279static int iwm_ntf_calib_complete(struct iwm_priv *iwm, u8 *buf,
280 unsigned long buf_size,
281 struct iwm_wifi_cmd *cmd)
282{
283 IWM_DBG_NTF(iwm, DBG, "Calibration completed\n");
284
285 return 0;
286}
287
288static int iwm_ntf_calib_cfg(struct iwm_priv *iwm, u8 *buf,
289 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
290{
291 struct iwm_lmac_cal_cfg_resp *cal_resp;
292
293 cal_resp = (struct iwm_lmac_cal_cfg_resp *)
294 (buf + sizeof(struct iwm_umac_wifi_in_hdr));
295
296 IWM_DBG_NTF(iwm, DBG, "Calibration CFG command status: %d\n",
297 le32_to_cpu(cal_resp->status));
298
299 return 0;
300}
301
302static int iwm_ntf_wifi_status(struct iwm_priv *iwm, u8 *buf,
303 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
304{
305 struct iwm_umac_notif_wifi_status *status =
306 (struct iwm_umac_notif_wifi_status *)buf;
307
308 iwm->core_enabled |= le16_to_cpu(status->status);
309
310 return 0;
311}
312
313static struct iwm_rx_ticket_node *
314iwm_rx_ticket_node_alloc(struct iwm_priv *iwm, struct iwm_rx_ticket *ticket)
315{
316 struct iwm_rx_ticket_node *ticket_node;
317
318 ticket_node = kzalloc(sizeof(struct iwm_rx_ticket_node), GFP_KERNEL);
319 if (!ticket_node) {
320 IWM_ERR(iwm, "Couldn't allocate ticket node\n");
321 return ERR_PTR(-ENOMEM);
322 }
323
324 ticket_node->ticket = kmemdup(ticket, sizeof(struct iwm_rx_ticket),
325 GFP_KERNEL);
326 if (!ticket_node->ticket) {
327 IWM_ERR(iwm, "Couldn't allocate RX ticket\n");
328 kfree(ticket_node);
329 return ERR_PTR(-ENOMEM);
330 }
331
332 INIT_LIST_HEAD(&ticket_node->node);
333
334 return ticket_node;
335}
336
337static void iwm_rx_ticket_node_free(struct iwm_rx_ticket_node *ticket_node)
338{
339 kfree(ticket_node->ticket);
340 kfree(ticket_node);
341}
342
343static struct iwm_rx_packet *iwm_rx_packet_get(struct iwm_priv *iwm, u16 id)
344{
345 u8 id_hash = IWM_RX_ID_GET_HASH(id);
346 struct iwm_rx_packet *packet;
347
348 spin_lock(&iwm->packet_lock[id_hash]);
349 list_for_each_entry(packet, &iwm->rx_packets[id_hash], node)
350 if (packet->id == id) {
351 list_del(&packet->node);
352 spin_unlock(&iwm->packet_lock[id_hash]);
353 return packet;
354 }
355
356 spin_unlock(&iwm->packet_lock[id_hash]);
357 return NULL;
358}
359
360static struct iwm_rx_packet *iwm_rx_packet_alloc(struct iwm_priv *iwm, u8 *buf,
361 u32 size, u16 id)
362{
363 struct iwm_rx_packet *packet;
364
365 packet = kzalloc(sizeof(struct iwm_rx_packet), GFP_KERNEL);
366 if (!packet) {
367 IWM_ERR(iwm, "Couldn't allocate packet\n");
368 return ERR_PTR(-ENOMEM);
369 }
370
371 packet->skb = dev_alloc_skb(size);
372 if (!packet->skb) {
373 IWM_ERR(iwm, "Couldn't allocate packet SKB\n");
374 kfree(packet);
375 return ERR_PTR(-ENOMEM);
376 }
377
378 packet->pkt_size = size;
379
380 skb_put(packet->skb, size);
381 memcpy(packet->skb->data, buf, size);
382 INIT_LIST_HEAD(&packet->node);
383 packet->id = id;
384
385 return packet;
386}
387
388void iwm_rx_free(struct iwm_priv *iwm)
389{
390 struct iwm_rx_ticket_node *ticket, *nt;
391 struct iwm_rx_packet *packet, *np;
392 int i;
393
394 spin_lock(&iwm->ticket_lock);
395 list_for_each_entry_safe(ticket, nt, &iwm->rx_tickets, node) {
396 list_del(&ticket->node);
397 iwm_rx_ticket_node_free(ticket);
398 }
399 spin_unlock(&iwm->ticket_lock);
400
401 for (i = 0; i < IWM_RX_ID_HASH; i++) {
402 spin_lock(&iwm->packet_lock[i]);
403 list_for_each_entry_safe(packet, np, &iwm->rx_packets[i],
404 node) {
405 list_del(&packet->node);
406 kfree_skb(packet->skb);
407 kfree(packet);
408 }
409 spin_unlock(&iwm->packet_lock[i]);
410 }
411}
412
413static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
414 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
415{
416 struct iwm_umac_notif_rx_ticket *ntf_rx_ticket =
417 (struct iwm_umac_notif_rx_ticket *)buf;
418 struct iwm_rx_ticket *ticket =
419 (struct iwm_rx_ticket *)ntf_rx_ticket->tickets;
420 int i, schedule_rx = 0;
421
422 for (i = 0; i < ntf_rx_ticket->num_tickets; i++) {
423 struct iwm_rx_ticket_node *ticket_node;
424
425 switch (le16_to_cpu(ticket->action)) {
426 case IWM_RX_TICKET_RELEASE:
427 case IWM_RX_TICKET_DROP:
428 /* We can push the packet to the stack */
429 ticket_node = iwm_rx_ticket_node_alloc(iwm, ticket);
430 if (IS_ERR(ticket_node))
431 return PTR_ERR(ticket_node);
432
433 IWM_DBG_RX(iwm, DBG, "TICKET %s(%d)\n",
434 __le16_to_cpu(ticket->action) ==
435 IWM_RX_TICKET_RELEASE ?
436 "RELEASE" : "DROP",
437 ticket->id);
438 spin_lock(&iwm->ticket_lock);
439 list_add_tail(&ticket_node->node, &iwm->rx_tickets);
440 spin_unlock(&iwm->ticket_lock);
441
442 /*
443 * We received an Rx ticket, most likely there's
444 * a packet pending for it, it's not worth going
445 * through the packet hash list to double check.
446 * Let's just fire the rx worker..
447 */
448 schedule_rx = 1;
449
450 break;
451
452 default:
453 IWM_ERR(iwm, "Invalid RX ticket action: 0x%x\n",
454 ticket->action);
455 }
456
457 ticket++;
458 }
459
460 if (schedule_rx)
461 queue_work(iwm->rx_wq, &iwm->rx_worker);
462
463 return 0;
464}
465
466static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf,
467 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
468{
469 struct iwm_umac_wifi_in_hdr *wifi_hdr;
470 struct iwm_rx_packet *packet;
471 u16 id, buf_offset;
472 u32 packet_size;
473 u8 id_hash;
474
475 IWM_DBG_RX(iwm, DBG, "\n");
476
477 wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
478 id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
479 buf_offset = sizeof(struct iwm_umac_wifi_in_hdr);
480 packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr);
481
482 IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
483 wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
484 IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id);
485 IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size);
486
487 packet = iwm_rx_packet_alloc(iwm, buf + buf_offset, packet_size, id);
488 if (IS_ERR(packet))
489 return PTR_ERR(packet);
490
491 id_hash = IWM_RX_ID_GET_HASH(id);
492 spin_lock(&iwm->packet_lock[id_hash]);
493 list_add_tail(&packet->node, &iwm->rx_packets[id_hash]);
494 spin_unlock(&iwm->packet_lock[id_hash]);
495
496 /* We might (unlikely) have received the packet _after_ the ticket */
497 queue_work(iwm->rx_wq, &iwm->rx_worker);
498
499 return 0;
500}
501
502/* MLME handlers */
503static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf,
504 unsigned long buf_size,
505 struct iwm_wifi_cmd *cmd)
506{
507 struct iwm_umac_notif_assoc_start *start;
508
509 start = (struct iwm_umac_notif_assoc_start *)buf;
510
511 IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n",
512 start->bssid, le32_to_cpu(start->roam_reason));
513
514 wake_up_interruptible(&iwm->mlme_queue);
515
516 return 0;
517}
518
519static u8 iwm_is_open_wep_profile(struct iwm_priv *iwm)
520{
521 if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 ||
522 iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) &&
523 (iwm->umac_profile->sec.ucast_cipher ==
524 iwm->umac_profile->sec.mcast_cipher) &&
525 (iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN))
526 return 1;
527
528 return 0;
529}
530
531static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
532 unsigned long buf_size,
533 struct iwm_wifi_cmd *cmd)
534{
535 struct wiphy *wiphy = iwm_to_wiphy(iwm);
536 struct ieee80211_channel *chan;
537 struct iwm_umac_notif_assoc_complete *complete =
538 (struct iwm_umac_notif_assoc_complete *)buf;
539
540 IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n",
541 complete->bssid, complete->status);
542
543 switch (le32_to_cpu(complete->status)) {
544 case UMAC_ASSOC_COMPLETE_SUCCESS:
545 chan = ieee80211_get_channel(wiphy,
546 ieee80211_channel_to_frequency(complete->channel,
547 complete->band == UMAC_BAND_2GHZ ?
548 IEEE80211_BAND_2GHZ :
549 IEEE80211_BAND_5GHZ));
550 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
551 /* Associated to a unallowed channel, disassociate. */
552 __iwm_invalidate_mlme_profile(iwm);
553 IWM_WARN(iwm, "Couldn't associate with %pM due to "
554 "channel %d is disabled. Check your local "
555 "regulatory setting.\n",
556 complete->bssid, complete->channel);
557 goto failure;
558 }
559
560 set_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
561 memcpy(iwm->bssid, complete->bssid, ETH_ALEN);
562 iwm->channel = complete->channel;
563
564 /* Internal roaming state, avoid notifying SME. */
565 if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
566 && iwm->conf.mode == UMAC_MODE_BSS) {
567 cancel_delayed_work(&iwm->disconnect);
568 cfg80211_roamed(iwm_to_ndev(iwm), NULL,
569 complete->bssid,
570 iwm->req_ie, iwm->req_ie_len,
571 iwm->resp_ie, iwm->resp_ie_len,
572 GFP_KERNEL);
573 break;
574 }
575
576 iwm_link_on(iwm);
577
578 if (iwm->conf.mode == UMAC_MODE_IBSS)
579 goto ibss;
580
581 if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
582 cfg80211_connect_result(iwm_to_ndev(iwm),
583 complete->bssid,
584 iwm->req_ie, iwm->req_ie_len,
585 iwm->resp_ie, iwm->resp_ie_len,
586 WLAN_STATUS_SUCCESS,
587 GFP_KERNEL);
588 else
589 cfg80211_roamed(iwm_to_ndev(iwm), NULL,
590 complete->bssid,
591 iwm->req_ie, iwm->req_ie_len,
592 iwm->resp_ie, iwm->resp_ie_len,
593 GFP_KERNEL);
594 break;
595 case UMAC_ASSOC_COMPLETE_FAILURE:
596 failure:
597 clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
598 memset(iwm->bssid, 0, ETH_ALEN);
599 iwm->channel = 0;
600
601 /* Internal roaming state, avoid notifying SME. */
602 if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
603 && iwm->conf.mode == UMAC_MODE_BSS) {
604 cancel_delayed_work(&iwm->disconnect);
605 break;
606 }
607
608 iwm_link_off(iwm);
609
610 if (iwm->conf.mode == UMAC_MODE_IBSS)
611 goto ibss;
612
613 if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
614 if (!iwm_is_open_wep_profile(iwm)) {
615 cfg80211_connect_result(iwm_to_ndev(iwm),
616 complete->bssid,
617 NULL, 0, NULL, 0,
618 WLAN_STATUS_UNSPECIFIED_FAILURE,
619 GFP_KERNEL);
620 } else {
621 /* Let's try shared WEP auth */
622 IWM_ERR(iwm, "Trying WEP shared auth\n");
623 schedule_work(&iwm->auth_retry_worker);
624 }
625 else
626 cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0,
627 GFP_KERNEL);
628 break;
629 default:
630 break;
631 }
632
633 clear_bit(IWM_STATUS_RESETTING, &iwm->status);
634 return 0;
635
636 ibss:
637 cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
638 clear_bit(IWM_STATUS_RESETTING, &iwm->status);
639 return 0;
640}
641
642static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf,
643 unsigned long buf_size,
644 struct iwm_wifi_cmd *cmd)
645{
646 struct iwm_umac_notif_profile_invalidate *invalid;
647 u32 reason;
648
649 invalid = (struct iwm_umac_notif_profile_invalidate *)buf;
650 reason = le32_to_cpu(invalid->reason);
651
652 IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", reason);
653
654 if (reason != UMAC_PROFILE_INVALID_REQUEST &&
655 test_bit(IWM_STATUS_SME_CONNECTING, &iwm->status))
656 cfg80211_connect_result(iwm_to_ndev(iwm), NULL, NULL, 0, NULL,
657 0, WLAN_STATUS_UNSPECIFIED_FAILURE,
658 GFP_KERNEL);
659
660 clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status);
661 clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
662
663 iwm->umac_profile_active = false;
664 memset(iwm->bssid, 0, ETH_ALEN);
665 iwm->channel = 0;
666
667 iwm_link_off(iwm);
668
669 wake_up_interruptible(&iwm->mlme_queue);
670
671 return 0;
672}
673
674#define IWM_DISCONNECT_INTERVAL (5 * HZ)
675
676static int iwm_mlme_connection_terminated(struct iwm_priv *iwm, u8 *buf,
677 unsigned long buf_size,
678 struct iwm_wifi_cmd *cmd)
679{
680 IWM_DBG_MLME(iwm, DBG, "Connection terminated\n");
681
682 schedule_delayed_work(&iwm->disconnect, IWM_DISCONNECT_INTERVAL);
683
684 return 0;
685}
686
687static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf,
688 unsigned long buf_size,
689 struct iwm_wifi_cmd *cmd)
690{
691 int ret;
692 struct iwm_umac_notif_scan_complete *scan_complete =
693 (struct iwm_umac_notif_scan_complete *)buf;
694 u32 result = le32_to_cpu(scan_complete->result);
695
696 IWM_DBG_MLME(iwm, INFO, "type:0x%x result:0x%x seq:%d\n",
697 le32_to_cpu(scan_complete->type),
698 le32_to_cpu(scan_complete->result),
699 scan_complete->seq_num);
700
701 if (!test_and_clear_bit(IWM_STATUS_SCANNING, &iwm->status)) {
702 IWM_ERR(iwm, "Scan complete while device not scanning\n");
703 return -EIO;
704 }
705 if (!iwm->scan_request)
706 return 0;
707
708 ret = iwm_cfg80211_inform_bss(iwm);
709
710 cfg80211_scan_done(iwm->scan_request,
711 (result & UMAC_SCAN_RESULT_ABORTED) ? 1 : !!ret);
712 iwm->scan_request = NULL;
713
714 return ret;
715}
716
717static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf,
718 unsigned long buf_size,
719 struct iwm_wifi_cmd *cmd)
720{
721 struct iwm_umac_notif_sta_info *umac_sta =
722 (struct iwm_umac_notif_sta_info *)buf;
723 struct iwm_sta_info *sta;
724 int i;
725
726 switch (le32_to_cpu(umac_sta->opcode)) {
727 case UMAC_OPCODE_ADD_MODIFY:
728 sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)];
729
730 IWM_DBG_MLME(iwm, INFO, "%s STA: ID = %d, Color = %d, "
731 "addr = %pM, qos = %d\n",
732 sta->valid ? "Modify" : "Add",
733 GET_VAL8(umac_sta->sta_id, LMAC_STA_ID),
734 GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR),
735 umac_sta->mac_addr,
736 umac_sta->flags & UMAC_STA_FLAG_QOS);
737
738 sta->valid = true;
739 sta->qos = umac_sta->flags & UMAC_STA_FLAG_QOS;
740 sta->color = GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR);
741 memcpy(sta->addr, umac_sta->mac_addr, ETH_ALEN);
742 break;
743 case UMAC_OPCODE_REMOVE:
744 IWM_DBG_MLME(iwm, INFO, "Remove STA: ID = %d, Color = %d, "
745 "addr = %pM\n",
746 GET_VAL8(umac_sta->sta_id, LMAC_STA_ID),
747 GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR),
748 umac_sta->mac_addr);
749
750 sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)];
751
752 if (!memcmp(sta->addr, umac_sta->mac_addr, ETH_ALEN))
753 sta->valid = false;
754
755 break;
756 case UMAC_OPCODE_CLEAR_ALL:
757 for (i = 0; i < IWM_STA_TABLE_NUM; i++)
758 iwm->sta_table[i].valid = false;
759
760 break;
761 default:
762 break;
763 }
764
765 return 0;
766}
767
768static int iwm_mlme_medium_lost(struct iwm_priv *iwm, u8 *buf,
769 unsigned long buf_size,
770 struct iwm_wifi_cmd *cmd)
771{
772 struct wiphy *wiphy = iwm_to_wiphy(iwm);
773
774 IWM_DBG_NTF(iwm, DBG, "WiFi/WiMax coexistence radio is OFF\n");
775
776 wiphy_rfkill_set_hw_state(wiphy, true);
777
778 return 0;
779}
780
781static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
782 unsigned long buf_size,
783 struct iwm_wifi_cmd *cmd)
784{
785 struct wiphy *wiphy = iwm_to_wiphy(iwm);
786 struct ieee80211_mgmt *mgmt;
787 struct iwm_umac_notif_bss_info *umac_bss =
788 (struct iwm_umac_notif_bss_info *)buf;
789 struct ieee80211_channel *channel;
790 struct ieee80211_supported_band *band;
791 struct iwm_bss_info *bss;
792 s32 signal;
793 int freq;
794 u16 frame_len = le16_to_cpu(umac_bss->frame_len);
795 size_t bss_len = sizeof(struct iwm_umac_notif_bss_info) + frame_len;
796
797 mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf);
798
799 IWM_DBG_MLME(iwm, DBG, "New BSS info entry: %pM\n", mgmt->bssid);
800 IWM_DBG_MLME(iwm, DBG, "\tType: 0x%x\n", le32_to_cpu(umac_bss->type));
801 IWM_DBG_MLME(iwm, DBG, "\tTimestamp: %d\n",
802 le32_to_cpu(umac_bss->timestamp));
803 IWM_DBG_MLME(iwm, DBG, "\tTable Index: %d\n",
804 le16_to_cpu(umac_bss->table_idx));
805 IWM_DBG_MLME(iwm, DBG, "\tBand: %d\n", umac_bss->band);
806 IWM_DBG_MLME(iwm, DBG, "\tChannel: %d\n", umac_bss->channel);
807 IWM_DBG_MLME(iwm, DBG, "\tRSSI: %d\n", umac_bss->rssi);
808 IWM_DBG_MLME(iwm, DBG, "\tFrame Length: %d\n", frame_len);
809
810 list_for_each_entry(bss, &iwm->bss_list, node)
811 if (bss->bss->table_idx == umac_bss->table_idx)
812 break;
813
814 if (&bss->node != &iwm->bss_list) {
815 /* Remove the old BSS entry, we will add it back later. */
816 list_del(&bss->node);
817 kfree(bss->bss);
818 } else {
819 /* New BSS entry */
820
821 bss = kzalloc(sizeof(struct iwm_bss_info), GFP_KERNEL);
822 if (!bss) {
823 IWM_ERR(iwm, "Couldn't allocate bss_info\n");
824 return -ENOMEM;
825 }
826 }
827
828 bss->bss = kzalloc(bss_len, GFP_KERNEL);
829 if (!bss->bss) {
830 kfree(bss);
831 IWM_ERR(iwm, "Couldn't allocate bss\n");
832 return -ENOMEM;
833 }
834
835 INIT_LIST_HEAD(&bss->node);
836 memcpy(bss->bss, umac_bss, bss_len);
837
838 if (umac_bss->band == UMAC_BAND_2GHZ)
839 band = wiphy->bands[IEEE80211_BAND_2GHZ];
840 else if (umac_bss->band == UMAC_BAND_5GHZ)
841 band = wiphy->bands[IEEE80211_BAND_5GHZ];
842 else {
843 IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band);
844 goto err;
845 }
846
847 freq = ieee80211_channel_to_frequency(umac_bss->channel, band->band);
848 channel = ieee80211_get_channel(wiphy, freq);
849 signal = umac_bss->rssi * 100;
850
851 bss->cfg_bss = cfg80211_inform_bss_frame(wiphy, channel,
852 mgmt, frame_len,
853 signal, GFP_KERNEL);
854 if (!bss->cfg_bss)
855 goto err;
856
857 list_add_tail(&bss->node, &iwm->bss_list);
858
859 return 0;
860 err:
861 kfree(bss->bss);
862 kfree(bss);
863
864 return -EINVAL;
865}
866
867static int iwm_mlme_remove_bss(struct iwm_priv *iwm, u8 *buf,
868 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
869{
870 struct iwm_umac_notif_bss_removed *bss_rm =
871 (struct iwm_umac_notif_bss_removed *)buf;
872 struct iwm_bss_info *bss, *next;
873 u16 table_idx;
874 int i;
875
876 for (i = 0; i < le32_to_cpu(bss_rm->count); i++) {
877 table_idx = le16_to_cpu(bss_rm->entries[i]) &
878 IWM_BSS_REMOVE_INDEX_MSK;
879 list_for_each_entry_safe(bss, next, &iwm->bss_list, node)
880 if (bss->bss->table_idx == cpu_to_le16(table_idx)) {
881 struct ieee80211_mgmt *mgmt;
882
883 mgmt = (struct ieee80211_mgmt *)
884 (bss->bss->frame_buf);
885 IWM_DBG_MLME(iwm, ERR, "BSS removed: %pM\n",
886 mgmt->bssid);
887 list_del(&bss->node);
888 kfree(bss->bss);
889 kfree(bss);
890 }
891 }
892
893 return 0;
894}
895
896static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
897 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
898{
899 struct iwm_umac_notif_mgt_frame *mgt_frame =
900 (struct iwm_umac_notif_mgt_frame *)buf;
901 struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
902
903 IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
904 le16_to_cpu(mgt_frame->len));
905
906 if (ieee80211_is_assoc_req(mgt->frame_control)) {
907 iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
908 - offsetof(struct ieee80211_mgmt,
909 u.assoc_req.variable);
910 kfree(iwm->req_ie);
911 iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
912 iwm->req_ie_len, GFP_KERNEL);
913 } else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
914 iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
915 - offsetof(struct ieee80211_mgmt,
916 u.reassoc_req.variable);
917 kfree(iwm->req_ie);
918 iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
919 iwm->req_ie_len, GFP_KERNEL);
920 } else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
921 iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
922 - offsetof(struct ieee80211_mgmt,
923 u.assoc_resp.variable);
924 kfree(iwm->resp_ie);
925 iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
926 iwm->resp_ie_len, GFP_KERNEL);
927 } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
928 iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
929 - offsetof(struct ieee80211_mgmt,
930 u.reassoc_resp.variable);
931 kfree(iwm->resp_ie);
932 iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
933 iwm->resp_ie_len, GFP_KERNEL);
934 } else {
935 IWM_ERR(iwm, "Unsupported management frame: 0x%x",
936 le16_to_cpu(mgt->frame_control));
937 return 0;
938 }
939
940 return 0;
941}
942
943static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf,
944 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
945{
946 struct iwm_umac_notif_wifi_if *notif =
947 (struct iwm_umac_notif_wifi_if *)buf;
948
949 switch (notif->status) {
950 case WIFI_IF_NTFY_ASSOC_START:
951 return iwm_mlme_assoc_start(iwm, buf, buf_size, cmd);
952 case WIFI_IF_NTFY_ASSOC_COMPLETE:
953 return iwm_mlme_assoc_complete(iwm, buf, buf_size, cmd);
954 case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE:
955 return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd);
956 case WIFI_IF_NTFY_CONNECTION_TERMINATED:
957 return iwm_mlme_connection_terminated(iwm, buf, buf_size, cmd);
958 case WIFI_IF_NTFY_SCAN_COMPLETE:
959 return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd);
960 case WIFI_IF_NTFY_STA_TABLE_CHANGE:
961 return iwm_mlme_update_sta_table(iwm, buf, buf_size, cmd);
962 case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED:
963 IWM_DBG_MLME(iwm, DBG, "Extended IE required\n");
964 break;
965 case WIFI_IF_NTFY_RADIO_PREEMPTION:
966 return iwm_mlme_medium_lost(iwm, buf, buf_size, cmd);
967 case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED:
968 return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd);
969 case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED:
970 return iwm_mlme_remove_bss(iwm, buf, buf_size, cmd);
971 break;
972 case WIFI_IF_NTFY_MGMT_FRAME:
973 return iwm_mlme_mgt_frame(iwm, buf, buf_size, cmd);
974 case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START:
975 case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE:
976 case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START:
977 case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT:
978 case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START:
979 case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE:
980 case WIFI_DBG_IF_NTFY_CNCT_ATC_START:
981 case WIFI_DBG_IF_NTFY_COEX_NOTIFICATION:
982 case WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP:
983 case WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP:
984 IWM_DBG_MLME(iwm, DBG, "MLME debug notification: 0x%x\n",
985 notif->status);
986 break;
987 default:
988 IWM_ERR(iwm, "Unhandled notification: 0x%x\n", notif->status);
989 break;
990 }
991
992 return 0;
993}
994
995#define IWM_STATS_UPDATE_INTERVAL (2 * HZ)
996
997static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf,
998 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
999{
1000 struct iwm_umac_notif_stats *stats = (struct iwm_umac_notif_stats *)buf;
1001 struct iw_statistics *wstats = &iwm->wstats;
1002 u16 max_rate = 0;
1003 int i;
1004
1005 IWM_DBG_MLME(iwm, DBG, "Statistics notification received\n");
1006
1007 if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
1008 for (i = 0; i < UMAC_NTF_RATE_SAMPLE_NR; i++) {
1009 max_rate = max_t(u16, max_rate,
1010 max(le16_to_cpu(stats->tx_rate[i]),
1011 le16_to_cpu(stats->rx_rate[i])));
1012 }
1013 /* UMAC passes rate info multiplies by 2 */
1014 iwm->rate = max_rate >> 1;
1015 }
1016 iwm->txpower = le32_to_cpu(stats->tx_power);
1017
1018 wstats->status = 0;
1019
1020 wstats->discard.nwid = le32_to_cpu(stats->rx_drop_other_bssid);
1021 wstats->discard.code = le32_to_cpu(stats->rx_drop_decode);
1022 wstats->discard.fragment = le32_to_cpu(stats->rx_drop_reassembly);
1023 wstats->discard.retries = le32_to_cpu(stats->tx_drop_max_retry);
1024
1025 wstats->miss.beacon = le32_to_cpu(stats->missed_beacons);
1026
1027 /* according to cfg80211 */
1028 if (stats->rssi_dbm < -110)
1029 wstats->qual.qual = 0;
1030 else if (stats->rssi_dbm > -40)
1031 wstats->qual.qual = 70;
1032 else
1033 wstats->qual.qual = stats->rssi_dbm + 110;
1034
1035 wstats->qual.level = stats->rssi_dbm;
1036 wstats->qual.noise = stats->noise_dbm;
1037 wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
1038
1039 schedule_delayed_work(&iwm->stats_request, IWM_STATS_UPDATE_INTERVAL);
1040
1041 mod_timer(&iwm->watchdog, round_jiffies(jiffies + IWM_WATCHDOG_PERIOD));
1042
1043 return 0;
1044}
1045
1046static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf,
1047 unsigned long buf_size,
1048 struct iwm_wifi_cmd *cmd)
1049{
1050 struct iwm_umac_cmd_eeprom_proxy *eeprom_proxy =
1051 (struct iwm_umac_cmd_eeprom_proxy *)
1052 (buf + sizeof(struct iwm_umac_wifi_in_hdr));
1053 struct iwm_umac_cmd_eeprom_proxy_hdr *hdr = &eeprom_proxy->hdr;
1054 u32 hdr_offset = le32_to_cpu(hdr->offset);
1055 u32 hdr_len = le32_to_cpu(hdr->len);
1056 u32 hdr_type = le32_to_cpu(hdr->type);
1057
1058 IWM_DBG_NTF(iwm, DBG, "type: 0x%x, len: %d, offset: 0x%x\n",
1059 hdr_type, hdr_len, hdr_offset);
1060
1061 if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN)
1062 return -EINVAL;
1063
1064 switch (hdr_type) {
1065 case IWM_UMAC_CMD_EEPROM_TYPE_READ:
1066 memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len);
1067 break;
1068 case IWM_UMAC_CMD_EEPROM_TYPE_WRITE:
1069 default:
1070 return -ENOTSUPP;
1071 }
1072
1073 return 0;
1074}
1075
1076static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf,
1077 unsigned long buf_size,
1078 struct iwm_wifi_cmd *cmd)
1079{
1080 struct iwm_umac_cmd_get_channel_list *ch_list =
1081 (struct iwm_umac_cmd_get_channel_list *)
1082 (buf + sizeof(struct iwm_umac_wifi_in_hdr));
1083 struct wiphy *wiphy = iwm_to_wiphy(iwm);
1084 struct ieee80211_supported_band *band;
1085 int i;
1086
1087 band = wiphy->bands[IEEE80211_BAND_2GHZ];
1088
1089 for (i = 0; i < band->n_channels; i++) {
1090 unsigned long ch_mask_0 =
1091 le32_to_cpu(ch_list->ch[0].channels_mask);
1092 unsigned long ch_mask_2 =
1093 le32_to_cpu(ch_list->ch[2].channels_mask);
1094
1095 if (!test_bit(i, &ch_mask_0))
1096 band->channels[i].flags |= IEEE80211_CHAN_DISABLED;
1097
1098 if (!test_bit(i, &ch_mask_2))
1099 band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS;
1100 }
1101
1102 band = wiphy->bands[IEEE80211_BAND_5GHZ];
1103
1104 for (i = 0; i < min(band->n_channels, 32); i++) {
1105 unsigned long ch_mask_1 =
1106 le32_to_cpu(ch_list->ch[1].channels_mask);
1107 unsigned long ch_mask_3 =
1108 le32_to_cpu(ch_list->ch[3].channels_mask);
1109
1110 if (!test_bit(i, &ch_mask_1))
1111 band->channels[i].flags |= IEEE80211_CHAN_DISABLED;
1112
1113 if (!test_bit(i, &ch_mask_3))
1114 band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS;
1115 }
1116
1117 return 0;
1118}
1119
1120static int iwm_ntf_stop_resume_tx(struct iwm_priv *iwm, u8 *buf,
1121 unsigned long buf_size,
1122 struct iwm_wifi_cmd *cmd)
1123{
1124 struct iwm_umac_notif_stop_resume_tx *stp_res_tx =
1125 (struct iwm_umac_notif_stop_resume_tx *)buf;
1126 struct iwm_sta_info *sta_info;
1127 struct iwm_tid_info *tid_info;
1128 u8 sta_id = STA_ID_N_COLOR_ID(stp_res_tx->sta_id);
1129 u16 tid_msk = le16_to_cpu(stp_res_tx->stop_resume_tid_msk);
1130 int bit, ret = 0;
1131 bool stop = false;
1132
1133 IWM_DBG_NTF(iwm, DBG, "stop/resume notification:\n"
1134 "\tflags: 0x%x\n"
1135 "\tSTA id: %d\n"
1136 "\tTID bitmask: 0x%x\n",
1137 stp_res_tx->flags, stp_res_tx->sta_id,
1138 stp_res_tx->stop_resume_tid_msk);
1139
1140 if (stp_res_tx->flags & UMAC_STOP_TX_FLAG)
1141 stop = true;
1142
1143 sta_info = &iwm->sta_table[sta_id];
1144 if (!sta_info->valid) {
1145 IWM_ERR(iwm, "Stoping an invalid STA: %d %d\n",
1146 sta_id, stp_res_tx->sta_id);
1147 return -EINVAL;
1148 }
1149
1150 for_each_set_bit(bit, (unsigned long *)&tid_msk, IWM_UMAC_TID_NR) {
1151 tid_info = &sta_info->tid_info[bit];
1152
1153 mutex_lock(&tid_info->mutex);
1154 tid_info->stopped = stop;
1155 mutex_unlock(&tid_info->mutex);
1156
1157 if (!stop) {
1158 struct iwm_tx_queue *txq;
1159 int queue = iwm_tid_to_queue(bit);
1160
1161 if (queue < 0)
1162 continue;
1163
1164 txq = &iwm->txq[queue];
1165 /*
1166 * If we resume, we have to move our SKBs
1167 * back to the tx queue and queue some work.
1168 */
1169 spin_lock_bh(&txq->lock);
1170 skb_queue_splice_init(&txq->queue, &txq->stopped_queue);
1171 spin_unlock_bh(&txq->lock);
1172
1173 queue_work(txq->wq, &txq->worker);
1174 }
1175
1176 }
1177
1178 /* We send an ACK only for the stop case */
1179 if (stop)
1180 ret = iwm_send_umac_stop_resume_tx(iwm, stp_res_tx);
1181
1182 return ret;
1183}
1184
1185static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
1186 unsigned long buf_size,
1187 struct iwm_wifi_cmd *cmd)
1188{
1189 struct iwm_umac_wifi_if *hdr;
1190
1191 if (cmd == NULL) {
1192 IWM_ERR(iwm, "Couldn't find expected wifi command\n");
1193 return -EINVAL;
1194 }
1195
1196 hdr = (struct iwm_umac_wifi_if *)cmd->buf.payload;
1197
1198 IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
1199 "oid is 0x%x\n", hdr->oid);
1200
1201 set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
1202 wake_up_interruptible(&iwm->wifi_ntfy_queue);
1203
1204 switch (hdr->oid) {
1205 case UMAC_WIFI_IF_CMD_SET_PROFILE:
1206 iwm->umac_profile_active = true;
1207 break;
1208 default:
1209 break;
1210 }
1211
1212 return 0;
1213}
1214
1215#define CT_KILL_DELAY (30 * HZ)
1216static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
1217 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
1218{
1219 struct wiphy *wiphy = iwm_to_wiphy(iwm);
1220 struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *)
1221 (buf + sizeof(struct iwm_umac_wifi_in_hdr));
1222 u32 flags = le32_to_cpu(state->flags);
1223
1224 IWM_INFO(iwm, "HW RF Kill %s, CT Kill %s\n",
1225 flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
1226 flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
1227
1228 if (flags & IWM_CARD_STATE_CTKILL_DISABLED) {
1229 /*
1230 * We got a CTKILL event: We bring the interface down in
1231 * oder to cool the device down, and try to bring it up
1232 * 30 seconds later. If it's still too hot, we'll go through
1233 * this code path again.
1234 */
1235 cancel_delayed_work_sync(&iwm->ct_kill_delay);
1236 schedule_delayed_work(&iwm->ct_kill_delay, CT_KILL_DELAY);
1237 }
1238
1239 wiphy_rfkill_set_hw_state(wiphy, flags &
1240 (IWM_CARD_STATE_HW_DISABLED |
1241 IWM_CARD_STATE_CTKILL_DISABLED));
1242
1243 return 0;
1244}
1245
1246static int iwm_rx_handle_wifi(struct iwm_priv *iwm, u8 *buf,
1247 unsigned long buf_size)
1248{
1249 struct iwm_umac_wifi_in_hdr *wifi_hdr;
1250 struct iwm_wifi_cmd *cmd;
1251 u8 source, cmd_id;
1252 u16 seq_num;
1253 u32 count;
1254
1255 wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
1256 cmd_id = wifi_hdr->sw_hdr.cmd.cmd;
1257 source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE);
1258 if (source >= IWM_SRC_NUM) {
1259 IWM_CRIT(iwm, "invalid source %d\n", source);
1260 return -EINVAL;
1261 }
1262
1263 if (cmd_id == REPLY_RX_MPDU_CMD)
1264 trace_iwm_rx_packet(iwm, buf, buf_size);
1265 else if ((cmd_id == UMAC_NOTIFY_OPCODE_RX_TICKET) &&
1266 (source == UMAC_HDI_IN_SOURCE_FW))
1267 trace_iwm_rx_ticket(iwm, buf, buf_size);
1268 else
1269 trace_iwm_rx_wifi_cmd(iwm, wifi_hdr);
1270
1271 count = GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT);
1272 count += sizeof(struct iwm_umac_wifi_in_hdr) -
1273 sizeof(struct iwm_dev_cmd_hdr);
1274 if (count > buf_size) {
1275 IWM_CRIT(iwm, "count %d, buf size:%ld\n", count, buf_size);
1276 return -EINVAL;
1277 }
1278
1279 seq_num = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
1280
1281 IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x, seqnum: %d\n",
1282 cmd_id, source, seq_num);
1283
1284 /*
1285 * If this is a response to a previously sent command, there must
1286 * be a pending command for this sequence number.
1287 */
1288 cmd = iwm_get_pending_wifi_cmd(iwm, seq_num);
1289
1290 /* Notify the caller only for sync commands. */
1291 switch (source) {
1292 case UMAC_HDI_IN_SOURCE_FHRX:
1293 if (iwm->lmac_handlers[cmd_id] &&
1294 test_bit(cmd_id, &iwm->lmac_handler_map[0]))
1295 return iwm_notif_send(iwm, cmd, cmd_id, source,
1296 buf, count);
1297 break;
1298 case UMAC_HDI_IN_SOURCE_FW:
1299 if (iwm->umac_handlers[cmd_id] &&
1300 test_bit(cmd_id, &iwm->umac_handler_map[0]))
1301 return iwm_notif_send(iwm, cmd, cmd_id, source,
1302 buf, count);
1303 break;
1304 case UMAC_HDI_IN_SOURCE_UDMA:
1305 break;
1306 }
1307
1308 return iwm_rx_handle_resp(iwm, buf, count, cmd);
1309}
1310
1311int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size,
1312 struct iwm_wifi_cmd *cmd)
1313{
1314 u8 source, cmd_id;
1315 struct iwm_umac_wifi_in_hdr *wifi_hdr;
1316 int ret = 0;
1317
1318 wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
1319 cmd_id = wifi_hdr->sw_hdr.cmd.cmd;
1320
1321 source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE);
1322
1323 IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x\n", cmd_id, source);
1324
1325 switch (source) {
1326 case UMAC_HDI_IN_SOURCE_FHRX:
1327 if (iwm->lmac_handlers[cmd_id])
1328 ret = iwm->lmac_handlers[cmd_id]
1329 (iwm, buf, buf_size, cmd);
1330 break;
1331 case UMAC_HDI_IN_SOURCE_FW:
1332 if (iwm->umac_handlers[cmd_id])
1333 ret = iwm->umac_handlers[cmd_id]
1334 (iwm, buf, buf_size, cmd);
1335 break;
1336 case UMAC_HDI_IN_SOURCE_UDMA:
1337 ret = -EINVAL;
1338 break;
1339 }
1340
1341 kfree(cmd);
1342
1343 return ret;
1344}
1345
1346static int iwm_rx_handle_nonwifi(struct iwm_priv *iwm, u8 *buf,
1347 unsigned long buf_size)
1348{
1349 u8 seq_num;
1350 struct iwm_udma_in_hdr *hdr = (struct iwm_udma_in_hdr *)buf;
1351 struct iwm_nonwifi_cmd *cmd;
1352
1353 trace_iwm_rx_nonwifi_cmd(iwm, buf, buf_size);
1354 seq_num = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM);
1355
1356 /*
1357 * We received a non wifi answer.
1358 * Let's check if there's a pending command for it, and if so
1359 * replace the command payload with the buffer, and then wake the
1360 * callers up.
1361 * That means we only support synchronised non wifi command response
1362 * schemes.
1363 */
1364 list_for_each_entry(cmd, &iwm->nonwifi_pending_cmd, pending)
1365 if (cmd->seq_num == seq_num) {
1366 cmd->resp_received = true;
1367 cmd->buf.len = buf_size;
1368 memcpy(cmd->buf.hdr, buf, buf_size);
1369 wake_up_interruptible(&iwm->nonwifi_queue);
1370 }
1371
1372 return 0;
1373}
1374
1375static int iwm_rx_handle_umac(struct iwm_priv *iwm, u8 *buf,
1376 unsigned long buf_size)
1377{
1378 int ret = 0;
1379 u8 op_code;
1380 unsigned long buf_offset = 0;
1381 struct iwm_udma_in_hdr *hdr;
1382
1383 /*
1384 * To allow for a more efficient bus usage, UMAC
1385 * messages are encapsulated into UDMA ones. This
1386 * way we can have several UMAC messages in one bus
1387 * transfer.
1388 * A UDMA frame size is always aligned on 16 bytes,
1389 * and a UDMA frame must not start with a UMAC_PAD_TERMINAL
1390 * word. This is how we parse a bus frame into several
1391 * UDMA ones.
1392 */
1393 while (buf_offset < buf_size) {
1394
1395 hdr = (struct iwm_udma_in_hdr *)(buf + buf_offset);
1396
1397 if (iwm_rx_check_udma_hdr(hdr) < 0) {
1398 IWM_DBG_RX(iwm, DBG, "End of frame\n");
1399 break;
1400 }
1401
1402 op_code = GET_VAL32(hdr->cmd, UMAC_HDI_IN_CMD_OPCODE);
1403
1404 IWM_DBG_RX(iwm, DBG, "Op code: 0x%x\n", op_code);
1405
1406 if (op_code == UMAC_HDI_IN_OPCODE_WIFI) {
1407 ret |= iwm_rx_handle_wifi(iwm, buf + buf_offset,
1408 buf_size - buf_offset);
1409 } else if (op_code < UMAC_HDI_IN_OPCODE_NONWIFI_MAX) {
1410 if (GET_VAL32(hdr->cmd,
1411 UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) !=
1412 UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) {
1413 IWM_ERR(iwm, "Incorrect hw signature\n");
1414 return -EINVAL;
1415 }
1416 ret |= iwm_rx_handle_nonwifi(iwm, buf + buf_offset,
1417 buf_size - buf_offset);
1418 } else {
1419 IWM_ERR(iwm, "Invalid RX opcode: 0x%x\n", op_code);
1420 ret |= -EINVAL;
1421 }
1422
1423 buf_offset += iwm_rx_resp_size(hdr);
1424 }
1425
1426 return ret;
1427}
1428
1429int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size)
1430{
1431 struct iwm_udma_in_hdr *hdr;
1432
1433 hdr = (struct iwm_udma_in_hdr *)buf;
1434
1435 switch (le32_to_cpu(hdr->cmd)) {
1436 case UMAC_REBOOT_BARKER:
1437 if (test_bit(IWM_STATUS_READY, &iwm->status)) {
1438 IWM_ERR(iwm, "Unexpected BARKER\n");
1439
1440 schedule_work(&iwm->reset_worker);
1441
1442 return 0;
1443 }
1444
1445 return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION,
1446 IWM_SRC_UDMA, buf, buf_size);
1447 case UMAC_ACK_BARKER:
1448 return iwm_notif_send(iwm, NULL, IWM_ACK_BARKER_NOTIFICATION,
1449 IWM_SRC_UDMA, NULL, 0);
1450 default:
1451 IWM_DBG_RX(iwm, DBG, "Received cmd: 0x%x\n", hdr->cmd);
1452 return iwm_rx_handle_umac(iwm, buf, buf_size);
1453 }
1454
1455 return 0;
1456}
1457
1458static const iwm_handler iwm_umac_handlers[] =
1459{
1460 [UMAC_NOTIFY_OPCODE_ERROR] = iwm_ntf_error,
1461 [UMAC_NOTIFY_OPCODE_ALIVE] = iwm_ntf_umac_alive,
1462 [UMAC_NOTIFY_OPCODE_INIT_COMPLETE] = iwm_ntf_init_complete,
1463 [UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS] = iwm_ntf_wifi_status,
1464 [UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_mlme,
1465 [UMAC_NOTIFY_OPCODE_PAGE_DEALLOC] = iwm_ntf_tx_credit_update,
1466 [UMAC_NOTIFY_OPCODE_RX_TICKET] = iwm_ntf_rx_ticket,
1467 [UMAC_CMD_OPCODE_RESET] = iwm_ntf_umac_reset,
1468 [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics,
1469 [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy,
1470 [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list,
1471 [UMAC_CMD_OPCODE_STOP_RESUME_STA_TX] = iwm_ntf_stop_resume_tx,
1472 [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet,
1473 [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper,
1474};
1475
1476static const iwm_handler iwm_lmac_handlers[] =
1477{
1478 [REPLY_TX] = iwm_ntf_tx,
1479 [REPLY_ALIVE] = iwm_ntf_lmac_version,
1480 [CALIBRATION_RES_NOTIFICATION] = iwm_ntf_calib_res,
1481 [CALIBRATION_COMPLETE_NOTIFICATION] = iwm_ntf_calib_complete,
1482 [CALIBRATION_CFG_CMD] = iwm_ntf_calib_cfg,
1483 [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet,
1484 [CARD_STATE_NOTIFICATION] = iwm_ntf_card_state,
1485};
1486
1487void iwm_rx_setup_handlers(struct iwm_priv *iwm)
1488{
1489 iwm->umac_handlers = (iwm_handler *) iwm_umac_handlers;
1490 iwm->lmac_handlers = (iwm_handler *) iwm_lmac_handlers;
1491}
1492
1493static void iwm_remove_iv(struct sk_buff *skb, u32 hdr_total_len)
1494{
1495 struct ieee80211_hdr *hdr;
1496 unsigned int hdr_len;
1497
1498 hdr = (struct ieee80211_hdr *)skb->data;
1499
1500 if (!ieee80211_has_protected(hdr->frame_control))
1501 return;
1502
1503 hdr_len = ieee80211_hdrlen(hdr->frame_control);
1504 if (hdr_total_len <= hdr_len)
1505 return;
1506
1507 memmove(skb->data + (hdr_total_len - hdr_len), skb->data, hdr_len);
1508 skb_pull(skb, (hdr_total_len - hdr_len));
1509}
1510
1511static void iwm_rx_adjust_packet(struct iwm_priv *iwm,
1512 struct iwm_rx_packet *packet,
1513 struct iwm_rx_ticket_node *ticket_node)
1514{
1515 u32 payload_offset = 0, payload_len;
1516 struct iwm_rx_ticket *ticket = ticket_node->ticket;
1517 struct iwm_rx_mpdu_hdr *mpdu_hdr;
1518 struct ieee80211_hdr *hdr;
1519
1520 mpdu_hdr = (struct iwm_rx_mpdu_hdr *)packet->skb->data;
1521 payload_offset += sizeof(struct iwm_rx_mpdu_hdr);
1522 /* Padding is 0 or 2 bytes */
1523 payload_len = le16_to_cpu(mpdu_hdr->len) +
1524 (le16_to_cpu(ticket->flags) & IWM_RX_TICKET_PAD_SIZE_MSK);
1525 payload_len -= ticket->tail_len;
1526
1527 IWM_DBG_RX(iwm, DBG, "Packet adjusted, len:%d, offset:%d, "
1528 "ticket offset:%d ticket tail len:%d\n",
1529 payload_len, payload_offset, ticket->payload_offset,
1530 ticket->tail_len);
1531
1532 IWM_HEXDUMP(iwm, DBG, RX, "RAW: ", packet->skb->data, packet->skb->len);
1533
1534 skb_pull(packet->skb, payload_offset);
1535 skb_trim(packet->skb, payload_len);
1536
1537 iwm_remove_iv(packet->skb, ticket->payload_offset);
1538
1539 hdr = (struct ieee80211_hdr *) packet->skb->data;
1540 if (ieee80211_is_data_qos(hdr->frame_control)) {
1541 /* UMAC handed QOS_DATA frame with 2 padding bytes appended
1542 * to the qos_ctl field in IEEE 802.11 headers. */
1543 memmove(packet->skb->data + IEEE80211_QOS_CTL_LEN + 2,
1544 packet->skb->data,
1545 ieee80211_hdrlen(hdr->frame_control) -
1546 IEEE80211_QOS_CTL_LEN);
1547 hdr = (struct ieee80211_hdr *) skb_pull(packet->skb,
1548 IEEE80211_QOS_CTL_LEN + 2);
1549 hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
1550 }
1551
1552 IWM_HEXDUMP(iwm, DBG, RX, "ADJUSTED: ",
1553 packet->skb->data, packet->skb->len);
1554}
1555
1556static void classify8023(struct sk_buff *skb)
1557{
1558 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
1559
1560 if (ieee80211_is_data_qos(hdr->frame_control)) {
1561 u8 *qc = ieee80211_get_qos_ctl(hdr);
1562 /* frame has qos control */
1563 skb->priority = *qc & IEEE80211_QOS_CTL_TID_MASK;
1564 } else {
1565 skb->priority = 0;
1566 }
1567}
1568
1569static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb)
1570{
1571 struct wireless_dev *wdev = iwm_to_wdev(iwm);
1572 struct net_device *ndev = iwm_to_ndev(iwm);
1573 struct sk_buff_head list;
1574 struct sk_buff *frame;
1575
1576 IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len);
1577
1578 __skb_queue_head_init(&list);
1579 ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0,
1580 true);
1581
1582 while ((frame = __skb_dequeue(&list))) {
1583 ndev->stats.rx_packets++;
1584 ndev->stats.rx_bytes += frame->len;
1585
1586 frame->protocol = eth_type_trans(frame, ndev);
1587 frame->ip_summed = CHECKSUM_NONE;
1588 memset(frame->cb, 0, sizeof(frame->cb));
1589
1590 if (netif_rx_ni(frame) == NET_RX_DROP) {
1591 IWM_ERR(iwm, "Packet dropped\n");
1592 ndev->stats.rx_dropped++;
1593 }
1594 }
1595}
1596
1597static void iwm_rx_process_packet(struct iwm_priv *iwm,
1598 struct iwm_rx_packet *packet,
1599 struct iwm_rx_ticket_node *ticket_node)
1600{
1601 int ret;
1602 struct sk_buff *skb = packet->skb;
1603 struct wireless_dev *wdev = iwm_to_wdev(iwm);
1604 struct net_device *ndev = iwm_to_ndev(iwm);
1605
1606 IWM_DBG_RX(iwm, DBG, "Processing packet ID %d\n", packet->id);
1607
1608 switch (le16_to_cpu(ticket_node->ticket->action)) {
1609 case IWM_RX_TICKET_RELEASE:
1610 IWM_DBG_RX(iwm, DBG, "RELEASE packet\n");
1611
1612 iwm_rx_adjust_packet(iwm, packet, ticket_node);
1613 skb->dev = iwm_to_ndev(iwm);
1614 classify8023(skb);
1615
1616 if (le16_to_cpu(ticket_node->ticket->flags) &
1617 IWM_RX_TICKET_AMSDU_MSK) {
1618 iwm_rx_process_amsdu(iwm, skb);
1619 break;
1620 }
1621
1622 ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype);
1623 if (ret < 0) {
1624 IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - "
1625 "%d\n", ret);
1626 kfree_skb(packet->skb);
1627 break;
1628 }
1629
1630 IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len);
1631
1632 ndev->stats.rx_packets++;
1633 ndev->stats.rx_bytes += skb->len;
1634
1635 skb->protocol = eth_type_trans(skb, ndev);
1636 skb->ip_summed = CHECKSUM_NONE;
1637 memset(skb->cb, 0, sizeof(skb->cb));
1638
1639 if (netif_rx_ni(skb) == NET_RX_DROP) {
1640 IWM_ERR(iwm, "Packet dropped\n");
1641 ndev->stats.rx_dropped++;
1642 }
1643 break;
1644 case IWM_RX_TICKET_DROP:
1645 IWM_DBG_RX(iwm, DBG, "DROP packet: 0x%x\n",
1646 le16_to_cpu(ticket_node->ticket->flags));
1647 kfree_skb(packet->skb);
1648 break;
1649 default:
1650 IWM_ERR(iwm, "Unknown ticket action: %d\n",
1651 le16_to_cpu(ticket_node->ticket->action));
1652 kfree_skb(packet->skb);
1653 }
1654
1655 kfree(packet);
1656 iwm_rx_ticket_node_free(ticket_node);
1657}
1658
1659/*
1660 * Rx data processing:
1661 *
1662 * We're receiving Rx packet from the LMAC, and Rx ticket from
1663 * the UMAC.
1664 * To forward a target data packet upstream (i.e. to the
1665 * kernel network stack), we must have received an Rx ticket
1666 * that tells us we're allowed to release this packet (ticket
1667 * action is IWM_RX_TICKET_RELEASE). The Rx ticket also indicates,
1668 * among other things, where valid data actually starts in the Rx
1669 * packet.
1670 */
1671void iwm_rx_worker(struct work_struct *work)
1672{
1673 struct iwm_priv *iwm;
1674 struct iwm_rx_ticket_node *ticket, *next;
1675
1676 iwm = container_of(work, struct iwm_priv, rx_worker);
1677
1678 /*
1679 * We go through the tickets list and if there is a pending
1680 * packet for it, we push it upstream.
1681 * We stop whenever a ticket is missing its packet, as we're
1682 * supposed to send the packets in order.
1683 */
1684 spin_lock(&iwm->ticket_lock);
1685 list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) {
1686 struct iwm_rx_packet *packet =
1687 iwm_rx_packet_get(iwm, le16_to_cpu(ticket->ticket->id));
1688
1689 if (!packet) {
1690 IWM_DBG_RX(iwm, DBG, "Skip rx_work: Wait for ticket %d "
1691 "to be handled first\n",
1692 le16_to_cpu(ticket->ticket->id));
1693 break;
1694 }
1695
1696 list_del(&ticket->node);
1697 iwm_rx_process_packet(iwm, packet, ticket);
1698 }
1699 spin_unlock(&iwm->ticket_lock);
1700}
1701
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.h b/drivers/net/wireless/iwmc3200wifi/rx.h
deleted file mode 100644
index da0db91cee59..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/rx.h
+++ /dev/null
@@ -1,60 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#ifndef __IWM_RX_H__
40#define __IWM_RX_H__
41
42#include <linux/skbuff.h>
43
44#include "umac.h"
45
46struct iwm_rx_ticket_node {
47 struct list_head node;
48 struct iwm_rx_ticket *ticket;
49};
50
51struct iwm_rx_packet {
52 struct list_head node;
53 u16 id;
54 struct sk_buff *skb;
55 unsigned long pkt_size;
56};
57
58void iwm_rx_worker(struct work_struct *work);
59
60#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c
deleted file mode 100644
index 0042f204b07f..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/sdio.c
+++ /dev/null
@@ -1,509 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39/*
40 * This is the SDIO bus specific hooks for iwm.
41 * It also is the module's entry point.
42 *
43 * Interesting code paths:
44 * iwm_sdio_probe() (Called by an SDIO bus scan)
45 * -> iwm_if_alloc() (netdev.c)
46 * -> iwm_wdev_alloc() (cfg80211.c, allocates and register our wiphy)
47 * -> wiphy_new()
48 * -> wiphy_register()
49 * -> alloc_netdev_mq()
50 * -> register_netdev()
51 *
52 * iwm_sdio_remove()
53 * -> iwm_if_free() (netdev.c)
54 * -> unregister_netdev()
55 * -> iwm_wdev_free() (cfg80211.c)
56 * -> wiphy_unregister()
57 * -> wiphy_free()
58 *
59 * iwm_sdio_isr() (called in process context from the SDIO core code)
60 * -> queue_work(.., isr_worker)
61 * -- [async] --> iwm_sdio_isr_worker()
62 * -> iwm_rx_handle()
63 */
64
65#include <linux/kernel.h>
66#include <linux/module.h>
67#include <linux/slab.h>
68#include <linux/netdevice.h>
69#include <linux/debugfs.h>
70#include <linux/mmc/sdio_ids.h>
71#include <linux/mmc/sdio.h>
72#include <linux/mmc/sdio_func.h>
73
74#include "iwm.h"
75#include "debug.h"
76#include "bus.h"
77#include "sdio.h"
78
79static void iwm_sdio_isr_worker(struct work_struct *work)
80{
81 struct iwm_sdio_priv *hw;
82 struct iwm_priv *iwm;
83 struct iwm_rx_info *rx_info;
84 struct sk_buff *skb;
85 u8 *rx_buf;
86 unsigned long rx_size;
87
88 hw = container_of(work, struct iwm_sdio_priv, isr_worker);
89 iwm = hw_to_iwm(hw);
90
91 while (!skb_queue_empty(&iwm->rx_list)) {
92 skb = skb_dequeue(&iwm->rx_list);
93 rx_info = skb_to_rx_info(skb);
94 rx_size = rx_info->rx_size;
95 rx_buf = skb->data;
96
97 IWM_HEXDUMP(iwm, DBG, SDIO, "RX: ", rx_buf, rx_size);
98 if (iwm_rx_handle(iwm, rx_buf, rx_size) < 0)
99 IWM_WARN(iwm, "RX error\n");
100
101 kfree_skb(skb);
102 }
103}
104
105static void iwm_sdio_isr(struct sdio_func *func)
106{
107 struct iwm_priv *iwm;
108 struct iwm_sdio_priv *hw;
109 struct iwm_rx_info *rx_info;
110 struct sk_buff *skb;
111 unsigned long buf_size, read_size;
112 int ret;
113 u8 val;
114
115 hw = sdio_get_drvdata(func);
116 iwm = hw_to_iwm(hw);
117
118 buf_size = hw->blk_size;
119
120 /* We're checking the status */
121 val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret);
122 if (val == 0 || ret < 0) {
123 IWM_ERR(iwm, "Wrong INTR_STATUS\n");
124 return;
125 }
126
127 /* See if we have free buffers */
128 if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) {
129 IWM_ERR(iwm, "No buffer for more Rx frames\n");
130 return;
131 }
132
133 /* We first read the transaction size */
134 read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret);
135 read_size = read_size << 8;
136
137 if (ret < 0) {
138 IWM_ERR(iwm, "Couldn't read the xfer size\n");
139 return;
140 }
141
142 /* We need to clear the INT register */
143 sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret);
144 if (ret < 0) {
145 IWM_ERR(iwm, "Couldn't clear the INT register\n");
146 return;
147 }
148
149 while (buf_size < read_size)
150 buf_size <<= 1;
151
152 skb = dev_alloc_skb(buf_size);
153 if (!skb) {
154 IWM_ERR(iwm, "Couldn't alloc RX skb\n");
155 return;
156 }
157 rx_info = skb_to_rx_info(skb);
158 rx_info->rx_size = read_size;
159 rx_info->rx_buf_size = buf_size;
160
161 /* Now we can read the actual buffer */
162 ret = sdio_memcpy_fromio(func, skb_put(skb, read_size),
163 IWM_SDIO_DATA_ADDR, read_size);
164
165 /* The skb is put on a driver's specific Rx SKB list */
166 skb_queue_tail(&iwm->rx_list, skb);
167
168 /* We can now schedule the actual worker */
169 queue_work(hw->isr_wq, &hw->isr_worker);
170}
171
172static void iwm_sdio_rx_free(struct iwm_sdio_priv *hw)
173{
174 struct iwm_priv *iwm = hw_to_iwm(hw);
175
176 flush_workqueue(hw->isr_wq);
177
178 skb_queue_purge(&iwm->rx_list);
179}
180
181/* Bus ops */
182static int if_sdio_enable(struct iwm_priv *iwm)
183{
184 struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
185 int ret;
186
187 sdio_claim_host(hw->func);
188
189 ret = sdio_enable_func(hw->func);
190 if (ret) {
191 IWM_ERR(iwm, "Couldn't enable the device: is TOP driver "
192 "loaded and functional?\n");
193 goto release_host;
194 }
195
196 iwm_reset(iwm);
197
198 ret = sdio_claim_irq(hw->func, iwm_sdio_isr);
199 if (ret) {
200 IWM_ERR(iwm, "Failed to claim irq: %d\n", ret);
201 goto release_host;
202 }
203
204 sdio_writeb(hw->func, 1, IWM_SDIO_INTR_ENABLE_ADDR, &ret);
205 if (ret < 0) {
206 IWM_ERR(iwm, "Couldn't enable INTR: %d\n", ret);
207 goto release_irq;
208 }
209
210 sdio_release_host(hw->func);
211
212 IWM_DBG_SDIO(iwm, INFO, "IWM SDIO enable\n");
213
214 return 0;
215
216 release_irq:
217 sdio_release_irq(hw->func);
218 release_host:
219 sdio_release_host(hw->func);
220
221 return ret;
222}
223
224static int if_sdio_disable(struct iwm_priv *iwm)
225{
226 struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
227 int ret;
228
229 sdio_claim_host(hw->func);
230 sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret);
231 if (ret < 0)
232 IWM_WARN(iwm, "Couldn't disable INTR: %d\n", ret);
233
234 sdio_release_irq(hw->func);
235 sdio_disable_func(hw->func);
236 sdio_release_host(hw->func);
237
238 iwm_sdio_rx_free(hw);
239
240 iwm_reset(iwm);
241
242 IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n");
243
244 return 0;
245}
246
247static int if_sdio_send_chunk(struct iwm_priv *iwm, u8 *buf, int count)
248{
249 struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
250 int aligned_count = ALIGN(count, hw->blk_size);
251 int ret;
252
253 if ((unsigned long)buf & 0x3) {
254 IWM_ERR(iwm, "buf <%p> is not dword aligned\n", buf);
255 /* TODO: Is this a hardware limitation? use get_unligned */
256 return -EINVAL;
257 }
258
259 sdio_claim_host(hw->func);
260 ret = sdio_memcpy_toio(hw->func, IWM_SDIO_DATA_ADDR, buf,
261 aligned_count);
262 sdio_release_host(hw->func);
263
264 return ret;
265}
266
267static ssize_t iwm_debugfs_sdio_read(struct file *filp, char __user *buffer,
268 size_t count, loff_t *ppos)
269{
270 struct iwm_priv *iwm = filp->private_data;
271 struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
272 char *buf;
273 u8 cccr;
274 int buf_len = 4096, ret;
275 size_t len = 0;
276
277 if (*ppos != 0)
278 return 0;
279 if (count < sizeof(buf))
280 return -ENOSPC;
281
282 buf = kzalloc(buf_len, GFP_KERNEL);
283 if (!buf)
284 return -ENOMEM;
285
286 sdio_claim_host(hw->func);
287
288 cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IOEx, &ret);
289 if (ret) {
290 IWM_ERR(iwm, "Could not read SDIO_CCCR_IOEx\n");
291 goto err;
292 }
293 len += snprintf(buf + len, buf_len - len, "CCCR_IOEx: 0x%x\n", cccr);
294
295 cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IORx, &ret);
296 if (ret) {
297 IWM_ERR(iwm, "Could not read SDIO_CCCR_IORx\n");
298 goto err;
299 }
300 len += snprintf(buf + len, buf_len - len, "CCCR_IORx: 0x%x\n", cccr);
301
302
303 cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IENx, &ret);
304 if (ret) {
305 IWM_ERR(iwm, "Could not read SDIO_CCCR_IENx\n");
306 goto err;
307 }
308 len += snprintf(buf + len, buf_len - len, "CCCR_IENx: 0x%x\n", cccr);
309
310
311 cccr = sdio_f0_readb(hw->func, SDIO_CCCR_INTx, &ret);
312 if (ret) {
313 IWM_ERR(iwm, "Could not read SDIO_CCCR_INTx\n");
314 goto err;
315 }
316 len += snprintf(buf + len, buf_len - len, "CCCR_INTx: 0x%x\n", cccr);
317
318
319 cccr = sdio_f0_readb(hw->func, SDIO_CCCR_ABORT, &ret);
320 if (ret) {
321 IWM_ERR(iwm, "Could not read SDIO_CCCR_ABORTx\n");
322 goto err;
323 }
324 len += snprintf(buf + len, buf_len - len, "CCCR_ABORT: 0x%x\n", cccr);
325
326 cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IF, &ret);
327 if (ret) {
328 IWM_ERR(iwm, "Could not read SDIO_CCCR_IF\n");
329 goto err;
330 }
331 len += snprintf(buf + len, buf_len - len, "CCCR_IF: 0x%x\n", cccr);
332
333
334 cccr = sdio_f0_readb(hw->func, SDIO_CCCR_CAPS, &ret);
335 if (ret) {
336 IWM_ERR(iwm, "Could not read SDIO_CCCR_CAPS\n");
337 goto err;
338 }
339 len += snprintf(buf + len, buf_len - len, "CCCR_CAPS: 0x%x\n", cccr);
340
341 cccr = sdio_f0_readb(hw->func, SDIO_CCCR_CIS, &ret);
342 if (ret) {
343 IWM_ERR(iwm, "Could not read SDIO_CCCR_CIS\n");
344 goto err;
345 }
346 len += snprintf(buf + len, buf_len - len, "CCCR_CIS: 0x%x\n", cccr);
347
348 ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
349err:
350 sdio_release_host(hw->func);
351
352 kfree(buf);
353
354 return ret;
355}
356
357static const struct file_operations iwm_debugfs_sdio_fops = {
358 .owner = THIS_MODULE,
359 .open = simple_open,
360 .read = iwm_debugfs_sdio_read,
361 .llseek = default_llseek,
362};
363
364static void if_sdio_debugfs_init(struct iwm_priv *iwm, struct dentry *parent_dir)
365{
366 struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
367
368 hw->cccr_dentry = debugfs_create_file("cccr", 0200,
369 parent_dir, iwm,
370 &iwm_debugfs_sdio_fops);
371}
372
373static void if_sdio_debugfs_exit(struct iwm_priv *iwm)
374{
375 struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
376
377 debugfs_remove(hw->cccr_dentry);
378}
379
380static struct iwm_if_ops if_sdio_ops = {
381 .enable = if_sdio_enable,
382 .disable = if_sdio_disable,
383 .send_chunk = if_sdio_send_chunk,
384 .debugfs_init = if_sdio_debugfs_init,
385 .debugfs_exit = if_sdio_debugfs_exit,
386 .umac_name = "iwmc3200wifi-umac-sdio.bin",
387 .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin",
388 .lmac_name = "iwmc3200wifi-lmac-sdio.bin",
389};
390MODULE_FIRMWARE("iwmc3200wifi-umac-sdio.bin");
391MODULE_FIRMWARE("iwmc3200wifi-calib-sdio.bin");
392MODULE_FIRMWARE("iwmc3200wifi-lmac-sdio.bin");
393
394static int iwm_sdio_probe(struct sdio_func *func,
395 const struct sdio_device_id *id)
396{
397 struct iwm_priv *iwm;
398 struct iwm_sdio_priv *hw;
399 struct device *dev = &func->dev;
400 int ret;
401
402 /* check if TOP has already initialized the card */
403 sdio_claim_host(func);
404 ret = sdio_enable_func(func);
405 if (ret) {
406 dev_err(dev, "wait for TOP to enable the device\n");
407 sdio_release_host(func);
408 return ret;
409 }
410
411 ret = sdio_set_block_size(func, IWM_SDIO_BLK_SIZE);
412
413 sdio_disable_func(func);
414 sdio_release_host(func);
415
416 if (ret < 0) {
417 dev_err(dev, "Failed to set block size: %d\n", ret);
418 return ret;
419 }
420
421 iwm = iwm_if_alloc(sizeof(struct iwm_sdio_priv), dev, &if_sdio_ops);
422 if (IS_ERR(iwm)) {
423 dev_err(dev, "allocate SDIO interface failed\n");
424 return PTR_ERR(iwm);
425 }
426
427 hw = iwm_private(iwm);
428 hw->iwm = iwm;
429
430 iwm_debugfs_init(iwm);
431
432 sdio_set_drvdata(func, hw);
433
434 hw->func = func;
435 hw->blk_size = IWM_SDIO_BLK_SIZE;
436
437 hw->isr_wq = create_singlethread_workqueue(KBUILD_MODNAME "_sdio");
438 if (!hw->isr_wq) {
439 ret = -ENOMEM;
440 goto debugfs_exit;
441 }
442
443 INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker);
444
445 ret = iwm_if_add(iwm);
446 if (ret) {
447 dev_err(dev, "add SDIO interface failed\n");
448 goto destroy_wq;
449 }
450
451 dev_info(dev, "IWM SDIO probe\n");
452
453 return 0;
454
455 destroy_wq:
456 destroy_workqueue(hw->isr_wq);
457 debugfs_exit:
458 iwm_debugfs_exit(iwm);
459 iwm_if_free(iwm);
460 return ret;
461}
462
463static void iwm_sdio_remove(struct sdio_func *func)
464{
465 struct iwm_sdio_priv *hw = sdio_get_drvdata(func);
466 struct iwm_priv *iwm = hw_to_iwm(hw);
467 struct device *dev = &func->dev;
468
469 iwm_if_remove(iwm);
470 destroy_workqueue(hw->isr_wq);
471 iwm_debugfs_exit(iwm);
472 iwm_if_free(iwm);
473
474 sdio_set_drvdata(func, NULL);
475
476 dev_info(dev, "IWM SDIO remove\n");
477}
478
479static const struct sdio_device_id iwm_sdio_ids[] = {
480 /* Global/AGN SKU */
481 { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1403) },
482 /* BGN SKU */
483 { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1408) },
484 { /* end: all zeroes */ },
485};
486MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids);
487
488static struct sdio_driver iwm_sdio_driver = {
489 .name = "iwm_sdio",
490 .id_table = iwm_sdio_ids,
491 .probe = iwm_sdio_probe,
492 .remove = iwm_sdio_remove,
493};
494
495static int __init iwm_sdio_init_module(void)
496{
497 return sdio_register_driver(&iwm_sdio_driver);
498}
499
500static void __exit iwm_sdio_exit_module(void)
501{
502 sdio_unregister_driver(&iwm_sdio_driver);
503}
504
505module_init(iwm_sdio_init_module);
506module_exit(iwm_sdio_exit_module);
507
508MODULE_LICENSE("GPL");
509MODULE_AUTHOR(IWM_COPYRIGHT " " IWM_AUTHOR);
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h
deleted file mode 100644
index aab6b6892e45..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/sdio.h
+++ /dev/null
@@ -1,64 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#ifndef __IWM_SDIO_H__
40#define __IWM_SDIO_H__
41
42#define IWM_SDIO_DATA_ADDR 0x0
43#define IWM_SDIO_INTR_ENABLE_ADDR 0x14
44#define IWM_SDIO_INTR_STATUS_ADDR 0x13
45#define IWM_SDIO_INTR_CLEAR_ADDR 0x13
46#define IWM_SDIO_INTR_GET_SIZE_ADDR 0x2C
47
48#define IWM_SDIO_BLK_SIZE 256
49
50#define iwm_to_if_sdio(i) (struct iwm_sdio_priv *)(iwm->private)
51
52struct iwm_sdio_priv {
53 struct sdio_func *func;
54 struct iwm_priv *iwm;
55
56 struct workqueue_struct *isr_wq;
57 struct work_struct isr_worker;
58
59 struct dentry *cccr_dentry;
60
61 unsigned int blk_size;
62};
63
64#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/trace.c b/drivers/net/wireless/iwmc3200wifi/trace.c
deleted file mode 100644
index 904d36f22311..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/trace.c
+++ /dev/null
@@ -1,3 +0,0 @@
1#include "iwm.h"
2#define CREATE_TRACE_POINTS
3#include "trace.h"
diff --git a/drivers/net/wireless/iwmc3200wifi/trace.h b/drivers/net/wireless/iwmc3200wifi/trace.h
deleted file mode 100644
index f5f7070b7e22..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/trace.h
+++ /dev/null
@@ -1,283 +0,0 @@
1#if !defined(__IWM_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ)
2#define __IWM_TRACE_H__
3
4#include <linux/tracepoint.h>
5
6#if !defined(CONFIG_IWM_TRACING)
7#undef TRACE_EVENT
8#define TRACE_EVENT(name, proto, ...) \
9static inline void trace_ ## name(proto) {}
10#endif
11
12#undef TRACE_SYSTEM
13#define TRACE_SYSTEM iwm
14
15#define IWM_ENTRY __array(char, ndev_name, 16)
16#define IWM_ASSIGN strlcpy(__entry->ndev_name, iwm_to_ndev(iwm)->name, 16)
17#define IWM_PR_FMT "%s"
18#define IWM_PR_ARG __entry->ndev_name
19
20TRACE_EVENT(iwm_tx_nonwifi_cmd,
21 TP_PROTO(struct iwm_priv *iwm, struct iwm_udma_out_nonwifi_hdr *hdr),
22
23 TP_ARGS(iwm, hdr),
24
25 TP_STRUCT__entry(
26 IWM_ENTRY
27 __field(u8, opcode)
28 __field(u8, resp)
29 __field(u8, eot)
30 __field(u8, hw)
31 __field(u16, seq)
32 __field(u32, addr)
33 __field(u32, op1)
34 __field(u32, op2)
35 ),
36
37 TP_fast_assign(
38 IWM_ASSIGN;
39 __entry->opcode = GET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE);
40 __entry->resp = GET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP);
41 __entry->eot = GET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT);
42 __entry->hw = GET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW);
43 __entry->seq = GET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM);
44 __entry->addr = le32_to_cpu(hdr->addr);
45 __entry->op1 = le32_to_cpu(hdr->op1_sz);
46 __entry->op2 = le32_to_cpu(hdr->op2);
47 ),
48
49 TP_printk(
50 IWM_PR_FMT " Tx TARGET CMD: opcode 0x%x, resp %d, eot %d, "
51 "hw %d, seq 0x%x, addr 0x%x, op1 0x%x, op2 0x%x",
52 IWM_PR_ARG, __entry->opcode, __entry->resp, __entry->eot,
53 __entry->hw, __entry->seq, __entry->addr, __entry->op1,
54 __entry->op2
55 )
56);
57
58TRACE_EVENT(iwm_tx_wifi_cmd,
59 TP_PROTO(struct iwm_priv *iwm, struct iwm_umac_wifi_out_hdr *hdr),
60
61 TP_ARGS(iwm, hdr),
62
63 TP_STRUCT__entry(
64 IWM_ENTRY
65 __field(u8, opcode)
66 __field(u8, lmac)
67 __field(u8, resp)
68 __field(u8, eot)
69 __field(u8, ra_tid)
70 __field(u8, credit_group)
71 __field(u8, color)
72 __field(u16, seq)
73 ),
74
75 TP_fast_assign(
76 IWM_ASSIGN;
77 __entry->opcode = hdr->sw_hdr.cmd.cmd;
78 __entry->lmac = 0;
79 __entry->seq = __le16_to_cpu(hdr->sw_hdr.cmd.seq_num);
80 __entry->resp = GET_VAL8(hdr->sw_hdr.cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ);
81 __entry->color = GET_VAL32(hdr->sw_hdr.meta_data, UMAC_FW_CMD_TX_STA_COLOR);
82 __entry->eot = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_OUT_CMD_EOT);
83 __entry->ra_tid = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_RATID);
84 __entry->credit_group = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_CREDIT_GRP);
85 if (__entry->opcode == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH ||
86 __entry->opcode == UMAC_CMD_OPCODE_WIFI_IF_WRAPPER) {
87 __entry->lmac = 1;
88 __entry->opcode = ((struct iwm_lmac_hdr *)(hdr + 1))->id;
89 }
90 ),
91
92 TP_printk(
93 IWM_PR_FMT " Tx %cMAC CMD: opcode 0x%x, resp %d, eot %d, "
94 "seq 0x%x, sta_color 0x%x, ra_tid 0x%x, credit_group 0x%x",
95 IWM_PR_ARG, __entry->lmac ? 'L' : 'U', __entry->opcode,
96 __entry->resp, __entry->eot, __entry->seq, __entry->color,
97 __entry->ra_tid, __entry->credit_group
98 )
99);
100
101TRACE_EVENT(iwm_tx_packets,
102 TP_PROTO(struct iwm_priv *iwm, u8 *buf, int len),
103
104 TP_ARGS(iwm, buf, len),
105
106 TP_STRUCT__entry(
107 IWM_ENTRY
108 __field(u8, eot)
109 __field(u8, ra_tid)
110 __field(u8, credit_group)
111 __field(u8, color)
112 __field(u16, seq)
113 __field(u8, npkt)
114 __field(u32, bytes)
115 ),
116
117 TP_fast_assign(
118 struct iwm_umac_wifi_out_hdr *hdr =
119 (struct iwm_umac_wifi_out_hdr *)buf;
120
121 IWM_ASSIGN;
122 __entry->eot = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_OUT_CMD_EOT);
123 __entry->ra_tid = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_RATID);
124 __entry->credit_group = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_CREDIT_GRP);
125 __entry->color = GET_VAL32(hdr->sw_hdr.meta_data, UMAC_FW_CMD_TX_STA_COLOR);
126 __entry->seq = __le16_to_cpu(hdr->sw_hdr.cmd.seq_num);
127 __entry->npkt = 1;
128 __entry->bytes = len;
129
130 if (!__entry->eot) {
131 int count;
132 u8 *ptr = buf;
133
134 __entry->npkt = 0;
135 while (ptr < buf + len) {
136 count = GET_VAL32(hdr->sw_hdr.meta_data,
137 UMAC_FW_CMD_BYTE_COUNT);
138 ptr += ALIGN(sizeof(*hdr) + count, 16);
139 hdr = (struct iwm_umac_wifi_out_hdr *)ptr;
140 __entry->npkt++;
141 }
142 }
143 ),
144
145 TP_printk(
146 IWM_PR_FMT " Tx %spacket: eot %d, seq 0x%x, sta_color 0x%x, "
147 "ra_tid 0x%x, credit_group 0x%x, embedded_packets %d, %d bytes",
148 IWM_PR_ARG, !__entry->eot ? "concatenated " : "",
149 __entry->eot, __entry->seq, __entry->color, __entry->ra_tid,
150 __entry->credit_group, __entry->npkt, __entry->bytes
151 )
152);
153
154TRACE_EVENT(iwm_rx_nonwifi_cmd,
155 TP_PROTO(struct iwm_priv *iwm, void *buf, int len),
156
157 TP_ARGS(iwm, buf, len),
158
159 TP_STRUCT__entry(
160 IWM_ENTRY
161 __field(u8, opcode)
162 __field(u16, seq)
163 __field(u32, len)
164 ),
165
166 TP_fast_assign(
167 struct iwm_udma_in_hdr *hdr = buf;
168
169 IWM_ASSIGN;
170 __entry->opcode = GET_VAL32(hdr->cmd, UDMA_HDI_IN_NW_CMD_OPCODE);
171 __entry->seq = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM);
172 __entry->len = len;
173 ),
174
175 TP_printk(
176 IWM_PR_FMT " Rx TARGET RESP: opcode 0x%x, seq 0x%x, len 0x%x",
177 IWM_PR_ARG, __entry->opcode, __entry->seq, __entry->len
178 )
179);
180
181TRACE_EVENT(iwm_rx_wifi_cmd,
182 TP_PROTO(struct iwm_priv *iwm, struct iwm_umac_wifi_in_hdr *hdr),
183
184 TP_ARGS(iwm, hdr),
185
186 TP_STRUCT__entry(
187 IWM_ENTRY
188 __field(u8, cmd)
189 __field(u8, source)
190 __field(u16, seq)
191 __field(u32, count)
192 ),
193
194 TP_fast_assign(
195 IWM_ASSIGN;
196 __entry->cmd = hdr->sw_hdr.cmd.cmd;
197 __entry->source = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE);
198 __entry->count = GET_VAL32(hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT);
199 __entry->seq = le16_to_cpu(hdr->sw_hdr.cmd.seq_num);
200 ),
201
202 TP_printk(
203 IWM_PR_FMT " Rx %s RESP: cmd 0x%x, seq 0x%x, count 0x%x",
204 IWM_PR_ARG, __entry->source == UMAC_HDI_IN_SOURCE_FHRX ? "LMAC" :
205 __entry->source == UMAC_HDI_IN_SOURCE_FW ? "UMAC" : "UDMA",
206 __entry->cmd, __entry->seq, __entry->count
207 )
208);
209
210#define iwm_ticket_action_symbol \
211 { IWM_RX_TICKET_DROP, "DROP" }, \
212 { IWM_RX_TICKET_RELEASE, "RELEASE" }, \
213 { IWM_RX_TICKET_SNIFFER, "SNIFFER" }, \
214 { IWM_RX_TICKET_ENQUEUE, "ENQUEUE" }
215
216TRACE_EVENT(iwm_rx_ticket,
217 TP_PROTO(struct iwm_priv *iwm, void *buf, int len),
218
219 TP_ARGS(iwm, buf, len),
220
221 TP_STRUCT__entry(
222 IWM_ENTRY
223 __field(u8, action)
224 __field(u8, reason)
225 __field(u16, id)
226 __field(u16, flags)
227 ),
228
229 TP_fast_assign(
230 struct iwm_rx_ticket *ticket =
231 ((struct iwm_umac_notif_rx_ticket *)buf)->tickets;
232
233 IWM_ASSIGN;
234 __entry->id = le16_to_cpu(ticket->id);
235 __entry->action = le16_to_cpu(ticket->action);
236 __entry->flags = le16_to_cpu(ticket->flags);
237 __entry->reason = (__entry->flags & IWM_RX_TICKET_DROP_REASON_MSK) >> IWM_RX_TICKET_DROP_REASON_POS;
238 ),
239
240 TP_printk(
241 IWM_PR_FMT " Rx ticket: id 0x%x, action %s, %s 0x%x%s",
242 IWM_PR_ARG, __entry->id,
243 __print_symbolic(__entry->action, iwm_ticket_action_symbol),
244 __entry->reason ? "reason" : "flags",
245 __entry->reason ? __entry->reason : __entry->flags,
246 __entry->flags & IWM_RX_TICKET_AMSDU_MSK ? ", AMSDU frame" : ""
247 )
248);
249
250TRACE_EVENT(iwm_rx_packet,
251 TP_PROTO(struct iwm_priv *iwm, void *buf, int len),
252
253 TP_ARGS(iwm, buf, len),
254
255 TP_STRUCT__entry(
256 IWM_ENTRY
257 __field(u8, source)
258 __field(u16, id)
259 __field(u32, len)
260 ),
261
262 TP_fast_assign(
263 struct iwm_umac_wifi_in_hdr *hdr = buf;
264
265 IWM_ASSIGN;
266 __entry->source = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE);
267 __entry->id = le16_to_cpu(hdr->sw_hdr.cmd.seq_num);
268 __entry->len = len - sizeof(*hdr);
269 ),
270
271 TP_printk(
272 IWM_PR_FMT " Rx %s packet: id 0x%x, %d bytes",
273 IWM_PR_ARG, __entry->source == UMAC_HDI_IN_SOURCE_FHRX ?
274 "LMAC" : "UMAC", __entry->id, __entry->len
275 )
276);
277#endif
278
279#undef TRACE_INCLUDE_PATH
280#define TRACE_INCLUDE_PATH .
281#undef TRACE_INCLUDE_FILE
282#define TRACE_INCLUDE_FILE trace
283#include <trace/define_trace.h>
diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c
deleted file mode 100644
index be98074c0608..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/tx.c
+++ /dev/null
@@ -1,529 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39/*
40 * iwm Tx theory of operation:
41 *
42 * 1) We receive a 802.3 frame from the stack
43 * 2) We convert it to a 802.11 frame [iwm_xmit_frame]
44 * 3) We queue it to its corresponding tx queue [iwm_xmit_frame]
45 * 4) We schedule the tx worker. There is one worker per tx
46 * queue. [iwm_xmit_frame]
47 * 5) The tx worker is scheduled
48 * 6) We go through every queued skb on the tx queue, and for each
49 * and every one of them: [iwm_tx_worker]
50 * a) We check if we have enough Tx credits (see below for a Tx
51 * credits description) for the frame length. [iwm_tx_worker]
52 * b) If we do, we aggregate the Tx frame into a UDMA one, by
53 * concatenating one REPLY_TX command per Tx frame. [iwm_tx_worker]
54 * c) When we run out of credits, or when we reach the maximum
55 * concatenation size, we actually send the concatenated UDMA
56 * frame. [iwm_tx_worker]
57 *
58 * When we run out of Tx credits, the skbs are filling the tx queue,
59 * and eventually we will stop the netdev queue. [iwm_tx_worker]
60 * The tx queue is emptied as we're getting new tx credits, by
61 * scheduling the tx_worker. [iwm_tx_credit_inc]
62 * The netdev queue is started again when we have enough tx credits,
63 * and when our tx queue has some reasonable amout of space available
64 * (i.e. half of the max size). [iwm_tx_worker]
65 */
66
67#include <linux/slab.h>
68#include <linux/skbuff.h>
69#include <linux/netdevice.h>
70#include <linux/ieee80211.h>
71
72#include "iwm.h"
73#include "debug.h"
74#include "commands.h"
75#include "hal.h"
76#include "umac.h"
77#include "bus.h"
78
79#define IWM_UMAC_PAGE_ALLOC_WRAP 0xffff
80
81#define BYTES_TO_PAGES(n) (1 + ((n) >> ilog2(IWM_UMAC_PAGE_SIZE)) - \
82 (((n) & (IWM_UMAC_PAGE_SIZE - 1)) == 0))
83
84#define pool_id_to_queue(id) ((id < IWM_TX_CMD_QUEUE) ? id : id - 1)
85#define queue_to_pool_id(q) ((q < IWM_TX_CMD_QUEUE) ? q : q + 1)
86
87/* require to hold tx_credit lock */
88static int iwm_tx_credit_get(struct iwm_tx_credit *tx_credit, int id)
89{
90 struct pool_entry *pool = &tx_credit->pools[id];
91 struct spool_entry *spool = &tx_credit->spools[pool->sid];
92 int spool_pages;
93
94 /* number of pages can be taken from spool by this pool */
95 spool_pages = spool->max_pages - spool->alloc_pages +
96 max(pool->min_pages - pool->alloc_pages, 0);
97
98 return min(pool->max_pages - pool->alloc_pages, spool_pages);
99}
100
101static bool iwm_tx_credit_ok(struct iwm_priv *iwm, int id, int nb)
102{
103 u32 npages = BYTES_TO_PAGES(nb);
104
105 if (npages <= iwm_tx_credit_get(&iwm->tx_credit, id))
106 return 1;
107
108 set_bit(id, &iwm->tx_credit.full_pools_map);
109
110 IWM_DBG_TX(iwm, DBG, "LINK: stop txq[%d], available credit: %d\n",
111 pool_id_to_queue(id),
112 iwm_tx_credit_get(&iwm->tx_credit, id));
113
114 return 0;
115}
116
117void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages)
118{
119 struct pool_entry *pool;
120 struct spool_entry *spool;
121 int freed_pages;
122 int queue;
123
124 BUG_ON(id >= IWM_MACS_OUT_GROUPS);
125
126 pool = &iwm->tx_credit.pools[id];
127 spool = &iwm->tx_credit.spools[pool->sid];
128
129 freed_pages = total_freed_pages - pool->total_freed_pages;
130 IWM_DBG_TX(iwm, DBG, "Free %d pages for pool[%d]\n", freed_pages, id);
131
132 if (!freed_pages) {
133 IWM_DBG_TX(iwm, DBG, "No pages are freed by UMAC\n");
134 return;
135 } else if (freed_pages < 0)
136 freed_pages += IWM_UMAC_PAGE_ALLOC_WRAP + 1;
137
138 if (pool->alloc_pages > pool->min_pages) {
139 int spool_pages = pool->alloc_pages - pool->min_pages;
140 spool_pages = min(spool_pages, freed_pages);
141 spool->alloc_pages -= spool_pages;
142 }
143
144 pool->alloc_pages -= freed_pages;
145 pool->total_freed_pages = total_freed_pages;
146
147 IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, "
148 "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages,
149 pool->total_freed_pages, pool->sid, spool->alloc_pages);
150
151 if (test_bit(id, &iwm->tx_credit.full_pools_map) &&
152 (pool->alloc_pages < pool->max_pages / 2)) {
153 clear_bit(id, &iwm->tx_credit.full_pools_map);
154
155 queue = pool_id_to_queue(id);
156
157 IWM_DBG_TX(iwm, DBG, "LINK: start txq[%d], available "
158 "credit: %d\n", queue,
159 iwm_tx_credit_get(&iwm->tx_credit, id));
160 queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker);
161 }
162}
163
164static void iwm_tx_credit_dec(struct iwm_priv *iwm, int id, int alloc_pages)
165{
166 struct pool_entry *pool;
167 struct spool_entry *spool;
168 int spool_pages;
169
170 IWM_DBG_TX(iwm, DBG, "Allocate %d pages for pool[%d]\n",
171 alloc_pages, id);
172
173 BUG_ON(id >= IWM_MACS_OUT_GROUPS);
174
175 pool = &iwm->tx_credit.pools[id];
176 spool = &iwm->tx_credit.spools[pool->sid];
177
178 spool_pages = pool->alloc_pages + alloc_pages - pool->min_pages;
179
180 if (pool->alloc_pages >= pool->min_pages)
181 spool->alloc_pages += alloc_pages;
182 else if (spool_pages > 0)
183 spool->alloc_pages += spool_pages;
184
185 pool->alloc_pages += alloc_pages;
186
187 IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, "
188 "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages,
189 pool->total_freed_pages, pool->sid, spool->alloc_pages);
190}
191
192int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb)
193{
194 u32 npages = BYTES_TO_PAGES(nb);
195 int ret = 0;
196
197 spin_lock(&iwm->tx_credit.lock);
198
199 if (!iwm_tx_credit_ok(iwm, id, nb)) {
200 IWM_DBG_TX(iwm, DBG, "No credit available for pool[%d]\n", id);
201 ret = -ENOSPC;
202 goto out;
203 }
204
205 iwm_tx_credit_dec(iwm, id, npages);
206
207 out:
208 spin_unlock(&iwm->tx_credit.lock);
209 return ret;
210}
211
212/*
213 * Since we're on an SDIO or USB bus, we are not sharing memory
214 * for storing to be transmitted frames. The host needs to push
215 * them upstream. As a consequence there needs to be a way for
216 * the target to let us know if it can actually take more TX frames
217 * or not. This is what Tx credits are for.
218 *
219 * For each Tx HW queue, we have a Tx pool, and then we have one
220 * unique super pool (spool), which is actually a global pool of
221 * all the UMAC pages.
222 * For each Tx pool we have a min_pages, a max_pages fields, and a
223 * alloc_pages fields. The alloc_pages tracks the number of pages
224 * currently allocated from the tx pool.
225 * Here are the rules to check if given a tx frame we have enough
226 * tx credits for it:
227 * 1) We translate the frame length into a number of UMAC pages.
228 * Let's call them n_pages.
229 * 2) For the corresponding tx pool, we check if n_pages +
230 * pool->alloc_pages is higher than pool->min_pages. min_pages
231 * represent a set of pre-allocated pages on the tx pool. If
232 * that's the case, then we need to allocate those pages from
233 * the spool. We can do so until we reach spool->max_pages.
234 * 3) Each tx pool is not allowed to allocate more than pool->max_pages
235 * from the spool, so once we're over min_pages, we can allocate
236 * pages from the spool, but not more than max_pages.
237 *
238 * When the tx code path needs to send a tx frame, it checks first
239 * if it has enough tx credits, following those rules. [iwm_tx_credit_get]
240 * If it does, it then updates the pool and spool counters and
241 * then send the frame. [iwm_tx_credit_alloc and iwm_tx_credit_dec]
242 * On the other side, when the UMAC is done transmitting frames, it
243 * will send a credit update notification to the host. This is when
244 * the pool and spool counters gets to be decreased. [iwm_tx_credit_inc,
245 * called from rx.c:iwm_ntf_tx_credit_update]
246 *
247 */
248void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
249 struct iwm_umac_notif_alive *alive)
250{
251 int i, sid, pool_pages;
252
253 spin_lock(&iwm->tx_credit.lock);
254
255 iwm->tx_credit.pool_nr = le16_to_cpu(alive->page_grp_count);
256 iwm->tx_credit.full_pools_map = 0;
257 memset(&iwm->tx_credit.spools[0], 0, sizeof(struct spool_entry));
258
259 IWM_DBG_TX(iwm, DBG, "Pools number is %d\n", iwm->tx_credit.pool_nr);
260
261 for (i = 0; i < iwm->tx_credit.pool_nr; i++) {
262 __le32 page_grp_state = alive->page_grp_state[i];
263
264 iwm->tx_credit.pools[i].id = GET_VAL32(page_grp_state,
265 UMAC_ALIVE_PAGE_STS_GRP_NUM);
266 iwm->tx_credit.pools[i].sid = GET_VAL32(page_grp_state,
267 UMAC_ALIVE_PAGE_STS_SGRP_NUM);
268 iwm->tx_credit.pools[i].min_pages = GET_VAL32(page_grp_state,
269 UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE);
270 iwm->tx_credit.pools[i].max_pages = GET_VAL32(page_grp_state,
271 UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE);
272 iwm->tx_credit.pools[i].alloc_pages = 0;
273 iwm->tx_credit.pools[i].total_freed_pages = 0;
274
275 sid = iwm->tx_credit.pools[i].sid;
276 pool_pages = iwm->tx_credit.pools[i].min_pages;
277
278 if (iwm->tx_credit.spools[sid].max_pages == 0) {
279 iwm->tx_credit.spools[sid].id = sid;
280 iwm->tx_credit.spools[sid].max_pages =
281 GET_VAL32(page_grp_state,
282 UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE);
283 iwm->tx_credit.spools[sid].alloc_pages = 0;
284 }
285
286 iwm->tx_credit.spools[sid].alloc_pages += pool_pages;
287
288 IWM_DBG_TX(iwm, DBG, "Pool idx: %d, id: %d, sid: %d, capacity "
289 "min: %d, max: %d, pool alloc: %d, total_free: %d, "
290 "super poll alloc: %d\n",
291 i, iwm->tx_credit.pools[i].id,
292 iwm->tx_credit.pools[i].sid,
293 iwm->tx_credit.pools[i].min_pages,
294 iwm->tx_credit.pools[i].max_pages,
295 iwm->tx_credit.pools[i].alloc_pages,
296 iwm->tx_credit.pools[i].total_freed_pages,
297 iwm->tx_credit.spools[sid].alloc_pages);
298 }
299
300 spin_unlock(&iwm->tx_credit.lock);
301}
302
303#define IWM_UDMA_HDR_LEN sizeof(struct iwm_umac_wifi_out_hdr)
304
305static __le16 iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb,
306 int pool_id, u8 *buf)
307{
308 struct iwm_umac_wifi_out_hdr *hdr = (struct iwm_umac_wifi_out_hdr *)buf;
309 struct iwm_udma_wifi_cmd udma_cmd;
310 struct iwm_umac_cmd umac_cmd;
311 struct iwm_tx_info *tx_info = skb_to_tx_info(skb);
312
313 udma_cmd.count = cpu_to_le16(skb->len +
314 sizeof(struct iwm_umac_fw_cmd_hdr));
315 /* set EOP to 0 here. iwm_udma_wifi_hdr_set_eop() will be
316 * called later to set EOP for the last packet. */
317 udma_cmd.eop = 0;
318 udma_cmd.credit_group = pool_id;
319 udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid;
320 udma_cmd.lmac_offset = 0;
321
322 umac_cmd.id = REPLY_TX;
323 umac_cmd.count = cpu_to_le16(skb->len);
324 umac_cmd.color = tx_info->color;
325 umac_cmd.resp = 0;
326 umac_cmd.seq_num = cpu_to_le16(iwm_alloc_wifi_cmd_seq(iwm));
327
328 iwm_build_udma_wifi_hdr(iwm, &hdr->hw_hdr, &udma_cmd);
329 iwm_build_umac_hdr(iwm, &hdr->sw_hdr, &umac_cmd);
330
331 memcpy(buf + sizeof(*hdr), skb->data, skb->len);
332
333 return umac_cmd.seq_num;
334}
335
336static int iwm_tx_send_concat_packets(struct iwm_priv *iwm,
337 struct iwm_tx_queue *txq)
338{
339 int ret;
340
341 if (!txq->concat_count)
342 return 0;
343
344 IWM_DBG_TX(iwm, DBG, "Send concatenated Tx: queue %d, %d bytes\n",
345 txq->id, txq->concat_count);
346
347 /* mark EOP for the last packet */
348 iwm_udma_wifi_hdr_set_eop(iwm, txq->concat_ptr, 1);
349
350 trace_iwm_tx_packets(iwm, txq->concat_buf, txq->concat_count);
351 ret = iwm_bus_send_chunk(iwm, txq->concat_buf, txq->concat_count);
352
353 txq->concat_count = 0;
354 txq->concat_ptr = txq->concat_buf;
355
356 return ret;
357}
358
359void iwm_tx_worker(struct work_struct *work)
360{
361 struct iwm_priv *iwm;
362 struct iwm_tx_info *tx_info = NULL;
363 struct sk_buff *skb;
364 struct iwm_tx_queue *txq;
365 struct iwm_sta_info *sta_info;
366 struct iwm_tid_info *tid_info;
367 int cmdlen, ret, pool_id;
368
369 txq = container_of(work, struct iwm_tx_queue, worker);
370 iwm = container_of(txq, struct iwm_priv, txq[txq->id]);
371
372 pool_id = queue_to_pool_id(txq->id);
373
374 while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) &&
375 !skb_queue_empty(&txq->queue)) {
376
377 spin_lock_bh(&txq->lock);
378 skb = skb_dequeue(&txq->queue);
379 spin_unlock_bh(&txq->lock);
380
381 tx_info = skb_to_tx_info(skb);
382 sta_info = &iwm->sta_table[tx_info->sta];
383 if (!sta_info->valid) {
384 IWM_ERR(iwm, "Trying to send a frame to unknown STA\n");
385 kfree_skb(skb);
386 continue;
387 }
388
389 tid_info = &sta_info->tid_info[tx_info->tid];
390
391 mutex_lock(&tid_info->mutex);
392
393 /*
394 * If the RAxTID is stopped, we queue the skb to the stopped
395 * queue.
396 * Whenever we'll get a UMAC notification to resume the tx flow
397 * for this RAxTID, we'll merge back the stopped queue into the
398 * regular queue. See iwm_ntf_stop_resume_tx() from rx.c.
399 */
400 if (tid_info->stopped) {
401 IWM_DBG_TX(iwm, DBG, "%dx%d stopped\n",
402 tx_info->sta, tx_info->tid);
403 spin_lock_bh(&txq->lock);
404 skb_queue_tail(&txq->stopped_queue, skb);
405 spin_unlock_bh(&txq->lock);
406
407 mutex_unlock(&tid_info->mutex);
408 continue;
409 }
410
411 cmdlen = IWM_UDMA_HDR_LEN + skb->len;
412
413 IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: "
414 "%d, color: %d\n", txq->id, skb, tx_info->sta,
415 tx_info->color);
416
417 if (txq->concat_count + cmdlen > IWM_HAL_CONCATENATE_BUF_SIZE)
418 iwm_tx_send_concat_packets(iwm, txq);
419
420 ret = iwm_tx_credit_alloc(iwm, pool_id, cmdlen);
421 if (ret) {
422 IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue "
423 "%d, Tx worker stopped\n", txq->id);
424 spin_lock_bh(&txq->lock);
425 skb_queue_head(&txq->queue, skb);
426 spin_unlock_bh(&txq->lock);
427
428 mutex_unlock(&tid_info->mutex);
429 break;
430 }
431
432 txq->concat_ptr = txq->concat_buf + txq->concat_count;
433 tid_info->last_seq_num =
434 iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr);
435 txq->concat_count += ALIGN(cmdlen, 16);
436
437 mutex_unlock(&tid_info->mutex);
438
439 kfree_skb(skb);
440 }
441
442 iwm_tx_send_concat_packets(iwm, txq);
443
444 if (__netif_subqueue_stopped(iwm_to_ndev(iwm), txq->id) &&
445 !test_bit(pool_id, &iwm->tx_credit.full_pools_map) &&
446 (skb_queue_len(&txq->queue) < IWM_TX_LIST_SIZE / 2)) {
447 IWM_DBG_TX(iwm, DBG, "LINK: start netif_subqueue[%d]", txq->id);
448 netif_wake_subqueue(iwm_to_ndev(iwm), txq->id);
449 }
450}
451
452int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
453{
454 struct iwm_priv *iwm = ndev_to_iwm(netdev);
455 struct wireless_dev *wdev = iwm_to_wdev(iwm);
456 struct iwm_tx_info *tx_info;
457 struct iwm_tx_queue *txq;
458 struct iwm_sta_info *sta_info;
459 u8 *dst_addr, sta_id;
460 u16 queue;
461 int ret;
462
463
464 if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
465 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: "
466 "not associated\n");
467 netif_tx_stop_all_queues(netdev);
468 goto drop;
469 }
470
471 queue = skb_get_queue_mapping(skb);
472 BUG_ON(queue >= IWM_TX_DATA_QUEUES); /* no iPAN yet */
473
474 txq = &iwm->txq[queue];
475
476 /* No free space for Tx, tx_worker is too slow */
477 if ((skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) ||
478 (skb_queue_len(&txq->stopped_queue) > IWM_TX_LIST_SIZE)) {
479 IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue);
480 netif_stop_subqueue(netdev, queue);
481 return NETDEV_TX_BUSY;
482 }
483
484 ret = ieee80211_data_from_8023(skb, netdev->dev_addr, wdev->iftype,
485 iwm->bssid, 0);
486 if (ret) {
487 IWM_ERR(iwm, "build wifi header failed\n");
488 goto drop;
489 }
490
491 dst_addr = ((struct ieee80211_hdr *)(skb->data))->addr1;
492
493 for (sta_id = 0; sta_id < IWM_STA_TABLE_NUM; sta_id++) {
494 sta_info = &iwm->sta_table[sta_id];
495 if (sta_info->valid &&
496 !memcmp(dst_addr, sta_info->addr, ETH_ALEN))
497 break;
498 }
499
500 if (sta_id == IWM_STA_TABLE_NUM) {
501 IWM_ERR(iwm, "STA %pM not found in sta_table, Tx ignored\n",
502 dst_addr);
503 goto drop;
504 }
505
506 tx_info = skb_to_tx_info(skb);
507 tx_info->sta = sta_id;
508 tx_info->color = sta_info->color;
509 /* UMAC uses TID 8 (vs. 0) for non QoS packets */
510 if (sta_info->qos)
511 tx_info->tid = skb->priority;
512 else
513 tx_info->tid = IWM_UMAC_MGMT_TID;
514
515 spin_lock_bh(&iwm->txq[queue].lock);
516 skb_queue_tail(&iwm->txq[queue].queue, skb);
517 spin_unlock_bh(&iwm->txq[queue].lock);
518
519 queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker);
520
521 netdev->stats.tx_packets++;
522 netdev->stats.tx_bytes += skb->len;
523 return NETDEV_TX_OK;
524
525 drop:
526 netdev->stats.tx_dropped++;
527 dev_kfree_skb_any(skb);
528 return NETDEV_TX_OK;
529}
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
deleted file mode 100644
index 4a137d334a42..000000000000
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ /dev/null
@@ -1,789 +0,0 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Intel Corporation nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 * Intel Corporation <ilw@linux.intel.com>
34 * Samuel Ortiz <samuel.ortiz@intel.com>
35 * Zhu Yi <yi.zhu@intel.com>
36 *
37 */
38
39#ifndef __IWM_UMAC_H__
40#define __IWM_UMAC_H__
41
42struct iwm_udma_in_hdr {
43 __le32 cmd;
44 __le32 size;
45} __packed;
46
47struct iwm_udma_out_nonwifi_hdr {
48 __le32 cmd;
49 __le32 addr;
50 __le32 op1_sz;
51 __le32 op2;
52} __packed;
53
54struct iwm_udma_out_wifi_hdr {
55 __le32 cmd;
56 __le32 meta_data;
57} __packed;
58
59/* Sequence numbering */
60#define UMAC_WIFI_SEQ_NUM_BASE 1
61#define UMAC_WIFI_SEQ_NUM_MAX 0x4000
62#define UMAC_NONWIFI_SEQ_NUM_BASE 1
63#define UMAC_NONWIFI_SEQ_NUM_MAX 0x10
64
65/* MAC address address */
66#define WICO_MAC_ADDRESS_ADDR 0x604008F8
67
68/* RA / TID */
69#define UMAC_HDI_ACT_TBL_IDX_TID_POS 0
70#define UMAC_HDI_ACT_TBL_IDX_TID_SEED 0xF
71
72#define UMAC_HDI_ACT_TBL_IDX_RA_POS 4
73#define UMAC_HDI_ACT_TBL_IDX_RA_SEED 0xF
74
75#define UMAC_HDI_ACT_TBL_IDX_RA_UMAC 0xF
76#define UMAC_HDI_ACT_TBL_IDX_TID_UMAC 0x9
77#define UMAC_HDI_ACT_TBL_IDX_TID_LMAC 0xA
78
79#define UMAC_HDI_ACT_TBL_IDX_HOST_CMD \
80 ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\
81 (UMAC_HDI_ACT_TBL_IDX_TID_UMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS))
82#define UMAC_HDI_ACT_TBL_IDX_UMAC_CMD \
83 ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\
84 (UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS))
85
86/* STA ID and color */
87#define STA_ID_SEED (0x0f)
88#define STA_ID_POS (0)
89#define STA_ID_MSK (STA_ID_SEED << STA_ID_POS)
90
91#define STA_COLOR_SEED (0x7)
92#define STA_COLOR_POS (4)
93#define STA_COLOR_MSK (STA_COLOR_SEED << STA_COLOR_POS)
94
95#define STA_ID_N_COLOR_COLOR(id_n_color) \
96 (((id_n_color) & STA_COLOR_MSK) >> STA_COLOR_POS)
97#define STA_ID_N_COLOR_ID(id_n_color) \
98 (((id_n_color) & STA_ID_MSK) >> STA_ID_POS)
99
100/* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */
101#define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0
102#define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF
103
104/* iwm_umac_notif_alive.page_grp_state Super group number -- bits [7:4] */
105#define UMAC_ALIVE_PAGE_STS_SGRP_NUM_POS 4
106#define UMAC_ALIVE_PAGE_STS_SGRP_NUM_SEED 0xF
107
108/* iwm_umac_notif_alive.page_grp_state Group min size -- bits [15:8] */
109#define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_POS 8
110#define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_SEED 0xFF
111
112/* iwm_umac_notif_alive.page_grp_state Group max size -- bits [23:16] */
113#define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_POS 16
114#define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_SEED 0xFF
115
116/* iwm_umac_notif_alive.page_grp_state Super group max size -- bits [31:24] */
117#define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_POS 24
118#define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_SEED 0xFF
119
120/* Barkers */
121#define UMAC_REBOOT_BARKER 0xdeadbeef
122#define UMAC_ACK_BARKER 0xfeedbabe
123#define UMAC_PAD_TERMINAL 0xadadadad
124
125/* UMAC JMP address */
126#define UMAC_MU_FW_INST_DATA_12_ADDR 0xBF0000
127
128/* iwm_umac_hdi_out_hdr.cmd OP code -- bits [3:0] */
129#define UMAC_HDI_OUT_CMD_OPCODE_POS 0
130#define UMAC_HDI_OUT_CMD_OPCODE_SEED 0xF
131
132/* iwm_umac_hdi_out_hdr.cmd End-Of-Transfer -- bits [10:10] */
133#define UMAC_HDI_OUT_CMD_EOT_POS 10
134#define UMAC_HDI_OUT_CMD_EOT_SEED 0x1
135
136/* iwm_umac_hdi_out_hdr.cmd UTFD only usage -- bits [11:11] */
137#define UMAC_HDI_OUT_CMD_UTFD_ONLY_POS 11
138#define UMAC_HDI_OUT_CMD_UTFD_ONLY_SEED 0x1
139
140/* iwm_umac_hdi_out_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */
141#define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_POS 12
142#define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_SEED 0xF
143
144/* iwm_umac_hdi_out_hdr.cmd Signature -- bits [31:16] */
145#define UMAC_HDI_OUT_CMD_SIGNATURE_POS 16
146#define UMAC_HDI_OUT_CMD_SIGNATURE_SEED 0xFFFF
147
148/* iwm_umac_hdi_out_hdr.meta_data Byte count -- bits [11:0] */
149#define UMAC_HDI_OUT_BYTE_COUNT_POS 0
150#define UMAC_HDI_OUT_BYTE_COUNT_SEED 0xFFF
151
152/* iwm_umac_hdi_out_hdr.meta_data Credit group -- bits [15:12] */
153#define UMAC_HDI_OUT_CREDIT_GRP_POS 12
154#define UMAC_HDI_OUT_CREDIT_GRP_SEED 0xF
155
156/* iwm_umac_hdi_out_hdr.meta_data RA/TID -- bits [23:16] */
157#define UMAC_HDI_OUT_RATID_POS 16
158#define UMAC_HDI_OUT_RATID_SEED 0xFF
159
160/* iwm_umac_hdi_out_hdr.meta_data LMAC offset -- bits [31:24] */
161#define UMAC_HDI_OUT_LMAC_OFFSET_POS 24
162#define UMAC_HDI_OUT_LMAC_OFFSET_SEED 0xFF
163
164/* Signature */
165#define UMAC_HDI_OUT_SIGNATURE 0xCBBC
166
167/* buffer alignment */
168#define UMAC_HDI_BUF_ALIGN_MSK 0xF
169
170/* iwm_umac_hdi_in_hdr.cmd OP code -- bits [3:0] */
171#define UMAC_HDI_IN_CMD_OPCODE_POS 0
172#define UMAC_HDI_IN_CMD_OPCODE_SEED 0xF
173
174/* iwm_umac_hdi_in_hdr.cmd Non-WiFi API response -- bits [6:4] */
175#define UMAC_HDI_IN_CMD_NON_WIFI_RESP_POS 4
176#define UMAC_HDI_IN_CMD_NON_WIFI_RESP_SEED 0x7
177
178/* iwm_umac_hdi_in_hdr.cmd WiFi API source -- bits [5:4] */
179#define UMAC_HDI_IN_CMD_SOURCE_POS 4
180#define UMAC_HDI_IN_CMD_SOURCE_SEED 0x3
181
182/* iwm_umac_hdi_in_hdr.cmd WiFi API EOT -- bits [6:6] */
183#define UMAC_HDI_IN_CMD_EOT_POS 6
184#define UMAC_HDI_IN_CMD_EOT_SEED 0x1
185
186/* iwm_umac_hdi_in_hdr.cmd timestamp present -- bits [7:7] */
187#define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_POS 7
188#define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_SEED 0x1
189
190/* iwm_umac_hdi_in_hdr.cmd WiFi Non-last AMSDU -- bits [8:8] */
191#define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_POS 8
192#define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_SEED 0x1
193
194/* iwm_umac_hdi_in_hdr.cmd WiFi HW sequence number -- bits [31:9] */
195#define UMAC_HDI_IN_CMD_HW_SEQ_NUM_POS 9
196#define UMAC_HDI_IN_CMD_HW_SEQ_NUM_SEED 0x7FFFFF
197
198/* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */
199#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_POS 12
200#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_SEED 0xF
201
202/* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW signature -- bits [16:31] */
203#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_POS 16
204#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_SEED 0xFFFF
205
206/* Fixed Non-WiFi signature */
207#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG 0xCBBC
208
209/* IN NTFY op-codes */
210#define UMAC_NOTIFY_OPCODE_ALIVE 0xA1
211#define UMAC_NOTIFY_OPCODE_INIT_COMPLETE 0xA2
212#define UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS 0xA3
213#define UMAC_NOTIFY_OPCODE_ERROR 0xA4
214#define UMAC_NOTIFY_OPCODE_DEBUG 0xA5
215#define UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER 0xB0
216#define UMAC_NOTIFY_OPCODE_STATS 0xB1
217#define UMAC_NOTIFY_OPCODE_PAGE_DEALLOC 0xB3
218#define UMAC_NOTIFY_OPCODE_RX_TICKET 0xB4
219#define UMAC_NOTIFY_OPCODE_MAX (UMAC_NOTIFY_OPCODE_RX_TICKET -\
220 UMAC_NOTIFY_OPCODE_ALIVE + 1)
221#define UMAC_NOTIFY_OPCODE_FIRST (UMAC_NOTIFY_OPCODE_ALIVE)
222
223/* HDI OUT OP CODE */
224#define UMAC_HDI_OUT_OPCODE_PING 0x0
225#define UMAC_HDI_OUT_OPCODE_READ 0x1
226#define UMAC_HDI_OUT_OPCODE_WRITE 0x2
227#define UMAC_HDI_OUT_OPCODE_JUMP 0x3
228#define UMAC_HDI_OUT_OPCODE_REBOOT 0x4
229#define UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT 0x5
230#define UMAC_HDI_OUT_OPCODE_READ_PERSISTENT 0x6
231#define UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE 0x7
232/* #define UMAC_HDI_OUT_OPCODE_RESERVED 0x8..0xA */
233#define UMAC_HDI_OUT_OPCODE_WRITE_AUX_REG 0xB
234#define UMAC_HDI_OUT_OPCODE_WIFI 0xF
235
236/* HDI IN OP CODE -- Non WiFi*/
237#define UMAC_HDI_IN_OPCODE_PING 0x0
238#define UMAC_HDI_IN_OPCODE_READ 0x1
239#define UMAC_HDI_IN_OPCODE_WRITE 0x2
240#define UMAC_HDI_IN_OPCODE_WRITE_PERSISTENT 0x5
241#define UMAC_HDI_IN_OPCODE_READ_PERSISTENT 0x6
242#define UMAC_HDI_IN_OPCODE_READ_MODIFY_WRITE 0x7
243#define UMAC_HDI_IN_OPCODE_EP_MGMT 0x8
244#define UMAC_HDI_IN_OPCODE_CREDIT_CHANGE 0x9
245#define UMAC_HDI_IN_OPCODE_CTRL_DATABASE 0xA
246#define UMAC_HDI_IN_OPCODE_WRITE_AUX_REG 0xB
247#define UMAC_HDI_IN_OPCODE_NONWIFI_MAX \
248 (UMAC_HDI_IN_OPCODE_WRITE_AUX_REG + 1)
249#define UMAC_HDI_IN_OPCODE_WIFI 0xF
250
251/* HDI IN SOURCE */
252#define UMAC_HDI_IN_SOURCE_FHRX 0x0
253#define UMAC_HDI_IN_SOURCE_UDMA 0x1
254#define UMAC_HDI_IN_SOURCE_FW 0x2
255#define UMAC_HDI_IN_SOURCE_RESERVED 0x3
256
257/* OUT CMD op-codes */
258#define UMAC_CMD_OPCODE_ECHO 0x01
259#define UMAC_CMD_OPCODE_HALT 0x02
260#define UMAC_CMD_OPCODE_RESET 0x03
261#define UMAC_CMD_OPCODE_BULK_EP_INACT_TIMEOUT 0x09
262#define UMAC_CMD_OPCODE_URB_CANCEL_ACK 0x0A
263#define UMAC_CMD_OPCODE_DCACHE_FLUSH 0x0B
264#define UMAC_CMD_OPCODE_EEPROM_PROXY 0x0C
265#define UMAC_CMD_OPCODE_TX_ECHO 0x0D
266#define UMAC_CMD_OPCODE_DBG_MON 0x0E
267#define UMAC_CMD_OPCODE_INTERNAL_TX 0x0F
268#define UMAC_CMD_OPCODE_SET_PARAM_FIX 0x10
269#define UMAC_CMD_OPCODE_SET_PARAM_VAR 0x11
270#define UMAC_CMD_OPCODE_GET_PARAM 0x12
271#define UMAC_CMD_OPCODE_DBG_EVENT_WRAPPER 0x13
272#define UMAC_CMD_OPCODE_TARGET 0x14
273#define UMAC_CMD_OPCODE_STATISTIC_REQUEST 0x15
274#define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16
275#define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17
276#define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18
277#define UMAC_CMD_OPCODE_STOP_RESUME_STA_TX 0x19
278#define UMAC_CMD_OPCODE_TEST_BLOCK_ACK 0x1A
279
280#define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA
281#define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB
282#define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC
283#define UMAC_CMD_OPCODE_WIFI_IF_WRAPPER 0xFD
284#define UMAC_CMD_OPCODE_WIFI_WRAPPER 0xFE
285#define UMAC_CMD_OPCODE_WIFI_PASS_THROUGH 0xFF
286
287/* UMAC WiFi interface op-codes */
288#define UMAC_WIFI_IF_CMD_SET_PROFILE 0x11
289#define UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE 0x12
290#define UMAC_WIFI_IF_CMD_SET_EXCLUDE_LIST 0x13
291#define UMAC_WIFI_IF_CMD_SCAN_REQUEST 0x14
292#define UMAC_WIFI_IF_CMD_SCAN_CONFIG 0x15
293#define UMAC_WIFI_IF_CMD_ADD_WEP40_KEY 0x16
294#define UMAC_WIFI_IF_CMD_ADD_WEP104_KEY 0x17
295#define UMAC_WIFI_IF_CMD_ADD_TKIP_KEY 0x18
296#define UMAC_WIFI_IF_CMD_ADD_CCMP_KEY 0x19
297#define UMAC_WIFI_IF_CMD_REMOVE_KEY 0x1A
298#define UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID 0x1B
299#define UMAC_WIFI_IF_CMD_SET_HOST_EXTENDED_IE 0x1C
300#define UMAC_WIFI_IF_CMD_GET_SUPPORTED_CHANNELS 0x1E
301#define UMAC_WIFI_IF_CMD_PMKID_UPDATE 0x1F
302#define UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER 0x20
303
304/* UMAC WiFi interface ports */
305#define UMAC_WIFI_IF_FLG_PORT_DEF 0x00
306#define UMAC_WIFI_IF_FLG_PORT_PAN 0x01
307#define UMAC_WIFI_IF_FLG_PORT_PAN_INVALID WIFI_IF_FLG_PORT_DEF
308
309/* UMAC WiFi interface actions */
310#define UMAC_WIFI_IF_FLG_ACT_GET 0x10
311#define UMAC_WIFI_IF_FLG_ACT_SET 0x20
312
313/* iwm_umac_fw_cmd_hdr.meta_data byte count -- bits [11:0] */
314#define UMAC_FW_CMD_BYTE_COUNT_POS 0
315#define UMAC_FW_CMD_BYTE_COUNT_SEED 0xFFF
316
317/* iwm_umac_fw_cmd_hdr.meta_data status -- bits [15:12] */
318#define UMAC_FW_CMD_STATUS_POS 12
319#define UMAC_FW_CMD_STATUS_SEED 0xF
320
321/* iwm_umac_fw_cmd_hdr.meta_data full TX command by Driver -- bits [16:16] */
322#define UMAC_FW_CMD_TX_DRV_FULL_CMD_POS 16
323#define UMAC_FW_CMD_TX_DRV_FULL_CMD_SEED 0x1
324
325/* iwm_umac_fw_cmd_hdr.meta_data TX command by FW -- bits [17:17] */
326#define UMAC_FW_CMD_TX_FW_CMD_POS 17
327#define UMAC_FW_CMD_TX_FW_CMD_SEED 0x1
328
329/* iwm_umac_fw_cmd_hdr.meta_data TX plaintext mode -- bits [18:18] */
330#define UMAC_FW_CMD_TX_PLAINTEXT_POS 18
331#define UMAC_FW_CMD_TX_PLAINTEXT_SEED 0x1
332
333/* iwm_umac_fw_cmd_hdr.meta_data STA color -- bits [22:20] */
334#define UMAC_FW_CMD_TX_STA_COLOR_POS 20
335#define UMAC_FW_CMD_TX_STA_COLOR_SEED 0x7
336
337/* iwm_umac_fw_cmd_hdr.meta_data TX life time (TU) -- bits [31:24] */
338#define UMAC_FW_CMD_TX_LIFETIME_TU_POS 24
339#define UMAC_FW_CMD_TX_LIFETIME_TU_SEED 0xFF
340
341/* iwm_dev_cmd_hdr.flags Response required -- bits [5:5] */
342#define UMAC_DEV_CMD_FLAGS_RESP_REQ_POS 5
343#define UMAC_DEV_CMD_FLAGS_RESP_REQ_SEED 0x1
344
345/* iwm_dev_cmd_hdr.flags Aborted command -- bits [6:6] */
346#define UMAC_DEV_CMD_FLAGS_ABORT_POS 6
347#define UMAC_DEV_CMD_FLAGS_ABORT_SEED 0x1
348
349/* iwm_dev_cmd_hdr.flags Internal command -- bits [7:7] */
350#define DEV_CMD_FLAGS_FLD_INTERNAL_POS 7
351#define DEV_CMD_FLAGS_FLD_INTERNAL_SEED 0x1
352
353/* Rx */
354/* Rx actions */
355#define IWM_RX_TICKET_DROP 0x0
356#define IWM_RX_TICKET_RELEASE 0x1
357#define IWM_RX_TICKET_SNIFFER 0x2
358#define IWM_RX_TICKET_ENQUEUE 0x3
359
360/* Rx flags */
361#define IWM_RX_TICKET_PAD_SIZE_MSK 0x2
362#define IWM_RX_TICKET_SPECIAL_SNAP_MSK 0x4
363#define IWM_RX_TICKET_AMSDU_MSK 0x8
364#define IWM_RX_TICKET_DROP_REASON_POS 4
365#define IWM_RX_TICKET_DROP_REASON_MSK (0x1F << IWM_RX_TICKET_DROP_REASON_POS)
366
367#define IWM_RX_DROP_NO_DROP 0x0
368#define IWM_RX_DROP_BAD_CRC 0x1
369/* L2P no address match */
370#define IWM_RX_DROP_LMAC_ADDR_FILTER 0x2
371/* Multicast address not in list */
372#define IWM_RX_DROP_MCAST_ADDR_FILTER 0x3
373/* Control frames are not sent to the driver */
374#define IWM_RX_DROP_CTL_FRAME 0x4
375/* Our frame is back */
376#define IWM_RX_DROP_OUR_TX 0x5
377/* Association class filtering */
378#define IWM_RX_DROP_CLASS_FILTER 0x6
379/* Duplicated frame */
380#define IWM_RX_DROP_DUPLICATE_FILTER 0x7
381/* Decryption error */
382#define IWM_RX_DROP_SEC_ERR 0x8
383/* Unencrypted frame while encryption is on */
384#define IWM_RX_DROP_SEC_NO_ENCRYPTION 0x9
385/* Replay check failure */
386#define IWM_RX_DROP_SEC_REPLAY_ERR 0xa
387/* uCode and FW key color mismatch, check before replay */
388#define IWM_RX_DROP_SEC_KEY_COLOR_MISMATCH 0xb
389#define IWM_RX_DROP_SEC_TKIP_COUNTER_MEASURE 0xc
390/* No fragmentations Db is found */
391#define IWM_RX_DROP_FRAG_NO_RESOURCE 0xd
392/* Fragmention Db has seqCtl mismatch Vs. non-1st frag */
393#define IWM_RX_DROP_FRAG_ERR 0xe
394#define IWM_RX_DROP_FRAG_LOST 0xf
395#define IWM_RX_DROP_FRAG_COMPLETE 0x10
396/* Should be handled by UMAC */
397#define IWM_RX_DROP_MANAGEMENT 0x11
398/* STA not found by UMAC */
399#define IWM_RX_DROP_NO_STATION 0x12
400/* NULL or QoS NULL */
401#define IWM_RX_DROP_NULL_DATA 0x13
402#define IWM_RX_DROP_BA_REORDER_OLD_SEQCTL 0x14
403#define IWM_RX_DROP_BA_REORDER_DUPLICATE 0x15
404
405struct iwm_rx_ticket {
406 __le16 action;
407 __le16 id;
408 __le16 flags;
409 u8 payload_offset; /* includes: MAC header, pad, IV */
410 u8 tail_len; /* includes: MIC, ICV, CRC (w/o STATUS) */
411} __packed;
412
413struct iwm_rx_mpdu_hdr {
414 __le16 len;
415 __le16 reserved;
416} __packed;
417
418/* UMAC SW WIFI API */
419
420struct iwm_dev_cmd_hdr {
421 u8 cmd;
422 u8 flags;
423 __le16 seq_num;
424} __packed;
425
426struct iwm_umac_fw_cmd_hdr {
427 __le32 meta_data;
428 struct iwm_dev_cmd_hdr cmd;
429} __packed;
430
431struct iwm_umac_wifi_out_hdr {
432 struct iwm_udma_out_wifi_hdr hw_hdr;
433 struct iwm_umac_fw_cmd_hdr sw_hdr;
434} __packed;
435
436struct iwm_umac_nonwifi_out_hdr {
437 struct iwm_udma_out_nonwifi_hdr hw_hdr;
438} __packed;
439
440struct iwm_umac_wifi_in_hdr {
441 struct iwm_udma_in_hdr hw_hdr;
442 struct iwm_umac_fw_cmd_hdr sw_hdr;
443} __packed;
444
445struct iwm_umac_nonwifi_in_hdr {
446 struct iwm_udma_in_hdr hw_hdr;
447 __le32 time_stamp;
448} __packed;
449
450#define IWM_UMAC_PAGE_SIZE 0x200
451
452/* Notify structures */
453struct iwm_fw_version {
454 u8 minor;
455 u8 major;
456 __le16 id;
457};
458
459struct iwm_fw_build {
460 u8 type;
461 u8 subtype;
462 u8 platform;
463 u8 opt;
464};
465
466struct iwm_fw_alive_hdr {
467 struct iwm_fw_version ver;
468 struct iwm_fw_build build;
469 __le32 os_build;
470 __le32 log_hdr_addr;
471 __le32 log_buf_addr;
472 __le32 sys_timer_addr;
473};
474
475#define WAIT_NOTIF_TIMEOUT (2 * HZ)
476#define SCAN_COMPLETE_TIMEOUT (3 * HZ)
477
478#define UMAC_NTFY_ALIVE_STATUS_ERR 0xDEAD
479#define UMAC_NTFY_ALIVE_STATUS_OK 0xCAFE
480
481#define UMAC_NTFY_INIT_COMPLETE_STATUS_ERR 0xDEAD
482#define UMAC_NTFY_INIT_COMPLETE_STATUS_OK 0xCAFE
483
484#define UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN 0x40
485#define UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN 0x80
486
487#define IWM_MACS_OUT_GROUPS 6
488#define IWM_MACS_OUT_SGROUPS 1
489
490
491#define WIFI_IF_NTFY_ASSOC_START 0x80
492#define WIFI_IF_NTFY_ASSOC_COMPLETE 0x81
493#define WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE 0x82
494#define WIFI_IF_NTFY_CONNECTION_TERMINATED 0x83
495#define WIFI_IF_NTFY_SCAN_COMPLETE 0x84
496#define WIFI_IF_NTFY_STA_TABLE_CHANGE 0x85
497#define WIFI_IF_NTFY_EXTENDED_IE_REQUIRED 0x86
498#define WIFI_IF_NTFY_RADIO_PREEMPTION 0x87
499#define WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED 0x88
500#define WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED 0x89
501#define WIFI_IF_NTFY_LINK_QUALITY_STATISTICS 0x8A
502#define WIFI_IF_NTFY_MGMT_FRAME 0x8B
503
504/* DEBUG INDICATIONS */
505#define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START 0xE0
506#define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE 0xE1
507#define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START 0xE2
508#define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT 0xE3
509#define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START 0xE4
510#define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE 0xE5
511#define WIFI_DBG_IF_NTFY_CNCT_ATC_START 0xE6
512#define WIFI_DBG_IF_NTFY_COEX_NOTIFICATION 0xE7
513#define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8
514#define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9
515
516#define WIFI_IF_NTFY_MAX 0xff
517
518/* Notification structures */
519struct iwm_umac_notif_wifi_if {
520 struct iwm_umac_wifi_in_hdr hdr;
521 u8 status;
522 u8 flags;
523 __le16 buf_size;
524} __packed;
525
526#define UMAC_ROAM_REASON_FIRST_SELECTION 0x1
527#define UMAC_ROAM_REASON_AP_DEAUTH 0x2
528#define UMAC_ROAM_REASON_AP_CONNECT_LOST 0x3
529#define UMAC_ROAM_REASON_RSSI 0x4
530#define UMAC_ROAM_REASON_AP_ASSISTED_ROAM 0x5
531#define UMAC_ROAM_REASON_IBSS_COALESCING 0x6
532
533struct iwm_umac_notif_assoc_start {
534 struct iwm_umac_notif_wifi_if mlme_hdr;
535 __le32 roam_reason;
536 u8 bssid[ETH_ALEN];
537 u8 reserved[2];
538} __packed;
539
540#define UMAC_ASSOC_COMPLETE_SUCCESS 0x0
541#define UMAC_ASSOC_COMPLETE_FAILURE 0x1
542
543struct iwm_umac_notif_assoc_complete {
544 struct iwm_umac_notif_wifi_if mlme_hdr;
545 __le32 status;
546 u8 bssid[ETH_ALEN];
547 u8 band;
548 u8 channel;
549} __packed;
550
551#define UMAC_PROFILE_INVALID_ASSOC_TIMEOUT 0x0
552#define UMAC_PROFILE_INVALID_ROAM_TIMEOUT 0x1
553#define UMAC_PROFILE_INVALID_REQUEST 0x2
554#define UMAC_PROFILE_INVALID_RF_PREEMPTED 0x3
555
556struct iwm_umac_notif_profile_invalidate {
557 struct iwm_umac_notif_wifi_if mlme_hdr;
558 __le32 reason;
559} __packed;
560
561#define UMAC_SCAN_RESULT_SUCCESS 0x0
562#define UMAC_SCAN_RESULT_ABORTED 0x1
563#define UMAC_SCAN_RESULT_REJECTED 0x2
564#define UMAC_SCAN_RESULT_FAILED 0x3
565
566struct iwm_umac_notif_scan_complete {
567 struct iwm_umac_notif_wifi_if mlme_hdr;
568 __le32 type;
569 __le32 result;
570 u8 seq_num;
571} __packed;
572
573#define UMAC_OPCODE_ADD_MODIFY 0x0
574#define UMAC_OPCODE_REMOVE 0x1
575#define UMAC_OPCODE_CLEAR_ALL 0x2
576
577#define UMAC_STA_FLAG_QOS 0x1
578
579struct iwm_umac_notif_sta_info {
580 struct iwm_umac_notif_wifi_if mlme_hdr;
581 __le32 opcode;
582 u8 mac_addr[ETH_ALEN];
583 u8 sta_id; /* bits 0-3: station ID, bits 4-7: station color */
584 u8 flags;
585} __packed;
586
587#define UMAC_BAND_2GHZ 0
588#define UMAC_BAND_5GHZ 1
589
590#define UMAC_CHANNEL_WIDTH_20MHZ 0
591#define UMAC_CHANNEL_WIDTH_40MHZ 1
592
593struct iwm_umac_notif_bss_info {
594 struct iwm_umac_notif_wifi_if mlme_hdr;
595 __le32 type;
596 __le32 timestamp;
597 __le16 table_idx;
598 __le16 frame_len;
599 u8 band;
600 u8 channel;
601 s8 rssi;
602 u8 reserved;
603 u8 frame_buf[1];
604} __packed;
605
606#define IWM_BSS_REMOVE_INDEX_MSK 0x0fff
607#define IWM_BSS_REMOVE_FLAGS_MSK 0xfc00
608
609#define IWM_BSS_REMOVE_FLG_AGE 0x1000
610#define IWM_BSS_REMOVE_FLG_TIMEOUT 0x2000
611#define IWM_BSS_REMOVE_FLG_TABLE_FULL 0x4000
612
613struct iwm_umac_notif_bss_removed {
614 struct iwm_umac_notif_wifi_if mlme_hdr;
615 __le32 count;
616 __le16 entries[0];
617} __packed;
618
619struct iwm_umac_notif_mgt_frame {
620 struct iwm_umac_notif_wifi_if mlme_hdr;
621 __le16 len;
622 u8 frame[1];
623} __packed;
624
625struct iwm_umac_notif_alive {
626 struct iwm_umac_wifi_in_hdr hdr;
627 __le16 status;
628 __le16 reserved1;
629 struct iwm_fw_alive_hdr alive_data;
630 __le16 reserved2;
631 __le16 page_grp_count;
632 __le32 page_grp_state[IWM_MACS_OUT_GROUPS];
633} __packed;
634
635struct iwm_umac_notif_init_complete {
636 struct iwm_umac_wifi_in_hdr hdr;
637 __le16 status;
638 __le16 reserved;
639} __packed;
640
641/* error categories */
642enum {
643 UMAC_SYS_ERR_CAT_NONE = 0,
644 UMAC_SYS_ERR_CAT_BOOT,
645 UMAC_SYS_ERR_CAT_UMAC,
646 UMAC_SYS_ERR_CAT_UAXM,
647 UMAC_SYS_ERR_CAT_LMAC,
648 UMAC_SYS_ERR_CAT_MAX
649};
650
651struct iwm_fw_error_hdr {
652 __le32 category;
653 __le32 status;
654 __le32 pc;
655 __le32 blink1;
656 __le32 blink2;
657 __le32 ilink1;
658 __le32 ilink2;
659 __le32 data1;
660 __le32 data2;
661 __le32 line_num;
662 __le32 umac_status;
663 __le32 lmac_status;
664 __le32 sdio_status;
665 __le32 dbm_sample_ctrl;
666 __le32 dbm_buf_base;
667 __le32 dbm_buf_end;
668 __le32 dbm_buf_write_ptr;
669 __le32 dbm_buf_cycle_cnt;
670} __packed;
671
672struct iwm_umac_notif_error {
673 struct iwm_umac_wifi_in_hdr hdr;
674 struct iwm_fw_error_hdr err;
675} __packed;
676
677#define UMAC_DEALLOC_NTFY_CHANGES_CNT_POS 0
678#define UMAC_DEALLOC_NTFY_CHANGES_CNT_SEED 0xff
679#define UMAC_DEALLOC_NTFY_CHANGES_MSK_POS 8
680#define UMAC_DEALLOC_NTFY_CHANGES_MSK_SEED 0xffffff
681#define UMAC_DEALLOC_NTFY_PAGE_CNT_POS 0
682#define UMAC_DEALLOC_NTFY_PAGE_CNT_SEED 0xffffff
683#define UMAC_DEALLOC_NTFY_GROUP_NUM_POS 24
684#define UMAC_DEALLOC_NTFY_GROUP_NUM_SEED 0xf
685
686struct iwm_umac_notif_page_dealloc {
687 struct iwm_umac_wifi_in_hdr hdr;
688 __le32 changes;
689 __le32 grp_info[IWM_MACS_OUT_GROUPS];
690} __packed;
691
692struct iwm_umac_notif_wifi_status {
693 struct iwm_umac_wifi_in_hdr hdr;
694 __le16 status;
695 __le16 reserved;
696} __packed;
697
698struct iwm_umac_notif_rx_ticket {
699 struct iwm_umac_wifi_in_hdr hdr;
700 u8 num_tickets;
701 u8 reserved[3];
702 struct iwm_rx_ticket tickets[1];
703} __packed;
704
705/* Tx/Rx rates window (number of max of last update window per second) */
706#define UMAC_NTF_RATE_SAMPLE_NR 4
707
708/* Max numbers of bits required to go through all antennae in bitmasks */
709#define UMAC_PHY_NUM_CHAINS 3
710
711#define IWM_UMAC_MGMT_TID 8
712#define IWM_UMAC_TID_NR 9 /* 8 TIDs + MGMT */
713
714struct iwm_umac_notif_stats {
715 struct iwm_umac_wifi_in_hdr hdr;
716 __le32 flags;
717 __le32 timestamp;
718 __le16 tid_load[IWM_UMAC_TID_NR + 1]; /* 1 non-QoS + 1 dword align */
719 __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR];
720 __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR];
721 __le32 chain_energy[UMAC_PHY_NUM_CHAINS];
722 s32 rssi_dbm;
723 s32 noise_dbm;
724 __le32 supp_rates;
725 __le32 supp_ht_rates;
726 __le32 missed_beacons;
727 __le32 rx_beacons;
728 __le32 rx_dir_pkts;
729 __le32 rx_nondir_pkts;
730 __le32 rx_multicast;
731 __le32 rx_errors;
732 __le32 rx_drop_other_bssid;
733 __le32 rx_drop_decode;
734 __le32 rx_drop_reassembly;
735 __le32 rx_drop_bad_len;
736 __le32 rx_drop_overflow;
737 __le32 rx_drop_crc;
738 __le32 rx_drop_missed;
739 __le32 tx_dir_pkts;
740 __le32 tx_nondir_pkts;
741 __le32 tx_failure;
742 __le32 tx_errors;
743 __le32 tx_drop_max_retry;
744 __le32 tx_err_abort;
745 __le32 tx_err_carrier;
746 __le32 rx_bytes;
747 __le32 tx_bytes;
748 __le32 tx_power;
749 __le32 tx_max_power;
750 __le32 roam_threshold;
751 __le32 ap_assoc_nr;
752 __le32 scan_full;
753 __le32 scan_abort;
754 __le32 ap_nr;
755 __le32 roam_nr;
756 __le32 roam_missed_beacons;
757 __le32 roam_rssi;
758 __le32 roam_unassoc;
759 __le32 roam_deauth;
760 __le32 roam_ap_loadblance;
761} __packed;
762
763#define UMAC_STOP_TX_FLAG 0x1
764#define UMAC_RESUME_TX_FLAG 0x2
765
766#define LAST_SEQ_NUM_INVALID 0xFFFF
767
768struct iwm_umac_notif_stop_resume_tx {
769 struct iwm_umac_wifi_in_hdr hdr;
770 u8 flags; /* UMAC_*_TX_FLAG_* */
771 u8 sta_id;
772 __le16 stop_resume_tid_msk; /* tid bitmask */
773} __packed;
774
775#define UMAC_MAX_NUM_PMKIDS 4
776
777/* WiFi interface wrapper header */
778struct iwm_umac_wifi_if {
779 u8 oid;
780 u8 flags;
781 __le16 buf_size;
782} __packed;
783
784#define IWM_SEQ_NUM_HOST_MSK 0x0000
785#define IWM_SEQ_NUM_UMAC_MSK 0x4000
786#define IWM_SEQ_NUM_LMAC_MSK 0x8000
787#define IWM_SEQ_NUM_MSK 0xC000
788
789#endif