blob: 04d5e6442bf668e5bd8ddfd9fac8b9f7b4c1e36e [file] [log] [blame]
James Ketrenos2c86c272005-03-23 17:32:29 -06001/******************************************************************************
2
Zhu Yi171e7b22006-02-15 07:17:56 +08003 Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
James Ketrenos2c86c272005-03-23 17:32:29 -06004
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of version 2 of the GNU General Public License as
7 published by the Free Software Foundation.
8
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc., 59
16 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 The full GNU General Public License is included in this distribution in the
19 file called LICENSE.
20
21 Contact Information:
Reinette Chatrec1eb2c82009-08-21 13:34:26 -070022 Intel Linux Wireless <ilw@linux.intel.com>
James Ketrenos2c86c272005-03-23 17:32:29 -060023 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24
25 Portions of this file are based on the sample_* files provided by Wireless
26 Extensions 0.26 package and copyright (c) 1997-2003 Jean Tourrilhes
27 <jt@hpl.hp.com>
28
29 Portions of this file are based on the Host AP project,
30 Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
Jouni Malinen85d32e72007-03-24 17:15:30 -070031 <j@w1.fi>
32 Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
James Ketrenos2c86c272005-03-23 17:32:29 -060033
34 Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and
35 ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c
36 available in the 2.4.25 kernel sources, and are copyright (c) Alan Cox
37
38******************************************************************************/
39/*
40
41 Initial driver on which this is based was developed by Janusz Gorycki,
42 Maciej Urbaniak, and Maciej Sosnowski.
43
44 Promiscuous mode support added by Jacek Wysoczynski and Maciej Urbaniak.
45
46Theory of Operation
47
48Tx - Commands and Data
49
50Firmware and host share a circular queue of Transmit Buffer Descriptors (TBDs)
51Each TBD contains a pointer to the physical (dma_addr_t) address of data being
52sent to the firmware as well as the length of the data.
53
54The host writes to the TBD queue at the WRITE index. The WRITE index points
55to the _next_ packet to be written and is advanced when after the TBD has been
56filled.
57
58The firmware pulls from the TBD queue at the READ index. The READ index points
59to the currently being read entry, and is advanced once the firmware is
60done with a packet.
61
62When data is sent to the firmware, the first TBD is used to indicate to the
63firmware if a Command or Data is being sent. If it is Command, all of the
64command information is contained within the physical address referred to by the
65TBD. If it is Data, the first TBD indicates the type of data packet, number
Lucas De Marchi25985ed2011-03-30 22:57:33 -030066of fragments, etc. The next TBD then refers to the actual packet location.
James Ketrenos2c86c272005-03-23 17:32:29 -060067
68The Tx flow cycle is as follows:
69
701) ipw2100_tx() is called by kernel with SKB to transmit
712) Packet is move from the tx_free_list and appended to the transmit pending
72 list (tx_pend_list)
733) work is scheduled to move pending packets into the shared circular queue.
744) when placing packet in the circular queue, the incoming SKB is DMA mapped
75 to a physical address. That address is entered into a TBD. Two TBDs are
76 filled out. The first indicating a data packet, the second referring to the
77 actual payload data.
785) the packet is removed from tx_pend_list and placed on the end of the
79 firmware pending list (fw_pend_list)
806) firmware is notified that the WRITE index has
817) Once the firmware has processed the TBD, INTA is triggered.
828) For each Tx interrupt received from the firmware, the READ index is checked
83 to see which TBDs are done being processed.
849) For each TBD that has been processed, the ISR pulls the oldest packet
85 from the fw_pend_list.
8610)The packet structure contained in the fw_pend_list is then used
87 to unmap the DMA address and to free the SKB originally passed to the driver
88 from the kernel.
8911)The packet structure is placed onto the tx_free_list
90
91The above steps are the same for commands, only the msg_free_list/msg_pend_list
92are used instead of tx_free_list/tx_pend_list
93
94...
95
96Critical Sections / Locking :
97
98There are two locks utilized. The first is the low level lock (priv->low_lock)
99that protects the following:
100
101- Access to the Tx/Rx queue lists via priv->low_lock. The lists are as follows:
102
103 tx_free_list : Holds pre-allocated Tx buffers.
104 TAIL modified in __ipw2100_tx_process()
105 HEAD modified in ipw2100_tx()
106
107 tx_pend_list : Holds used Tx buffers waiting to go into the TBD ring
108 TAIL modified ipw2100_tx()
Jiri Benc19f7f742005-08-25 20:02:10 -0400109 HEAD modified by ipw2100_tx_send_data()
James Ketrenos2c86c272005-03-23 17:32:29 -0600110
111 msg_free_list : Holds pre-allocated Msg (Command) buffers
112 TAIL modified in __ipw2100_tx_process()
113 HEAD modified in ipw2100_hw_send_command()
114
115 msg_pend_list : Holds used Msg buffers waiting to go into the TBD ring
116 TAIL modified in ipw2100_hw_send_command()
Jiri Benc19f7f742005-08-25 20:02:10 -0400117 HEAD modified in ipw2100_tx_send_commands()
James Ketrenos2c86c272005-03-23 17:32:29 -0600118
119 The flow of data on the TX side is as follows:
120
121 MSG_FREE_LIST + COMMAND => MSG_PEND_LIST => TBD => MSG_FREE_LIST
122 TX_FREE_LIST + DATA => TX_PEND_LIST => TBD => TX_FREE_LIST
123
124 The methods that work on the TBD ring are protected via priv->low_lock.
125
126- The internal data state of the device itself
127- Access to the firmware read/write indexes for the BD queues
128 and associated logic
129
130All external entry functions are locked with the priv->action_lock to ensure
131that only one external action is invoked at a time.
132
133
134*/
135
136#include <linux/compiler.h>
James Ketrenos2c86c272005-03-23 17:32:29 -0600137#include <linux/errno.h>
138#include <linux/if_arp.h>
139#include <linux/in6.h>
140#include <linux/in.h>
141#include <linux/ip.h>
142#include <linux/kernel.h>
143#include <linux/kmod.h>
144#include <linux/module.h>
145#include <linux/netdevice.h>
146#include <linux/ethtool.h>
147#include <linux/pci.h>
Tobias Klauser05743d12005-06-20 14:28:40 -0700148#include <linux/dma-mapping.h>
James Ketrenos2c86c272005-03-23 17:32:29 -0600149#include <linux/proc_fs.h>
150#include <linux/skbuff.h>
151#include <asm/uaccess.h>
152#include <asm/io.h>
James Ketrenos2c86c272005-03-23 17:32:29 -0600153#include <linux/fs.h>
154#include <linux/mm.h>
155#include <linux/slab.h>
156#include <linux/unistd.h>
157#include <linux/stringify.h>
158#include <linux/tcp.h>
159#include <linux/types.h>
James Ketrenos2c86c272005-03-23 17:32:29 -0600160#include <linux/time.h>
161#include <linux/firmware.h>
162#include <linux/acpi.h>
163#include <linux/ctype.h>
Jean Pihete8db0be2011-08-25 15:35:03 +0200164#include <linux/pm_qos.h>
James Ketrenos2c86c272005-03-23 17:32:29 -0600165
John W. Linville9387b7c2008-09-30 20:59:05 -0400166#include <net/lib80211.h>
167
James Ketrenos2c86c272005-03-23 17:32:29 -0600168#include "ipw2100.h"
Stanislav Yakovleva141e6a2012-04-10 21:44:47 -0400169#include "ipw.h"
James Ketrenos2c86c272005-03-23 17:32:29 -0600170
Zhu Yicc8279f2006-02-21 18:46:15 +0800171#define IPW2100_VERSION "git-1.2.2"
James Ketrenos2c86c272005-03-23 17:32:29 -0600172
173#define DRV_NAME "ipw2100"
174#define DRV_VERSION IPW2100_VERSION
175#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver"
Zhu Yi171e7b22006-02-15 07:17:56 +0800176#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
James Ketrenos2c86c272005-03-23 17:32:29 -0600177
Jean Pihetcc749982011-08-25 15:35:12 +0200178static struct pm_qos_request ipw2100_pm_qos_req;
Mark Grossed771342010-05-06 01:59:26 +0200179
James Ketrenos2c86c272005-03-23 17:32:29 -0600180/* Debugging stuff */
Brice Goglin0f52bf92005-12-01 01:41:46 -0800181#ifdef CONFIG_IPW2100_DEBUG
Robert P. J. Dayae800312007-01-31 02:39:40 -0500182#define IPW2100_RX_DEBUG /* Reception debugging */
James Ketrenos2c86c272005-03-23 17:32:29 -0600183#endif
184
185MODULE_DESCRIPTION(DRV_DESCRIPTION);
186MODULE_VERSION(DRV_VERSION);
187MODULE_AUTHOR(DRV_COPYRIGHT);
188MODULE_LICENSE("GPL");
189
190static int debug = 0;
Reinette Chatre21f8a732009-08-18 10:25:05 -0700191static int network_mode = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -0600192static int channel = 0;
Tim Gardner5c7f9b72008-10-14 10:38:03 -0600193static int associate = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -0600194static int disable = 0;
195#ifdef CONFIG_PM
196static struct ipw2100_fw ipw2100_firmware;
197#endif
198
199#include <linux/moduleparam.h>
200module_param(debug, int, 0444);
Reinette Chatre21f8a732009-08-18 10:25:05 -0700201module_param_named(mode, network_mode, int, 0444);
James Ketrenos2c86c272005-03-23 17:32:29 -0600202module_param(channel, int, 0444);
203module_param(associate, int, 0444);
204module_param(disable, int, 0444);
205
206MODULE_PARM_DESC(debug, "debug level");
207MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
208MODULE_PARM_DESC(channel, "channel");
Tim Gardner5c7f9b72008-10-14 10:38:03 -0600209MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
James Ketrenos2c86c272005-03-23 17:32:29 -0600210MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
211
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400212static u32 ipw2100_debug_level = IPW_DL_NONE;
213
Brice Goglin0f52bf92005-12-01 01:41:46 -0800214#ifdef CONFIG_IPW2100_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400215#define IPW_DEBUG(level, message...) \
216do { \
217 if (ipw2100_debug_level & (level)) { \
218 printk(KERN_DEBUG "ipw2100: %c %s ", \
Harvey Harrisonc94c93d2008-07-28 23:01:34 -0700219 in_interrupt() ? 'I' : 'U', __func__); \
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400220 printk(message); \
221 } \
222} while (0)
223#else
224#define IPW_DEBUG(level, message...) do {} while (0)
Brice Goglin0f52bf92005-12-01 01:41:46 -0800225#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -0600226
Brice Goglin0f52bf92005-12-01 01:41:46 -0800227#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -0600228static const char *command_types[] = {
229 "undefined",
James Ketrenosee8e3652005-09-14 09:47:29 -0500230 "unused", /* HOST_ATTENTION */
James Ketrenos2c86c272005-03-23 17:32:29 -0600231 "HOST_COMPLETE",
James Ketrenosee8e3652005-09-14 09:47:29 -0500232 "unused", /* SLEEP */
233 "unused", /* HOST_POWER_DOWN */
James Ketrenos2c86c272005-03-23 17:32:29 -0600234 "unused",
235 "SYSTEM_CONFIG",
James Ketrenosee8e3652005-09-14 09:47:29 -0500236 "unused", /* SET_IMR */
James Ketrenos2c86c272005-03-23 17:32:29 -0600237 "SSID",
238 "MANDATORY_BSSID",
239 "AUTHENTICATION_TYPE",
240 "ADAPTER_ADDRESS",
241 "PORT_TYPE",
242 "INTERNATIONAL_MODE",
243 "CHANNEL",
244 "RTS_THRESHOLD",
245 "FRAG_THRESHOLD",
246 "POWER_MODE",
247 "TX_RATES",
248 "BASIC_TX_RATES",
249 "WEP_KEY_INFO",
250 "unused",
251 "unused",
252 "unused",
253 "unused",
254 "WEP_KEY_INDEX",
255 "WEP_FLAGS",
256 "ADD_MULTICAST",
257 "CLEAR_ALL_MULTICAST",
258 "BEACON_INTERVAL",
259 "ATIM_WINDOW",
260 "CLEAR_STATISTICS",
261 "undefined",
262 "undefined",
263 "undefined",
264 "undefined",
265 "TX_POWER_INDEX",
266 "undefined",
267 "undefined",
268 "undefined",
269 "undefined",
270 "undefined",
271 "undefined",
272 "BROADCAST_SCAN",
273 "CARD_DISABLE",
274 "PREFERRED_BSSID",
275 "SET_SCAN_OPTIONS",
276 "SCAN_DWELL_TIME",
277 "SWEEP_TABLE",
278 "AP_OR_STATION_TABLE",
279 "GROUP_ORDINALS",
280 "SHORT_RETRY_LIMIT",
281 "LONG_RETRY_LIMIT",
James Ketrenosee8e3652005-09-14 09:47:29 -0500282 "unused", /* SAVE_CALIBRATION */
283 "unused", /* RESTORE_CALIBRATION */
James Ketrenos2c86c272005-03-23 17:32:29 -0600284 "undefined",
285 "undefined",
286 "undefined",
287 "HOST_PRE_POWER_DOWN",
James Ketrenosee8e3652005-09-14 09:47:29 -0500288 "unused", /* HOST_INTERRUPT_COALESCING */
James Ketrenos2c86c272005-03-23 17:32:29 -0600289 "undefined",
290 "CARD_DISABLE_PHY_OFF",
Jean Delvare96a95c12011-07-06 00:27:06 +0200291 "MSDU_TX_RATES",
James Ketrenos2c86c272005-03-23 17:32:29 -0600292 "undefined",
293 "SET_STATION_STAT_BITS",
294 "CLEAR_STATIONS_STAT_BITS",
295 "LEAP_ROGUE_MODE",
296 "SET_SECURITY_INFORMATION",
297 "DISASSOCIATION_BSSID",
298 "SET_WPA_ASS_IE"
299};
300#endif
301
Matthew Garrettc26409a2009-11-11 14:36:30 -0500302static const long ipw2100_frequencies[] = {
303 2412, 2417, 2422, 2427,
304 2432, 2437, 2442, 2447,
305 2452, 2457, 2462, 2467,
306 2472, 2484
307};
308
309#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies)
310
Matthew Garrettc26409a2009-11-11 14:36:30 -0500311static struct ieee80211_rate ipw2100_bg_rates[] = {
312 { .bitrate = 10 },
313 { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
314 { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
315 { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
316};
317
Stanislav Yakovlev4d94c152012-02-09 20:23:52 -0500318#define RATE_COUNT ARRAY_SIZE(ipw2100_bg_rates)
Matthew Garrettc26409a2009-11-11 14:36:30 -0500319
James Ketrenos2c86c272005-03-23 17:32:29 -0600320/* Pre-decl until we get the code solid and then we can clean it up */
Jiri Benc19f7f742005-08-25 20:02:10 -0400321static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
322static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
James Ketrenos2c86c272005-03-23 17:32:29 -0600323static int ipw2100_adapter_setup(struct ipw2100_priv *priv);
324
325static void ipw2100_queues_initialize(struct ipw2100_priv *priv);
326static void ipw2100_queues_free(struct ipw2100_priv *priv);
327static int ipw2100_queues_allocate(struct ipw2100_priv *priv);
328
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400329static int ipw2100_fw_download(struct ipw2100_priv *priv,
330 struct ipw2100_fw *fw);
331static int ipw2100_get_firmware(struct ipw2100_priv *priv,
332 struct ipw2100_fw *fw);
333static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
334 size_t max);
335static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
336 size_t max);
337static void ipw2100_release_firmware(struct ipw2100_priv *priv,
338 struct ipw2100_fw *fw);
339static int ipw2100_ucode_download(struct ipw2100_priv *priv,
340 struct ipw2100_fw *fw);
David Howellsc4028952006-11-22 14:57:56 +0000341static void ipw2100_wx_event_work(struct work_struct *work);
James Ketrenosee8e3652005-09-14 09:47:29 -0500342static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev);
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400343static struct iw_handler_def ipw2100_wx_handler_def;
344
James Ketrenosee8e3652005-09-14 09:47:29 -0500345static inline void read_register(struct net_device *dev, u32 reg, u32 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600346{
Francois Romieu9b717072012-03-24 11:37:16 +0100347 struct ipw2100_priv *priv = libipw_priv(dev);
348
349 *val = ioread32(priv->ioaddr + reg);
James Ketrenos2c86c272005-03-23 17:32:29 -0600350 IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
351}
352
353static inline void write_register(struct net_device *dev, u32 reg, u32 val)
354{
Francois Romieu9b717072012-03-24 11:37:16 +0100355 struct ipw2100_priv *priv = libipw_priv(dev);
356
357 iowrite32(val, priv->ioaddr + reg);
James Ketrenos2c86c272005-03-23 17:32:29 -0600358 IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
359}
360
James Ketrenosee8e3652005-09-14 09:47:29 -0500361static inline void read_register_word(struct net_device *dev, u32 reg,
362 u16 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600363{
Francois Romieu9b717072012-03-24 11:37:16 +0100364 struct ipw2100_priv *priv = libipw_priv(dev);
365
366 *val = ioread16(priv->ioaddr + reg);
James Ketrenos2c86c272005-03-23 17:32:29 -0600367 IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
368}
369
James Ketrenosee8e3652005-09-14 09:47:29 -0500370static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600371{
Francois Romieu9b717072012-03-24 11:37:16 +0100372 struct ipw2100_priv *priv = libipw_priv(dev);
373
374 *val = ioread8(priv->ioaddr + reg);
James Ketrenos2c86c272005-03-23 17:32:29 -0600375 IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
376}
377
378static inline void write_register_word(struct net_device *dev, u32 reg, u16 val)
379{
Francois Romieu9b717072012-03-24 11:37:16 +0100380 struct ipw2100_priv *priv = libipw_priv(dev);
381
382 iowrite16(val, priv->ioaddr + reg);
James Ketrenos2c86c272005-03-23 17:32:29 -0600383 IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
384}
385
James Ketrenos2c86c272005-03-23 17:32:29 -0600386static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
387{
Francois Romieu9b717072012-03-24 11:37:16 +0100388 struct ipw2100_priv *priv = libipw_priv(dev);
389
390 iowrite8(val, priv->ioaddr + reg);
James Ketrenos2c86c272005-03-23 17:32:29 -0600391 IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
392}
393
James Ketrenosee8e3652005-09-14 09:47:29 -0500394static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600395{
396 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
397 addr & IPW_REG_INDIRECT_ADDR_MASK);
398 read_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
399}
400
401static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val)
402{
403 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
404 addr & IPW_REG_INDIRECT_ADDR_MASK);
405 write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
406}
407
James Ketrenosee8e3652005-09-14 09:47:29 -0500408static inline void read_nic_word(struct net_device *dev, u32 addr, u16 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600409{
410 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
411 addr & IPW_REG_INDIRECT_ADDR_MASK);
412 read_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
413}
414
415static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val)
416{
417 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
418 addr & IPW_REG_INDIRECT_ADDR_MASK);
419 write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
420}
421
James Ketrenosee8e3652005-09-14 09:47:29 -0500422static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600423{
424 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
425 addr & IPW_REG_INDIRECT_ADDR_MASK);
426 read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
427}
428
429static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val)
430{
431 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
432 addr & IPW_REG_INDIRECT_ADDR_MASK);
433 write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
434}
435
436static inline void write_nic_auto_inc_address(struct net_device *dev, u32 addr)
437{
438 write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
439 addr & IPW_REG_INDIRECT_ADDR_MASK);
440}
441
442static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val)
443{
444 write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val);
445}
446
Arjan van de Ven858119e2006-01-14 13:20:43 -0800447static void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
James Ketrenosee8e3652005-09-14 09:47:29 -0500448 const u8 * buf)
James Ketrenos2c86c272005-03-23 17:32:29 -0600449{
450 u32 aligned_addr;
451 u32 aligned_len;
452 u32 dif_len;
453 u32 i;
454
455 /* read first nibble byte by byte */
456 aligned_addr = addr & (~0x3);
457 dif_len = addr - aligned_addr;
458 if (dif_len) {
459 /* Start reading at aligned_addr + dif_len */
460 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
461 aligned_addr);
462 for (i = dif_len; i < 4; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500463 write_register_byte(dev,
464 IPW_REG_INDIRECT_ACCESS_DATA + i,
465 *buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600466
467 len -= dif_len;
468 aligned_addr += 4;
469 }
470
471 /* read DWs through autoincrement registers */
James Ketrenosee8e3652005-09-14 09:47:29 -0500472 write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600473 aligned_len = len & (~0x3);
474 for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
James Ketrenosee8e3652005-09-14 09:47:29 -0500475 write_register(dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *) buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600476
477 /* copy the last nibble */
478 dif_len = len - aligned_len;
479 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
480 for (i = 0; i < dif_len; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500481 write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
482 *buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600483}
484
Arjan van de Ven858119e2006-01-14 13:20:43 -0800485static void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
James Ketrenosee8e3652005-09-14 09:47:29 -0500486 u8 * buf)
James Ketrenos2c86c272005-03-23 17:32:29 -0600487{
488 u32 aligned_addr;
489 u32 aligned_len;
490 u32 dif_len;
491 u32 i;
492
493 /* read first nibble byte by byte */
494 aligned_addr = addr & (~0x3);
495 dif_len = addr - aligned_addr;
496 if (dif_len) {
497 /* Start reading at aligned_addr + dif_len */
498 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
499 aligned_addr);
500 for (i = dif_len; i < 4; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500501 read_register_byte(dev,
502 IPW_REG_INDIRECT_ACCESS_DATA + i,
503 buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600504
505 len -= dif_len;
506 aligned_addr += 4;
507 }
508
509 /* read DWs through autoincrement registers */
James Ketrenosee8e3652005-09-14 09:47:29 -0500510 write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600511 aligned_len = len & (~0x3);
512 for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
James Ketrenosee8e3652005-09-14 09:47:29 -0500513 read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600514
515 /* copy the last nibble */
516 dif_len = len - aligned_len;
James Ketrenosee8e3652005-09-14 09:47:29 -0500517 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600518 for (i = 0; i < dif_len; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500519 read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600520}
521
Francois Romieu9b717072012-03-24 11:37:16 +0100522static bool ipw2100_hw_is_adapter_in_system(struct net_device *dev)
James Ketrenos2c86c272005-03-23 17:32:29 -0600523{
Francois Romieu9b717072012-03-24 11:37:16 +0100524 u32 dbg;
525
526 read_register(dev, IPW_REG_DOA_DEBUG_AREA_START, &dbg);
527
528 return dbg == IPW_DATA_DOA_DEBUG_VALUE;
James Ketrenos2c86c272005-03-23 17:32:29 -0600529}
530
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400531static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
James Ketrenosee8e3652005-09-14 09:47:29 -0500532 void *val, u32 * len)
James Ketrenos2c86c272005-03-23 17:32:29 -0600533{
534 struct ipw2100_ordinals *ordinals = &priv->ordinals;
535 u32 addr;
536 u32 field_info;
537 u16 field_len;
538 u16 field_count;
539 u32 total_length;
540
541 if (ordinals->table1_addr == 0) {
Jiri Benc797b4f72005-08-25 20:03:27 -0400542 printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals "
James Ketrenos2c86c272005-03-23 17:32:29 -0600543 "before they have been loaded.\n");
544 return -EINVAL;
545 }
546
547 if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
548 if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) {
549 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
550
Jiri Benc797b4f72005-08-25 20:03:27 -0400551 printk(KERN_WARNING DRV_NAME
Jiri Bencaaa4d302005-06-07 14:58:41 +0200552 ": ordinal buffer length too small, need %zd\n",
James Ketrenos2c86c272005-03-23 17:32:29 -0600553 IPW_ORD_TAB_1_ENTRY_SIZE);
554
555 return -EINVAL;
556 }
557
James Ketrenosee8e3652005-09-14 09:47:29 -0500558 read_nic_dword(priv->net_dev,
559 ordinals->table1_addr + (ord << 2), &addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600560 read_nic_dword(priv->net_dev, addr, val);
561
562 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
563
564 return 0;
565 }
566
567 if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) {
568
569 ord -= IPW_START_ORD_TAB_2;
570
571 /* get the address of statistic */
James Ketrenosee8e3652005-09-14 09:47:29 -0500572 read_nic_dword(priv->net_dev,
573 ordinals->table2_addr + (ord << 3), &addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600574
575 /* get the second DW of statistics ;
576 * two 16-bit words - first is length, second is count */
577 read_nic_dword(priv->net_dev,
578 ordinals->table2_addr + (ord << 3) + sizeof(u32),
579 &field_info);
580
581 /* get each entry length */
James Ketrenosee8e3652005-09-14 09:47:29 -0500582 field_len = *((u16 *) & field_info);
James Ketrenos2c86c272005-03-23 17:32:29 -0600583
584 /* get number of entries */
James Ketrenosee8e3652005-09-14 09:47:29 -0500585 field_count = *(((u16 *) & field_info) + 1);
James Ketrenos2c86c272005-03-23 17:32:29 -0600586
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200587 /* abort if no enough memory */
James Ketrenos2c86c272005-03-23 17:32:29 -0600588 total_length = field_len * field_count;
589 if (total_length > *len) {
590 *len = total_length;
591 return -EINVAL;
592 }
593
594 *len = total_length;
595 if (!total_length)
596 return 0;
597
598 /* read the ordinal data from the SRAM */
599 read_nic_memory(priv->net_dev, addr, total_length, val);
600
601 return 0;
602 }
603
Jiri Benc797b4f72005-08-25 20:03:27 -0400604 printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor "
James Ketrenos2c86c272005-03-23 17:32:29 -0600605 "in table 2\n", ord);
606
607 return -EINVAL;
608}
609
James Ketrenosee8e3652005-09-14 09:47:29 -0500610static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val,
611 u32 * len)
James Ketrenos2c86c272005-03-23 17:32:29 -0600612{
613 struct ipw2100_ordinals *ordinals = &priv->ordinals;
614 u32 addr;
615
616 if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
617 if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) {
618 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
619 IPW_DEBUG_INFO("wrong size\n");
620 return -EINVAL;
621 }
622
James Ketrenosee8e3652005-09-14 09:47:29 -0500623 read_nic_dword(priv->net_dev,
624 ordinals->table1_addr + (ord << 2), &addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600625
626 write_nic_dword(priv->net_dev, addr, *val);
627
628 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
629
630 return 0;
631 }
632
633 IPW_DEBUG_INFO("wrong table\n");
634 if (IS_ORDINAL_TABLE_TWO(ordinals, ord))
635 return -EINVAL;
636
637 return -EINVAL;
638}
639
640static char *snprint_line(char *buf, size_t count,
James Ketrenosee8e3652005-09-14 09:47:29 -0500641 const u8 * data, u32 len, u32 ofs)
James Ketrenos2c86c272005-03-23 17:32:29 -0600642{
643 int out, i, j, l;
644 char c;
645
646 out = snprintf(buf, count, "%08X", ofs);
647
648 for (l = 0, i = 0; i < 2; i++) {
649 out += snprintf(buf + out, count - out, " ");
650 for (j = 0; j < 8 && l < len; j++, l++)
651 out += snprintf(buf + out, count - out, "%02X ",
652 data[(i * 8 + j)]);
653 for (; j < 8; j++)
654 out += snprintf(buf + out, count - out, " ");
655 }
656
657 out += snprintf(buf + out, count - out, " ");
658 for (l = 0, i = 0; i < 2; i++) {
659 out += snprintf(buf + out, count - out, " ");
660 for (j = 0; j < 8 && l < len; j++, l++) {
661 c = data[(i * 8 + j)];
662 if (!isascii(c) || !isprint(c))
663 c = '.';
664
665 out += snprintf(buf + out, count - out, "%c", c);
666 }
667
668 for (; j < 8; j++)
669 out += snprintf(buf + out, count - out, " ");
670 }
671
672 return buf;
673}
674
James Ketrenosee8e3652005-09-14 09:47:29 -0500675static void printk_buf(int level, const u8 * data, u32 len)
James Ketrenos2c86c272005-03-23 17:32:29 -0600676{
677 char line[81];
678 u32 ofs = 0;
679 if (!(ipw2100_debug_level & level))
680 return;
681
682 while (len) {
683 printk(KERN_DEBUG "%s\n",
684 snprint_line(line, sizeof(line), &data[ofs],
685 min(len, 16U), ofs));
686 ofs += 16;
687 len -= min(len, 16U);
688 }
689}
690
James Ketrenos2c86c272005-03-23 17:32:29 -0600691#define MAX_RESET_BACKOFF 10
692
Arjan van de Ven858119e2006-01-14 13:20:43 -0800693static void schedule_reset(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -0600694{
695 unsigned long now = get_seconds();
696
697 /* If we haven't received a reset request within the backoff period,
698 * then we can reset the backoff interval so this reset occurs
699 * immediately */
700 if (priv->reset_backoff &&
701 (now - priv->last_reset > priv->reset_backoff))
702 priv->reset_backoff = 0;
703
704 priv->last_reset = get_seconds();
705
706 if (!(priv->status & STATUS_RESET_PENDING)) {
707 IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n",
708 priv->net_dev->name, priv->reset_backoff);
709 netif_carrier_off(priv->net_dev);
710 netif_stop_queue(priv->net_dev);
711 priv->status |= STATUS_RESET_PENDING;
712 if (priv->reset_backoff)
Tejun Heobcb6d912011-01-26 12:12:50 +0100713 schedule_delayed_work(&priv->reset_work,
714 priv->reset_backoff * HZ);
James Ketrenos2c86c272005-03-23 17:32:29 -0600715 else
Tejun Heobcb6d912011-01-26 12:12:50 +0100716 schedule_delayed_work(&priv->reset_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -0600717
718 if (priv->reset_backoff < MAX_RESET_BACKOFF)
719 priv->reset_backoff++;
720
721 wake_up_interruptible(&priv->wait_command_queue);
722 } else
723 IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n",
724 priv->net_dev->name);
725
726}
727
728#define HOST_COMPLETE_TIMEOUT (2 * HZ)
729static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
James Ketrenosee8e3652005-09-14 09:47:29 -0500730 struct host_command *cmd)
James Ketrenos2c86c272005-03-23 17:32:29 -0600731{
732 struct list_head *element;
733 struct ipw2100_tx_packet *packet;
734 unsigned long flags;
735 int err = 0;
736
737 IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
738 command_types[cmd->host_command], cmd->host_command,
739 cmd->host_command_length);
James Ketrenosee8e3652005-09-14 09:47:29 -0500740 printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters,
James Ketrenos2c86c272005-03-23 17:32:29 -0600741 cmd->host_command_length);
742
743 spin_lock_irqsave(&priv->low_lock, flags);
744
745 if (priv->fatal_error) {
James Ketrenosee8e3652005-09-14 09:47:29 -0500746 IPW_DEBUG_INFO
747 ("Attempt to send command while hardware in fatal error condition.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -0600748 err = -EIO;
749 goto fail_unlock;
750 }
751
752 if (!(priv->status & STATUS_RUNNING)) {
James Ketrenosee8e3652005-09-14 09:47:29 -0500753 IPW_DEBUG_INFO
754 ("Attempt to send command while hardware is not running.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -0600755 err = -EIO;
756 goto fail_unlock;
757 }
758
759 if (priv->status & STATUS_CMD_ACTIVE) {
James Ketrenosee8e3652005-09-14 09:47:29 -0500760 IPW_DEBUG_INFO
761 ("Attempt to send command while another command is pending.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -0600762 err = -EBUSY;
763 goto fail_unlock;
764 }
765
766 if (list_empty(&priv->msg_free_list)) {
767 IPW_DEBUG_INFO("no available msg buffers\n");
768 goto fail_unlock;
769 }
770
771 priv->status |= STATUS_CMD_ACTIVE;
772 priv->messages_sent++;
773
774 element = priv->msg_free_list.next;
775
776 packet = list_entry(element, struct ipw2100_tx_packet, list);
777 packet->jiffy_start = jiffies;
778
779 /* initialize the firmware command packet */
780 packet->info.c_struct.cmd->host_command_reg = cmd->host_command;
781 packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1;
James Ketrenosee8e3652005-09-14 09:47:29 -0500782 packet->info.c_struct.cmd->host_command_len_reg =
783 cmd->host_command_length;
James Ketrenos2c86c272005-03-23 17:32:29 -0600784 packet->info.c_struct.cmd->sequence = cmd->host_command_sequence;
785
786 memcpy(packet->info.c_struct.cmd->host_command_params_reg,
787 cmd->host_command_parameters,
788 sizeof(packet->info.c_struct.cmd->host_command_params_reg));
789
790 list_del(element);
791 DEC_STAT(&priv->msg_free_stat);
792
793 list_add_tail(element, &priv->msg_pend_list);
794 INC_STAT(&priv->msg_pend_stat);
795
Jiri Benc19f7f742005-08-25 20:02:10 -0400796 ipw2100_tx_send_commands(priv);
797 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -0600798
799 spin_unlock_irqrestore(&priv->low_lock, flags);
800
801 /*
802 * We must wait for this command to complete before another
803 * command can be sent... but if we wait more than 3 seconds
804 * then there is a problem.
805 */
806
James Ketrenosee8e3652005-09-14 09:47:29 -0500807 err =
808 wait_event_interruptible_timeout(priv->wait_command_queue,
809 !(priv->
810 status & STATUS_CMD_ACTIVE),
811 HOST_COMPLETE_TIMEOUT);
James Ketrenos2c86c272005-03-23 17:32:29 -0600812
813 if (err == 0) {
814 IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
James Ketrenos82328352005-08-24 22:33:31 -0500815 1000 * (HOST_COMPLETE_TIMEOUT / HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -0600816 priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT;
817 priv->status &= ~STATUS_CMD_ACTIVE;
818 schedule_reset(priv);
819 return -EIO;
820 }
821
822 if (priv->fatal_error) {
Jiri Benc797b4f72005-08-25 20:03:27 -0400823 printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n",
James Ketrenos2c86c272005-03-23 17:32:29 -0600824 priv->net_dev->name);
825 return -EIO;
826 }
827
828 /* !!!!! HACK TEST !!!!!
829 * When lots of debug trace statements are enabled, the driver
830 * doesn't seem to have as many firmware restart cycles...
831 *
832 * As a test, we're sticking in a 1/100s delay here */
Nishanth Aravamudan3173c892005-09-11 02:09:55 -0700833 schedule_timeout_uninterruptible(msecs_to_jiffies(10));
James Ketrenos2c86c272005-03-23 17:32:29 -0600834
835 return 0;
836
James Ketrenosee8e3652005-09-14 09:47:29 -0500837 fail_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -0600838 spin_unlock_irqrestore(&priv->low_lock, flags);
839
840 return err;
841}
842
James Ketrenos2c86c272005-03-23 17:32:29 -0600843/*
844 * Verify the values and data access of the hardware
845 * No locks needed or used. No functions called.
846 */
847static int ipw2100_verify(struct ipw2100_priv *priv)
848{
849 u32 data1, data2;
850 u32 address;
851
852 u32 val1 = 0x76543210;
853 u32 val2 = 0xFEDCBA98;
854
855 /* Domain 0 check - all values should be DOA_DEBUG */
856 for (address = IPW_REG_DOA_DEBUG_AREA_START;
James Ketrenosee8e3652005-09-14 09:47:29 -0500857 address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) {
James Ketrenos2c86c272005-03-23 17:32:29 -0600858 read_register(priv->net_dev, address, &data1);
859 if (data1 != IPW_DATA_DOA_DEBUG_VALUE)
860 return -EIO;
861 }
862
863 /* Domain 1 check - use arbitrary read/write compare */
864 for (address = 0; address < 5; address++) {
865 /* The memory area is not used now */
866 write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
867 val1);
868 write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
869 val2);
870 read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
871 &data1);
872 read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
873 &data2);
874 if (val1 == data1 && val2 == data2)
875 return 0;
876 }
877
878 return -EIO;
879}
880
881/*
882 *
883 * Loop until the CARD_DISABLED bit is the same value as the
884 * supplied parameter
885 *
886 * TODO: See if it would be more efficient to do a wait/wake
887 * cycle and have the completion event trigger the wakeup
888 *
889 */
890#define IPW_CARD_DISABLE_COMPLETE_WAIT 100 // 100 milli
891static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state)
892{
893 int i;
894 u32 card_state;
895 u32 len = sizeof(card_state);
896 int err;
897
898 for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) {
899 err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED,
900 &card_state, &len);
901 if (err) {
902 IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal "
903 "failed.\n");
904 return 0;
905 }
906
907 /* We'll break out if either the HW state says it is
908 * in the state we want, or if HOST_COMPLETE command
909 * finishes */
910 if ((card_state == state) ||
911 ((priv->status & STATUS_ENABLED) ?
912 IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) {
913 if (state == IPW_HW_STATE_ENABLED)
914 priv->status |= STATUS_ENABLED;
915 else
916 priv->status &= ~STATUS_ENABLED;
917
918 return 0;
919 }
920
921 udelay(50);
922 }
923
924 IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n",
925 state ? "DISABLED" : "ENABLED");
926 return -EIO;
927}
928
James Ketrenos2c86c272005-03-23 17:32:29 -0600929/*********************************************************************
930 Procedure : sw_reset_and_clock
931 Purpose : Asserts s/w reset, asserts clock initialization
932 and waits for clock stabilization
933 ********************************************************************/
934static int sw_reset_and_clock(struct ipw2100_priv *priv)
935{
936 int i;
937 u32 r;
938
939 // assert s/w reset
940 write_register(priv->net_dev, IPW_REG_RESET_REG,
941 IPW_AUX_HOST_RESET_REG_SW_RESET);
942
943 // wait for clock stabilization
944 for (i = 0; i < 1000; i++) {
945 udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY);
946
947 // check clock ready bit
948 read_register(priv->net_dev, IPW_REG_RESET_REG, &r);
949 if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET)
950 break;
951 }
952
953 if (i == 1000)
954 return -EIO; // TODO: better error value
955
956 /* set "initialization complete" bit to move adapter to
957 * D0 state */
958 write_register(priv->net_dev, IPW_REG_GP_CNTRL,
959 IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE);
960
961 /* wait for clock stabilization */
962 for (i = 0; i < 10000; i++) {
963 udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4);
964
965 /* check clock ready bit */
966 read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
967 if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY)
968 break;
969 }
970
971 if (i == 10000)
972 return -EIO; /* TODO: better error value */
973
James Ketrenos2c86c272005-03-23 17:32:29 -0600974 /* set D0 standby bit */
975 read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
976 write_register(priv->net_dev, IPW_REG_GP_CNTRL,
977 r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
James Ketrenos2c86c272005-03-23 17:32:29 -0600978
979 return 0;
980}
981
982/*********************************************************************
Pavel Machek8724a112005-06-20 14:28:43 -0700983 Procedure : ipw2100_download_firmware
James Ketrenos2c86c272005-03-23 17:32:29 -0600984 Purpose : Initiaze adapter after power on.
985 The sequence is:
986 1. assert s/w reset first!
987 2. awake clocks & wait for clock stabilization
988 3. hold ARC (don't ask me why...)
989 4. load Dino ucode and reset/clock init again
990 5. zero-out shared mem
991 6. download f/w
992 *******************************************************************/
993static int ipw2100_download_firmware(struct ipw2100_priv *priv)
994{
995 u32 address;
996 int err;
997
998#ifndef CONFIG_PM
999 /* Fetch the firmware and microcode */
1000 struct ipw2100_fw ipw2100_firmware;
1001#endif
1002
1003 if (priv->fatal_error) {
1004 IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after "
James Ketrenosee8e3652005-09-14 09:47:29 -05001005 "fatal error %d. Interface must be brought down.\n",
1006 priv->net_dev->name, priv->fatal_error);
James Ketrenos2c86c272005-03-23 17:32:29 -06001007 return -EINVAL;
1008 }
James Ketrenos2c86c272005-03-23 17:32:29 -06001009#ifdef CONFIG_PM
1010 if (!ipw2100_firmware.version) {
1011 err = ipw2100_get_firmware(priv, &ipw2100_firmware);
1012 if (err) {
1013 IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001014 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001015 priv->fatal_error = IPW2100_ERR_FW_LOAD;
1016 goto fail;
1017 }
1018 }
1019#else
1020 err = ipw2100_get_firmware(priv, &ipw2100_firmware);
1021 if (err) {
1022 IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001023 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001024 priv->fatal_error = IPW2100_ERR_FW_LOAD;
1025 goto fail;
1026 }
1027#endif
1028 priv->firmware_version = ipw2100_firmware.version;
1029
1030 /* s/w reset and clock stabilization */
1031 err = sw_reset_and_clock(priv);
1032 if (err) {
1033 IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001034 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001035 goto fail;
1036 }
1037
1038 err = ipw2100_verify(priv);
1039 if (err) {
1040 IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001041 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001042 goto fail;
1043 }
1044
1045 /* Hold ARC */
1046 write_nic_dword(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05001047 IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000);
James Ketrenos2c86c272005-03-23 17:32:29 -06001048
1049 /* allow ARC to run */
1050 write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
1051
1052 /* load microcode */
1053 err = ipw2100_ucode_download(priv, &ipw2100_firmware);
1054 if (err) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001055 printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001056 priv->net_dev->name, err);
1057 goto fail;
1058 }
1059
1060 /* release ARC */
1061 write_nic_dword(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05001062 IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000);
James Ketrenos2c86c272005-03-23 17:32:29 -06001063
1064 /* s/w reset and clock stabilization (again!!!) */
1065 err = sw_reset_and_clock(priv);
1066 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001067 printk(KERN_ERR DRV_NAME
1068 ": %s: sw_reset_and_clock failed: %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001069 priv->net_dev->name, err);
1070 goto fail;
1071 }
1072
1073 /* load f/w */
1074 err = ipw2100_fw_download(priv, &ipw2100_firmware);
1075 if (err) {
1076 IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001077 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001078 goto fail;
1079 }
James Ketrenos2c86c272005-03-23 17:32:29 -06001080#ifndef CONFIG_PM
1081 /*
1082 * When the .resume method of the driver is called, the other
1083 * part of the system, i.e. the ide driver could still stay in
1084 * the suspend stage. This prevents us from loading the firmware
1085 * from the disk. --YZ
1086 */
1087
1088 /* free any storage allocated for firmware image */
1089 ipw2100_release_firmware(priv, &ipw2100_firmware);
1090#endif
1091
1092 /* zero out Domain 1 area indirectly (Si requirement) */
1093 for (address = IPW_HOST_FW_SHARED_AREA0;
1094 address < IPW_HOST_FW_SHARED_AREA0_END; address += 4)
1095 write_nic_dword(priv->net_dev, address, 0);
1096 for (address = IPW_HOST_FW_SHARED_AREA1;
1097 address < IPW_HOST_FW_SHARED_AREA1_END; address += 4)
1098 write_nic_dword(priv->net_dev, address, 0);
1099 for (address = IPW_HOST_FW_SHARED_AREA2;
1100 address < IPW_HOST_FW_SHARED_AREA2_END; address += 4)
1101 write_nic_dword(priv->net_dev, address, 0);
1102 for (address = IPW_HOST_FW_SHARED_AREA3;
1103 address < IPW_HOST_FW_SHARED_AREA3_END; address += 4)
1104 write_nic_dword(priv->net_dev, address, 0);
1105 for (address = IPW_HOST_FW_INTERRUPT_AREA;
1106 address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4)
1107 write_nic_dword(priv->net_dev, address, 0);
1108
1109 return 0;
1110
James Ketrenosee8e3652005-09-14 09:47:29 -05001111 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06001112 ipw2100_release_firmware(priv, &ipw2100_firmware);
1113 return err;
1114}
1115
1116static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv)
1117{
1118 if (priv->status & STATUS_INT_ENABLED)
1119 return;
1120 priv->status |= STATUS_INT_ENABLED;
1121 write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK);
1122}
1123
1124static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv)
1125{
1126 if (!(priv->status & STATUS_INT_ENABLED))
1127 return;
1128 priv->status &= ~STATUS_INT_ENABLED;
1129 write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0);
1130}
1131
James Ketrenos2c86c272005-03-23 17:32:29 -06001132static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv)
1133{
1134 struct ipw2100_ordinals *ord = &priv->ordinals;
1135
1136 IPW_DEBUG_INFO("enter\n");
1137
1138 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1,
1139 &ord->table1_addr);
1140
1141 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2,
1142 &ord->table2_addr);
1143
1144 read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size);
1145 read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size);
1146
1147 ord->table2_size &= 0x0000FFFF;
1148
1149 IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size);
1150 IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size);
1151 IPW_DEBUG_INFO("exit\n");
1152}
1153
1154static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv)
1155{
1156 u32 reg = 0;
1157 /*
1158 * Set GPIO 3 writable by FW; GPIO 1 writable
1159 * by driver and enable clock
1160 */
1161 reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE |
1162 IPW_BIT_GPIO_LED_OFF);
1163 write_register(priv->net_dev, IPW_REG_GPIO, reg);
1164}
1165
Arjan van de Ven858119e2006-01-14 13:20:43 -08001166static int rf_kill_active(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06001167{
1168#define MAX_RF_KILL_CHECKS 5
1169#define RF_KILL_CHECK_DELAY 40
James Ketrenos2c86c272005-03-23 17:32:29 -06001170
1171 unsigned short value = 0;
1172 u32 reg = 0;
1173 int i;
1174
1175 if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
Matthew Garrettc26409a2009-11-11 14:36:30 -05001176 wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
James Ketrenos2c86c272005-03-23 17:32:29 -06001177 priv->status &= ~STATUS_RF_KILL_HW;
1178 return 0;
1179 }
1180
1181 for (i = 0; i < MAX_RF_KILL_CHECKS; i++) {
1182 udelay(RF_KILL_CHECK_DELAY);
1183 read_register(priv->net_dev, IPW_REG_GPIO, &reg);
1184 value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1);
1185 }
1186
Matthew Garrettc26409a2009-11-11 14:36:30 -05001187 if (value == 0) {
1188 wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
James Ketrenos2c86c272005-03-23 17:32:29 -06001189 priv->status |= STATUS_RF_KILL_HW;
Matthew Garrettc26409a2009-11-11 14:36:30 -05001190 } else {
1191 wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
James Ketrenos2c86c272005-03-23 17:32:29 -06001192 priv->status &= ~STATUS_RF_KILL_HW;
Matthew Garrettc26409a2009-11-11 14:36:30 -05001193 }
James Ketrenos2c86c272005-03-23 17:32:29 -06001194
1195 return (value == 0);
1196}
1197
1198static int ipw2100_get_hw_features(struct ipw2100_priv *priv)
1199{
1200 u32 addr, len;
1201 u32 val;
1202
1203 /*
1204 * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1
1205 */
1206 len = sizeof(addr);
James Ketrenosee8e3652005-09-14 09:47:29 -05001207 if (ipw2100_get_ordinal
1208 (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06001209 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001210 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06001211 return -EIO;
1212 }
1213
1214 IPW_DEBUG_INFO("EEPROM address: %08X\n", addr);
1215
1216 /*
1217 * EEPROM version is the byte at offset 0xfd in firmware
1218 * We read 4 bytes, then shift out the byte we actually want */
1219 read_nic_dword(priv->net_dev, addr + 0xFC, &val);
1220 priv->eeprom_version = (val >> 24) & 0xFF;
1221 IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version);
1222
James Ketrenosee8e3652005-09-14 09:47:29 -05001223 /*
James Ketrenos2c86c272005-03-23 17:32:29 -06001224 * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware
1225 *
1226 * notice that the EEPROM bit is reverse polarity, i.e.
1227 * bit = 0 signifies HW RF kill switch is supported
1228 * bit = 1 signifies HW RF kill switch is NOT supported
1229 */
1230 read_nic_dword(priv->net_dev, addr + 0x20, &val);
1231 if (!((val >> 24) & 0x01))
1232 priv->hw_features |= HW_FEATURE_RFKILL;
1233
1234 IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001235 (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not ");
James Ketrenos2c86c272005-03-23 17:32:29 -06001236
1237 return 0;
1238}
1239
1240/*
1241 * Start firmware execution after power on and intialization
1242 * The sequence is:
1243 * 1. Release ARC
1244 * 2. Wait for f/w initialization completes;
1245 */
1246static int ipw2100_start_adapter(struct ipw2100_priv *priv)
1247{
James Ketrenos2c86c272005-03-23 17:32:29 -06001248 int i;
1249 u32 inta, inta_mask, gpio;
1250
1251 IPW_DEBUG_INFO("enter\n");
1252
1253 if (priv->status & STATUS_RUNNING)
1254 return 0;
1255
1256 /*
1257 * Initialize the hw - drive adapter to DO state by setting
1258 * init_done bit. Wait for clk_ready bit and Download
1259 * fw & dino ucode
1260 */
1261 if (ipw2100_download_firmware(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001262 printk(KERN_ERR DRV_NAME
1263 ": %s: Failed to power on the adapter.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001264 priv->net_dev->name);
1265 return -EIO;
1266 }
1267
1268 /* Clear the Tx, Rx and Msg queues and the r/w indexes
1269 * in the firmware RBD and TBD ring queue */
1270 ipw2100_queues_initialize(priv);
1271
1272 ipw2100_hw_set_gpio(priv);
1273
1274 /* TODO -- Look at disabling interrupts here to make sure none
1275 * get fired during FW initialization */
1276
1277 /* Release ARC - clear reset bit */
1278 write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
1279
1280 /* wait for f/w intialization complete */
1281 IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n");
1282 i = 5000;
1283 do {
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001284 schedule_timeout_uninterruptible(msecs_to_jiffies(40));
James Ketrenos2c86c272005-03-23 17:32:29 -06001285 /* Todo... wait for sync command ... */
1286
1287 read_register(priv->net_dev, IPW_REG_INTA, &inta);
1288
1289 /* check "init done" bit */
1290 if (inta & IPW2100_INTA_FW_INIT_DONE) {
1291 /* reset "init done" bit */
1292 write_register(priv->net_dev, IPW_REG_INTA,
1293 IPW2100_INTA_FW_INIT_DONE);
1294 break;
1295 }
1296
1297 /* check error conditions : we check these after the firmware
1298 * check so that if there is an error, the interrupt handler
1299 * will see it and the adapter will be reset */
1300 if (inta &
1301 (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) {
1302 /* clear error conditions */
1303 write_register(priv->net_dev, IPW_REG_INTA,
1304 IPW2100_INTA_FATAL_ERROR |
1305 IPW2100_INTA_PARITY_ERROR);
1306 }
Roel Kluina2a1c3e2007-11-05 23:55:02 +01001307 } while (--i);
James Ketrenos2c86c272005-03-23 17:32:29 -06001308
1309 /* Clear out any pending INTAs since we aren't supposed to have
1310 * interrupts enabled at this point... */
1311 read_register(priv->net_dev, IPW_REG_INTA, &inta);
1312 read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
1313 inta &= IPW_INTERRUPT_MASK;
1314 /* Clear out any pending interrupts */
1315 if (inta & inta_mask)
1316 write_register(priv->net_dev, IPW_REG_INTA, inta);
1317
1318 IPW_DEBUG_FW("f/w initialization complete: %s\n",
1319 i ? "SUCCESS" : "FAILED");
1320
1321 if (!i) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001322 printk(KERN_WARNING DRV_NAME
1323 ": %s: Firmware did not initialize.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001324 priv->net_dev->name);
1325 return -EIO;
1326 }
1327
1328 /* allow firmware to write to GPIO1 & GPIO3 */
1329 read_register(priv->net_dev, IPW_REG_GPIO, &gpio);
1330
1331 gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK);
1332
1333 write_register(priv->net_dev, IPW_REG_GPIO, gpio);
1334
1335 /* Ready to receive commands */
1336 priv->status |= STATUS_RUNNING;
1337
1338 /* The adapter has been reset; we are not associated */
1339 priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
1340
1341 IPW_DEBUG_INFO("exit\n");
1342
1343 return 0;
1344}
1345
1346static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv)
1347{
1348 if (!priv->fatal_error)
1349 return;
1350
1351 priv->fatal_errors[priv->fatal_index++] = priv->fatal_error;
1352 priv->fatal_index %= IPW2100_ERROR_QUEUE;
1353 priv->fatal_error = 0;
1354}
1355
James Ketrenos2c86c272005-03-23 17:32:29 -06001356/* NOTE: Our interrupt is disabled when this method is called */
1357static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
1358{
1359 u32 reg;
1360 int i;
1361
1362 IPW_DEBUG_INFO("Power cycling the hardware.\n");
1363
1364 ipw2100_hw_set_gpio(priv);
1365
1366 /* Step 1. Stop Master Assert */
1367 write_register(priv->net_dev, IPW_REG_RESET_REG,
1368 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
1369
1370 /* Step 2. Wait for stop Master Assert
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02001371 * (not more than 50us, otherwise ret error */
James Ketrenos2c86c272005-03-23 17:32:29 -06001372 i = 5;
1373 do {
1374 udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
1375 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
1376
1377 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
1378 break;
Roel Kluina2a1c3e2007-11-05 23:55:02 +01001379 } while (--i);
James Ketrenos2c86c272005-03-23 17:32:29 -06001380
1381 priv->status &= ~STATUS_RESET_PENDING;
1382
1383 if (!i) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001384 IPW_DEBUG_INFO
1385 ("exit - waited too long for master assert stop\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06001386 return -EIO;
1387 }
1388
1389 write_register(priv->net_dev, IPW_REG_RESET_REG,
1390 IPW_AUX_HOST_RESET_REG_SW_RESET);
1391
James Ketrenos2c86c272005-03-23 17:32:29 -06001392 /* Reset any fatal_error conditions */
1393 ipw2100_reset_fatalerror(priv);
1394
1395 /* At this point, the adapter is now stopped and disabled */
1396 priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING |
1397 STATUS_ASSOCIATED | STATUS_ENABLED);
1398
1399 return 0;
1400}
1401
1402/*
Justin P. Mattock942a8492011-02-01 21:06:21 -08001403 * Send the CARD_DISABLE_PHY_OFF command to the card to disable it
James Ketrenos2c86c272005-03-23 17:32:29 -06001404 *
1405 * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent.
1406 *
1407 * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of
1408 * if STATUS_ASSN_LOST is sent.
1409 */
1410static int ipw2100_hw_phy_off(struct ipw2100_priv *priv)
1411{
1412
1413#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000)
1414
1415 struct host_command cmd = {
1416 .host_command = CARD_DISABLE_PHY_OFF,
1417 .host_command_sequence = 0,
1418 .host_command_length = 0,
1419 };
1420 int err, i;
1421 u32 val1, val2;
1422
1423 IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n");
1424
1425 /* Turn off the radio */
1426 err = ipw2100_hw_send_command(priv, &cmd);
1427 if (err)
1428 return err;
1429
1430 for (i = 0; i < 2500; i++) {
1431 read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1);
1432 read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2);
1433
1434 if ((val1 & IPW2100_CONTROL_PHY_OFF) &&
1435 (val2 & IPW2100_COMMAND_PHY_OFF))
1436 return 0;
1437
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001438 schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY);
James Ketrenos2c86c272005-03-23 17:32:29 -06001439 }
1440
1441 return -EIO;
1442}
1443
James Ketrenos2c86c272005-03-23 17:32:29 -06001444static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
1445{
1446 struct host_command cmd = {
1447 .host_command = HOST_COMPLETE,
1448 .host_command_sequence = 0,
1449 .host_command_length = 0
1450 };
1451 int err = 0;
1452
1453 IPW_DEBUG_HC("HOST_COMPLETE\n");
1454
1455 if (priv->status & STATUS_ENABLED)
1456 return 0;
1457
Ingo Molnar752e3772006-02-28 07:20:54 +08001458 mutex_lock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001459
1460 if (rf_kill_active(priv)) {
1461 IPW_DEBUG_HC("Command aborted due to RF kill active.\n");
1462 goto fail_up;
1463 }
1464
1465 err = ipw2100_hw_send_command(priv, &cmd);
1466 if (err) {
1467 IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n");
1468 goto fail_up;
1469 }
1470
1471 err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED);
1472 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001473 IPW_DEBUG_INFO("%s: card not responding to init command.\n",
1474 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001475 goto fail_up;
1476 }
1477
1478 if (priv->stop_hang_check) {
1479 priv->stop_hang_check = 0;
Tejun Heobcb6d912011-01-26 12:12:50 +01001480 schedule_delayed_work(&priv->hang_check, HZ / 2);
James Ketrenos2c86c272005-03-23 17:32:29 -06001481 }
1482
James Ketrenosee8e3652005-09-14 09:47:29 -05001483 fail_up:
Ingo Molnar752e3772006-02-28 07:20:54 +08001484 mutex_unlock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001485 return err;
1486}
1487
1488static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
1489{
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001490#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100))
James Ketrenos2c86c272005-03-23 17:32:29 -06001491
1492 struct host_command cmd = {
1493 .host_command = HOST_PRE_POWER_DOWN,
1494 .host_command_sequence = 0,
1495 .host_command_length = 0,
1496 };
1497 int err, i;
1498 u32 reg;
1499
1500 if (!(priv->status & STATUS_RUNNING))
1501 return 0;
1502
1503 priv->status |= STATUS_STOPPING;
1504
1505 /* We can only shut down the card if the firmware is operational. So,
1506 * if we haven't reset since a fatal_error, then we can not send the
1507 * shutdown commands. */
1508 if (!priv->fatal_error) {
1509 /* First, make sure the adapter is enabled so that the PHY_OFF
1510 * command can shut it down */
1511 ipw2100_enable_adapter(priv);
1512
1513 err = ipw2100_hw_phy_off(priv);
1514 if (err)
James Ketrenosee8e3652005-09-14 09:47:29 -05001515 printk(KERN_WARNING DRV_NAME
1516 ": Error disabling radio %d\n", err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001517
1518 /*
1519 * If in D0-standby mode going directly to D3 may cause a
1520 * PCI bus violation. Therefore we must change out of the D0
1521 * state.
1522 *
1523 * Sending the PREPARE_FOR_POWER_DOWN will restrict the
1524 * hardware from going into standby mode and will transition
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001525 * out of D0-standby if it is already in that state.
James Ketrenos2c86c272005-03-23 17:32:29 -06001526 *
1527 * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the
1528 * driver upon completion. Once received, the driver can
1529 * proceed to the D3 state.
1530 *
1531 * Prepare for power down command to fw. This command would
1532 * take HW out of D0-standby and prepare it for D3 state.
1533 *
1534 * Currently FW does not support event notification for this
1535 * event. Therefore, skip waiting for it. Just wait a fixed
1536 * 100ms
1537 */
1538 IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n");
1539
1540 err = ipw2100_hw_send_command(priv, &cmd);
1541 if (err)
Jiri Benc797b4f72005-08-25 20:03:27 -04001542 printk(KERN_WARNING DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06001543 "%s: Power down command failed: Error %d\n",
1544 priv->net_dev->name, err);
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001545 else
1546 schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY);
James Ketrenos2c86c272005-03-23 17:32:29 -06001547 }
1548
1549 priv->status &= ~STATUS_ENABLED;
1550
1551 /*
1552 * Set GPIO 3 writable by FW; GPIO 1 writable
1553 * by driver and enable clock
1554 */
1555 ipw2100_hw_set_gpio(priv);
1556
1557 /*
1558 * Power down adapter. Sequence:
1559 * 1. Stop master assert (RESET_REG[9]=1)
1560 * 2. Wait for stop master (RESET_REG[8]==1)
1561 * 3. S/w reset assert (RESET_REG[7] = 1)
1562 */
1563
1564 /* Stop master assert */
1565 write_register(priv->net_dev, IPW_REG_RESET_REG,
1566 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
1567
1568 /* wait stop master not more than 50 usec.
1569 * Otherwise return error. */
1570 for (i = 5; i > 0; i--) {
1571 udelay(10);
1572
1573 /* Check master stop bit */
1574 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
1575
1576 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
1577 break;
1578 }
1579
1580 if (i == 0)
Jiri Benc797b4f72005-08-25 20:03:27 -04001581 printk(KERN_WARNING DRV_NAME
James Ketrenos2c86c272005-03-23 17:32:29 -06001582 ": %s: Could now power down adapter.\n",
1583 priv->net_dev->name);
1584
1585 /* assert s/w reset */
1586 write_register(priv->net_dev, IPW_REG_RESET_REG,
1587 IPW_AUX_HOST_RESET_REG_SW_RESET);
1588
1589 priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING);
1590
1591 return 0;
1592}
1593
James Ketrenos2c86c272005-03-23 17:32:29 -06001594static int ipw2100_disable_adapter(struct ipw2100_priv *priv)
1595{
1596 struct host_command cmd = {
1597 .host_command = CARD_DISABLE,
1598 .host_command_sequence = 0,
1599 .host_command_length = 0
1600 };
1601 int err = 0;
1602
1603 IPW_DEBUG_HC("CARD_DISABLE\n");
1604
1605 if (!(priv->status & STATUS_ENABLED))
1606 return 0;
1607
1608 /* Make sure we clear the associated state */
1609 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1610
1611 if (!priv->stop_hang_check) {
1612 priv->stop_hang_check = 1;
1613 cancel_delayed_work(&priv->hang_check);
1614 }
1615
Ingo Molnar752e3772006-02-28 07:20:54 +08001616 mutex_lock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001617
1618 err = ipw2100_hw_send_command(priv, &cmd);
1619 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001620 printk(KERN_WARNING DRV_NAME
1621 ": exit - failed to send CARD_DISABLE command\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06001622 goto fail_up;
1623 }
1624
1625 err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED);
1626 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001627 printk(KERN_WARNING DRV_NAME
1628 ": exit - card failed to change to DISABLED\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06001629 goto fail_up;
1630 }
1631
1632 IPW_DEBUG_INFO("TODO: implement scan state machine\n");
1633
James Ketrenosee8e3652005-09-14 09:47:29 -05001634 fail_up:
Ingo Molnar752e3772006-02-28 07:20:54 +08001635 mutex_unlock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001636 return err;
1637}
1638
Jiri Bencc4aee8c2005-08-25 20:04:43 -04001639static int ipw2100_set_scan_options(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06001640{
1641 struct host_command cmd = {
1642 .host_command = SET_SCAN_OPTIONS,
1643 .host_command_sequence = 0,
1644 .host_command_length = 8
1645 };
1646 int err;
1647
1648 IPW_DEBUG_INFO("enter\n");
1649
1650 IPW_DEBUG_SCAN("setting scan options\n");
1651
1652 cmd.host_command_parameters[0] = 0;
1653
1654 if (!(priv->config & CFG_ASSOCIATE))
1655 cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE;
25b645b2005-07-12 15:45:30 -05001656 if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled)
James Ketrenos2c86c272005-03-23 17:32:29 -06001657 cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL;
1658 if (priv->config & CFG_PASSIVE_SCAN)
1659 cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE;
1660
1661 cmd.host_command_parameters[1] = priv->channel_mask;
1662
1663 err = ipw2100_hw_send_command(priv, &cmd);
1664
1665 IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n",
1666 cmd.host_command_parameters[0]);
1667
1668 return err;
1669}
1670
Jiri Bencc4aee8c2005-08-25 20:04:43 -04001671static int ipw2100_start_scan(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06001672{
1673 struct host_command cmd = {
1674 .host_command = BROADCAST_SCAN,
1675 .host_command_sequence = 0,
1676 .host_command_length = 4
1677 };
1678 int err;
1679
1680 IPW_DEBUG_HC("START_SCAN\n");
1681
1682 cmd.host_command_parameters[0] = 0;
1683
1684 /* No scanning if in monitor mode */
1685 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
1686 return 1;
1687
1688 if (priv->status & STATUS_SCANNING) {
1689 IPW_DEBUG_SCAN("Scan requested while already in scan...\n");
1690 return 0;
1691 }
1692
1693 IPW_DEBUG_INFO("enter\n");
1694
1695 /* Not clearing here; doing so makes iwlist always return nothing...
1696 *
1697 * We should modify the table logic to use aging tables vs. clearing
1698 * the table on each scan start.
1699 */
1700 IPW_DEBUG_SCAN("starting scan\n");
1701
1702 priv->status |= STATUS_SCANNING;
1703 err = ipw2100_hw_send_command(priv, &cmd);
1704 if (err)
1705 priv->status &= ~STATUS_SCANNING;
1706
1707 IPW_DEBUG_INFO("exit\n");
1708
1709 return err;
1710}
1711
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04001712static const struct libipw_geo ipw_geos[] = {
Zhu Yibe6b3b12006-01-24 13:49:08 +08001713 { /* Restricted */
1714 "---",
1715 .bg_channels = 14,
1716 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
1717 {2427, 4}, {2432, 5}, {2437, 6},
1718 {2442, 7}, {2447, 8}, {2452, 9},
1719 {2457, 10}, {2462, 11}, {2467, 12},
1720 {2472, 13}, {2484, 14}},
1721 },
1722};
1723
James Ketrenos2c86c272005-03-23 17:32:29 -06001724static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
1725{
1726 unsigned long flags;
1727 int rc = 0;
1728 u32 lock;
1729 u32 ord_len = sizeof(lock);
1730
Dan Williamsc3d72b92009-02-11 13:26:06 -05001731 /* Age scan list entries found before suspend */
1732 if (priv->suspend_time) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04001733 libipw_networks_age(priv->ieee, priv->suspend_time);
Dan Williamsc3d72b92009-02-11 13:26:06 -05001734 priv->suspend_time = 0;
1735 }
1736
1737 /* Quiet if manually disabled. */
James Ketrenos2c86c272005-03-23 17:32:29 -06001738 if (priv->status & STATUS_RF_KILL_SW) {
1739 IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "
1740 "switch\n", priv->net_dev->name);
1741 return 0;
1742 }
1743
Arjan van de Ven5c875792006-09-30 23:27:17 -07001744 /* the ipw2100 hardware really doesn't want power management delays
1745 * longer than 175usec
1746 */
James Bottomley82f68252010-07-05 22:53:06 +02001747 pm_qos_update_request(&ipw2100_pm_qos_req, 175);
Arjan van de Ven5c875792006-09-30 23:27:17 -07001748
James Ketrenos2c86c272005-03-23 17:32:29 -06001749 /* If the interrupt is enabled, turn it off... */
1750 spin_lock_irqsave(&priv->low_lock, flags);
1751 ipw2100_disable_interrupts(priv);
1752
1753 /* Reset any fatal_error conditions */
1754 ipw2100_reset_fatalerror(priv);
1755 spin_unlock_irqrestore(&priv->low_lock, flags);
1756
1757 if (priv->status & STATUS_POWERED ||
1758 (priv->status & STATUS_RESET_PENDING)) {
1759 /* Power cycle the card ... */
1760 if (ipw2100_power_cycle_adapter(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001761 printk(KERN_WARNING DRV_NAME
1762 ": %s: Could not cycle adapter.\n",
1763 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001764 rc = 1;
1765 goto exit;
1766 }
1767 } else
1768 priv->status |= STATUS_POWERED;
1769
Pavel Machek8724a112005-06-20 14:28:43 -07001770 /* Load the firmware, start the clocks, etc. */
James Ketrenos2c86c272005-03-23 17:32:29 -06001771 if (ipw2100_start_adapter(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001772 printk(KERN_ERR DRV_NAME
1773 ": %s: Failed to start the firmware.\n",
1774 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001775 rc = 1;
1776 goto exit;
1777 }
1778
1779 ipw2100_initialize_ordinals(priv);
1780
1781 /* Determine capabilities of this particular HW configuration */
1782 if (ipw2100_get_hw_features(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001783 printk(KERN_ERR DRV_NAME
1784 ": %s: Failed to determine HW features.\n",
1785 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001786 rc = 1;
1787 goto exit;
1788 }
1789
Zhu Yibe6b3b12006-01-24 13:49:08 +08001790 /* Initialize the geo */
Stanislav Yakovlev9c033be2012-11-15 03:07:47 +00001791 libipw_set_geo(priv->ieee, &ipw_geos[0]);
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04001792 priv->ieee->freq_band = LIBIPW_24GHZ_BAND;
Zhu Yibe6b3b12006-01-24 13:49:08 +08001793
James Ketrenos2c86c272005-03-23 17:32:29 -06001794 lock = LOCK_NONE;
1795 if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001796 printk(KERN_ERR DRV_NAME
1797 ": %s: Failed to clear ordinal lock.\n",
1798 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001799 rc = 1;
1800 goto exit;
1801 }
1802
1803 priv->status &= ~STATUS_SCANNING;
1804
1805 if (rf_kill_active(priv)) {
1806 printk(KERN_INFO "%s: Radio is disabled by RF switch.\n",
1807 priv->net_dev->name);
1808
1809 if (priv->stop_rf_kill) {
1810 priv->stop_rf_kill = 0;
Tejun Heobcb6d912011-01-26 12:12:50 +01001811 schedule_delayed_work(&priv->rf_kill,
1812 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06001813 }
1814
1815 deferred = 1;
1816 }
1817
1818 /* Turn on the interrupt so that commands can be processed */
1819 ipw2100_enable_interrupts(priv);
1820
1821 /* Send all of the commands that must be sent prior to
1822 * HOST_COMPLETE */
1823 if (ipw2100_adapter_setup(priv)) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001824 printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001825 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001826 rc = 1;
1827 goto exit;
1828 }
1829
1830 if (!deferred) {
1831 /* Enable the adapter - sends HOST_COMPLETE */
1832 if (ipw2100_enable_adapter(priv)) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001833 printk(KERN_ERR DRV_NAME ": "
James Ketrenosee8e3652005-09-14 09:47:29 -05001834 "%s: failed in call to enable adapter.\n",
1835 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001836 ipw2100_hw_stop_adapter(priv);
1837 rc = 1;
1838 goto exit;
1839 }
1840
James Ketrenos2c86c272005-03-23 17:32:29 -06001841 /* Start a scan . . . */
1842 ipw2100_set_scan_options(priv);
1843 ipw2100_start_scan(priv);
1844 }
1845
James Ketrenosee8e3652005-09-14 09:47:29 -05001846 exit:
James Ketrenos2c86c272005-03-23 17:32:29 -06001847 return rc;
1848}
1849
James Ketrenos2c86c272005-03-23 17:32:29 -06001850static void ipw2100_down(struct ipw2100_priv *priv)
1851{
1852 unsigned long flags;
1853 union iwreq_data wrqu = {
1854 .ap_addr = {
James Ketrenosee8e3652005-09-14 09:47:29 -05001855 .sa_family = ARPHRD_ETHER}
James Ketrenos2c86c272005-03-23 17:32:29 -06001856 };
1857 int associated = priv->status & STATUS_ASSOCIATED;
1858
1859 /* Kill the RF switch timer */
1860 if (!priv->stop_rf_kill) {
1861 priv->stop_rf_kill = 1;
1862 cancel_delayed_work(&priv->rf_kill);
1863 }
1864
Nick Andrew44072452009-01-03 18:52:40 +11001865 /* Kill the firmware hang check timer */
James Ketrenos2c86c272005-03-23 17:32:29 -06001866 if (!priv->stop_hang_check) {
1867 priv->stop_hang_check = 1;
1868 cancel_delayed_work(&priv->hang_check);
1869 }
1870
1871 /* Kill any pending resets */
1872 if (priv->status & STATUS_RESET_PENDING)
1873 cancel_delayed_work(&priv->reset_work);
1874
1875 /* Make sure the interrupt is on so that FW commands will be
1876 * processed correctly */
1877 spin_lock_irqsave(&priv->low_lock, flags);
1878 ipw2100_enable_interrupts(priv);
1879 spin_unlock_irqrestore(&priv->low_lock, flags);
1880
1881 if (ipw2100_hw_stop_adapter(priv))
Jiri Benc797b4f72005-08-25 20:03:27 -04001882 printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001883 priv->net_dev->name);
1884
1885 /* Do not disable the interrupt until _after_ we disable
1886 * the adaptor. Otherwise the CARD_DISABLE command will never
1887 * be ack'd by the firmware */
1888 spin_lock_irqsave(&priv->low_lock, flags);
1889 ipw2100_disable_interrupts(priv);
1890 spin_unlock_irqrestore(&priv->low_lock, flags);
1891
James Bottomley82f68252010-07-05 22:53:06 +02001892 pm_qos_update_request(&ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
Arjan van de Ven5c875792006-09-30 23:27:17 -07001893
James Ketrenos2c86c272005-03-23 17:32:29 -06001894 /* We have to signal any supplicant if we are disassociating */
1895 if (associated)
1896 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
1897
1898 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1899 netif_carrier_off(priv->net_dev);
1900 netif_stop_queue(priv->net_dev);
1901}
1902
Stanislaw Gruszka7cabafc2011-09-14 16:47:50 +02001903static int ipw2100_wdev_init(struct net_device *dev)
1904{
1905 struct ipw2100_priv *priv = libipw_priv(dev);
Matthew Garrettc26409a2009-11-11 14:36:30 -05001906 const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
1907 struct wireless_dev *wdev = &priv->ieee->wdev;
Matthew Garrettc26409a2009-11-11 14:36:30 -05001908 int i;
1909
Matthew Garrettc26409a2009-11-11 14:36:30 -05001910 memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
1911
1912 /* fill-out priv->ieee->bg_band */
1913 if (geo->bg_channels) {
1914 struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
1915
1916 bg_band->band = IEEE80211_BAND_2GHZ;
1917 bg_band->n_channels = geo->bg_channels;
Joe Perchesbaeb2ff2010-08-11 07:02:48 +00001918 bg_band->channels = kcalloc(geo->bg_channels,
1919 sizeof(struct ieee80211_channel),
1920 GFP_KERNEL);
Christoph Fritz93c05842010-08-03 12:54:20 +02001921 if (!bg_band->channels) {
1922 ipw2100_down(priv);
1923 return -ENOMEM;
1924 }
Matthew Garrettc26409a2009-11-11 14:36:30 -05001925 /* translate geo->bg to bg_band.channels */
1926 for (i = 0; i < geo->bg_channels; i++) {
1927 bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
1928 bg_band->channels[i].center_freq = geo->bg[i].freq;
1929 bg_band->channels[i].hw_value = geo->bg[i].channel;
1930 bg_band->channels[i].max_power = geo->bg[i].max_power;
1931 if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
1932 bg_band->channels[i].flags |=
1933 IEEE80211_CHAN_PASSIVE_SCAN;
1934 if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
1935 bg_band->channels[i].flags |=
1936 IEEE80211_CHAN_NO_IBSS;
1937 if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
1938 bg_band->channels[i].flags |=
1939 IEEE80211_CHAN_RADAR;
1940 /* No equivalent for LIBIPW_CH_80211H_RULES,
1941 LIBIPW_CH_UNIFORM_SPREADING, or
1942 LIBIPW_CH_B_ONLY... */
1943 }
1944 /* point at bitrate info */
1945 bg_band->bitrates = ipw2100_bg_rates;
1946 bg_band->n_bitrates = RATE_COUNT;
1947
1948 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band;
1949 }
1950
Stanislav Yakovleva141e6a2012-04-10 21:44:47 -04001951 wdev->wiphy->cipher_suites = ipw_cipher_suites;
1952 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites);
1953
Matthew Garrettc26409a2009-11-11 14:36:30 -05001954 set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
Ben Hutchingse19d8baf2012-01-22 03:11:12 +00001955 if (wiphy_register(wdev->wiphy))
Matthew Garrettc26409a2009-11-11 14:36:30 -05001956 return -EIO;
Matthew Garrettc26409a2009-11-11 14:36:30 -05001957 return 0;
1958}
1959
David Howellsc4028952006-11-22 14:57:56 +00001960static void ipw2100_reset_adapter(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06001961{
David Howellsc4028952006-11-22 14:57:56 +00001962 struct ipw2100_priv *priv =
1963 container_of(work, struct ipw2100_priv, reset_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06001964 unsigned long flags;
1965 union iwreq_data wrqu = {
1966 .ap_addr = {
James Ketrenosee8e3652005-09-14 09:47:29 -05001967 .sa_family = ARPHRD_ETHER}
James Ketrenos2c86c272005-03-23 17:32:29 -06001968 };
1969 int associated = priv->status & STATUS_ASSOCIATED;
1970
1971 spin_lock_irqsave(&priv->low_lock, flags);
Zhu Yia1e695a2005-07-04 14:06:00 +08001972 IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001973 priv->resets++;
1974 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1975 priv->status |= STATUS_SECURITY_UPDATED;
1976
1977 /* Force a power cycle even if interface hasn't been opened
1978 * yet */
1979 cancel_delayed_work(&priv->reset_work);
1980 priv->status |= STATUS_RESET_PENDING;
1981 spin_unlock_irqrestore(&priv->low_lock, flags);
1982
Ingo Molnar752e3772006-02-28 07:20:54 +08001983 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001984 /* stop timed checks so that they don't interfere with reset */
1985 priv->stop_hang_check = 1;
1986 cancel_delayed_work(&priv->hang_check);
1987
1988 /* We have to signal any supplicant if we are disassociating */
1989 if (associated)
1990 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
1991
1992 ipw2100_up(priv, 0);
Ingo Molnar752e3772006-02-28 07:20:54 +08001993 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001994
1995}
1996
James Ketrenos2c86c272005-03-23 17:32:29 -06001997static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
1998{
1999
2000#define MAC_ASSOCIATION_READ_DELAY (HZ)
Hannes Ederb9da9e92009-02-14 11:50:26 +00002001 int ret;
2002 unsigned int len, essid_len;
James Ketrenos2c86c272005-03-23 17:32:29 -06002003 char essid[IW_ESSID_MAX_SIZE];
2004 u32 txrate;
2005 u32 chan;
2006 char *txratename;
James Ketrenosee8e3652005-09-14 09:47:29 -05002007 u8 bssid[ETH_ALEN];
John W. Linville9387b7c2008-09-30 20:59:05 -04002008 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002009
2010 /*
2011 * TBD: BSSID is usually 00:00:00:00:00:00 here and not
2012 * an actual MAC of the AP. Seems like FW sets this
2013 * address too late. Read it later and expose through
2014 * /proc or schedule a later task to query and update
2015 */
2016
2017 essid_len = IW_ESSID_MAX_SIZE;
2018 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID,
2019 essid, &essid_len);
2020 if (ret) {
2021 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002022 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06002023 return;
2024 }
2025
2026 len = sizeof(u32);
James Ketrenosee8e3652005-09-14 09:47:29 -05002027 ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002028 if (ret) {
2029 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002030 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06002031 return;
2032 }
2033
2034 len = sizeof(u32);
2035 ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len);
2036 if (ret) {
2037 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002038 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06002039 return;
2040 }
2041 len = ETH_ALEN;
Julia Lawall7b4e6cf2012-08-19 11:49:58 +02002042 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, bssid,
2043 &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002044 if (ret) {
2045 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002046 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06002047 return;
2048 }
2049 memcpy(priv->ieee->bssid, bssid, ETH_ALEN);
2050
James Ketrenos2c86c272005-03-23 17:32:29 -06002051 switch (txrate) {
2052 case TX_RATE_1_MBIT:
2053 txratename = "1Mbps";
2054 break;
2055 case TX_RATE_2_MBIT:
2056 txratename = "2Mbsp";
2057 break;
2058 case TX_RATE_5_5_MBIT:
2059 txratename = "5.5Mbps";
2060 break;
2061 case TX_RATE_11_MBIT:
2062 txratename = "11Mbps";
2063 break;
2064 default:
2065 IPW_DEBUG_INFO("Unknown rate: %d\n", txrate);
2066 txratename = "unknown rate";
2067 break;
2068 }
2069
Johannes Berge1749612008-10-27 15:59:26 -07002070 IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04002071 priv->net_dev->name, print_ssid(ssid, essid, essid_len),
Johannes Berge1749612008-10-27 15:59:26 -07002072 txratename, chan, bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002073
2074 /* now we copy read ssid into dev */
2075 if (!(priv->config & CFG_STATIC_ESSID)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002076 priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002077 memcpy(priv->essid, essid, priv->essid_len);
2078 }
2079 priv->channel = chan;
2080 memcpy(priv->bssid, bssid, ETH_ALEN);
2081
2082 priv->status |= STATUS_ASSOCIATING;
2083 priv->connect_start = get_seconds();
2084
Tejun Heobcb6d912011-01-26 12:12:50 +01002085 schedule_delayed_work(&priv->wx_event_work, HZ / 10);
James Ketrenos2c86c272005-03-23 17:32:29 -06002086}
2087
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002088static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
2089 int length, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06002090{
2091 int ssid_len = min(length, IW_ESSID_MAX_SIZE);
2092 struct host_command cmd = {
2093 .host_command = SSID,
2094 .host_command_sequence = 0,
2095 .host_command_length = ssid_len
2096 };
2097 int err;
John W. Linville9387b7c2008-09-30 20:59:05 -04002098 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002099
John W. Linville9387b7c2008-09-30 20:59:05 -04002100 IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len));
James Ketrenos2c86c272005-03-23 17:32:29 -06002101
2102 if (ssid_len)
James Ketrenos82328352005-08-24 22:33:31 -05002103 memcpy(cmd.host_command_parameters, essid, ssid_len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002104
2105 if (!batch_mode) {
2106 err = ipw2100_disable_adapter(priv);
2107 if (err)
2108 return err;
2109 }
2110
2111 /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to
2112 * disable auto association -- so we cheat by setting a bogus SSID */
2113 if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) {
2114 int i;
James Ketrenosee8e3652005-09-14 09:47:29 -05002115 u8 *bogus = (u8 *) cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06002116 for (i = 0; i < IW_ESSID_MAX_SIZE; i++)
2117 bogus[i] = 0x18 + i;
2118 cmd.host_command_length = IW_ESSID_MAX_SIZE;
2119 }
2120
2121 /* NOTE: We always send the SSID command even if the provided ESSID is
2122 * the same as what we currently think is set. */
2123
2124 err = ipw2100_hw_send_command(priv, &cmd);
2125 if (!err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002126 memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002127 memcpy(priv->essid, essid, ssid_len);
2128 priv->essid_len = ssid_len;
2129 }
2130
2131 if (!batch_mode) {
2132 if (ipw2100_enable_adapter(priv))
2133 err = -EIO;
2134 }
2135
2136 return err;
2137}
2138
2139static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
2140{
John W. Linville9387b7c2008-09-30 20:59:05 -04002141 DECLARE_SSID_BUF(ssid);
2142
James Ketrenos2c86c272005-03-23 17:32:29 -06002143 IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
Frans Pop9fd1ea42010-03-24 19:46:31 +01002144 "disassociated: '%s' %pM\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04002145 print_ssid(ssid, priv->essid, priv->essid_len),
Johannes Berge1749612008-10-27 15:59:26 -07002146 priv->bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002147
2148 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
2149
2150 if (priv->status & STATUS_STOPPING) {
2151 IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n");
2152 return;
2153 }
2154
2155 memset(priv->bssid, 0, ETH_ALEN);
2156 memset(priv->ieee->bssid, 0, ETH_ALEN);
2157
2158 netif_carrier_off(priv->net_dev);
2159 netif_stop_queue(priv->net_dev);
2160
2161 if (!(priv->status & STATUS_RUNNING))
2162 return;
2163
2164 if (priv->status & STATUS_SECURITY_UPDATED)
Tejun Heobcb6d912011-01-26 12:12:50 +01002165 schedule_delayed_work(&priv->security_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06002166
Tejun Heobcb6d912011-01-26 12:12:50 +01002167 schedule_delayed_work(&priv->wx_event_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06002168}
2169
2170static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
2171{
2172 IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002173 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002174
2175 /* RF_KILL is now enabled (else we wouldn't be here) */
Matthew Garrettc26409a2009-11-11 14:36:30 -05002176 wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
James Ketrenos2c86c272005-03-23 17:32:29 -06002177 priv->status |= STATUS_RF_KILL_HW;
2178
James Ketrenos2c86c272005-03-23 17:32:29 -06002179 /* Make sure the RF Kill check timer is running */
2180 priv->stop_rf_kill = 0;
Tejun Heo41f63c52012-08-03 10:30:47 -07002181 mod_delayed_work(system_wq, &priv->rf_kill, round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06002182}
2183
Dan Williamsd20c6782007-10-10 12:28:07 -04002184static void send_scan_event(void *data)
2185{
2186 struct ipw2100_priv *priv = data;
2187 union iwreq_data wrqu;
2188
2189 wrqu.data.length = 0;
2190 wrqu.data.flags = 0;
2191 wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
2192}
2193
2194static void ipw2100_scan_event_later(struct work_struct *work)
2195{
2196 send_scan_event(container_of(work, struct ipw2100_priv,
2197 scan_event_later.work));
2198}
2199
2200static void ipw2100_scan_event_now(struct work_struct *work)
2201{
2202 send_scan_event(container_of(work, struct ipw2100_priv,
2203 scan_event_now));
2204}
2205
James Ketrenos2c86c272005-03-23 17:32:29 -06002206static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
2207{
2208 IPW_DEBUG_SCAN("scan complete\n");
2209 /* Age the scan results... */
2210 priv->ieee->scans++;
2211 priv->status &= ~STATUS_SCANNING;
Dan Williamsd20c6782007-10-10 12:28:07 -04002212
2213 /* Only userspace-requested scan completion events go out immediately */
2214 if (!priv->user_requested_scan) {
2215 if (!delayed_work_pending(&priv->scan_event_later))
Tejun Heobcb6d912011-01-26 12:12:50 +01002216 schedule_delayed_work(&priv->scan_event_later,
2217 round_jiffies_relative(msecs_to_jiffies(4000)));
Dan Williamsd20c6782007-10-10 12:28:07 -04002218 } else {
2219 priv->user_requested_scan = 0;
2220 cancel_delayed_work(&priv->scan_event_later);
Tejun Heobcb6d912011-01-26 12:12:50 +01002221 schedule_work(&priv->scan_event_now);
Dan Williamsd20c6782007-10-10 12:28:07 -04002222 }
James Ketrenos2c86c272005-03-23 17:32:29 -06002223}
2224
Brice Goglin0f52bf92005-12-01 01:41:46 -08002225#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002226#define IPW2100_HANDLER(v, f) { v, f, # v }
2227struct ipw2100_status_indicator {
2228 int status;
James Ketrenosee8e3652005-09-14 09:47:29 -05002229 void (*cb) (struct ipw2100_priv * priv, u32 status);
James Ketrenos2c86c272005-03-23 17:32:29 -06002230 char *name;
2231};
2232#else
2233#define IPW2100_HANDLER(v, f) { v, f }
2234struct ipw2100_status_indicator {
2235 int status;
James Ketrenosee8e3652005-09-14 09:47:29 -05002236 void (*cb) (struct ipw2100_priv * priv, u32 status);
James Ketrenos2c86c272005-03-23 17:32:29 -06002237};
Brice Goglin0f52bf92005-12-01 01:41:46 -08002238#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -06002239
2240static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
2241{
2242 IPW_DEBUG_SCAN("Scanning...\n");
2243 priv->status |= STATUS_SCANNING;
2244}
2245
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002246static const struct ipw2100_status_indicator status_handlers[] = {
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002247 IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL),
2248 IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002249 IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated),
2250 IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002251 IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002252 IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002253 IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL),
2254 IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002255 IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002256 IPW2100_HANDLER(IPW_STATE_DISABLED, NULL),
2257 IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002258 IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002259 IPW2100_HANDLER(-1, NULL)
James Ketrenos2c86c272005-03-23 17:32:29 -06002260};
2261
James Ketrenos2c86c272005-03-23 17:32:29 -06002262static void isr_status_change(struct ipw2100_priv *priv, int status)
2263{
2264 int i;
2265
2266 if (status == IPW_STATE_SCANNING &&
2267 priv->status & STATUS_ASSOCIATED &&
2268 !(priv->status & STATUS_SCANNING)) {
2269 IPW_DEBUG_INFO("Scan detected while associated, with "
2270 "no scan request. Restarting firmware.\n");
2271
2272 /* Wake up any sleeping jobs */
2273 schedule_reset(priv);
2274 }
2275
2276 for (i = 0; status_handlers[i].status != -1; i++) {
2277 if (status == status_handlers[i].status) {
2278 IPW_DEBUG_NOTIF("Status change: %s\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002279 status_handlers[i].name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002280 if (status_handlers[i].cb)
2281 status_handlers[i].cb(priv, status);
2282 priv->wstats.status = status;
2283 return;
2284 }
2285 }
2286
2287 IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);
2288}
2289
James Ketrenosee8e3652005-09-14 09:47:29 -05002290static void isr_rx_complete_command(struct ipw2100_priv *priv,
2291 struct ipw2100_cmd_header *cmd)
James Ketrenos2c86c272005-03-23 17:32:29 -06002292{
Brice Goglin0f52bf92005-12-01 01:41:46 -08002293#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002294 if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
2295 IPW_DEBUG_HC("Command completed '%s (%d)'\n",
2296 command_types[cmd->host_command_reg],
2297 cmd->host_command_reg);
2298 }
2299#endif
2300 if (cmd->host_command_reg == HOST_COMPLETE)
2301 priv->status |= STATUS_ENABLED;
2302
2303 if (cmd->host_command_reg == CARD_DISABLE)
2304 priv->status &= ~STATUS_ENABLED;
2305
2306 priv->status &= ~STATUS_CMD_ACTIVE;
2307
2308 wake_up_interruptible(&priv->wait_command_queue);
2309}
2310
Brice Goglin0f52bf92005-12-01 01:41:46 -08002311#ifdef CONFIG_IPW2100_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002312static const char *frame_types[] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06002313 "COMMAND_STATUS_VAL",
2314 "STATUS_CHANGE_VAL",
2315 "P80211_DATA_VAL",
2316 "P8023_DATA_VAL",
2317 "HOST_NOTIFICATION_VAL"
2318};
2319#endif
2320
Arjan van de Ven858119e2006-01-14 13:20:43 -08002321static int ipw2100_alloc_skb(struct ipw2100_priv *priv,
James Ketrenosee8e3652005-09-14 09:47:29 -05002322 struct ipw2100_rx_packet *packet)
James Ketrenos2c86c272005-03-23 17:32:29 -06002323{
2324 packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
2325 if (!packet->skb)
2326 return -ENOMEM;
2327
2328 packet->rxp = (struct ipw2100_rx *)packet->skb->data;
2329 packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data,
2330 sizeof(struct ipw2100_rx),
2331 PCI_DMA_FROMDEVICE);
2332 /* NOTE: pci_map_single does not return an error code, and 0 is a valid
2333 * dma_addr */
2334
2335 return 0;
2336}
2337
James Ketrenos2c86c272005-03-23 17:32:29 -06002338#define SEARCH_ERROR 0xffffffff
2339#define SEARCH_FAIL 0xfffffffe
2340#define SEARCH_SUCCESS 0xfffffff0
2341#define SEARCH_DISCARD 0
2342#define SEARCH_SNAPSHOT 1
2343
2344#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
Zhu Yi3c5eca52006-01-24 13:49:26 +08002345static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
2346{
2347 int i;
2348 if (!priv->snapshot[0])
2349 return;
2350 for (i = 0; i < 0x30; i++)
2351 kfree(priv->snapshot[i]);
2352 priv->snapshot[0] = NULL;
2353}
2354
Robert P. J. Dayae800312007-01-31 02:39:40 -05002355#ifdef IPW2100_DEBUG_C3
Arjan van de Ven858119e2006-01-14 13:20:43 -08002356static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002357{
2358 int i;
2359 if (priv->snapshot[0])
2360 return 1;
2361 for (i = 0; i < 0x30; i++) {
Robert P. J. Day5cbded52006-12-13 00:35:56 -08002362 priv->snapshot[i] = kmalloc(0x1000, GFP_ATOMIC);
James Ketrenos2c86c272005-03-23 17:32:29 -06002363 if (!priv->snapshot[i]) {
2364 IPW_DEBUG_INFO("%s: Error allocating snapshot "
James Ketrenosee8e3652005-09-14 09:47:29 -05002365 "buffer %d\n", priv->net_dev->name, i);
James Ketrenos2c86c272005-03-23 17:32:29 -06002366 while (i > 0)
2367 kfree(priv->snapshot[--i]);
2368 priv->snapshot[0] = NULL;
2369 return 0;
2370 }
2371 }
2372
2373 return 1;
2374}
2375
Arjan van de Ven858119e2006-01-14 13:20:43 -08002376static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
James Ketrenos2c86c272005-03-23 17:32:29 -06002377 size_t len, int mode)
2378{
2379 u32 i, j;
2380 u32 tmp;
2381 u8 *s, *d;
2382 u32 ret;
2383
2384 s = in_buf;
2385 if (mode == SEARCH_SNAPSHOT) {
2386 if (!ipw2100_snapshot_alloc(priv))
2387 mode = SEARCH_DISCARD;
2388 }
2389
2390 for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) {
2391 read_nic_dword(priv->net_dev, i, &tmp);
2392 if (mode == SEARCH_SNAPSHOT)
James Ketrenosee8e3652005-09-14 09:47:29 -05002393 *(u32 *) SNAPSHOT_ADDR(i) = tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06002394 if (ret == SEARCH_FAIL) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002395 d = (u8 *) & tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06002396 for (j = 0; j < 4; j++) {
2397 if (*s != *d) {
2398 s = in_buf;
2399 continue;
2400 }
2401
2402 s++;
2403 d++;
2404
2405 if ((s - in_buf) == len)
2406 ret = (i + j) - len + 1;
2407 }
2408 } else if (mode == SEARCH_DISCARD)
2409 return ret;
2410 }
2411
2412 return ret;
2413}
Zhu Yi3c5eca52006-01-24 13:49:26 +08002414#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06002415
2416/*
2417 *
2418 * 0) Disconnect the SKB from the firmware (just unmap)
2419 * 1) Pack the ETH header into the SKB
2420 * 2) Pass the SKB to the network stack
2421 *
2422 * When packet is provided by the firmware, it contains the following:
2423 *
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002424 * . libipw_hdr
2425 * . libipw_snap_hdr
James Ketrenos2c86c272005-03-23 17:32:29 -06002426 *
2427 * The size of the constructed ethernet
2428 *
2429 */
Robert P. J. Dayae800312007-01-31 02:39:40 -05002430#ifdef IPW2100_RX_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002431static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
James Ketrenos2c86c272005-03-23 17:32:29 -06002432#endif
2433
Arjan van de Ven858119e2006-01-14 13:20:43 -08002434static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
James Ketrenos2c86c272005-03-23 17:32:29 -06002435{
Robert P. J. Dayae800312007-01-31 02:39:40 -05002436#ifdef IPW2100_DEBUG_C3
James Ketrenos2c86c272005-03-23 17:32:29 -06002437 struct ipw2100_status *status = &priv->status_queue.drv[i];
2438 u32 match, reg;
2439 int j;
2440#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06002441
Zhu Yia1e695a2005-07-04 14:06:00 +08002442 IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n",
2443 i * sizeof(struct ipw2100_status));
James Ketrenos2c86c272005-03-23 17:32:29 -06002444
Robert P. J. Dayae800312007-01-31 02:39:40 -05002445#ifdef IPW2100_DEBUG_C3
Nick Andrew877d0312009-01-26 11:06:57 +01002446 /* Halt the firmware so we can get a good image */
James Ketrenos2c86c272005-03-23 17:32:29 -06002447 write_register(priv->net_dev, IPW_REG_RESET_REG,
2448 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
2449 j = 5;
2450 do {
2451 udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
2452 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
2453
2454 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
2455 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05002456 } while (j--);
James Ketrenos2c86c272005-03-23 17:32:29 -06002457
James Ketrenosee8e3652005-09-14 09:47:29 -05002458 match = ipw2100_match_buf(priv, (u8 *) status,
James Ketrenos2c86c272005-03-23 17:32:29 -06002459 sizeof(struct ipw2100_status),
2460 SEARCH_SNAPSHOT);
2461 if (match < SEARCH_SUCCESS)
2462 IPW_DEBUG_INFO("%s: DMA status match in Firmware at "
2463 "offset 0x%06X, length %d:\n",
2464 priv->net_dev->name, match,
2465 sizeof(struct ipw2100_status));
2466 else
2467 IPW_DEBUG_INFO("%s: No DMA status match in "
2468 "Firmware.\n", priv->net_dev->name);
2469
James Ketrenosee8e3652005-09-14 09:47:29 -05002470 printk_buf((u8 *) priv->status_queue.drv,
James Ketrenos2c86c272005-03-23 17:32:29 -06002471 sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);
2472#endif
2473
2474 priv->fatal_error = IPW2100_ERR_C3_CORRUPTION;
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002475 priv->net_dev->stats.rx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002476 schedule_reset(priv);
2477}
2478
Arjan van de Ven858119e2006-01-14 13:20:43 -08002479static void isr_rx(struct ipw2100_priv *priv, int i,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002480 struct libipw_rx_stats *stats)
James Ketrenos2c86c272005-03-23 17:32:29 -06002481{
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002482 struct net_device *dev = priv->net_dev;
James Ketrenos2c86c272005-03-23 17:32:29 -06002483 struct ipw2100_status *status = &priv->status_queue.drv[i];
2484 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
2485
2486 IPW_DEBUG_RX("Handler...\n");
2487
2488 if (unlikely(status->frame_size > skb_tailroom(packet->skb))) {
2489 IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
2490 " Dropping.\n",
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002491 dev->name,
James Ketrenos2c86c272005-03-23 17:32:29 -06002492 status->frame_size, skb_tailroom(packet->skb));
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002493 dev->stats.rx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002494 return;
2495 }
2496
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002497 if (unlikely(!netif_running(dev))) {
2498 dev->stats.rx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002499 priv->wstats.discard.misc++;
2500 IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
2501 return;
2502 }
James Ketrenos2c86c272005-03-23 17:32:29 -06002503
2504 if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
James Ketrenosee8e3652005-09-14 09:47:29 -05002505 !(priv->status & STATUS_ASSOCIATED))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002506 IPW_DEBUG_DROP("Dropping packet while not associated.\n");
2507 priv->wstats.discard.misc++;
2508 return;
2509 }
2510
James Ketrenos2c86c272005-03-23 17:32:29 -06002511 pci_unmap_single(priv->pci_dev,
2512 packet->dma_addr,
James Ketrenosee8e3652005-09-14 09:47:29 -05002513 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002514
2515 skb_put(packet->skb, status->frame_size);
2516
Robert P. J. Dayae800312007-01-31 02:39:40 -05002517#ifdef IPW2100_RX_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002518 /* Make a copy of the frame so we can dump it to the logs if
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002519 * libipw_rx fails */
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03002520 skb_copy_from_linear_data(packet->skb, packet_data,
2521 min_t(u32, status->frame_size,
2522 IPW_RX_NIC_BUFFER_LENGTH));
James Ketrenos2c86c272005-03-23 17:32:29 -06002523#endif
2524
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002525 if (!libipw_rx(priv->ieee, packet->skb, stats)) {
Robert P. J. Dayae800312007-01-31 02:39:40 -05002526#ifdef IPW2100_RX_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002527 IPW_DEBUG_DROP("%s: Non consumed packet:\n",
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002528 dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002529 printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
2530#endif
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002531 dev->stats.rx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002532
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002533 /* libipw_rx failed, so it didn't free the SKB */
James Ketrenos2c86c272005-03-23 17:32:29 -06002534 dev_kfree_skb_any(packet->skb);
2535 packet->skb = NULL;
2536 }
2537
2538 /* We need to allocate a new SKB and attach it to the RDB. */
2539 if (unlikely(ipw2100_alloc_skb(priv, packet))) {
Jiri Benc797b4f72005-08-25 20:03:27 -04002540 printk(KERN_WARNING DRV_NAME ": "
James Ketrenosee8e3652005-09-14 09:47:29 -05002541 "%s: Unable to allocate SKB onto RBD ring - disabling "
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002542 "adapter.\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002543 /* TODO: schedule adapter shutdown */
2544 IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
2545 }
2546
2547 /* Update the RDB entry */
2548 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
2549}
2550
Stefan Rompf15745a72006-02-21 18:36:17 +08002551#ifdef CONFIG_IPW2100_MONITOR
2552
2553static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002554 struct libipw_rx_stats *stats)
Stefan Rompf15745a72006-02-21 18:36:17 +08002555{
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002556 struct net_device *dev = priv->net_dev;
Stefan Rompf15745a72006-02-21 18:36:17 +08002557 struct ipw2100_status *status = &priv->status_queue.drv[i];
2558 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
2559
Stefan Rompf15745a72006-02-21 18:36:17 +08002560 /* Magic struct that slots into the radiotap header -- no reason
2561 * to build this manually element by element, we can write it much
2562 * more efficiently than we can parse it. ORDER MATTERS HERE */
2563 struct ipw_rt_hdr {
2564 struct ieee80211_radiotap_header rt_hdr;
2565 s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
2566 } *ipw_rt;
2567
Zhu Yicae16292006-02-21 18:41:14 +08002568 IPW_DEBUG_RX("Handler...\n");
2569
2570 if (unlikely(status->frame_size > skb_tailroom(packet->skb) -
2571 sizeof(struct ipw_rt_hdr))) {
Stefan Rompf15745a72006-02-21 18:36:17 +08002572 IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
2573 " Dropping.\n",
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002574 dev->name,
Zhu Yicae16292006-02-21 18:41:14 +08002575 status->frame_size,
2576 skb_tailroom(packet->skb));
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002577 dev->stats.rx_errors++;
Stefan Rompf15745a72006-02-21 18:36:17 +08002578 return;
2579 }
2580
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002581 if (unlikely(!netif_running(dev))) {
2582 dev->stats.rx_errors++;
Stefan Rompf15745a72006-02-21 18:36:17 +08002583 priv->wstats.discard.misc++;
2584 IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
2585 return;
2586 }
2587
2588 if (unlikely(priv->config & CFG_CRC_CHECK &&
2589 status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
2590 IPW_DEBUG_RX("CRC error in packet. Dropping.\n");
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002591 dev->stats.rx_errors++;
Stefan Rompf15745a72006-02-21 18:36:17 +08002592 return;
2593 }
2594
Zhu Yicae16292006-02-21 18:41:14 +08002595 pci_unmap_single(priv->pci_dev, packet->dma_addr,
Stefan Rompf15745a72006-02-21 18:36:17 +08002596 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
2597 memmove(packet->skb->data + sizeof(struct ipw_rt_hdr),
2598 packet->skb->data, status->frame_size);
2599
2600 ipw_rt = (struct ipw_rt_hdr *) packet->skb->data;
2601
2602 ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
2603 ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
Al Viro1edd3a52007-12-21 00:15:18 -05002604 ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total hdr+data */
Stefan Rompf15745a72006-02-21 18:36:17 +08002605
Al Viro1edd3a52007-12-21 00:15:18 -05002606 ipw_rt->rt_hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
Stefan Rompf15745a72006-02-21 18:36:17 +08002607
2608 ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM;
2609
2610 skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr));
2611
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002612 if (!libipw_rx(priv->ieee, packet->skb, stats)) {
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002613 dev->stats.rx_errors++;
Stefan Rompf15745a72006-02-21 18:36:17 +08002614
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002615 /* libipw_rx failed, so it didn't free the SKB */
Stefan Rompf15745a72006-02-21 18:36:17 +08002616 dev_kfree_skb_any(packet->skb);
2617 packet->skb = NULL;
2618 }
2619
2620 /* We need to allocate a new SKB and attach it to the RDB. */
2621 if (unlikely(ipw2100_alloc_skb(priv, packet))) {
2622 IPW_DEBUG_WARNING(
2623 "%s: Unable to allocate SKB onto RBD ring - disabling "
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002624 "adapter.\n", dev->name);
Stefan Rompf15745a72006-02-21 18:36:17 +08002625 /* TODO: schedule adapter shutdown */
2626 IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
2627 }
2628
2629 /* Update the RDB entry */
2630 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
2631}
2632
2633#endif
2634
Arjan van de Ven858119e2006-01-14 13:20:43 -08002635static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
James Ketrenos2c86c272005-03-23 17:32:29 -06002636{
2637 struct ipw2100_status *status = &priv->status_queue.drv[i];
2638 struct ipw2100_rx *u = priv->rx_buffers[i].rxp;
2639 u16 frame_type = status->status_fields & STATUS_TYPE_MASK;
2640
2641 switch (frame_type) {
2642 case COMMAND_STATUS_VAL:
2643 return (status->frame_size != sizeof(u->rx_data.command));
2644 case STATUS_CHANGE_VAL:
2645 return (status->frame_size != sizeof(u->rx_data.status));
2646 case HOST_NOTIFICATION_VAL:
2647 return (status->frame_size < sizeof(u->rx_data.notification));
2648 case P80211_DATA_VAL:
2649 case P8023_DATA_VAL:
2650#ifdef CONFIG_IPW2100_MONITOR
2651 return 0;
2652#else
Al Viro1edd3a52007-12-21 00:15:18 -05002653 switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002654 case IEEE80211_FTYPE_MGMT:
2655 case IEEE80211_FTYPE_CTL:
2656 return 0;
2657 case IEEE80211_FTYPE_DATA:
2658 return (status->frame_size >
2659 IPW_MAX_802_11_PAYLOAD_LENGTH);
2660 }
2661#endif
2662 }
2663
2664 return 1;
2665}
2666
2667/*
2668 * ipw2100 interrupts are disabled at this point, and the ISR
2669 * is the only code that calls this method. So, we do not need
2670 * to play with any locks.
2671 *
2672 * RX Queue works as follows:
2673 *
2674 * Read index - firmware places packet in entry identified by the
2675 * Read index and advances Read index. In this manner,
2676 * Read index will always point to the next packet to
2677 * be filled--but not yet valid.
2678 *
2679 * Write index - driver fills this entry with an unused RBD entry.
2680 * This entry has not filled by the firmware yet.
2681 *
2682 * In between the W and R indexes are the RBDs that have been received
2683 * but not yet processed.
2684 *
2685 * The process of handling packets will start at WRITE + 1 and advance
2686 * until it reaches the READ index.
2687 *
2688 * The WRITE index is cached in the variable 'priv->rx_queue.next'.
2689 *
2690 */
Arjan van de Ven858119e2006-01-14 13:20:43 -08002691static void __ipw2100_rx_process(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002692{
2693 struct ipw2100_bd_queue *rxq = &priv->rx_queue;
2694 struct ipw2100_status_queue *sq = &priv->status_queue;
2695 struct ipw2100_rx_packet *packet;
2696 u16 frame_type;
2697 u32 r, w, i, s;
2698 struct ipw2100_rx *u;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002699 struct libipw_rx_stats stats = {
James Ketrenos2c86c272005-03-23 17:32:29 -06002700 .mac_time = jiffies,
2701 };
2702
2703 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r);
2704 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w);
2705
2706 if (r >= rxq->entries) {
2707 IPW_DEBUG_RX("exit - bad read index\n");
2708 return;
2709 }
2710
2711 i = (rxq->next + 1) % rxq->entries;
2712 s = i;
2713 while (i != r) {
2714 /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n",
2715 r, rxq->next, i); */
2716
2717 packet = &priv->rx_buffers[i];
2718
James Ketrenos2c86c272005-03-23 17:32:29 -06002719 /* Sync the DMA for the RX buffer so CPU is sure to get
2720 * the correct values */
2721 pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr,
2722 sizeof(struct ipw2100_rx),
2723 PCI_DMA_FROMDEVICE);
2724
2725 if (unlikely(ipw2100_corruption_check(priv, i))) {
2726 ipw2100_corruption_detected(priv, i);
2727 goto increment;
2728 }
2729
2730 u = packet->rxp;
James Ketrenosee8e3652005-09-14 09:47:29 -05002731 frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK;
James Ketrenos2c86c272005-03-23 17:32:29 -06002732 stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM;
2733 stats.len = sq->drv[i].frame_size;
2734
2735 stats.mask = 0;
2736 if (stats.rssi != 0)
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002737 stats.mask |= LIBIPW_STATMASK_RSSI;
2738 stats.freq = LIBIPW_24GHZ_BAND;
James Ketrenos2c86c272005-03-23 17:32:29 -06002739
James Ketrenosee8e3652005-09-14 09:47:29 -05002740 IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n",
2741 priv->net_dev->name, frame_types[frame_type],
2742 stats.len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002743
2744 switch (frame_type) {
2745 case COMMAND_STATUS_VAL:
2746 /* Reset Rx watchdog */
James Ketrenosee8e3652005-09-14 09:47:29 -05002747 isr_rx_complete_command(priv, &u->rx_data.command);
James Ketrenos2c86c272005-03-23 17:32:29 -06002748 break;
2749
2750 case STATUS_CHANGE_VAL:
2751 isr_status_change(priv, u->rx_data.status);
2752 break;
2753
2754 case P80211_DATA_VAL:
2755 case P8023_DATA_VAL:
2756#ifdef CONFIG_IPW2100_MONITOR
2757 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
Stefan Rompf15745a72006-02-21 18:36:17 +08002758 isr_rx_monitor(priv, i, &stats);
James Ketrenos2c86c272005-03-23 17:32:29 -06002759 break;
2760 }
2761#endif
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002762 if (stats.len < sizeof(struct libipw_hdr_3addr))
James Ketrenos2c86c272005-03-23 17:32:29 -06002763 break;
Al Viro1edd3a52007-12-21 00:15:18 -05002764 switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002765 case IEEE80211_FTYPE_MGMT:
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002766 libipw_rx_mgt(priv->ieee,
James Ketrenosee8e3652005-09-14 09:47:29 -05002767 &u->rx_data.header, &stats);
James Ketrenos2c86c272005-03-23 17:32:29 -06002768 break;
2769
2770 case IEEE80211_FTYPE_CTL:
2771 break;
2772
2773 case IEEE80211_FTYPE_DATA:
2774 isr_rx(priv, i, &stats);
2775 break;
2776
2777 }
2778 break;
2779 }
2780
James Ketrenosee8e3652005-09-14 09:47:29 -05002781 increment:
James Ketrenos2c86c272005-03-23 17:32:29 -06002782 /* clear status field associated with this RBD */
2783 rxq->drv[i].status.info.field = 0;
2784
2785 i = (i + 1) % rxq->entries;
2786 }
2787
2788 if (i != s) {
2789 /* backtrack one entry, wrapping to end if at 0 */
2790 rxq->next = (i ? i : rxq->entries) - 1;
2791
2792 write_register(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05002793 IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next);
James Ketrenos2c86c272005-03-23 17:32:29 -06002794 }
2795}
2796
James Ketrenos2c86c272005-03-23 17:32:29 -06002797/*
2798 * __ipw2100_tx_process
2799 *
2800 * This routine will determine whether the next packet on
2801 * the fw_pend_list has been processed by the firmware yet.
2802 *
2803 * If not, then it does nothing and returns.
2804 *
2805 * If so, then it removes the item from the fw_pend_list, frees
2806 * any associated storage, and places the item back on the
2807 * free list of its source (either msg_free_list or tx_free_list)
2808 *
2809 * TX Queue works as follows:
2810 *
2811 * Read index - points to the next TBD that the firmware will
2812 * process. The firmware will read the data, and once
2813 * done processing, it will advance the Read index.
2814 *
2815 * Write index - driver fills this entry with an constructed TBD
2816 * entry. The Write index is not advanced until the
2817 * packet has been configured.
2818 *
2819 * In between the W and R indexes are the TBDs that have NOT been
2820 * processed. Lagging behind the R index are packets that have
2821 * been processed but have not been freed by the driver.
2822 *
2823 * In order to free old storage, an internal index will be maintained
2824 * that points to the next packet to be freed. When all used
2825 * packets have been freed, the oldest index will be the same as the
2826 * firmware's read index.
2827 *
2828 * The OLDEST index is cached in the variable 'priv->tx_queue.oldest'
2829 *
2830 * Because the TBD structure can not contain arbitrary data, the
2831 * driver must keep an internal queue of cached allocations such that
2832 * it can put that data back into the tx_free_list and msg_free_list
2833 * for use by future command and data packets.
2834 *
2835 */
Arjan van de Ven858119e2006-01-14 13:20:43 -08002836static int __ipw2100_tx_process(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002837{
2838 struct ipw2100_bd_queue *txq = &priv->tx_queue;
James Ketrenosee8e3652005-09-14 09:47:29 -05002839 struct ipw2100_bd *tbd;
James Ketrenos2c86c272005-03-23 17:32:29 -06002840 struct list_head *element;
2841 struct ipw2100_tx_packet *packet;
2842 int descriptors_used;
2843 int e, i;
2844 u32 r, w, frag_num = 0;
2845
2846 if (list_empty(&priv->fw_pend_list))
2847 return 0;
2848
2849 element = priv->fw_pend_list.next;
2850
2851 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenosee8e3652005-09-14 09:47:29 -05002852 tbd = &txq->drv[packet->index];
James Ketrenos2c86c272005-03-23 17:32:29 -06002853
2854 /* Determine how many TBD entries must be finished... */
2855 switch (packet->type) {
2856 case COMMAND:
2857 /* COMMAND uses only one slot; don't advance */
2858 descriptors_used = 1;
2859 e = txq->oldest;
2860 break;
2861
2862 case DATA:
2863 /* DATA uses two slots; advance and loop position. */
2864 descriptors_used = tbd->num_fragments;
James Ketrenosee8e3652005-09-14 09:47:29 -05002865 frag_num = tbd->num_fragments - 1;
James Ketrenos2c86c272005-03-23 17:32:29 -06002866 e = txq->oldest + frag_num;
2867 e %= txq->entries;
2868 break;
2869
2870 default:
Jiri Benc797b4f72005-08-25 20:03:27 -04002871 printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002872 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002873 return 0;
2874 }
2875
2876 /* if the last TBD is not done by NIC yet, then packet is
2877 * not ready to be released.
2878 *
2879 */
2880 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
2881 &r);
2882 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
2883 &w);
2884 if (w != txq->next)
Jiri Benc797b4f72005-08-25 20:03:27 -04002885 printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06002886 priv->net_dev->name);
2887
James Ketrenosee8e3652005-09-14 09:47:29 -05002888 /*
James Ketrenos2c86c272005-03-23 17:32:29 -06002889 * txq->next is the index of the last packet written txq->oldest is
2890 * the index of the r is the index of the next packet to be read by
2891 * firmware
2892 */
2893
James Ketrenos2c86c272005-03-23 17:32:29 -06002894 /*
2895 * Quick graphic to help you visualize the following
2896 * if / else statement
2897 *
2898 * ===>| s---->|===============
2899 * e>|
2900 * | a | b | c | d | e | f | g | h | i | j | k | l
2901 * r---->|
2902 * w
2903 *
2904 * w - updated by driver
2905 * r - updated by firmware
2906 * s - start of oldest BD entry (txq->oldest)
2907 * e - end of oldest BD entry
2908 *
2909 */
2910 if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) {
2911 IPW_DEBUG_TX("exit - no processed packets ready to release.\n");
2912 return 0;
2913 }
2914
2915 list_del(element);
2916 DEC_STAT(&priv->fw_pend_stat);
2917
Brice Goglin0f52bf92005-12-01 01:41:46 -08002918#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002919 {
Reinette Chatre21f8a732009-08-18 10:25:05 -07002920 i = txq->oldest;
James Ketrenosee8e3652005-09-14 09:47:29 -05002921 IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
2922 &txq->drv[i],
2923 (u32) (txq->nic + i * sizeof(struct ipw2100_bd)),
2924 txq->drv[i].host_addr, txq->drv[i].buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002925
2926 if (packet->type == DATA) {
2927 i = (i + 1) % txq->entries;
2928
James Ketrenosee8e3652005-09-14 09:47:29 -05002929 IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
2930 &txq->drv[i],
2931 (u32) (txq->nic + i *
2932 sizeof(struct ipw2100_bd)),
2933 (u32) txq->drv[i].host_addr,
2934 txq->drv[i].buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002935 }
2936 }
2937#endif
2938
2939 switch (packet->type) {
2940 case DATA:
2941 if (txq->drv[txq->oldest].status.info.fields.txType != 0)
Jiri Benc797b4f72005-08-25 20:03:27 -04002942 printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
James Ketrenos2c86c272005-03-23 17:32:29 -06002943 "Expecting DATA TBD but pulled "
2944 "something else: ids %d=%d.\n",
2945 priv->net_dev->name, txq->oldest, packet->index);
2946
2947 /* DATA packet; we have to unmap and free the SKB */
James Ketrenos2c86c272005-03-23 17:32:29 -06002948 for (i = 0; i < frag_num; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002949 tbd = &txq->drv[(packet->index + 1 + i) % txq->entries];
James Ketrenos2c86c272005-03-23 17:32:29 -06002950
James Ketrenosee8e3652005-09-14 09:47:29 -05002951 IPW_DEBUG_TX("TX%d P=%08x L=%d\n",
2952 (packet->index + 1 + i) % txq->entries,
2953 tbd->host_addr, tbd->buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002954
2955 pci_unmap_single(priv->pci_dev,
2956 tbd->host_addr,
James Ketrenosee8e3652005-09-14 09:47:29 -05002957 tbd->buf_length, PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002958 }
2959
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002960 libipw_txb_free(packet->info.d_struct.txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06002961 packet->info.d_struct.txb = NULL;
2962
2963 list_add_tail(element, &priv->tx_free_list);
2964 INC_STAT(&priv->tx_free_stat);
2965
2966 /* We have a free slot in the Tx queue, so wake up the
2967 * transmit layer if it is stopped. */
James Ketrenos82328352005-08-24 22:33:31 -05002968 if (priv->status & STATUS_ASSOCIATED)
James Ketrenos2c86c272005-03-23 17:32:29 -06002969 netif_wake_queue(priv->net_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06002970
2971 /* A packet was processed by the hardware, so update the
2972 * watchdog */
2973 priv->net_dev->trans_start = jiffies;
2974
2975 break;
2976
2977 case COMMAND:
2978 if (txq->drv[txq->oldest].status.info.fields.txType != 1)
Jiri Benc797b4f72005-08-25 20:03:27 -04002979 printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
James Ketrenos2c86c272005-03-23 17:32:29 -06002980 "Expecting COMMAND TBD but pulled "
2981 "something else: ids %d=%d.\n",
2982 priv->net_dev->name, txq->oldest, packet->index);
2983
Brice Goglin0f52bf92005-12-01 01:41:46 -08002984#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002985 if (packet->info.c_struct.cmd->host_command_reg <
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02002986 ARRAY_SIZE(command_types))
James Ketrenosee8e3652005-09-14 09:47:29 -05002987 IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n",
2988 command_types[packet->info.c_struct.cmd->
2989 host_command_reg],
2990 packet->info.c_struct.cmd->
2991 host_command_reg,
2992 packet->info.c_struct.cmd->cmd_status_reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06002993#endif
2994
2995 list_add_tail(element, &priv->msg_free_list);
2996 INC_STAT(&priv->msg_free_stat);
2997 break;
2998 }
2999
3000 /* advance oldest used TBD pointer to start of next entry */
3001 txq->oldest = (e + 1) % txq->entries;
3002 /* increase available TBDs number */
3003 txq->available += descriptors_used;
3004 SET_STAT(&priv->txq_stat, txq->available);
3005
3006 IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003007 jiffies - packet->jiffy_start);
James Ketrenos2c86c272005-03-23 17:32:29 -06003008
3009 return (!list_empty(&priv->fw_pend_list));
3010}
3011
James Ketrenos2c86c272005-03-23 17:32:29 -06003012static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
3013{
3014 int i = 0;
3015
James Ketrenosee8e3652005-09-14 09:47:29 -05003016 while (__ipw2100_tx_process(priv) && i < 200)
3017 i++;
James Ketrenos2c86c272005-03-23 17:32:29 -06003018
3019 if (i == 200) {
Jiri Benc19f7f742005-08-25 20:02:10 -04003020 printk(KERN_WARNING DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06003021 "%s: Driver is running slow (%d iters).\n",
3022 priv->net_dev->name, i);
3023 }
3024}
3025
Jiri Benc19f7f742005-08-25 20:02:10 -04003026static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06003027{
3028 struct list_head *element;
3029 struct ipw2100_tx_packet *packet;
3030 struct ipw2100_bd_queue *txq = &priv->tx_queue;
3031 struct ipw2100_bd *tbd;
3032 int next = txq->next;
3033
3034 while (!list_empty(&priv->msg_pend_list)) {
3035 /* if there isn't enough space in TBD queue, then
3036 * don't stuff a new one in.
3037 * NOTE: 3 are needed as a command will take one,
3038 * and there is a minimum of 2 that must be
3039 * maintained between the r and w indexes
3040 */
3041 if (txq->available <= 3) {
3042 IPW_DEBUG_TX("no room in tx_queue\n");
3043 break;
3044 }
3045
3046 element = priv->msg_pend_list.next;
3047 list_del(element);
3048 DEC_STAT(&priv->msg_pend_stat);
3049
James Ketrenosee8e3652005-09-14 09:47:29 -05003050 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06003051
John W. Linvilleaa0d52c2010-08-10 13:08:11 -04003052 IPW_DEBUG_TX("using TBD at virt=%p, phys=%04X\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003053 &txq->drv[txq->next],
John W. Linvilleaa0d52c2010-08-10 13:08:11 -04003054 (u32) (txq->nic + txq->next *
James Ketrenosee8e3652005-09-14 09:47:29 -05003055 sizeof(struct ipw2100_bd)));
James Ketrenos2c86c272005-03-23 17:32:29 -06003056
3057 packet->index = txq->next;
3058
3059 tbd = &txq->drv[txq->next];
3060
3061 /* initialize TBD */
3062 tbd->host_addr = packet->info.c_struct.cmd_phys;
3063 tbd->buf_length = sizeof(struct ipw2100_cmd_header);
3064 /* not marking number of fragments causes problems
3065 * with f/w debug version */
3066 tbd->num_fragments = 1;
3067 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003068 IPW_BD_STATUS_TX_FRAME_COMMAND |
3069 IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06003070
3071 /* update TBD queue counters */
3072 txq->next++;
3073 txq->next %= txq->entries;
3074 txq->available--;
3075 DEC_STAT(&priv->txq_stat);
3076
3077 list_add_tail(element, &priv->fw_pend_list);
3078 INC_STAT(&priv->fw_pend_stat);
3079 }
3080
3081 if (txq->next != next) {
3082 /* kick off the DMA by notifying firmware the
3083 * write index has moved; make sure TBD stores are sync'd */
3084 wmb();
3085 write_register(priv->net_dev,
3086 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
3087 txq->next);
3088 }
3089}
3090
James Ketrenos2c86c272005-03-23 17:32:29 -06003091/*
Jiri Benc19f7f742005-08-25 20:02:10 -04003092 * ipw2100_tx_send_data
James Ketrenos2c86c272005-03-23 17:32:29 -06003093 *
3094 */
Jiri Benc19f7f742005-08-25 20:02:10 -04003095static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06003096{
3097 struct list_head *element;
3098 struct ipw2100_tx_packet *packet;
3099 struct ipw2100_bd_queue *txq = &priv->tx_queue;
3100 struct ipw2100_bd *tbd;
3101 int next = txq->next;
James Ketrenosee8e3652005-09-14 09:47:29 -05003102 int i = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06003103 struct ipw2100_data_header *ipw_hdr;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003104 struct libipw_hdr_3addr *hdr;
James Ketrenos2c86c272005-03-23 17:32:29 -06003105
3106 while (!list_empty(&priv->tx_pend_list)) {
3107 /* if there isn't enough space in TBD queue, then
3108 * don't stuff a new one in.
3109 * NOTE: 4 are needed as a data will take two,
3110 * and there is a minimum of 2 that must be
3111 * maintained between the r and w indexes
3112 */
3113 element = priv->tx_pend_list.next;
James Ketrenosee8e3652005-09-14 09:47:29 -05003114 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06003115
3116 if (unlikely(1 + packet->info.d_struct.txb->nr_frags >
3117 IPW_MAX_BDS)) {
3118 /* TODO: Support merging buffers if more than
3119 * IPW_MAX_BDS are used */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02003120 IPW_DEBUG_INFO("%s: Maximum BD threshold exceeded. "
James Ketrenosee8e3652005-09-14 09:47:29 -05003121 "Increase fragmentation level.\n",
3122 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003123 }
3124
James Ketrenosee8e3652005-09-14 09:47:29 -05003125 if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003126 IPW_DEBUG_TX("no room in tx_queue\n");
3127 break;
3128 }
3129
3130 list_del(element);
3131 DEC_STAT(&priv->tx_pend_stat);
3132
3133 tbd = &txq->drv[txq->next];
3134
3135 packet->index = txq->next;
3136
3137 ipw_hdr = packet->info.d_struct.data;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003138 hdr = (struct libipw_hdr_3addr *)packet->info.d_struct.txb->
James Ketrenosee8e3652005-09-14 09:47:29 -05003139 fragments[0]->data;
James Ketrenos2c86c272005-03-23 17:32:29 -06003140
3141 if (priv->ieee->iw_mode == IW_MODE_INFRA) {
3142 /* To DS: Addr1 = BSSID, Addr2 = SA,
3143 Addr3 = DA */
3144 memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
3145 memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN);
3146 } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
3147 /* not From/To DS: Addr1 = DA, Addr2 = SA,
3148 Addr3 = BSSID */
3149 memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
3150 memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN);
3151 }
3152
3153 ipw_hdr->host_command_reg = SEND;
3154 ipw_hdr->host_command_reg1 = 0;
3155
3156 /* For now we only support host based encryption */
3157 ipw_hdr->needs_encryption = 0;
3158 ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted;
3159 if (packet->info.d_struct.txb->nr_frags > 1)
3160 ipw_hdr->fragment_size =
James Ketrenosee8e3652005-09-14 09:47:29 -05003161 packet->info.d_struct.txb->frag_size -
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003162 LIBIPW_3ADDR_LEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06003163 else
3164 ipw_hdr->fragment_size = 0;
3165
3166 tbd->host_addr = packet->info.d_struct.data_phys;
3167 tbd->buf_length = sizeof(struct ipw2100_data_header);
3168 tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags;
3169 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003170 IPW_BD_STATUS_TX_FRAME_802_3 |
3171 IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
James Ketrenos2c86c272005-03-23 17:32:29 -06003172 txq->next++;
3173 txq->next %= txq->entries;
3174
James Ketrenosee8e3652005-09-14 09:47:29 -05003175 IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n",
3176 packet->index, tbd->host_addr, tbd->buf_length);
Brice Goglin0f52bf92005-12-01 01:41:46 -08003177#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06003178 if (packet->info.d_struct.txb->nr_frags > 1)
3179 IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
3180 packet->info.d_struct.txb->nr_frags);
3181#endif
3182
James Ketrenosee8e3652005-09-14 09:47:29 -05003183 for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
3184 tbd = &txq->drv[txq->next];
James Ketrenos2c86c272005-03-23 17:32:29 -06003185 if (i == packet->info.d_struct.txb->nr_frags - 1)
3186 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003187 IPW_BD_STATUS_TX_FRAME_802_3 |
3188 IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06003189 else
3190 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003191 IPW_BD_STATUS_TX_FRAME_802_3 |
3192 IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
James Ketrenos2c86c272005-03-23 17:32:29 -06003193
3194 tbd->buf_length = packet->info.d_struct.txb->
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003195 fragments[i]->len - LIBIPW_3ADDR_LEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06003196
James Ketrenosee8e3652005-09-14 09:47:29 -05003197 tbd->host_addr = pci_map_single(priv->pci_dev,
3198 packet->info.d_struct.
3199 txb->fragments[i]->
3200 data +
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003201 LIBIPW_3ADDR_LEN,
James Ketrenosee8e3652005-09-14 09:47:29 -05003202 tbd->buf_length,
3203 PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003204
James Ketrenosee8e3652005-09-14 09:47:29 -05003205 IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n",
3206 txq->next, tbd->host_addr,
3207 tbd->buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06003208
James Ketrenosee8e3652005-09-14 09:47:29 -05003209 pci_dma_sync_single_for_device(priv->pci_dev,
3210 tbd->host_addr,
3211 tbd->buf_length,
3212 PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003213
3214 txq->next++;
3215 txq->next %= txq->entries;
James Ketrenosee8e3652005-09-14 09:47:29 -05003216 }
James Ketrenos2c86c272005-03-23 17:32:29 -06003217
3218 txq->available -= 1 + packet->info.d_struct.txb->nr_frags;
3219 SET_STAT(&priv->txq_stat, txq->available);
3220
3221 list_add_tail(element, &priv->fw_pend_list);
3222 INC_STAT(&priv->fw_pend_stat);
3223 }
3224
3225 if (txq->next != next) {
3226 /* kick off the DMA by notifying firmware the
3227 * write index has moved; make sure TBD stores are sync'd */
3228 write_register(priv->net_dev,
3229 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
3230 txq->next);
3231 }
James Ketrenos2c86c272005-03-23 17:32:29 -06003232}
3233
3234static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
3235{
3236 struct net_device *dev = priv->net_dev;
3237 unsigned long flags;
3238 u32 inta, tmp;
3239
3240 spin_lock_irqsave(&priv->low_lock, flags);
3241 ipw2100_disable_interrupts(priv);
3242
3243 read_register(dev, IPW_REG_INTA, &inta);
3244
3245 IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n",
3246 (unsigned long)inta & IPW_INTERRUPT_MASK);
3247
3248 priv->in_isr++;
3249 priv->interrupts++;
3250
3251 /* We do not loop and keep polling for more interrupts as this
3252 * is frowned upon and doesn't play nicely with other potentially
3253 * chained IRQs */
3254 IPW_DEBUG_ISR("INTA: 0x%08lX\n",
3255 (unsigned long)inta & IPW_INTERRUPT_MASK);
3256
3257 if (inta & IPW2100_INTA_FATAL_ERROR) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003258 printk(KERN_WARNING DRV_NAME
James Ketrenosee8e3652005-09-14 09:47:29 -05003259 ": Fatal interrupt. Scheduling firmware restart.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003260 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003261 write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003262
3263 read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error);
3264 IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n",
3265 priv->net_dev->name, priv->fatal_error);
3266
3267 read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp);
3268 IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n",
3269 priv->net_dev->name, tmp);
3270
3271 /* Wake up any sleeping jobs */
3272 schedule_reset(priv);
3273 }
3274
3275 if (inta & IPW2100_INTA_PARITY_ERROR) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003276 printk(KERN_ERR DRV_NAME
Frans Pop9fd1ea42010-03-24 19:46:31 +01003277 ": ***** PARITY ERROR INTERRUPT !!!!\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003278 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003279 write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003280 }
3281
3282 if (inta & IPW2100_INTA_RX_TRANSFER) {
3283 IPW_DEBUG_ISR("RX interrupt\n");
3284
3285 priv->rx_interrupts++;
3286
James Ketrenosee8e3652005-09-14 09:47:29 -05003287 write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER);
James Ketrenos2c86c272005-03-23 17:32:29 -06003288
3289 __ipw2100_rx_process(priv);
3290 __ipw2100_tx_complete(priv);
3291 }
3292
3293 if (inta & IPW2100_INTA_TX_TRANSFER) {
3294 IPW_DEBUG_ISR("TX interrupt\n");
3295
3296 priv->tx_interrupts++;
3297
James Ketrenosee8e3652005-09-14 09:47:29 -05003298 write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER);
James Ketrenos2c86c272005-03-23 17:32:29 -06003299
3300 __ipw2100_tx_complete(priv);
Jiri Benc19f7f742005-08-25 20:02:10 -04003301 ipw2100_tx_send_commands(priv);
3302 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06003303 }
3304
3305 if (inta & IPW2100_INTA_TX_COMPLETE) {
3306 IPW_DEBUG_ISR("TX complete\n");
3307 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003308 write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003309
3310 __ipw2100_tx_complete(priv);
3311 }
3312
3313 if (inta & IPW2100_INTA_EVENT_INTERRUPT) {
3314 /* ipw2100_handle_event(dev); */
3315 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003316 write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT);
James Ketrenos2c86c272005-03-23 17:32:29 -06003317 }
3318
3319 if (inta & IPW2100_INTA_FW_INIT_DONE) {
3320 IPW_DEBUG_ISR("FW init done interrupt\n");
3321 priv->inta_other++;
3322
3323 read_register(dev, IPW_REG_INTA, &tmp);
3324 if (tmp & (IPW2100_INTA_FATAL_ERROR |
3325 IPW2100_INTA_PARITY_ERROR)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003326 write_register(dev, IPW_REG_INTA,
3327 IPW2100_INTA_FATAL_ERROR |
3328 IPW2100_INTA_PARITY_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003329 }
3330
James Ketrenosee8e3652005-09-14 09:47:29 -05003331 write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003332 }
3333
3334 if (inta & IPW2100_INTA_STATUS_CHANGE) {
3335 IPW_DEBUG_ISR("Status change interrupt\n");
3336 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003337 write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003338 }
3339
3340 if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) {
3341 IPW_DEBUG_ISR("slave host mode interrupt\n");
3342 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003343 write_register(dev, IPW_REG_INTA,
3344 IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003345 }
3346
3347 priv->in_isr--;
3348 ipw2100_enable_interrupts(priv);
3349
3350 spin_unlock_irqrestore(&priv->low_lock, flags);
3351
3352 IPW_DEBUG_ISR("exit\n");
3353}
3354
David Howells7d12e782006-10-05 14:55:46 +01003355static irqreturn_t ipw2100_interrupt(int irq, void *data)
James Ketrenos2c86c272005-03-23 17:32:29 -06003356{
3357 struct ipw2100_priv *priv = data;
3358 u32 inta, inta_mask;
3359
3360 if (!data)
3361 return IRQ_NONE;
3362
James Ketrenosee8e3652005-09-14 09:47:29 -05003363 spin_lock(&priv->low_lock);
James Ketrenos2c86c272005-03-23 17:32:29 -06003364
3365 /* We check to see if we should be ignoring interrupts before
3366 * we touch the hardware. During ucode load if we try and handle
3367 * an interrupt we can cause keyboard problems as well as cause
3368 * the ucode to fail to initialize */
3369 if (!(priv->status & STATUS_INT_ENABLED)) {
3370 /* Shared IRQ */
3371 goto none;
3372 }
3373
3374 read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
3375 read_register(priv->net_dev, IPW_REG_INTA, &inta);
3376
3377 if (inta == 0xFFFFFFFF) {
3378 /* Hardware disappeared */
Jiri Benc797b4f72005-08-25 20:03:27 -04003379 printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003380 goto none;
3381 }
3382
3383 inta &= IPW_INTERRUPT_MASK;
3384
3385 if (!(inta & inta_mask)) {
3386 /* Shared interrupt */
3387 goto none;
3388 }
3389
3390 /* We disable the hardware interrupt here just to prevent unneeded
3391 * calls to be made. We disable this again within the actual
3392 * work tasklet, so if another part of the code re-enables the
3393 * interrupt, that is fine */
3394 ipw2100_disable_interrupts(priv);
3395
3396 tasklet_schedule(&priv->irq_tasklet);
James Ketrenosee8e3652005-09-14 09:47:29 -05003397 spin_unlock(&priv->low_lock);
James Ketrenos2c86c272005-03-23 17:32:29 -06003398
3399 return IRQ_HANDLED;
James Ketrenosee8e3652005-09-14 09:47:29 -05003400 none:
James Ketrenos2c86c272005-03-23 17:32:29 -06003401 spin_unlock(&priv->low_lock);
3402 return IRQ_NONE;
3403}
3404
Stephen Hemmingerd0cf9c02009-08-31 19:50:57 +00003405static netdev_tx_t ipw2100_tx(struct libipw_txb *txb,
3406 struct net_device *dev, int pri)
James Ketrenos2c86c272005-03-23 17:32:29 -06003407{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003408 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06003409 struct list_head *element;
3410 struct ipw2100_tx_packet *packet;
3411 unsigned long flags;
3412
3413 spin_lock_irqsave(&priv->low_lock, flags);
3414
3415 if (!(priv->status & STATUS_ASSOCIATED)) {
3416 IPW_DEBUG_INFO("Can not transmit when not connected.\n");
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00003417 priv->net_dev->stats.tx_carrier_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06003418 netif_stop_queue(dev);
3419 goto fail_unlock;
3420 }
3421
3422 if (list_empty(&priv->tx_free_list))
3423 goto fail_unlock;
3424
3425 element = priv->tx_free_list.next;
3426 packet = list_entry(element, struct ipw2100_tx_packet, list);
3427
3428 packet->info.d_struct.txb = txb;
3429
James Ketrenosee8e3652005-09-14 09:47:29 -05003430 IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len);
3431 printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len);
James Ketrenos2c86c272005-03-23 17:32:29 -06003432
3433 packet->jiffy_start = jiffies;
3434
3435 list_del(element);
3436 DEC_STAT(&priv->tx_free_stat);
3437
3438 list_add_tail(element, &priv->tx_pend_list);
3439 INC_STAT(&priv->tx_pend_stat);
3440
Jiri Benc19f7f742005-08-25 20:02:10 -04003441 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06003442
3443 spin_unlock_irqrestore(&priv->low_lock, flags);
Stephen Hemmingerd0cf9c02009-08-31 19:50:57 +00003444 return NETDEV_TX_OK;
James Ketrenos2c86c272005-03-23 17:32:29 -06003445
Stephen Hemmingerd0cf9c02009-08-31 19:50:57 +00003446fail_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -06003447 netif_stop_queue(dev);
3448 spin_unlock_irqrestore(&priv->low_lock, flags);
Stephen Hemmingerd0cf9c02009-08-31 19:50:57 +00003449 return NETDEV_TX_BUSY;
James Ketrenos2c86c272005-03-23 17:32:29 -06003450}
3451
James Ketrenos2c86c272005-03-23 17:32:29 -06003452static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
3453{
3454 int i, j, err = -EINVAL;
3455 void *v;
3456 dma_addr_t p;
3457
James Ketrenosee8e3652005-09-14 09:47:29 -05003458 priv->msg_buffers =
Joe Perchesefe4c452010-05-31 20:23:15 -07003459 kmalloc(IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet),
3460 GFP_KERNEL);
Joe Perchese404dec2012-01-29 12:56:23 +00003461 if (!priv->msg_buffers)
James Ketrenos2c86c272005-03-23 17:32:29 -06003462 return -ENOMEM;
James Ketrenos2c86c272005-03-23 17:32:29 -06003463
3464 for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003465 v = pci_alloc_consistent(priv->pci_dev,
3466 sizeof(struct ipw2100_cmd_header), &p);
James Ketrenos2c86c272005-03-23 17:32:29 -06003467 if (!v) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003468 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06003469 "%s: PCI alloc failed for msg "
James Ketrenosee8e3652005-09-14 09:47:29 -05003470 "buffers.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003471 err = -ENOMEM;
3472 break;
3473 }
3474
3475 memset(v, 0, sizeof(struct ipw2100_cmd_header));
3476
3477 priv->msg_buffers[i].type = COMMAND;
3478 priv->msg_buffers[i].info.c_struct.cmd =
James Ketrenosee8e3652005-09-14 09:47:29 -05003479 (struct ipw2100_cmd_header *)v;
James Ketrenos2c86c272005-03-23 17:32:29 -06003480 priv->msg_buffers[i].info.c_struct.cmd_phys = p;
3481 }
3482
3483 if (i == IPW_COMMAND_POOL_SIZE)
3484 return 0;
3485
3486 for (j = 0; j < i; j++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003487 pci_free_consistent(priv->pci_dev,
3488 sizeof(struct ipw2100_cmd_header),
3489 priv->msg_buffers[j].info.c_struct.cmd,
3490 priv->msg_buffers[j].info.c_struct.
3491 cmd_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06003492 }
3493
3494 kfree(priv->msg_buffers);
3495 priv->msg_buffers = NULL;
3496
3497 return err;
3498}
3499
3500static int ipw2100_msg_initialize(struct ipw2100_priv *priv)
3501{
3502 int i;
3503
3504 INIT_LIST_HEAD(&priv->msg_free_list);
3505 INIT_LIST_HEAD(&priv->msg_pend_list);
3506
3507 for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++)
3508 list_add_tail(&priv->msg_buffers[i].list, &priv->msg_free_list);
3509 SET_STAT(&priv->msg_free_stat, i);
3510
3511 return 0;
3512}
3513
3514static void ipw2100_msg_free(struct ipw2100_priv *priv)
3515{
3516 int i;
3517
3518 if (!priv->msg_buffers)
3519 return;
3520
3521 for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
3522 pci_free_consistent(priv->pci_dev,
3523 sizeof(struct ipw2100_cmd_header),
3524 priv->msg_buffers[i].info.c_struct.cmd,
James Ketrenosee8e3652005-09-14 09:47:29 -05003525 priv->msg_buffers[i].info.c_struct.
3526 cmd_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06003527 }
3528
3529 kfree(priv->msg_buffers);
3530 priv->msg_buffers = NULL;
3531}
3532
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003533static ssize_t show_pci(struct device *d, struct device_attribute *attr,
3534 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003535{
3536 struct pci_dev *pci_dev = container_of(d, struct pci_dev, dev);
3537 char *out = buf;
3538 int i, j;
3539 u32 val;
3540
3541 for (i = 0; i < 16; i++) {
3542 out += sprintf(out, "[%08X] ", i * 16);
3543 for (j = 0; j < 16; j += 4) {
3544 pci_read_config_dword(pci_dev, i * 16 + j, &val);
3545 out += sprintf(out, "%08X ", val);
3546 }
3547 out += sprintf(out, "\n");
3548 }
3549
3550 return out - buf;
3551}
James Ketrenosee8e3652005-09-14 09:47:29 -05003552
James Ketrenos2c86c272005-03-23 17:32:29 -06003553static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL);
3554
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003555static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
3556 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003557{
Greg Kroah-Hartman928841b2009-04-30 23:02:47 -07003558 struct ipw2100_priv *p = dev_get_drvdata(d);
James Ketrenos2c86c272005-03-23 17:32:29 -06003559 return sprintf(buf, "0x%08x\n", (int)p->config);
3560}
James Ketrenosee8e3652005-09-14 09:47:29 -05003561
James Ketrenos2c86c272005-03-23 17:32:29 -06003562static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
3563
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003564static ssize_t show_status(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003565 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003566{
Greg Kroah-Hartman928841b2009-04-30 23:02:47 -07003567 struct ipw2100_priv *p = dev_get_drvdata(d);
James Ketrenos2c86c272005-03-23 17:32:29 -06003568 return sprintf(buf, "0x%08x\n", (int)p->status);
3569}
James Ketrenosee8e3652005-09-14 09:47:29 -05003570
James Ketrenos2c86c272005-03-23 17:32:29 -06003571static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
3572
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003573static ssize_t show_capability(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003574 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003575{
Greg Kroah-Hartman928841b2009-04-30 23:02:47 -07003576 struct ipw2100_priv *p = dev_get_drvdata(d);
James Ketrenos2c86c272005-03-23 17:32:29 -06003577 return sprintf(buf, "0x%08x\n", (int)p->capability);
3578}
James Ketrenos2c86c272005-03-23 17:32:29 -06003579
James Ketrenosee8e3652005-09-14 09:47:29 -05003580static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL);
James Ketrenos2c86c272005-03-23 17:32:29 -06003581
3582#define IPW2100_REG(x) { IPW_ ##x, #x }
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003583static const struct {
James Ketrenos2c86c272005-03-23 17:32:29 -06003584 u32 addr;
3585 const char *name;
3586} hw_data[] = {
James Ketrenosee8e3652005-09-14 09:47:29 -05003587IPW2100_REG(REG_GP_CNTRL),
3588 IPW2100_REG(REG_GPIO),
3589 IPW2100_REG(REG_INTA),
3590 IPW2100_REG(REG_INTA_MASK), IPW2100_REG(REG_RESET_REG),};
James Ketrenos2c86c272005-03-23 17:32:29 -06003591#define IPW2100_NIC(x, s) { x, #x, s }
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003592static const struct {
James Ketrenos2c86c272005-03-23 17:32:29 -06003593 u32 addr;
3594 const char *name;
3595 size_t size;
3596} nic_data[] = {
James Ketrenosee8e3652005-09-14 09:47:29 -05003597IPW2100_NIC(IPW2100_CONTROL_REG, 2),
3598 IPW2100_NIC(0x210014, 1), IPW2100_NIC(0x210000, 1),};
James Ketrenos2c86c272005-03-23 17:32:29 -06003599#define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d }
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003600static const struct {
James Ketrenos2c86c272005-03-23 17:32:29 -06003601 u8 index;
3602 const char *name;
3603 const char *desc;
3604} ord_data[] = {
James Ketrenosee8e3652005-09-14 09:47:29 -05003605IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
3606 IPW2100_ORD(STAT_TX_HOST_COMPLETE,
3607 "successful Host Tx's (MSDU)"),
3608 IPW2100_ORD(STAT_TX_DIR_DATA,
3609 "successful Directed Tx's (MSDU)"),
3610 IPW2100_ORD(STAT_TX_DIR_DATA1,
3611 "successful Directed Tx's (MSDU) @ 1MB"),
3612 IPW2100_ORD(STAT_TX_DIR_DATA2,
3613 "successful Directed Tx's (MSDU) @ 2MB"),
3614 IPW2100_ORD(STAT_TX_DIR_DATA5_5,
3615 "successful Directed Tx's (MSDU) @ 5_5MB"),
3616 IPW2100_ORD(STAT_TX_DIR_DATA11,
3617 "successful Directed Tx's (MSDU) @ 11MB"),
3618 IPW2100_ORD(STAT_TX_NODIR_DATA1,
3619 "successful Non_Directed Tx's (MSDU) @ 1MB"),
3620 IPW2100_ORD(STAT_TX_NODIR_DATA2,
3621 "successful Non_Directed Tx's (MSDU) @ 2MB"),
3622 IPW2100_ORD(STAT_TX_NODIR_DATA5_5,
3623 "successful Non_Directed Tx's (MSDU) @ 5.5MB"),
3624 IPW2100_ORD(STAT_TX_NODIR_DATA11,
3625 "successful Non_Directed Tx's (MSDU) @ 11MB"),
3626 IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"),
3627 IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"),
3628 IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"),
3629 IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"),
3630 IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"),
3631 IPW2100_ORD(STAT_TX_ASSN_RESP,
3632 "successful Association response Tx's"),
3633 IPW2100_ORD(STAT_TX_REASSN,
3634 "successful Reassociation Tx's"),
3635 IPW2100_ORD(STAT_TX_REASSN_RESP,
3636 "successful Reassociation response Tx's"),
3637 IPW2100_ORD(STAT_TX_PROBE,
3638 "probes successfully transmitted"),
3639 IPW2100_ORD(STAT_TX_PROBE_RESP,
3640 "probe responses successfully transmitted"),
3641 IPW2100_ORD(STAT_TX_BEACON, "tx beacon"),
3642 IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"),
3643 IPW2100_ORD(STAT_TX_DISASSN,
3644 "successful Disassociation TX"),
3645 IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"),
3646 IPW2100_ORD(STAT_TX_DEAUTH,
3647 "successful Deauthentication TX"),
3648 IPW2100_ORD(STAT_TX_TOTAL_BYTES,
3649 "Total successful Tx data bytes"),
3650 IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"),
3651 IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"),
3652 IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"),
3653 IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"),
3654 IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"),
3655 IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"),
3656 IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,
3657 "times max tries in a hop failed"),
3658 IPW2100_ORD(STAT_TX_DISASSN_FAIL,
3659 "times disassociation failed"),
3660 IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"),
3661 IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"),
3662 IPW2100_ORD(STAT_RX_HOST, "packets passed to host"),
3663 IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"),
3664 IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"),
3665 IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"),
3666 IPW2100_ORD(STAT_RX_DIR_DATA5_5,
3667 "directed packets at 5.5MB"),
3668 IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"),
3669 IPW2100_ORD(STAT_RX_NODIR_DATA, "nondirected packets"),
3670 IPW2100_ORD(STAT_RX_NODIR_DATA1,
3671 "nondirected packets at 1MB"),
3672 IPW2100_ORD(STAT_RX_NODIR_DATA2,
3673 "nondirected packets at 2MB"),
3674 IPW2100_ORD(STAT_RX_NODIR_DATA5_5,
3675 "nondirected packets at 5.5MB"),
3676 IPW2100_ORD(STAT_RX_NODIR_DATA11,
3677 "nondirected packets at 11MB"),
3678 IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"),
3679 IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), IPW2100_ORD(STAT_RX_CTS,
3680 "Rx CTS"),
3681 IPW2100_ORD(STAT_RX_ACK, "Rx ACK"),
3682 IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"),
3683 IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"),
3684 IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"),
3685 IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"),
3686 IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"),
3687 IPW2100_ORD(STAT_RX_REASSN_RESP,
3688 "Reassociation response Rx's"),
3689 IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"),
3690 IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"),
3691 IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"),
3692 IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"),
3693 IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"),
3694 IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"),
3695 IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"),
3696 IPW2100_ORD(STAT_RX_TOTAL_BYTES,
3697 "Total rx data bytes received"),
3698 IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"),
3699 IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"),
3700 IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"),
3701 IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"),
3702 IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"),
3703 IPW2100_ORD(STAT_RX_DUPLICATE1,
3704 "duplicate rx packets at 1MB"),
3705 IPW2100_ORD(STAT_RX_DUPLICATE2,
3706 "duplicate rx packets at 2MB"),
3707 IPW2100_ORD(STAT_RX_DUPLICATE5_5,
3708 "duplicate rx packets at 5.5MB"),
3709 IPW2100_ORD(STAT_RX_DUPLICATE11,
3710 "duplicate rx packets at 11MB"),
3711 IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
3712 IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"),
3713 IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"),
3714 IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"),
3715 IPW2100_ORD(STAT_RX_INVALID_PROTOCOL,
3716 "rx frames with invalid protocol"),
3717 IPW2100_ORD(SYS_BOOT_TIME, "Boot time"),
3718 IPW2100_ORD(STAT_RX_NO_BUFFER,
3719 "rx frames rejected due to no buffer"),
3720 IPW2100_ORD(STAT_RX_MISSING_FRAG,
3721 "rx frames dropped due to missing fragment"),
3722 IPW2100_ORD(STAT_RX_ORPHAN_FRAG,
3723 "rx frames dropped due to non-sequential fragment"),
3724 IPW2100_ORD(STAT_RX_ORPHAN_FRAME,
3725 "rx frames dropped due to unmatched 1st frame"),
3726 IPW2100_ORD(STAT_RX_FRAG_AGEOUT,
3727 "rx frames dropped due to uncompleted frame"),
3728 IPW2100_ORD(STAT_RX_ICV_ERRORS,
3729 "ICV errors during decryption"),
3730 IPW2100_ORD(STAT_PSP_SUSPENSION, "times adapter suspended"),
3731 IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"),
3732 IPW2100_ORD(STAT_PSP_POLL_TIMEOUT,
3733 "poll response timeouts"),
3734 IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT,
3735 "timeouts waiting for last {broad,multi}cast pkt"),
3736 IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"),
3737 IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"),
3738 IPW2100_ORD(STAT_PSP_STATION_ID, "PSP Station ID"),
3739 IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"),
3740 IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,
3741 "current calculation of % missed beacons"),
3742 IPW2100_ORD(STAT_PERCENT_RETRIES,
3743 "current calculation of % missed tx retries"),
3744 IPW2100_ORD(ASSOCIATED_AP_PTR,
3745 "0 if not associated, else pointer to AP table entry"),
3746 IPW2100_ORD(AVAILABLE_AP_CNT,
3747 "AP's decsribed in the AP table"),
3748 IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"),
3749 IPW2100_ORD(STAT_AP_ASSNS, "associations"),
3750 IPW2100_ORD(STAT_ASSN_FAIL, "association failures"),
3751 IPW2100_ORD(STAT_ASSN_RESP_FAIL,
3752 "failures due to response fail"),
3753 IPW2100_ORD(STAT_FULL_SCANS, "full scans"),
3754 IPW2100_ORD(CARD_DISABLED, "Card Disabled"),
3755 IPW2100_ORD(STAT_ROAM_INHIBIT,
3756 "times roaming was inhibited due to activity"),
3757 IPW2100_ORD(RSSI_AT_ASSN,
3758 "RSSI of associated AP at time of association"),
3759 IPW2100_ORD(STAT_ASSN_CAUSE1,
3760 "reassociation: no probe response or TX on hop"),
3761 IPW2100_ORD(STAT_ASSN_CAUSE2,
3762 "reassociation: poor tx/rx quality"),
3763 IPW2100_ORD(STAT_ASSN_CAUSE3,
3764 "reassociation: tx/rx quality (excessive AP load"),
3765 IPW2100_ORD(STAT_ASSN_CAUSE4,
3766 "reassociation: AP RSSI level"),
3767 IPW2100_ORD(STAT_ASSN_CAUSE5,
3768 "reassociations due to load leveling"),
3769 IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"),
3770 IPW2100_ORD(STAT_AUTH_RESP_FAIL,
3771 "times authentication response failed"),
3772 IPW2100_ORD(STATION_TABLE_CNT,
3773 "entries in association table"),
3774 IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"),
3775 IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"),
3776 IPW2100_ORD(COUNTRY_CODE,
3777 "IEEE country code as recv'd from beacon"),
3778 IPW2100_ORD(COUNTRY_CHANNELS,
Masanari Iidafd9071e2012-04-13 04:33:20 +00003779 "channels supported by country"),
James Ketrenosee8e3652005-09-14 09:47:29 -05003780 IPW2100_ORD(RESET_CNT, "adapter resets (warm)"),
3781 IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"),
3782 IPW2100_ORD(ANTENNA_DIVERSITY,
3783 "TRUE if antenna diversity is disabled"),
3784 IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"),
3785 IPW2100_ORD(OUR_FREQ,
3786 "current radio freq lower digits - channel ID"),
3787 IPW2100_ORD(RTC_TIME, "current RTC time"),
3788 IPW2100_ORD(PORT_TYPE, "operating mode"),
3789 IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"),
3790 IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"),
3791 IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"),
3792 IPW2100_ORD(BASIC_RATES, "basic tx rates"),
3793 IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"),
3794 IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"),
3795 IPW2100_ORD(CAPABILITIES,
3796 "Management frame capability field"),
3797 IPW2100_ORD(AUTH_TYPE, "Type of authentication"),
3798 IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"),
3799 IPW2100_ORD(RTS_THRESHOLD,
3800 "Min packet length for RTS handshaking"),
3801 IPW2100_ORD(INT_MODE, "International mode"),
3802 IPW2100_ORD(FRAGMENTATION_THRESHOLD,
3803 "protocol frag threshold"),
3804 IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
3805 "EEPROM offset in SRAM"),
3806 IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE,
3807 "EEPROM size in SRAM"),
3808 IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"),
3809 IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS,
3810 "EEPROM IBSS 11b channel set"),
3811 IPW2100_ORD(MAC_VERSION, "MAC Version"),
3812 IPW2100_ORD(MAC_REVISION, "MAC Revision"),
3813 IPW2100_ORD(RADIO_VERSION, "Radio Version"),
3814 IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"),
3815 IPW2100_ORD(UCODE_VERSION, "Ucode Version"),};
James Ketrenos2c86c272005-03-23 17:32:29 -06003816
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003817static ssize_t show_registers(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003818 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003819{
3820 int i;
3821 struct ipw2100_priv *priv = dev_get_drvdata(d);
3822 struct net_device *dev = priv->net_dev;
James Ketrenosee8e3652005-09-14 09:47:29 -05003823 char *out = buf;
James Ketrenos2c86c272005-03-23 17:32:29 -06003824 u32 val = 0;
3825
3826 out += sprintf(out, "%30s [Address ] : Hex\n", "Register");
3827
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003828 for (i = 0; i < ARRAY_SIZE(hw_data); i++) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003829 read_register(dev, hw_data[i].addr, &val);
3830 out += sprintf(out, "%30s [%08X] : %08X\n",
3831 hw_data[i].name, hw_data[i].addr, val);
3832 }
3833
3834 return out - buf;
3835}
James Ketrenosee8e3652005-09-14 09:47:29 -05003836
James Ketrenos2c86c272005-03-23 17:32:29 -06003837static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
3838
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003839static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003840 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003841{
3842 struct ipw2100_priv *priv = dev_get_drvdata(d);
3843 struct net_device *dev = priv->net_dev;
James Ketrenosee8e3652005-09-14 09:47:29 -05003844 char *out = buf;
James Ketrenos2c86c272005-03-23 17:32:29 -06003845 int i;
3846
3847 out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry");
3848
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003849 for (i = 0; i < ARRAY_SIZE(nic_data); i++) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003850 u8 tmp8;
3851 u16 tmp16;
3852 u32 tmp32;
3853
3854 switch (nic_data[i].size) {
3855 case 1:
3856 read_nic_byte(dev, nic_data[i].addr, &tmp8);
3857 out += sprintf(out, "%30s [%08X] : %02X\n",
3858 nic_data[i].name, nic_data[i].addr,
3859 tmp8);
3860 break;
3861 case 2:
3862 read_nic_word(dev, nic_data[i].addr, &tmp16);
3863 out += sprintf(out, "%30s [%08X] : %04X\n",
3864 nic_data[i].name, nic_data[i].addr,
3865 tmp16);
3866 break;
3867 case 4:
3868 read_nic_dword(dev, nic_data[i].addr, &tmp32);
3869 out += sprintf(out, "%30s [%08X] : %08X\n",
3870 nic_data[i].name, nic_data[i].addr,
3871 tmp32);
3872 break;
3873 }
3874 }
3875 return out - buf;
3876}
James Ketrenosee8e3652005-09-14 09:47:29 -05003877
James Ketrenos2c86c272005-03-23 17:32:29 -06003878static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
3879
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003880static ssize_t show_memory(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003881 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003882{
3883 struct ipw2100_priv *priv = dev_get_drvdata(d);
3884 struct net_device *dev = priv->net_dev;
3885 static unsigned long loop = 0;
3886 int len = 0;
3887 u32 buffer[4];
3888 int i;
3889 char line[81];
3890
3891 if (loop >= 0x30000)
3892 loop = 0;
3893
3894 /* sysfs provides us PAGE_SIZE buffer */
3895 while (len < PAGE_SIZE - 128 && loop < 0x30000) {
3896
James Ketrenosee8e3652005-09-14 09:47:29 -05003897 if (priv->snapshot[0])
3898 for (i = 0; i < 4; i++)
3899 buffer[i] =
3900 *(u32 *) SNAPSHOT_ADDR(loop + i * 4);
3901 else
3902 for (i = 0; i < 4; i++)
3903 read_nic_dword(dev, loop + i * 4, &buffer[i]);
James Ketrenos2c86c272005-03-23 17:32:29 -06003904
3905 if (priv->dump_raw)
3906 len += sprintf(buf + len,
3907 "%c%c%c%c"
3908 "%c%c%c%c"
3909 "%c%c%c%c"
3910 "%c%c%c%c",
James Ketrenosee8e3652005-09-14 09:47:29 -05003911 ((u8 *) buffer)[0x0],
3912 ((u8 *) buffer)[0x1],
3913 ((u8 *) buffer)[0x2],
3914 ((u8 *) buffer)[0x3],
3915 ((u8 *) buffer)[0x4],
3916 ((u8 *) buffer)[0x5],
3917 ((u8 *) buffer)[0x6],
3918 ((u8 *) buffer)[0x7],
3919 ((u8 *) buffer)[0x8],
3920 ((u8 *) buffer)[0x9],
3921 ((u8 *) buffer)[0xa],
3922 ((u8 *) buffer)[0xb],
3923 ((u8 *) buffer)[0xc],
3924 ((u8 *) buffer)[0xd],
3925 ((u8 *) buffer)[0xe],
3926 ((u8 *) buffer)[0xf]);
James Ketrenos2c86c272005-03-23 17:32:29 -06003927 else
3928 len += sprintf(buf + len, "%s\n",
3929 snprint_line(line, sizeof(line),
James Ketrenosee8e3652005-09-14 09:47:29 -05003930 (u8 *) buffer, 16, loop));
James Ketrenos2c86c272005-03-23 17:32:29 -06003931 loop += 16;
3932 }
3933
3934 return len;
3935}
3936
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003937static ssize_t store_memory(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003938 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06003939{
3940 struct ipw2100_priv *priv = dev_get_drvdata(d);
3941 struct net_device *dev = priv->net_dev;
3942 const char *p = buf;
3943
Zhu Yi8ed55a42006-01-24 13:49:20 +08003944 (void)dev; /* kill unused-var warning for debug-only code */
Jeff Garzikc2a8fad2005-11-09 00:49:38 -05003945
James Ketrenos2c86c272005-03-23 17:32:29 -06003946 if (count < 1)
3947 return count;
3948
3949 if (p[0] == '1' ||
3950 (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) {
3951 IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003952 dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003953 priv->dump_raw = 1;
3954
3955 } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' &&
James Ketrenosee8e3652005-09-14 09:47:29 -05003956 tolower(p[1]) == 'f')) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003957 IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003958 dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003959 priv->dump_raw = 0;
3960
3961 } else if (tolower(p[0]) == 'r') {
James Ketrenosee8e3652005-09-14 09:47:29 -05003962 IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003963 ipw2100_snapshot_free(priv);
3964
3965 } else
3966 IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, "
James Ketrenosee8e3652005-09-14 09:47:29 -05003967 "reset = clear memory snapshot\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003968
3969 return count;
3970}
James Ketrenos2c86c272005-03-23 17:32:29 -06003971
James Ketrenosee8e3652005-09-14 09:47:29 -05003972static DEVICE_ATTR(memory, S_IWUSR | S_IRUGO, show_memory, store_memory);
James Ketrenos2c86c272005-03-23 17:32:29 -06003973
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003974static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003975 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003976{
3977 struct ipw2100_priv *priv = dev_get_drvdata(d);
3978 u32 val = 0;
3979 int len = 0;
3980 u32 val_len;
3981 static int loop = 0;
3982
James Ketrenos82328352005-08-24 22:33:31 -05003983 if (priv->status & STATUS_RF_KILL_MASK)
3984 return 0;
3985
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003986 if (loop >= ARRAY_SIZE(ord_data))
James Ketrenos2c86c272005-03-23 17:32:29 -06003987 loop = 0;
3988
3989 /* sysfs provides us PAGE_SIZE buffer */
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003990 while (len < PAGE_SIZE - 128 && loop < ARRAY_SIZE(ord_data)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003991 val_len = sizeof(u32);
3992
3993 if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val,
3994 &val_len))
3995 len += sprintf(buf + len, "[0x%02X] = ERROR %s\n",
3996 ord_data[loop].index,
3997 ord_data[loop].desc);
3998 else
3999 len += sprintf(buf + len, "[0x%02X] = 0x%08X %s\n",
4000 ord_data[loop].index, val,
4001 ord_data[loop].desc);
4002 loop++;
4003 }
4004
4005 return len;
4006}
James Ketrenosee8e3652005-09-14 09:47:29 -05004007
James Ketrenos2c86c272005-03-23 17:32:29 -06004008static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL);
4009
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004010static ssize_t show_stats(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004011 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004012{
4013 struct ipw2100_priv *priv = dev_get_drvdata(d);
James Ketrenosee8e3652005-09-14 09:47:29 -05004014 char *out = buf;
James Ketrenos2c86c272005-03-23 17:32:29 -06004015
4016 out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n",
4017 priv->interrupts, priv->tx_interrupts,
4018 priv->rx_interrupts, priv->inta_other);
4019 out += sprintf(out, "firmware resets: %d\n", priv->resets);
4020 out += sprintf(out, "firmware hangs: %d\n", priv->hangs);
Brice Goglin0f52bf92005-12-01 01:41:46 -08004021#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06004022 out += sprintf(out, "packet mismatch image: %s\n",
4023 priv->snapshot[0] ? "YES" : "NO");
4024#endif
4025
4026 return out - buf;
4027}
James Ketrenos2c86c272005-03-23 17:32:29 -06004028
James Ketrenosee8e3652005-09-14 09:47:29 -05004029static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL);
James Ketrenos2c86c272005-03-23 17:32:29 -06004030
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004031static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004032{
4033 int err;
4034
4035 if (mode == priv->ieee->iw_mode)
4036 return 0;
4037
4038 err = ipw2100_disable_adapter(priv);
4039 if (err) {
Jiri Benc797b4f72005-08-25 20:03:27 -04004040 printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06004041 priv->net_dev->name, err);
4042 return err;
4043 }
4044
4045 switch (mode) {
4046 case IW_MODE_INFRA:
4047 priv->net_dev->type = ARPHRD_ETHER;
4048 break;
4049 case IW_MODE_ADHOC:
4050 priv->net_dev->type = ARPHRD_ETHER;
4051 break;
4052#ifdef CONFIG_IPW2100_MONITOR
4053 case IW_MODE_MONITOR:
4054 priv->last_mode = priv->ieee->iw_mode;
Stefan Rompf15745a72006-02-21 18:36:17 +08004055 priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
James Ketrenos2c86c272005-03-23 17:32:29 -06004056 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05004057#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06004058 }
4059
4060 priv->ieee->iw_mode = mode;
4061
4062#ifdef CONFIG_PM
James Ketrenosee8e3652005-09-14 09:47:29 -05004063 /* Indicate ipw2100_download_firmware download firmware
James Ketrenos2c86c272005-03-23 17:32:29 -06004064 * from disk instead of memory. */
4065 ipw2100_firmware.version = 0;
4066#endif
4067
Masanari Iidafd9071e2012-04-13 04:33:20 +00004068 printk(KERN_INFO "%s: Resetting on mode change.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004069 priv->reset_backoff = 0;
4070 schedule_reset(priv);
4071
4072 return 0;
4073}
4074
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004075static ssize_t show_internals(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004076 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004077{
4078 struct ipw2100_priv *priv = dev_get_drvdata(d);
4079 int len = 0;
4080
James Ketrenosee8e3652005-09-14 09:47:29 -05004081#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x)
James Ketrenos2c86c272005-03-23 17:32:29 -06004082
4083 if (priv->status & STATUS_ASSOCIATED)
4084 len += sprintf(buf + len, "connected: %lu\n",
4085 get_seconds() - priv->connect_start);
4086 else
4087 len += sprintf(buf + len, "not connected\n");
4088
John W. Linville274bfb82008-10-29 11:35:05 -04004089 DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p");
James Ketrenosee8e3652005-09-14 09:47:29 -05004090 DUMP_VAR(status, "08lx");
4091 DUMP_VAR(config, "08lx");
4092 DUMP_VAR(capability, "08lx");
James Ketrenos2c86c272005-03-23 17:32:29 -06004093
James Ketrenosee8e3652005-09-14 09:47:29 -05004094 len +=
4095 sprintf(buf + len, "last_rtc: %lu\n",
4096 (unsigned long)priv->last_rtc);
James Ketrenos2c86c272005-03-23 17:32:29 -06004097
James Ketrenosee8e3652005-09-14 09:47:29 -05004098 DUMP_VAR(fatal_error, "d");
4099 DUMP_VAR(stop_hang_check, "d");
4100 DUMP_VAR(stop_rf_kill, "d");
4101 DUMP_VAR(messages_sent, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004102
James Ketrenosee8e3652005-09-14 09:47:29 -05004103 DUMP_VAR(tx_pend_stat.value, "d");
4104 DUMP_VAR(tx_pend_stat.hi, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004105
James Ketrenosee8e3652005-09-14 09:47:29 -05004106 DUMP_VAR(tx_free_stat.value, "d");
4107 DUMP_VAR(tx_free_stat.lo, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004108
James Ketrenosee8e3652005-09-14 09:47:29 -05004109 DUMP_VAR(msg_free_stat.value, "d");
4110 DUMP_VAR(msg_free_stat.lo, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004111
James Ketrenosee8e3652005-09-14 09:47:29 -05004112 DUMP_VAR(msg_pend_stat.value, "d");
4113 DUMP_VAR(msg_pend_stat.hi, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004114
James Ketrenosee8e3652005-09-14 09:47:29 -05004115 DUMP_VAR(fw_pend_stat.value, "d");
4116 DUMP_VAR(fw_pend_stat.hi, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004117
James Ketrenosee8e3652005-09-14 09:47:29 -05004118 DUMP_VAR(txq_stat.value, "d");
4119 DUMP_VAR(txq_stat.lo, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004120
James Ketrenosee8e3652005-09-14 09:47:29 -05004121 DUMP_VAR(ieee->scans, "d");
4122 DUMP_VAR(reset_backoff, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004123
4124 return len;
4125}
James Ketrenosee8e3652005-09-14 09:47:29 -05004126
James Ketrenos2c86c272005-03-23 17:32:29 -06004127static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL);
4128
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004129static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004130 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004131{
4132 struct ipw2100_priv *priv = dev_get_drvdata(d);
4133 char essid[IW_ESSID_MAX_SIZE + 1];
4134 u8 bssid[ETH_ALEN];
4135 u32 chan = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05004136 char *out = buf;
Hannes Ederb9da9e92009-02-14 11:50:26 +00004137 unsigned int length;
James Ketrenos2c86c272005-03-23 17:32:29 -06004138 int ret;
4139
James Ketrenos82328352005-08-24 22:33:31 -05004140 if (priv->status & STATUS_RF_KILL_MASK)
4141 return 0;
4142
James Ketrenos2c86c272005-03-23 17:32:29 -06004143 memset(essid, 0, sizeof(essid));
4144 memset(bssid, 0, sizeof(bssid));
4145
4146 length = IW_ESSID_MAX_SIZE;
4147 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &length);
4148 if (ret)
4149 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
4150 __LINE__);
4151
4152 length = sizeof(bssid);
4153 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
4154 bssid, &length);
4155 if (ret)
4156 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
4157 __LINE__);
4158
4159 length = sizeof(u32);
4160 ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &length);
4161 if (ret)
4162 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
4163 __LINE__);
4164
4165 out += sprintf(out, "ESSID: %s\n", essid);
Johannes Berge1749612008-10-27 15:59:26 -07004166 out += sprintf(out, "BSSID: %pM\n", bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06004167 out += sprintf(out, "Channel: %d\n", chan);
4168
4169 return out - buf;
4170}
James Ketrenos2c86c272005-03-23 17:32:29 -06004171
James Ketrenosee8e3652005-09-14 09:47:29 -05004172static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
James Ketrenos2c86c272005-03-23 17:32:29 -06004173
Brice Goglin0f52bf92005-12-01 01:41:46 -08004174#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06004175static ssize_t show_debug_level(struct device_driver *d, char *buf)
4176{
4177 return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
4178}
4179
James Ketrenos82328352005-08-24 22:33:31 -05004180static ssize_t store_debug_level(struct device_driver *d,
4181 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004182{
4183 char *p = (char *)buf;
4184 u32 val;
4185
4186 if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
4187 p++;
4188 if (p[0] == 'x' || p[0] == 'X')
4189 p++;
4190 val = simple_strtoul(p, &p, 16);
4191 } else
4192 val = simple_strtoul(p, &p, 10);
4193 if (p == buf)
Zhu Yia1e695a2005-07-04 14:06:00 +08004194 IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf);
James Ketrenos2c86c272005-03-23 17:32:29 -06004195 else
4196 ipw2100_debug_level = val;
4197
4198 return strnlen(buf, count);
4199}
James Ketrenosee8e3652005-09-14 09:47:29 -05004200
James Ketrenos2c86c272005-03-23 17:32:29 -06004201static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level,
4202 store_debug_level);
Brice Goglin0f52bf92005-12-01 01:41:46 -08004203#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -06004204
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004205static ssize_t show_fatal_error(struct device *d,
James Ketrenosee8e3652005-09-14 09:47:29 -05004206 struct device_attribute *attr, char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004207{
4208 struct ipw2100_priv *priv = dev_get_drvdata(d);
4209 char *out = buf;
4210 int i;
4211
4212 if (priv->fatal_error)
James Ketrenosee8e3652005-09-14 09:47:29 -05004213 out += sprintf(out, "0x%08X\n", priv->fatal_error);
James Ketrenos2c86c272005-03-23 17:32:29 -06004214 else
4215 out += sprintf(out, "0\n");
4216
4217 for (i = 1; i <= IPW2100_ERROR_QUEUE; i++) {
4218 if (!priv->fatal_errors[(priv->fatal_index - i) %
4219 IPW2100_ERROR_QUEUE])
4220 continue;
4221
4222 out += sprintf(out, "%d. 0x%08X\n", i,
4223 priv->fatal_errors[(priv->fatal_index - i) %
4224 IPW2100_ERROR_QUEUE]);
4225 }
4226
4227 return out - buf;
4228}
4229
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004230static ssize_t store_fatal_error(struct device *d,
James Ketrenosee8e3652005-09-14 09:47:29 -05004231 struct device_attribute *attr, const char *buf,
4232 size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004233{
4234 struct ipw2100_priv *priv = dev_get_drvdata(d);
4235 schedule_reset(priv);
4236 return count;
4237}
James Ketrenos2c86c272005-03-23 17:32:29 -06004238
James Ketrenosee8e3652005-09-14 09:47:29 -05004239static DEVICE_ATTR(fatal_error, S_IWUSR | S_IRUGO, show_fatal_error,
4240 store_fatal_error);
James Ketrenos2c86c272005-03-23 17:32:29 -06004241
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004242static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004243 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004244{
4245 struct ipw2100_priv *priv = dev_get_drvdata(d);
4246 return sprintf(buf, "%d\n", priv->ieee->scan_age);
4247}
4248
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004249static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004250 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004251{
4252 struct ipw2100_priv *priv = dev_get_drvdata(d);
4253 struct net_device *dev = priv->net_dev;
4254 char buffer[] = "00000000";
4255 unsigned long len =
4256 (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
4257 unsigned long val;
4258 char *p = buffer;
4259
Zhu Yi8ed55a42006-01-24 13:49:20 +08004260 (void)dev; /* kill unused-var warning for debug-only code */
Jeff Garzikc2a8fad2005-11-09 00:49:38 -05004261
James Ketrenos2c86c272005-03-23 17:32:29 -06004262 IPW_DEBUG_INFO("enter\n");
4263
4264 strncpy(buffer, buf, len);
4265 buffer[len] = 0;
4266
4267 if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
4268 p++;
4269 if (p[0] == 'x' || p[0] == 'X')
4270 p++;
4271 val = simple_strtoul(p, &p, 16);
4272 } else
4273 val = simple_strtoul(p, &p, 10);
4274 if (p == buffer) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004275 IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004276 } else {
4277 priv->ieee->scan_age = val;
4278 IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
4279 }
4280
4281 IPW_DEBUG_INFO("exit\n");
4282 return len;
4283}
James Ketrenosee8e3652005-09-14 09:47:29 -05004284
James Ketrenos2c86c272005-03-23 17:32:29 -06004285static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
4286
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004287static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004288 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004289{
4290 /* 0 - RF kill not enabled
4291 1 - SW based RF kill active (sysfs)
4292 2 - HW based RF kill active
4293 3 - Both HW and SW baed RF kill active */
Greg Kroah-Hartman928841b2009-04-30 23:02:47 -07004294 struct ipw2100_priv *priv = dev_get_drvdata(d);
James Ketrenos2c86c272005-03-23 17:32:29 -06004295 int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
James Ketrenosee8e3652005-09-14 09:47:29 -05004296 (rf_kill_active(priv) ? 0x2 : 0x0);
James Ketrenos2c86c272005-03-23 17:32:29 -06004297 return sprintf(buf, "%i\n", val);
4298}
4299
4300static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
4301{
4302 if ((disable_radio ? 1 : 0) ==
4303 (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
James Ketrenosee8e3652005-09-14 09:47:29 -05004304 return 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06004305
4306 IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
4307 disable_radio ? "OFF" : "ON");
4308
Ingo Molnar752e3772006-02-28 07:20:54 +08004309 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06004310
4311 if (disable_radio) {
4312 priv->status |= STATUS_RF_KILL_SW;
4313 ipw2100_down(priv);
4314 } else {
4315 priv->status &= ~STATUS_RF_KILL_SW;
4316 if (rf_kill_active(priv)) {
4317 IPW_DEBUG_RF_KILL("Can not turn radio back on - "
4318 "disabled by HW switch\n");
4319 /* Make sure the RF_KILL check timer is running */
4320 priv->stop_rf_kill = 0;
Tejun Heo41f63c52012-08-03 10:30:47 -07004321 mod_delayed_work(system_wq, &priv->rf_kill,
4322 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06004323 } else
4324 schedule_reset(priv);
4325 }
4326
Ingo Molnar752e3772006-02-28 07:20:54 +08004327 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06004328 return 1;
4329}
4330
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004331static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004332 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004333{
4334 struct ipw2100_priv *priv = dev_get_drvdata(d);
4335 ipw_radio_kill_sw(priv, buf[0] == '1');
4336 return count;
4337}
James Ketrenos2c86c272005-03-23 17:32:29 -06004338
James Ketrenosee8e3652005-09-14 09:47:29 -05004339static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
James Ketrenos2c86c272005-03-23 17:32:29 -06004340
4341static struct attribute *ipw2100_sysfs_entries[] = {
4342 &dev_attr_hardware.attr,
4343 &dev_attr_registers.attr,
4344 &dev_attr_ordinals.attr,
4345 &dev_attr_pci.attr,
4346 &dev_attr_stats.attr,
4347 &dev_attr_internals.attr,
4348 &dev_attr_bssinfo.attr,
4349 &dev_attr_memory.attr,
4350 &dev_attr_scan_age.attr,
4351 &dev_attr_fatal_error.attr,
4352 &dev_attr_rf_kill.attr,
4353 &dev_attr_cfg.attr,
4354 &dev_attr_status.attr,
4355 &dev_attr_capability.attr,
4356 NULL,
4357};
4358
4359static struct attribute_group ipw2100_attribute_group = {
4360 .attrs = ipw2100_sysfs_entries,
4361};
4362
James Ketrenos2c86c272005-03-23 17:32:29 -06004363static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
4364{
4365 struct ipw2100_status_queue *q = &priv->status_queue;
4366
4367 IPW_DEBUG_INFO("enter\n");
4368
4369 q->size = entries * sizeof(struct ipw2100_status);
James Ketrenosee8e3652005-09-14 09:47:29 -05004370 q->drv =
4371 (struct ipw2100_status *)pci_alloc_consistent(priv->pci_dev,
4372 q->size, &q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004373 if (!q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004374 IPW_DEBUG_WARNING("Can not allocate status queue.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06004375 return -ENOMEM;
4376 }
4377
4378 memset(q->drv, 0, q->size);
4379
4380 IPW_DEBUG_INFO("exit\n");
4381
4382 return 0;
4383}
4384
4385static void status_queue_free(struct ipw2100_priv *priv)
4386{
4387 IPW_DEBUG_INFO("enter\n");
4388
4389 if (priv->status_queue.drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004390 pci_free_consistent(priv->pci_dev, priv->status_queue.size,
4391 priv->status_queue.drv,
4392 priv->status_queue.nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004393 priv->status_queue.drv = NULL;
4394 }
4395
4396 IPW_DEBUG_INFO("exit\n");
4397}
4398
4399static int bd_queue_allocate(struct ipw2100_priv *priv,
4400 struct ipw2100_bd_queue *q, int entries)
4401{
4402 IPW_DEBUG_INFO("enter\n");
4403
4404 memset(q, 0, sizeof(struct ipw2100_bd_queue));
4405
4406 q->entries = entries;
4407 q->size = entries * sizeof(struct ipw2100_bd);
4408 q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic);
4409 if (!q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004410 IPW_DEBUG_INFO
4411 ("can't allocate shared memory for buffer descriptors\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06004412 return -ENOMEM;
4413 }
4414 memset(q->drv, 0, q->size);
4415
4416 IPW_DEBUG_INFO("exit\n");
4417
4418 return 0;
4419}
4420
James Ketrenosee8e3652005-09-14 09:47:29 -05004421static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q)
James Ketrenos2c86c272005-03-23 17:32:29 -06004422{
4423 IPW_DEBUG_INFO("enter\n");
4424
4425 if (!q)
4426 return;
4427
4428 if (q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004429 pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004430 q->drv = NULL;
4431 }
4432
4433 IPW_DEBUG_INFO("exit\n");
4434}
4435
James Ketrenosee8e3652005-09-14 09:47:29 -05004436static void bd_queue_initialize(struct ipw2100_priv *priv,
4437 struct ipw2100_bd_queue *q, u32 base, u32 size,
4438 u32 r, u32 w)
James Ketrenos2c86c272005-03-23 17:32:29 -06004439{
4440 IPW_DEBUG_INFO("enter\n");
4441
James Ketrenosee8e3652005-09-14 09:47:29 -05004442 IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv,
4443 (u32) q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004444
4445 write_register(priv->net_dev, base, q->nic);
4446 write_register(priv->net_dev, size, q->entries);
4447 write_register(priv->net_dev, r, q->oldest);
4448 write_register(priv->net_dev, w, q->next);
4449
4450 IPW_DEBUG_INFO("exit\n");
4451}
4452
Tejun Heobcb6d912011-01-26 12:12:50 +01004453static void ipw2100_kill_works(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06004454{
Tejun Heobcb6d912011-01-26 12:12:50 +01004455 priv->stop_rf_kill = 1;
4456 priv->stop_hang_check = 1;
4457 cancel_delayed_work_sync(&priv->reset_work);
4458 cancel_delayed_work_sync(&priv->security_work);
4459 cancel_delayed_work_sync(&priv->wx_event_work);
4460 cancel_delayed_work_sync(&priv->hang_check);
4461 cancel_delayed_work_sync(&priv->rf_kill);
4462 cancel_work_sync(&priv->scan_event_now);
4463 cancel_delayed_work_sync(&priv->scan_event_later);
James Ketrenos2c86c272005-03-23 17:32:29 -06004464}
4465
4466static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
4467{
4468 int i, j, err = -EINVAL;
4469 void *v;
4470 dma_addr_t p;
4471
4472 IPW_DEBUG_INFO("enter\n");
4473
4474 err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH);
4475 if (err) {
4476 IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05004477 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004478 return err;
4479 }
4480
Joe Perches0d2e7a52013-02-03 17:28:14 +00004481 priv->tx_buffers = kmalloc_array(TX_PENDED_QUEUE_LENGTH,
4482 sizeof(struct ipw2100_tx_packet),
4483 GFP_ATOMIC);
James Ketrenos2c86c272005-03-23 17:32:29 -06004484 if (!priv->tx_buffers) {
James Ketrenos2c86c272005-03-23 17:32:29 -06004485 bd_queue_free(priv, &priv->tx_queue);
4486 return -ENOMEM;
4487 }
4488
4489 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004490 v = pci_alloc_consistent(priv->pci_dev,
4491 sizeof(struct ipw2100_data_header),
4492 &p);
James Ketrenos2c86c272005-03-23 17:32:29 -06004493 if (!v) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004494 printk(KERN_ERR DRV_NAME
4495 ": %s: PCI alloc failed for tx " "buffers.\n",
4496 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004497 err = -ENOMEM;
4498 break;
4499 }
4500
4501 priv->tx_buffers[i].type = DATA;
James Ketrenosee8e3652005-09-14 09:47:29 -05004502 priv->tx_buffers[i].info.d_struct.data =
4503 (struct ipw2100_data_header *)v;
James Ketrenos2c86c272005-03-23 17:32:29 -06004504 priv->tx_buffers[i].info.d_struct.data_phys = p;
4505 priv->tx_buffers[i].info.d_struct.txb = NULL;
4506 }
4507
4508 if (i == TX_PENDED_QUEUE_LENGTH)
4509 return 0;
4510
4511 for (j = 0; j < i; j++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004512 pci_free_consistent(priv->pci_dev,
4513 sizeof(struct ipw2100_data_header),
4514 priv->tx_buffers[j].info.d_struct.data,
4515 priv->tx_buffers[j].info.d_struct.
4516 data_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06004517 }
4518
4519 kfree(priv->tx_buffers);
4520 priv->tx_buffers = NULL;
4521
4522 return err;
4523}
4524
4525static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
4526{
4527 int i;
4528
4529 IPW_DEBUG_INFO("enter\n");
4530
4531 /*
4532 * reinitialize packet info lists
4533 */
4534 INIT_LIST_HEAD(&priv->fw_pend_list);
4535 INIT_STAT(&priv->fw_pend_stat);
4536
4537 /*
4538 * reinitialize lists
4539 */
4540 INIT_LIST_HEAD(&priv->tx_pend_list);
4541 INIT_LIST_HEAD(&priv->tx_free_list);
4542 INIT_STAT(&priv->tx_pend_stat);
4543 INIT_STAT(&priv->tx_free_stat);
4544
4545 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
4546 /* We simply drop any SKBs that have been queued for
4547 * transmit */
4548 if (priv->tx_buffers[i].info.d_struct.txb) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04004549 libipw_txb_free(priv->tx_buffers[i].info.d_struct.
James Ketrenosee8e3652005-09-14 09:47:29 -05004550 txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06004551 priv->tx_buffers[i].info.d_struct.txb = NULL;
4552 }
4553
4554 list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list);
4555 }
4556
4557 SET_STAT(&priv->tx_free_stat, i);
4558
4559 priv->tx_queue.oldest = 0;
4560 priv->tx_queue.available = priv->tx_queue.entries;
4561 priv->tx_queue.next = 0;
4562 INIT_STAT(&priv->txq_stat);
4563 SET_STAT(&priv->txq_stat, priv->tx_queue.available);
4564
4565 bd_queue_initialize(priv, &priv->tx_queue,
4566 IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE,
4567 IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE,
4568 IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
4569 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX);
4570
4571 IPW_DEBUG_INFO("exit\n");
4572
4573}
4574
4575static void ipw2100_tx_free(struct ipw2100_priv *priv)
4576{
4577 int i;
4578
4579 IPW_DEBUG_INFO("enter\n");
4580
4581 bd_queue_free(priv, &priv->tx_queue);
4582
4583 if (!priv->tx_buffers)
4584 return;
4585
4586 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
4587 if (priv->tx_buffers[i].info.d_struct.txb) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04004588 libipw_txb_free(priv->tx_buffers[i].info.d_struct.
James Ketrenosee8e3652005-09-14 09:47:29 -05004589 txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06004590 priv->tx_buffers[i].info.d_struct.txb = NULL;
4591 }
4592 if (priv->tx_buffers[i].info.d_struct.data)
James Ketrenosee8e3652005-09-14 09:47:29 -05004593 pci_free_consistent(priv->pci_dev,
4594 sizeof(struct ipw2100_data_header),
4595 priv->tx_buffers[i].info.d_struct.
4596 data,
4597 priv->tx_buffers[i].info.d_struct.
4598 data_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06004599 }
4600
4601 kfree(priv->tx_buffers);
4602 priv->tx_buffers = NULL;
4603
4604 IPW_DEBUG_INFO("exit\n");
4605}
4606
James Ketrenos2c86c272005-03-23 17:32:29 -06004607static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
4608{
4609 int i, j, err = -EINVAL;
4610
4611 IPW_DEBUG_INFO("enter\n");
4612
4613 err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH);
4614 if (err) {
4615 IPW_DEBUG_INFO("failed bd_queue_allocate\n");
4616 return err;
4617 }
4618
4619 err = status_queue_allocate(priv, RX_QUEUE_LENGTH);
4620 if (err) {
4621 IPW_DEBUG_INFO("failed status_queue_allocate\n");
4622 bd_queue_free(priv, &priv->rx_queue);
4623 return err;
4624 }
4625
4626 /*
4627 * allocate packets
4628 */
Joe Perchesefe4c452010-05-31 20:23:15 -07004629 priv->rx_buffers = kmalloc(RX_QUEUE_LENGTH *
4630 sizeof(struct ipw2100_rx_packet),
4631 GFP_KERNEL);
James Ketrenos2c86c272005-03-23 17:32:29 -06004632 if (!priv->rx_buffers) {
4633 IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
4634
4635 bd_queue_free(priv, &priv->rx_queue);
4636
4637 status_queue_free(priv);
4638
4639 return -ENOMEM;
4640 }
4641
4642 for (i = 0; i < RX_QUEUE_LENGTH; i++) {
4643 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
4644
4645 err = ipw2100_alloc_skb(priv, packet);
4646 if (unlikely(err)) {
4647 err = -ENOMEM;
4648 break;
4649 }
4650
4651 /* The BD holds the cache aligned address */
4652 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
4653 priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH;
4654 priv->status_queue.drv[i].status_fields = 0;
4655 }
4656
4657 if (i == RX_QUEUE_LENGTH)
4658 return 0;
4659
4660 for (j = 0; j < i; j++) {
4661 pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr,
4662 sizeof(struct ipw2100_rx_packet),
4663 PCI_DMA_FROMDEVICE);
4664 dev_kfree_skb(priv->rx_buffers[j].skb);
4665 }
4666
4667 kfree(priv->rx_buffers);
4668 priv->rx_buffers = NULL;
4669
4670 bd_queue_free(priv, &priv->rx_queue);
4671
4672 status_queue_free(priv);
4673
4674 return err;
4675}
4676
4677static void ipw2100_rx_initialize(struct ipw2100_priv *priv)
4678{
4679 IPW_DEBUG_INFO("enter\n");
4680
4681 priv->rx_queue.oldest = 0;
4682 priv->rx_queue.available = priv->rx_queue.entries - 1;
4683 priv->rx_queue.next = priv->rx_queue.entries - 1;
4684
4685 INIT_STAT(&priv->rxq_stat);
4686 SET_STAT(&priv->rxq_stat, priv->rx_queue.available);
4687
4688 bd_queue_initialize(priv, &priv->rx_queue,
4689 IPW_MEM_HOST_SHARED_RX_BD_BASE,
4690 IPW_MEM_HOST_SHARED_RX_BD_SIZE,
4691 IPW_MEM_HOST_SHARED_RX_READ_INDEX,
4692 IPW_MEM_HOST_SHARED_RX_WRITE_INDEX);
4693
4694 /* set up the status queue */
4695 write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE,
4696 priv->status_queue.nic);
4697
4698 IPW_DEBUG_INFO("exit\n");
4699}
4700
4701static void ipw2100_rx_free(struct ipw2100_priv *priv)
4702{
4703 int i;
4704
4705 IPW_DEBUG_INFO("enter\n");
4706
4707 bd_queue_free(priv, &priv->rx_queue);
4708 status_queue_free(priv);
4709
4710 if (!priv->rx_buffers)
4711 return;
4712
4713 for (i = 0; i < RX_QUEUE_LENGTH; i++) {
4714 if (priv->rx_buffers[i].rxp) {
4715 pci_unmap_single(priv->pci_dev,
4716 priv->rx_buffers[i].dma_addr,
4717 sizeof(struct ipw2100_rx),
4718 PCI_DMA_FROMDEVICE);
4719 dev_kfree_skb(priv->rx_buffers[i].skb);
4720 }
4721 }
4722
4723 kfree(priv->rx_buffers);
4724 priv->rx_buffers = NULL;
4725
4726 IPW_DEBUG_INFO("exit\n");
4727}
4728
4729static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
4730{
4731 u32 length = ETH_ALEN;
Joe Perches0795af52007-10-03 17:59:30 -07004732 u8 addr[ETH_ALEN];
James Ketrenos2c86c272005-03-23 17:32:29 -06004733
4734 int err;
4735
Joe Perches0795af52007-10-03 17:59:30 -07004736 err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
James Ketrenos2c86c272005-03-23 17:32:29 -06004737 if (err) {
4738 IPW_DEBUG_INFO("MAC address read failed\n");
4739 return -EIO;
4740 }
James Ketrenos2c86c272005-03-23 17:32:29 -06004741
Joe Perches0795af52007-10-03 17:59:30 -07004742 memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN);
Johannes Berge1749612008-10-27 15:59:26 -07004743 IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06004744
4745 return 0;
4746}
4747
4748/********************************************************************
4749 *
4750 * Firmware Commands
4751 *
4752 ********************************************************************/
4753
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004754static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004755{
4756 struct host_command cmd = {
4757 .host_command = ADAPTER_ADDRESS,
4758 .host_command_sequence = 0,
4759 .host_command_length = ETH_ALEN
4760 };
4761 int err;
4762
4763 IPW_DEBUG_HC("SET_MAC_ADDRESS\n");
4764
4765 IPW_DEBUG_INFO("enter\n");
4766
4767 if (priv->config & CFG_CUSTOM_MAC) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004768 memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06004769 memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
4770 } else
4771 memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr,
4772 ETH_ALEN);
4773
4774 err = ipw2100_hw_send_command(priv, &cmd);
4775
4776 IPW_DEBUG_INFO("exit\n");
4777 return err;
4778}
4779
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004780static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type,
James Ketrenos2c86c272005-03-23 17:32:29 -06004781 int batch_mode)
4782{
4783 struct host_command cmd = {
4784 .host_command = PORT_TYPE,
4785 .host_command_sequence = 0,
4786 .host_command_length = sizeof(u32)
4787 };
4788 int err;
4789
4790 switch (port_type) {
4791 case IW_MODE_INFRA:
4792 cmd.host_command_parameters[0] = IPW_BSS;
4793 break;
4794 case IW_MODE_ADHOC:
4795 cmd.host_command_parameters[0] = IPW_IBSS;
4796 break;
4797 }
4798
4799 IPW_DEBUG_HC("PORT_TYPE: %s\n",
4800 port_type == IPW_IBSS ? "Ad-Hoc" : "Managed");
4801
4802 if (!batch_mode) {
4803 err = ipw2100_disable_adapter(priv);
4804 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004805 printk(KERN_ERR DRV_NAME
4806 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06004807 priv->net_dev->name, err);
4808 return err;
4809 }
4810 }
4811
4812 /* send cmd to firmware */
4813 err = ipw2100_hw_send_command(priv, &cmd);
4814
4815 if (!batch_mode)
4816 ipw2100_enable_adapter(priv);
4817
4818 return err;
4819}
4820
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004821static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
4822 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004823{
4824 struct host_command cmd = {
4825 .host_command = CHANNEL,
4826 .host_command_sequence = 0,
4827 .host_command_length = sizeof(u32)
4828 };
4829 int err;
4830
4831 cmd.host_command_parameters[0] = channel;
4832
4833 IPW_DEBUG_HC("CHANNEL: %d\n", channel);
4834
4835 /* If BSS then we don't support channel selection */
4836 if (priv->ieee->iw_mode == IW_MODE_INFRA)
4837 return 0;
4838
4839 if ((channel != 0) &&
4840 ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL)))
4841 return -EINVAL;
4842
4843 if (!batch_mode) {
4844 err = ipw2100_disable_adapter(priv);
4845 if (err)
4846 return err;
4847 }
4848
4849 err = ipw2100_hw_send_command(priv, &cmd);
4850 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004851 IPW_DEBUG_INFO("Failed to set channel to %d", channel);
James Ketrenos2c86c272005-03-23 17:32:29 -06004852 return err;
4853 }
4854
4855 if (channel)
4856 priv->config |= CFG_STATIC_CHANNEL;
4857 else
4858 priv->config &= ~CFG_STATIC_CHANNEL;
4859
4860 priv->channel = channel;
4861
4862 if (!batch_mode) {
4863 err = ipw2100_enable_adapter(priv);
4864 if (err)
4865 return err;
4866 }
4867
4868 return 0;
4869}
4870
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004871static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004872{
4873 struct host_command cmd = {
4874 .host_command = SYSTEM_CONFIG,
4875 .host_command_sequence = 0,
4876 .host_command_length = 12,
4877 };
4878 u32 ibss_mask, len = sizeof(u32);
4879 int err;
4880
4881 /* Set system configuration */
4882
4883 if (!batch_mode) {
4884 err = ipw2100_disable_adapter(priv);
4885 if (err)
4886 return err;
4887 }
4888
4889 if (priv->ieee->iw_mode == IW_MODE_ADHOC)
4890 cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START;
4891
4892 cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK |
James Ketrenosee8e3652005-09-14 09:47:29 -05004893 IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06004894
4895 if (!(priv->config & CFG_LONG_PREAMBLE))
4896 cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO;
4897
4898 err = ipw2100_get_ordinal(priv,
4899 IPW_ORD_EEPROM_IBSS_11B_CHANNELS,
James Ketrenosee8e3652005-09-14 09:47:29 -05004900 &ibss_mask, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06004901 if (err)
4902 ibss_mask = IPW_IBSS_11B_DEFAULT_MASK;
4903
4904 cmd.host_command_parameters[1] = REG_CHANNEL_MASK;
4905 cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask;
4906
4907 /* 11b only */
James Ketrenosee8e3652005-09-14 09:47:29 -05004908 /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */
James Ketrenos2c86c272005-03-23 17:32:29 -06004909
4910 err = ipw2100_hw_send_command(priv, &cmd);
4911 if (err)
4912 return err;
4913
4914/* If IPv6 is configured in the kernel then we don't want to filter out all
4915 * of the multicast packets as IPv6 needs some. */
4916#if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE)
4917 cmd.host_command = ADD_MULTICAST;
4918 cmd.host_command_sequence = 0;
4919 cmd.host_command_length = 0;
4920
4921 ipw2100_hw_send_command(priv, &cmd);
4922#endif
4923 if (!batch_mode) {
4924 err = ipw2100_enable_adapter(priv);
4925 if (err)
4926 return err;
4927 }
4928
4929 return 0;
4930}
4931
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004932static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate,
4933 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004934{
4935 struct host_command cmd = {
4936 .host_command = BASIC_TX_RATES,
4937 .host_command_sequence = 0,
4938 .host_command_length = 4
4939 };
4940 int err;
4941
4942 cmd.host_command_parameters[0] = rate & TX_RATE_MASK;
4943
4944 if (!batch_mode) {
4945 err = ipw2100_disable_adapter(priv);
4946 if (err)
4947 return err;
4948 }
4949
4950 /* Set BASIC TX Rate first */
4951 ipw2100_hw_send_command(priv, &cmd);
4952
4953 /* Set TX Rate */
4954 cmd.host_command = TX_RATES;
4955 ipw2100_hw_send_command(priv, &cmd);
4956
4957 /* Set MSDU TX Rate */
4958 cmd.host_command = MSDU_TX_RATES;
4959 ipw2100_hw_send_command(priv, &cmd);
4960
4961 if (!batch_mode) {
4962 err = ipw2100_enable_adapter(priv);
4963 if (err)
4964 return err;
4965 }
4966
4967 priv->tx_rates = rate;
4968
4969 return 0;
4970}
4971
James Ketrenosee8e3652005-09-14 09:47:29 -05004972static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
James Ketrenos2c86c272005-03-23 17:32:29 -06004973{
4974 struct host_command cmd = {
4975 .host_command = POWER_MODE,
4976 .host_command_sequence = 0,
4977 .host_command_length = 4
4978 };
4979 int err;
4980
4981 cmd.host_command_parameters[0] = power_level;
4982
4983 err = ipw2100_hw_send_command(priv, &cmd);
4984 if (err)
4985 return err;
4986
4987 if (power_level == IPW_POWER_MODE_CAM)
4988 priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
4989 else
4990 priv->power_mode = IPW_POWER_ENABLED | power_level;
4991
Robert P. J. Dayae800312007-01-31 02:39:40 -05004992#ifdef IPW2100_TX_POWER
James Ketrenosee8e3652005-09-14 09:47:29 -05004993 if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
James Ketrenos2c86c272005-03-23 17:32:29 -06004994 /* Set beacon interval */
4995 cmd.host_command = TX_POWER_INDEX;
James Ketrenosee8e3652005-09-14 09:47:29 -05004996 cmd.host_command_parameters[0] = (u32) priv->adhoc_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06004997
4998 err = ipw2100_hw_send_command(priv, &cmd);
4999 if (err)
5000 return err;
5001 }
5002#endif
5003
5004 return 0;
5005}
5006
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005007static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold)
James Ketrenos2c86c272005-03-23 17:32:29 -06005008{
5009 struct host_command cmd = {
5010 .host_command = RTS_THRESHOLD,
5011 .host_command_sequence = 0,
5012 .host_command_length = 4
5013 };
5014 int err;
5015
5016 if (threshold & RTS_DISABLED)
5017 cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD;
5018 else
5019 cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED;
5020
5021 err = ipw2100_hw_send_command(priv, &cmd);
5022 if (err)
5023 return err;
5024
5025 priv->rts_threshold = threshold;
5026
5027 return 0;
5028}
5029
5030#if 0
5031int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv,
5032 u32 threshold, int batch_mode)
5033{
5034 struct host_command cmd = {
5035 .host_command = FRAG_THRESHOLD,
5036 .host_command_sequence = 0,
5037 .host_command_length = 4,
5038 .host_command_parameters[0] = 0,
5039 };
5040 int err;
5041
5042 if (!batch_mode) {
5043 err = ipw2100_disable_adapter(priv);
5044 if (err)
5045 return err;
5046 }
5047
5048 if (threshold == 0)
5049 threshold = DEFAULT_FRAG_THRESHOLD;
5050 else {
5051 threshold = max(threshold, MIN_FRAG_THRESHOLD);
5052 threshold = min(threshold, MAX_FRAG_THRESHOLD);
5053 }
5054
5055 cmd.host_command_parameters[0] = threshold;
5056
5057 IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold);
5058
5059 err = ipw2100_hw_send_command(priv, &cmd);
5060
5061 if (!batch_mode)
5062 ipw2100_enable_adapter(priv);
5063
5064 if (!err)
5065 priv->frag_threshold = threshold;
5066
5067 return err;
5068}
5069#endif
5070
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005071static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry)
James Ketrenos2c86c272005-03-23 17:32:29 -06005072{
5073 struct host_command cmd = {
5074 .host_command = SHORT_RETRY_LIMIT,
5075 .host_command_sequence = 0,
5076 .host_command_length = 4
5077 };
5078 int err;
5079
5080 cmd.host_command_parameters[0] = retry;
5081
5082 err = ipw2100_hw_send_command(priv, &cmd);
5083 if (err)
5084 return err;
5085
5086 priv->short_retry_limit = retry;
5087
5088 return 0;
5089}
5090
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005091static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry)
James Ketrenos2c86c272005-03-23 17:32:29 -06005092{
5093 struct host_command cmd = {
5094 .host_command = LONG_RETRY_LIMIT,
5095 .host_command_sequence = 0,
5096 .host_command_length = 4
5097 };
5098 int err;
5099
5100 cmd.host_command_parameters[0] = retry;
5101
5102 err = ipw2100_hw_send_command(priv, &cmd);
5103 if (err)
5104 return err;
5105
5106 priv->long_retry_limit = retry;
5107
5108 return 0;
5109}
5110
James Ketrenosee8e3652005-09-14 09:47:29 -05005111static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005112 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005113{
5114 struct host_command cmd = {
5115 .host_command = MANDATORY_BSSID,
5116 .host_command_sequence = 0,
5117 .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN
5118 };
5119 int err;
5120
Brice Goglin0f52bf92005-12-01 01:41:46 -08005121#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06005122 if (bssid != NULL)
Johannes Berge1749612008-10-27 15:59:26 -07005123 IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06005124 else
5125 IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
5126#endif
5127 /* if BSSID is empty then we disable mandatory bssid mode */
5128 if (bssid != NULL)
James Ketrenos82328352005-08-24 22:33:31 -05005129 memcpy(cmd.host_command_parameters, bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06005130
5131 if (!batch_mode) {
5132 err = ipw2100_disable_adapter(priv);
5133 if (err)
5134 return err;
5135 }
5136
5137 err = ipw2100_hw_send_command(priv, &cmd);
5138
5139 if (!batch_mode)
5140 ipw2100_enable_adapter(priv);
5141
5142 return err;
5143}
5144
James Ketrenos2c86c272005-03-23 17:32:29 -06005145static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
5146{
5147 struct host_command cmd = {
5148 .host_command = DISASSOCIATION_BSSID,
5149 .host_command_sequence = 0,
5150 .host_command_length = ETH_ALEN
5151 };
5152 int err;
5153 int len;
5154
5155 IPW_DEBUG_HC("DISASSOCIATION_BSSID\n");
5156
5157 len = ETH_ALEN;
5158 /* The Firmware currently ignores the BSSID and just disassociates from
5159 * the currently associated AP -- but in the off chance that a future
5160 * firmware does use the BSSID provided here, we go ahead and try and
5161 * set it to the currently associated AP's BSSID */
5162 memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN);
5163
5164 err = ipw2100_hw_send_command(priv, &cmd);
5165
5166 return err;
5167}
James Ketrenos2c86c272005-03-23 17:32:29 -06005168
5169static int ipw2100_set_wpa_ie(struct ipw2100_priv *,
5170 struct ipw2100_wpa_assoc_frame *, int)
James Ketrenosee8e3652005-09-14 09:47:29 -05005171 __attribute__ ((unused));
James Ketrenos2c86c272005-03-23 17:32:29 -06005172
5173static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv,
5174 struct ipw2100_wpa_assoc_frame *wpa_frame,
5175 int batch_mode)
5176{
5177 struct host_command cmd = {
5178 .host_command = SET_WPA_IE,
5179 .host_command_sequence = 0,
5180 .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame),
5181 };
5182 int err;
5183
5184 IPW_DEBUG_HC("SET_WPA_IE\n");
5185
5186 if (!batch_mode) {
5187 err = ipw2100_disable_adapter(priv);
5188 if (err)
5189 return err;
5190 }
5191
5192 memcpy(cmd.host_command_parameters, wpa_frame,
5193 sizeof(struct ipw2100_wpa_assoc_frame));
5194
5195 err = ipw2100_hw_send_command(priv, &cmd);
5196
5197 if (!batch_mode) {
5198 if (ipw2100_enable_adapter(priv))
5199 err = -EIO;
5200 }
5201
5202 return err;
5203}
5204
5205struct security_info_params {
5206 u32 allowed_ciphers;
5207 u16 version;
5208 u8 auth_mode;
5209 u8 replay_counters_number;
5210 u8 unicast_using_group;
Eric Dumazetba2d3582010-06-02 18:10:09 +00005211} __packed;
James Ketrenos2c86c272005-03-23 17:32:29 -06005212
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005213static int ipw2100_set_security_information(struct ipw2100_priv *priv,
5214 int auth_mode,
5215 int security_level,
5216 int unicast_using_group,
5217 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005218{
5219 struct host_command cmd = {
5220 .host_command = SET_SECURITY_INFORMATION,
5221 .host_command_sequence = 0,
5222 .host_command_length = sizeof(struct security_info_params)
5223 };
5224 struct security_info_params *security =
James Ketrenosee8e3652005-09-14 09:47:29 -05005225 (struct security_info_params *)&cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06005226 int err;
5227 memset(security, 0, sizeof(*security));
5228
5229 /* If shared key AP authentication is turned on, then we need to
5230 * configure the firmware to try and use it.
5231 *
5232 * Actual data encryption/decryption is handled by the host. */
5233 security->auth_mode = auth_mode;
5234 security->unicast_using_group = unicast_using_group;
5235
5236 switch (security_level) {
5237 default:
5238 case SEC_LEVEL_0:
5239 security->allowed_ciphers = IPW_NONE_CIPHER;
5240 break;
5241 case SEC_LEVEL_1:
5242 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005243 IPW_WEP104_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005244 break;
5245 case SEC_LEVEL_2:
5246 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005247 IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005248 break;
5249 case SEC_LEVEL_2_CKIP:
5250 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005251 IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005252 break;
5253 case SEC_LEVEL_3:
5254 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005255 IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005256 break;
5257 }
5258
James Ketrenosee8e3652005-09-14 09:47:29 -05005259 IPW_DEBUG_HC
5260 ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
5261 security->auth_mode, security->allowed_ciphers, security_level);
James Ketrenos2c86c272005-03-23 17:32:29 -06005262
5263 security->replay_counters_number = 0;
5264
5265 if (!batch_mode) {
5266 err = ipw2100_disable_adapter(priv);
5267 if (err)
5268 return err;
5269 }
5270
5271 err = ipw2100_hw_send_command(priv, &cmd);
5272
5273 if (!batch_mode)
5274 ipw2100_enable_adapter(priv);
5275
5276 return err;
5277}
5278
James Ketrenosee8e3652005-09-14 09:47:29 -05005279static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power)
James Ketrenos2c86c272005-03-23 17:32:29 -06005280{
5281 struct host_command cmd = {
5282 .host_command = TX_POWER_INDEX,
5283 .host_command_sequence = 0,
5284 .host_command_length = 4
5285 };
5286 int err = 0;
Zhu Yi3173ca02006-01-24 13:49:01 +08005287 u32 tmp = tx_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06005288
Liu Hongf75459e2005-07-13 12:29:21 -05005289 if (tx_power != IPW_TX_POWER_DEFAULT)
Zhu Yi3173ca02006-01-24 13:49:01 +08005290 tmp = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 /
5291 (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
Liu Hongf75459e2005-07-13 12:29:21 -05005292
Zhu Yi3173ca02006-01-24 13:49:01 +08005293 cmd.host_command_parameters[0] = tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06005294
5295 if (priv->ieee->iw_mode == IW_MODE_ADHOC)
5296 err = ipw2100_hw_send_command(priv, &cmd);
5297 if (!err)
5298 priv->tx_power = tx_power;
5299
5300 return 0;
5301}
5302
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005303static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv,
5304 u32 interval, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005305{
5306 struct host_command cmd = {
5307 .host_command = BEACON_INTERVAL,
5308 .host_command_sequence = 0,
5309 .host_command_length = 4
5310 };
5311 int err;
5312
5313 cmd.host_command_parameters[0] = interval;
5314
5315 IPW_DEBUG_INFO("enter\n");
5316
5317 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
5318 if (!batch_mode) {
5319 err = ipw2100_disable_adapter(priv);
5320 if (err)
5321 return err;
5322 }
5323
5324 ipw2100_hw_send_command(priv, &cmd);
5325
5326 if (!batch_mode) {
5327 err = ipw2100_enable_adapter(priv);
5328 if (err)
5329 return err;
5330 }
5331 }
5332
5333 IPW_DEBUG_INFO("exit\n");
5334
5335 return 0;
5336}
5337
Hannes Edera3d1fd22008-12-26 00:14:41 -08005338static void ipw2100_queues_initialize(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005339{
5340 ipw2100_tx_initialize(priv);
5341 ipw2100_rx_initialize(priv);
5342 ipw2100_msg_initialize(priv);
5343}
5344
Hannes Edera3d1fd22008-12-26 00:14:41 -08005345static void ipw2100_queues_free(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005346{
5347 ipw2100_tx_free(priv);
5348 ipw2100_rx_free(priv);
5349 ipw2100_msg_free(priv);
5350}
5351
Hannes Edera3d1fd22008-12-26 00:14:41 -08005352static int ipw2100_queues_allocate(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005353{
5354 if (ipw2100_tx_allocate(priv) ||
James Ketrenosee8e3652005-09-14 09:47:29 -05005355 ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv))
James Ketrenos2c86c272005-03-23 17:32:29 -06005356 goto fail;
5357
5358 return 0;
5359
James Ketrenosee8e3652005-09-14 09:47:29 -05005360 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06005361 ipw2100_tx_free(priv);
5362 ipw2100_rx_free(priv);
5363 ipw2100_msg_free(priv);
5364 return -ENOMEM;
5365}
5366
5367#define IPW_PRIVACY_CAPABLE 0x0008
5368
5369static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags,
5370 int batch_mode)
5371{
5372 struct host_command cmd = {
5373 .host_command = WEP_FLAGS,
5374 .host_command_sequence = 0,
5375 .host_command_length = 4
5376 };
5377 int err;
5378
5379 cmd.host_command_parameters[0] = flags;
5380
5381 IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags);
5382
5383 if (!batch_mode) {
5384 err = ipw2100_disable_adapter(priv);
5385 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005386 printk(KERN_ERR DRV_NAME
5387 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005388 priv->net_dev->name, err);
5389 return err;
5390 }
5391 }
5392
5393 /* send cmd to firmware */
5394 err = ipw2100_hw_send_command(priv, &cmd);
5395
5396 if (!batch_mode)
5397 ipw2100_enable_adapter(priv);
5398
5399 return err;
5400}
5401
5402struct ipw2100_wep_key {
5403 u8 idx;
5404 u8 len;
5405 u8 key[13];
5406};
5407
5408/* Macros to ease up priting WEP keys */
5409#define WEP_FMT_64 "%02X%02X%02X%02X-%02X"
5410#define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X"
5411#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4]
5412#define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10]
5413
James Ketrenos2c86c272005-03-23 17:32:29 -06005414/**
5415 * Set a the wep key
5416 *
5417 * @priv: struct to work on
5418 * @idx: index of the key we want to set
5419 * @key: ptr to the key data to set
5420 * @len: length of the buffer at @key
5421 * @batch_mode: FIXME perform the operation in batch mode, not
5422 * disabling the device.
5423 *
5424 * @returns 0 if OK, < 0 errno code on error.
5425 *
5426 * Fill out a command structure with the new wep key, length an
5427 * index and send it down the wire.
5428 */
5429static int ipw2100_set_key(struct ipw2100_priv *priv,
5430 int idx, char *key, int len, int batch_mode)
5431{
5432 int keylen = len ? (len <= 5 ? 5 : 13) : 0;
5433 struct host_command cmd = {
5434 .host_command = WEP_KEY_INFO,
5435 .host_command_sequence = 0,
5436 .host_command_length = sizeof(struct ipw2100_wep_key),
5437 };
James Ketrenosee8e3652005-09-14 09:47:29 -05005438 struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06005439 int err;
5440
5441 IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005442 idx, keylen, len);
James Ketrenos2c86c272005-03-23 17:32:29 -06005443
5444 /* NOTE: We don't check cached values in case the firmware was reset
Adrian Bunk80f72282006-06-30 18:27:16 +02005445 * or some other problem is occurring. If the user is setting the key,
James Ketrenos2c86c272005-03-23 17:32:29 -06005446 * then we push the change */
5447
5448 wep_key->idx = idx;
5449 wep_key->len = keylen;
5450
5451 if (keylen) {
5452 memcpy(wep_key->key, key, len);
5453 memset(wep_key->key + len, 0, keylen - len);
5454 }
5455
5456 /* Will be optimized out on debug not being configured in */
5457 if (keylen == 0)
5458 IPW_DEBUG_WEP("%s: Clearing key %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005459 priv->net_dev->name, wep_key->idx);
James Ketrenos2c86c272005-03-23 17:32:29 -06005460 else if (keylen == 5)
5461 IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005462 priv->net_dev->name, wep_key->idx, wep_key->len,
5463 WEP_STR_64(wep_key->key));
James Ketrenos2c86c272005-03-23 17:32:29 -06005464 else
5465 IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128
James Ketrenosee8e3652005-09-14 09:47:29 -05005466 "\n",
5467 priv->net_dev->name, wep_key->idx, wep_key->len,
5468 WEP_STR_128(wep_key->key));
James Ketrenos2c86c272005-03-23 17:32:29 -06005469
5470 if (!batch_mode) {
5471 err = ipw2100_disable_adapter(priv);
5472 /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */
5473 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005474 printk(KERN_ERR DRV_NAME
5475 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005476 priv->net_dev->name, err);
5477 return err;
5478 }
5479 }
5480
5481 /* send cmd to firmware */
5482 err = ipw2100_hw_send_command(priv, &cmd);
5483
5484 if (!batch_mode) {
5485 int err2 = ipw2100_enable_adapter(priv);
5486 if (err == 0)
5487 err = err2;
5488 }
5489 return err;
5490}
5491
5492static int ipw2100_set_key_index(struct ipw2100_priv *priv,
5493 int idx, int batch_mode)
5494{
5495 struct host_command cmd = {
5496 .host_command = WEP_KEY_INDEX,
5497 .host_command_sequence = 0,
5498 .host_command_length = 4,
James Ketrenosee8e3652005-09-14 09:47:29 -05005499 .host_command_parameters = {idx},
James Ketrenos2c86c272005-03-23 17:32:29 -06005500 };
5501 int err;
5502
5503 IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx);
5504
5505 if (idx < 0 || idx > 3)
5506 return -EINVAL;
5507
5508 if (!batch_mode) {
5509 err = ipw2100_disable_adapter(priv);
5510 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005511 printk(KERN_ERR DRV_NAME
5512 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005513 priv->net_dev->name, err);
5514 return err;
5515 }
5516 }
5517
5518 /* send cmd to firmware */
5519 err = ipw2100_hw_send_command(priv, &cmd);
5520
5521 if (!batch_mode)
5522 ipw2100_enable_adapter(priv);
5523
5524 return err;
5525}
5526
James Ketrenosee8e3652005-09-14 09:47:29 -05005527static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005528{
5529 int i, err, auth_mode, sec_level, use_group;
5530
5531 if (!(priv->status & STATUS_RUNNING))
5532 return 0;
5533
5534 if (!batch_mode) {
5535 err = ipw2100_disable_adapter(priv);
5536 if (err)
5537 return err;
5538 }
5539
25b645b2005-07-12 15:45:30 -05005540 if (!priv->ieee->sec.enabled) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005541 err =
5542 ipw2100_set_security_information(priv, IPW_AUTH_OPEN,
5543 SEC_LEVEL_0, 0, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005544 } else {
5545 auth_mode = IPW_AUTH_OPEN;
Zhu Yicbbdd032006-01-24 13:48:53 +08005546 if (priv->ieee->sec.flags & SEC_AUTH_MODE) {
5547 if (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)
5548 auth_mode = IPW_AUTH_SHARED;
5549 else if (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)
5550 auth_mode = IPW_AUTH_LEAP_CISCO_ID;
5551 }
James Ketrenos2c86c272005-03-23 17:32:29 -06005552
5553 sec_level = SEC_LEVEL_0;
25b645b2005-07-12 15:45:30 -05005554 if (priv->ieee->sec.flags & SEC_LEVEL)
5555 sec_level = priv->ieee->sec.level;
James Ketrenos2c86c272005-03-23 17:32:29 -06005556
5557 use_group = 0;
25b645b2005-07-12 15:45:30 -05005558 if (priv->ieee->sec.flags & SEC_UNICAST_GROUP)
5559 use_group = priv->ieee->sec.unicast_uses_group;
James Ketrenos2c86c272005-03-23 17:32:29 -06005560
James Ketrenosee8e3652005-09-14 09:47:29 -05005561 err =
5562 ipw2100_set_security_information(priv, auth_mode, sec_level,
5563 use_group, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005564 }
5565
5566 if (err)
5567 goto exit;
5568
25b645b2005-07-12 15:45:30 -05005569 if (priv->ieee->sec.enabled) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005570 for (i = 0; i < 4; i++) {
25b645b2005-07-12 15:45:30 -05005571 if (!(priv->ieee->sec.flags & (1 << i))) {
5572 memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN);
5573 priv->ieee->sec.key_sizes[i] = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005574 } else {
5575 err = ipw2100_set_key(priv, i,
25b645b2005-07-12 15:45:30 -05005576 priv->ieee->sec.keys[i],
5577 priv->ieee->sec.
5578 key_sizes[i], 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005579 if (err)
5580 goto exit;
5581 }
5582 }
5583
John W. Linville274bfb82008-10-29 11:35:05 -04005584 ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005585 }
5586
5587 /* Always enable privacy so the Host can filter WEP packets if
5588 * encrypted data is sent up */
James Ketrenosee8e3652005-09-14 09:47:29 -05005589 err =
5590 ipw2100_set_wep_flags(priv,
25b645b2005-07-12 15:45:30 -05005591 priv->ieee->sec.
5592 enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005593 if (err)
5594 goto exit;
5595
5596 priv->status &= ~STATUS_SECURITY_UPDATED;
5597
James Ketrenosee8e3652005-09-14 09:47:29 -05005598 exit:
James Ketrenos2c86c272005-03-23 17:32:29 -06005599 if (!batch_mode)
5600 ipw2100_enable_adapter(priv);
5601
5602 return err;
5603}
5604
David Howellsc4028952006-11-22 14:57:56 +00005605static void ipw2100_security_work(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06005606{
David Howellsc4028952006-11-22 14:57:56 +00005607 struct ipw2100_priv *priv =
5608 container_of(work, struct ipw2100_priv, security_work.work);
5609
James Ketrenos2c86c272005-03-23 17:32:29 -06005610 /* If we happen to have reconnected before we get a chance to
5611 * process this, then update the security settings--which causes
5612 * a disassociation to occur */
5613 if (!(priv->status & STATUS_ASSOCIATED) &&
5614 priv->status & STATUS_SECURITY_UPDATED)
5615 ipw2100_configure_security(priv, 0);
5616}
5617
5618static void shim__set_security(struct net_device *dev,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005619 struct libipw_security *sec)
James Ketrenos2c86c272005-03-23 17:32:29 -06005620{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005621 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005622 int i, force_update = 0;
5623
Ingo Molnar752e3772006-02-28 07:20:54 +08005624 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005625 if (!(priv->status & STATUS_INITIALIZED))
5626 goto done;
5627
5628 for (i = 0; i < 4; i++) {
5629 if (sec->flags & (1 << i)) {
25b645b2005-07-12 15:45:30 -05005630 priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
James Ketrenos2c86c272005-03-23 17:32:29 -06005631 if (sec->key_sizes[i] == 0)
25b645b2005-07-12 15:45:30 -05005632 priv->ieee->sec.flags &= ~(1 << i);
James Ketrenos2c86c272005-03-23 17:32:29 -06005633 else
25b645b2005-07-12 15:45:30 -05005634 memcpy(priv->ieee->sec.keys[i], sec->keys[i],
James Ketrenos2c86c272005-03-23 17:32:29 -06005635 sec->key_sizes[i]);
Hong Liu054b08d2005-08-25 17:45:49 +08005636 if (sec->level == SEC_LEVEL_1) {
5637 priv->ieee->sec.flags |= (1 << i);
5638 priv->status |= STATUS_SECURITY_UPDATED;
5639 } else
5640 priv->ieee->sec.flags &= ~(1 << i);
James Ketrenos2c86c272005-03-23 17:32:29 -06005641 }
5642 }
5643
5644 if ((sec->flags & SEC_ACTIVE_KEY) &&
25b645b2005-07-12 15:45:30 -05005645 priv->ieee->sec.active_key != sec->active_key) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005646 if (sec->active_key <= 3) {
25b645b2005-07-12 15:45:30 -05005647 priv->ieee->sec.active_key = sec->active_key;
5648 priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
James Ketrenos2c86c272005-03-23 17:32:29 -06005649 } else
25b645b2005-07-12 15:45:30 -05005650 priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
James Ketrenos2c86c272005-03-23 17:32:29 -06005651
5652 priv->status |= STATUS_SECURITY_UPDATED;
5653 }
5654
5655 if ((sec->flags & SEC_AUTH_MODE) &&
25b645b2005-07-12 15:45:30 -05005656 (priv->ieee->sec.auth_mode != sec->auth_mode)) {
5657 priv->ieee->sec.auth_mode = sec->auth_mode;
5658 priv->ieee->sec.flags |= SEC_AUTH_MODE;
James Ketrenos2c86c272005-03-23 17:32:29 -06005659 priv->status |= STATUS_SECURITY_UPDATED;
5660 }
5661
25b645b2005-07-12 15:45:30 -05005662 if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
5663 priv->ieee->sec.flags |= SEC_ENABLED;
5664 priv->ieee->sec.enabled = sec->enabled;
James Ketrenos2c86c272005-03-23 17:32:29 -06005665 priv->status |= STATUS_SECURITY_UPDATED;
5666 force_update = 1;
5667 }
5668
25b645b2005-07-12 15:45:30 -05005669 if (sec->flags & SEC_ENCRYPT)
5670 priv->ieee->sec.encrypt = sec->encrypt;
5671
5672 if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
5673 priv->ieee->sec.level = sec->level;
5674 priv->ieee->sec.flags |= SEC_LEVEL;
James Ketrenos2c86c272005-03-23 17:32:29 -06005675 priv->status |= STATUS_SECURITY_UPDATED;
5676 }
5677
5678 IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n",
25b645b2005-07-12 15:45:30 -05005679 priv->ieee->sec.flags & (1 << 8) ? '1' : '0',
5680 priv->ieee->sec.flags & (1 << 7) ? '1' : '0',
5681 priv->ieee->sec.flags & (1 << 6) ? '1' : '0',
5682 priv->ieee->sec.flags & (1 << 5) ? '1' : '0',
5683 priv->ieee->sec.flags & (1 << 4) ? '1' : '0',
5684 priv->ieee->sec.flags & (1 << 3) ? '1' : '0',
5685 priv->ieee->sec.flags & (1 << 2) ? '1' : '0',
5686 priv->ieee->sec.flags & (1 << 1) ? '1' : '0',
5687 priv->ieee->sec.flags & (1 << 0) ? '1' : '0');
James Ketrenos2c86c272005-03-23 17:32:29 -06005688
5689/* As a temporary work around to enable WPA until we figure out why
5690 * wpa_supplicant toggles the security capability of the driver, which
5691 * forces a disassocation with force_update...
5692 *
5693 * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/
5694 if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
5695 ipw2100_configure_security(priv, 0);
James Ketrenosee8e3652005-09-14 09:47:29 -05005696 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08005697 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005698}
5699
5700static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
5701{
5702 int err;
5703 int batch_mode = 1;
5704 u8 *bssid;
5705
5706 IPW_DEBUG_INFO("enter\n");
5707
5708 err = ipw2100_disable_adapter(priv);
5709 if (err)
5710 return err;
5711#ifdef CONFIG_IPW2100_MONITOR
5712 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
5713 err = ipw2100_set_channel(priv, priv->channel, batch_mode);
5714 if (err)
5715 return err;
5716
5717 IPW_DEBUG_INFO("exit\n");
5718
5719 return 0;
5720 }
James Ketrenosee8e3652005-09-14 09:47:29 -05005721#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06005722
5723 err = ipw2100_read_mac_address(priv);
5724 if (err)
5725 return -EIO;
5726
5727 err = ipw2100_set_mac_address(priv, batch_mode);
5728 if (err)
5729 return err;
5730
5731 err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode);
5732 if (err)
5733 return err;
5734
5735 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
5736 err = ipw2100_set_channel(priv, priv->channel, batch_mode);
5737 if (err)
5738 return err;
5739 }
5740
James Ketrenosee8e3652005-09-14 09:47:29 -05005741 err = ipw2100_system_config(priv, batch_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06005742 if (err)
5743 return err;
5744
5745 err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode);
5746 if (err)
5747 return err;
5748
5749 /* Default to power mode OFF */
5750 err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
5751 if (err)
5752 return err;
5753
5754 err = ipw2100_set_rts_threshold(priv, priv->rts_threshold);
5755 if (err)
5756 return err;
5757
5758 if (priv->config & CFG_STATIC_BSSID)
5759 bssid = priv->bssid;
5760 else
5761 bssid = NULL;
5762 err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode);
5763 if (err)
5764 return err;
5765
5766 if (priv->config & CFG_STATIC_ESSID)
5767 err = ipw2100_set_essid(priv, priv->essid, priv->essid_len,
5768 batch_mode);
5769 else
5770 err = ipw2100_set_essid(priv, NULL, 0, batch_mode);
5771 if (err)
5772 return err;
5773
5774 err = ipw2100_configure_security(priv, batch_mode);
5775 if (err)
5776 return err;
5777
5778 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005779 err =
5780 ipw2100_set_ibss_beacon_interval(priv,
5781 priv->beacon_interval,
5782 batch_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06005783 if (err)
5784 return err;
5785
5786 err = ipw2100_set_tx_power(priv, priv->tx_power);
5787 if (err)
5788 return err;
5789 }
5790
5791 /*
James Ketrenosee8e3652005-09-14 09:47:29 -05005792 err = ipw2100_set_fragmentation_threshold(
5793 priv, priv->frag_threshold, batch_mode);
5794 if (err)
5795 return err;
5796 */
James Ketrenos2c86c272005-03-23 17:32:29 -06005797
5798 IPW_DEBUG_INFO("exit\n");
5799
5800 return 0;
5801}
5802
James Ketrenos2c86c272005-03-23 17:32:29 -06005803/*************************************************************************
5804 *
5805 * EXTERNALLY CALLED METHODS
5806 *
5807 *************************************************************************/
5808
5809/* This method is called by the network layer -- not to be confused with
5810 * ipw2100_set_mac_address() declared above called by this driver (and this
5811 * method as well) to talk to the firmware */
5812static int ipw2100_set_address(struct net_device *dev, void *p)
5813{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005814 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005815 struct sockaddr *addr = p;
5816 int err = 0;
5817
5818 if (!is_valid_ether_addr(addr->sa_data))
5819 return -EADDRNOTAVAIL;
5820
Ingo Molnar752e3772006-02-28 07:20:54 +08005821 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005822
5823 priv->config |= CFG_CUSTOM_MAC;
5824 memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
5825
5826 err = ipw2100_set_mac_address(priv, 0);
5827 if (err)
5828 goto done;
5829
5830 priv->reset_backoff = 0;
Ingo Molnar752e3772006-02-28 07:20:54 +08005831 mutex_unlock(&priv->action_mutex);
David Howellsc4028952006-11-22 14:57:56 +00005832 ipw2100_reset_adapter(&priv->reset_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06005833 return 0;
5834
James Ketrenosee8e3652005-09-14 09:47:29 -05005835 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08005836 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005837 return err;
5838}
5839
5840static int ipw2100_open(struct net_device *dev)
5841{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005842 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005843 unsigned long flags;
5844 IPW_DEBUG_INFO("dev->open\n");
5845
5846 spin_lock_irqsave(&priv->low_lock, flags);
Jiri Benc3ce329c2005-08-25 20:07:01 -04005847 if (priv->status & STATUS_ASSOCIATED) {
5848 netif_carrier_on(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005849 netif_start_queue(dev);
Jiri Benc3ce329c2005-08-25 20:07:01 -04005850 }
James Ketrenos2c86c272005-03-23 17:32:29 -06005851 spin_unlock_irqrestore(&priv->low_lock, flags);
5852
5853 return 0;
5854}
5855
5856static int ipw2100_close(struct net_device *dev)
5857{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005858 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005859 unsigned long flags;
5860 struct list_head *element;
5861 struct ipw2100_tx_packet *packet;
5862
5863 IPW_DEBUG_INFO("enter\n");
5864
5865 spin_lock_irqsave(&priv->low_lock, flags);
5866
5867 if (priv->status & STATUS_ASSOCIATED)
5868 netif_carrier_off(dev);
5869 netif_stop_queue(dev);
5870
5871 /* Flush the TX queue ... */
5872 while (!list_empty(&priv->tx_pend_list)) {
5873 element = priv->tx_pend_list.next;
James Ketrenosee8e3652005-09-14 09:47:29 -05005874 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06005875
5876 list_del(element);
5877 DEC_STAT(&priv->tx_pend_stat);
5878
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005879 libipw_txb_free(packet->info.d_struct.txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06005880 packet->info.d_struct.txb = NULL;
5881
5882 list_add_tail(element, &priv->tx_free_list);
5883 INC_STAT(&priv->tx_free_stat);
5884 }
5885 spin_unlock_irqrestore(&priv->low_lock, flags);
5886
5887 IPW_DEBUG_INFO("exit\n");
5888
5889 return 0;
5890}
5891
James Ketrenos2c86c272005-03-23 17:32:29 -06005892/*
5893 * TODO: Fix this function... its just wrong
5894 */
5895static void ipw2100_tx_timeout(struct net_device *dev)
5896{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005897 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005898
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00005899 dev->stats.tx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06005900
5901#ifdef CONFIG_IPW2100_MONITOR
5902 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
5903 return;
5904#endif
5905
5906 IPW_DEBUG_INFO("%s: TX timed out. Scheduling firmware restart.\n",
5907 dev->name);
5908 schedule_reset(priv);
5909}
5910
James Ketrenosee8e3652005-09-14 09:47:29 -05005911static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value)
5912{
James Ketrenos82328352005-08-24 22:33:31 -05005913 /* This is called when wpa_supplicant loads and closes the driver
5914 * interface. */
5915 priv->ieee->wpa_enabled = value;
5916 return 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005917}
5918
James Ketrenosee8e3652005-09-14 09:47:29 -05005919static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value)
5920{
James Ketrenos2c86c272005-03-23 17:32:29 -06005921
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005922 struct libipw_device *ieee = priv->ieee;
5923 struct libipw_security sec = {
James Ketrenos2c86c272005-03-23 17:32:29 -06005924 .flags = SEC_AUTH_MODE,
5925 };
5926 int ret = 0;
5927
James Ketrenos82328352005-08-24 22:33:31 -05005928 if (value & IW_AUTH_ALG_SHARED_KEY) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005929 sec.auth_mode = WLAN_AUTH_SHARED_KEY;
5930 ieee->open_wep = 0;
James Ketrenos82328352005-08-24 22:33:31 -05005931 } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005932 sec.auth_mode = WLAN_AUTH_OPEN;
5933 ieee->open_wep = 1;
Zhu Yicbbdd032006-01-24 13:48:53 +08005934 } else if (value & IW_AUTH_ALG_LEAP) {
5935 sec.auth_mode = WLAN_AUTH_LEAP;
5936 ieee->open_wep = 1;
James Ketrenos82328352005-08-24 22:33:31 -05005937 } else
5938 return -EINVAL;
James Ketrenos2c86c272005-03-23 17:32:29 -06005939
5940 if (ieee->set_security)
5941 ieee->set_security(ieee->dev, &sec);
5942 else
5943 ret = -EOPNOTSUPP;
5944
5945 return ret;
5946}
5947
Adrian Bunk3c398b82006-01-21 01:36:36 +01005948static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
5949 char *wpa_ie, int wpa_ie_len)
James Ketrenosee8e3652005-09-14 09:47:29 -05005950{
James Ketrenos2c86c272005-03-23 17:32:29 -06005951
5952 struct ipw2100_wpa_assoc_frame frame;
5953
5954 frame.fixed_ie_mask = 0;
5955
5956 /* copy WPA IE */
5957 memcpy(frame.var_ie, wpa_ie, wpa_ie_len);
5958 frame.var_ie_len = wpa_ie_len;
5959
5960 /* make sure WPA is enabled */
5961 ipw2100_wpa_enable(priv, 1);
5962 ipw2100_set_wpa_ie(priv, &frame, 0);
5963}
5964
James Ketrenos2c86c272005-03-23 17:32:29 -06005965static void ipw_ethtool_get_drvinfo(struct net_device *dev,
5966 struct ethtool_drvinfo *info)
5967{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005968 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005969 char fw_ver[64], ucode_ver[64];
5970
Rick Jones1f80c232011-11-15 10:40:49 -08005971 strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
5972 strlcpy(info->version, DRV_VERSION, sizeof(info->version));
James Ketrenos2c86c272005-03-23 17:32:29 -06005973
5974 ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver));
5975 ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver));
5976
5977 snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s",
5978 fw_ver, priv->eeprom_version, ucode_ver);
5979
Rick Jones1f80c232011-11-15 10:40:49 -08005980 strlcpy(info->bus_info, pci_name(priv->pci_dev),
5981 sizeof(info->bus_info));
James Ketrenos2c86c272005-03-23 17:32:29 -06005982}
5983
5984static u32 ipw2100_ethtool_get_link(struct net_device *dev)
5985{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005986 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05005987 return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005988}
5989
Jeff Garzik7282d492006-09-13 14:30:00 -04005990static const struct ethtool_ops ipw2100_ethtool_ops = {
James Ketrenosee8e3652005-09-14 09:47:29 -05005991 .get_link = ipw2100_ethtool_get_link,
5992 .get_drvinfo = ipw_ethtool_get_drvinfo,
James Ketrenos2c86c272005-03-23 17:32:29 -06005993};
5994
David Howellsc4028952006-11-22 14:57:56 +00005995static void ipw2100_hang_check(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06005996{
David Howellsc4028952006-11-22 14:57:56 +00005997 struct ipw2100_priv *priv =
5998 container_of(work, struct ipw2100_priv, hang_check.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06005999 unsigned long flags;
6000 u32 rtc = 0xa5a5a5a5;
6001 u32 len = sizeof(rtc);
6002 int restart = 0;
6003
6004 spin_lock_irqsave(&priv->low_lock, flags);
6005
6006 if (priv->fatal_error != 0) {
6007 /* If fatal_error is set then we need to restart */
6008 IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n",
6009 priv->net_dev->name);
6010
6011 restart = 1;
6012 } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) ||
6013 (rtc == priv->last_rtc)) {
6014 /* Check if firmware is hung */
6015 IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n",
6016 priv->net_dev->name);
6017
6018 restart = 1;
6019 }
6020
6021 if (restart) {
6022 /* Kill timer */
6023 priv->stop_hang_check = 1;
6024 priv->hangs++;
6025
6026 /* Restart the NIC */
6027 schedule_reset(priv);
6028 }
6029
6030 priv->last_rtc = rtc;
6031
6032 if (!priv->stop_hang_check)
Tejun Heobcb6d912011-01-26 12:12:50 +01006033 schedule_delayed_work(&priv->hang_check, HZ / 2);
James Ketrenos2c86c272005-03-23 17:32:29 -06006034
6035 spin_unlock_irqrestore(&priv->low_lock, flags);
6036}
6037
David Howellsc4028952006-11-22 14:57:56 +00006038static void ipw2100_rf_kill(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06006039{
David Howellsc4028952006-11-22 14:57:56 +00006040 struct ipw2100_priv *priv =
6041 container_of(work, struct ipw2100_priv, rf_kill.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06006042 unsigned long flags;
6043
6044 spin_lock_irqsave(&priv->low_lock, flags);
6045
6046 if (rf_kill_active(priv)) {
6047 IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
6048 if (!priv->stop_rf_kill)
Tejun Heobcb6d912011-01-26 12:12:50 +01006049 schedule_delayed_work(&priv->rf_kill,
6050 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06006051 goto exit_unlock;
6052 }
6053
6054 /* RF Kill is now disabled, so bring the device back up */
6055
6056 if (!(priv->status & STATUS_RF_KILL_MASK)) {
6057 IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
6058 "device\n");
6059 schedule_reset(priv);
6060 } else
6061 IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
6062 "enabled\n");
6063
James Ketrenosee8e3652005-09-14 09:47:29 -05006064 exit_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -06006065 spin_unlock_irqrestore(&priv->low_lock, flags);
6066}
6067
6068static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
6069
Stephen Hemminger3e47fce2009-03-20 19:36:40 +00006070static const struct net_device_ops ipw2100_netdev_ops = {
6071 .ndo_open = ipw2100_open,
6072 .ndo_stop = ipw2100_close,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006073 .ndo_start_xmit = libipw_xmit,
6074 .ndo_change_mtu = libipw_change_mtu,
Stephen Hemminger3e47fce2009-03-20 19:36:40 +00006075 .ndo_tx_timeout = ipw2100_tx_timeout,
6076 .ndo_set_mac_address = ipw2100_set_address,
6077 .ndo_validate_addr = eth_validate_addr,
6078};
6079
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006080/* Look into using netdev destructor to shutdown libipw? */
James Ketrenos2c86c272005-03-23 17:32:29 -06006081
James Ketrenosee8e3652005-09-14 09:47:29 -05006082static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
Francois Romieu9b717072012-03-24 11:37:16 +01006083 void __iomem * ioaddr)
James Ketrenos2c86c272005-03-23 17:32:29 -06006084{
6085 struct ipw2100_priv *priv;
6086 struct net_device *dev;
6087
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006088 dev = alloc_libipw(sizeof(struct ipw2100_priv), 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006089 if (!dev)
6090 return NULL;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006091 priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006092 priv->ieee = netdev_priv(dev);
6093 priv->pci_dev = pci_dev;
6094 priv->net_dev = dev;
Francois Romieu9b717072012-03-24 11:37:16 +01006095 priv->ioaddr = ioaddr;
James Ketrenos2c86c272005-03-23 17:32:29 -06006096
6097 priv->ieee->hard_start_xmit = ipw2100_tx;
6098 priv->ieee->set_security = shim__set_security;
6099
James Ketrenos82328352005-08-24 22:33:31 -05006100 priv->ieee->perfect_rssi = -20;
6101 priv->ieee->worst_rssi = -85;
6102
Stephen Hemminger3e47fce2009-03-20 19:36:40 +00006103 dev->netdev_ops = &ipw2100_netdev_ops;
James Ketrenos2c86c272005-03-23 17:32:29 -06006104 dev->ethtool_ops = &ipw2100_ethtool_ops;
James Ketrenos2c86c272005-03-23 17:32:29 -06006105 dev->wireless_handlers = &ipw2100_wx_handler_def;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006106 priv->wireless_data.libipw = priv->ieee;
James Ketrenoseaf8f53b2005-11-12 12:50:12 -06006107 dev->wireless_data = &priv->wireless_data;
James Ketrenosee8e3652005-09-14 09:47:29 -05006108 dev->watchdog_timeo = 3 * HZ;
James Ketrenos2c86c272005-03-23 17:32:29 -06006109 dev->irq = 0;
6110
James Ketrenos2c86c272005-03-23 17:32:29 -06006111 /* NOTE: We don't use the wireless_handlers hook
6112 * in dev as the system will start throwing WX requests
6113 * to us before we're actually initialized and it just
6114 * ends up causing problems. So, we just handle
6115 * the WX extensions through the ipw2100_ioctl interface */
6116
Jean Delvarec03983a2007-10-19 23:22:55 +02006117 /* memset() puts everything to 0, so we only have explicitly set
James Ketrenos2c86c272005-03-23 17:32:29 -06006118 * those values that need to be something else */
6119
6120 /* If power management is turned on, default to AUTO mode */
6121 priv->power_mode = IPW_POWER_AUTO;
6122
James Ketrenos82328352005-08-24 22:33:31 -05006123#ifdef CONFIG_IPW2100_MONITOR
6124 priv->config |= CFG_CRC_CHECK;
6125#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06006126 priv->ieee->wpa_enabled = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06006127 priv->ieee->drop_unencrypted = 0;
6128 priv->ieee->privacy_invoked = 0;
6129 priv->ieee->ieee802_1x = 1;
James Ketrenos2c86c272005-03-23 17:32:29 -06006130
6131 /* Set module parameters */
Reinette Chatre21f8a732009-08-18 10:25:05 -07006132 switch (network_mode) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006133 case 1:
6134 priv->ieee->iw_mode = IW_MODE_ADHOC;
6135 break;
6136#ifdef CONFIG_IPW2100_MONITOR
6137 case 2:
6138 priv->ieee->iw_mode = IW_MODE_MONITOR;
6139 break;
6140#endif
6141 default:
6142 case 0:
6143 priv->ieee->iw_mode = IW_MODE_INFRA;
6144 break;
6145 }
6146
6147 if (disable == 1)
6148 priv->status |= STATUS_RF_KILL_SW;
6149
6150 if (channel != 0 &&
James Ketrenosee8e3652005-09-14 09:47:29 -05006151 ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006152 priv->config |= CFG_STATIC_CHANNEL;
6153 priv->channel = channel;
6154 }
6155
6156 if (associate)
6157 priv->config |= CFG_ASSOCIATE;
6158
6159 priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
6160 priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
6161 priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
6162 priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED;
6163 priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED;
6164 priv->tx_power = IPW_TX_POWER_DEFAULT;
6165 priv->tx_rates = DEFAULT_TX_RATES;
6166
6167 strcpy(priv->nick, "ipw2100");
6168
6169 spin_lock_init(&priv->low_lock);
Ingo Molnar752e3772006-02-28 07:20:54 +08006170 mutex_init(&priv->action_mutex);
6171 mutex_init(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006172
6173 init_waitqueue_head(&priv->wait_command_queue);
6174
6175 netif_carrier_off(dev);
6176
6177 INIT_LIST_HEAD(&priv->msg_free_list);
6178 INIT_LIST_HEAD(&priv->msg_pend_list);
6179 INIT_STAT(&priv->msg_free_stat);
6180 INIT_STAT(&priv->msg_pend_stat);
6181
6182 INIT_LIST_HEAD(&priv->tx_free_list);
6183 INIT_LIST_HEAD(&priv->tx_pend_list);
6184 INIT_STAT(&priv->tx_free_stat);
6185 INIT_STAT(&priv->tx_pend_stat);
6186
6187 INIT_LIST_HEAD(&priv->fw_pend_list);
6188 INIT_STAT(&priv->fw_pend_stat);
6189
David Howellsc4028952006-11-22 14:57:56 +00006190 INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter);
6191 INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work);
6192 INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
6193 INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
6194 INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
Dan Williamsd20c6782007-10-10 12:28:07 -04006195 INIT_WORK(&priv->scan_event_now, ipw2100_scan_event_now);
6196 INIT_DELAYED_WORK(&priv->scan_event_later, ipw2100_scan_event_later);
James Ketrenos2c86c272005-03-23 17:32:29 -06006197
6198 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
6199 ipw2100_irq_tasklet, (unsigned long)priv);
6200
6201 /* NOTE: We do not start the deferred work for status checks yet */
6202 priv->stop_rf_kill = 1;
6203 priv->stop_hang_check = 1;
6204
6205 return dev;
6206}
6207
James Ketrenos2c86c272005-03-23 17:32:29 -06006208static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
6209 const struct pci_device_id *ent)
6210{
Francois Romieu9b717072012-03-24 11:37:16 +01006211 void __iomem *ioaddr;
James Ketrenos2c86c272005-03-23 17:32:29 -06006212 struct net_device *dev = NULL;
6213 struct ipw2100_priv *priv = NULL;
6214 int err = 0;
6215 int registered = 0;
6216 u32 val;
6217
6218 IPW_DEBUG_INFO("enter\n");
6219
Francois Romieu9b717072012-03-24 11:37:16 +01006220 if (!(pci_resource_flags(pci_dev, 0) & IORESOURCE_MEM)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006221 IPW_DEBUG_INFO("weird - resource type is not memory\n");
6222 err = -ENODEV;
Francois Romieu9b717072012-03-24 11:37:16 +01006223 goto out;
James Ketrenos2c86c272005-03-23 17:32:29 -06006224 }
6225
Francois Romieu9b717072012-03-24 11:37:16 +01006226 ioaddr = pci_iomap(pci_dev, 0, 0);
6227 if (!ioaddr) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006228 printk(KERN_WARNING DRV_NAME
6229 "Error calling ioremap_nocache.\n");
6230 err = -EIO;
6231 goto fail;
6232 }
6233
6234 /* allocate and initialize our net_device */
Francois Romieu9b717072012-03-24 11:37:16 +01006235 dev = ipw2100_alloc_device(pci_dev, ioaddr);
James Ketrenos2c86c272005-03-23 17:32:29 -06006236 if (!dev) {
6237 printk(KERN_WARNING DRV_NAME
6238 "Error calling ipw2100_alloc_device.\n");
6239 err = -ENOMEM;
6240 goto fail;
6241 }
6242
6243 /* set up PCI mappings for device */
6244 err = pci_enable_device(pci_dev);
6245 if (err) {
6246 printk(KERN_WARNING DRV_NAME
6247 "Error calling pci_enable_device.\n");
6248 return err;
6249 }
6250
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006251 priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006252
6253 pci_set_master(pci_dev);
6254 pci_set_drvdata(pci_dev, priv);
6255
Yang Hongyang284901a2009-04-06 19:01:15 -07006256 err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
James Ketrenos2c86c272005-03-23 17:32:29 -06006257 if (err) {
6258 printk(KERN_WARNING DRV_NAME
6259 "Error calling pci_set_dma_mask.\n");
6260 pci_disable_device(pci_dev);
6261 return err;
6262 }
6263
6264 err = pci_request_regions(pci_dev, DRV_NAME);
6265 if (err) {
6266 printk(KERN_WARNING DRV_NAME
6267 "Error calling pci_request_regions.\n");
6268 pci_disable_device(pci_dev);
6269 return err;
6270 }
6271
James Ketrenosee8e3652005-09-14 09:47:29 -05006272 /* We disable the RETRY_TIMEOUT register (0x41) to keep
James Ketrenos2c86c272005-03-23 17:32:29 -06006273 * PCI Tx retries from interfering with C3 CPU state */
6274 pci_read_config_dword(pci_dev, 0x40, &val);
6275 if ((val & 0x0000ff00) != 0)
6276 pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
6277
Pavel Machek8724a112005-06-20 14:28:43 -07006278 pci_set_power_state(pci_dev, PCI_D0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006279
6280 if (!ipw2100_hw_is_adapter_in_system(dev)) {
6281 printk(KERN_WARNING DRV_NAME
6282 "Device not found via register read.\n");
6283 err = -ENODEV;
6284 goto fail;
6285 }
6286
6287 SET_NETDEV_DEV(dev, &pci_dev->dev);
6288
6289 /* Force interrupts to be shut off on the device */
6290 priv->status |= STATUS_INT_ENABLED;
6291 ipw2100_disable_interrupts(priv);
6292
6293 /* Allocate and initialize the Tx/Rx queues and lists */
6294 if (ipw2100_queues_allocate(priv)) {
6295 printk(KERN_WARNING DRV_NAME
Zhu Yi90c009a2006-12-05 14:41:32 +08006296 "Error calling ipw2100_queues_allocate.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06006297 err = -ENOMEM;
6298 goto fail;
6299 }
6300 ipw2100_queues_initialize(priv);
6301
6302 err = request_irq(pci_dev->irq,
Thomas Gleixner1fb9df52006-07-01 19:29:39 -07006303 ipw2100_interrupt, IRQF_SHARED, dev->name, priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006304 if (err) {
6305 printk(KERN_WARNING DRV_NAME
James Ketrenosee8e3652005-09-14 09:47:29 -05006306 "Error calling request_irq: %d.\n", pci_dev->irq);
James Ketrenos2c86c272005-03-23 17:32:29 -06006307 goto fail;
6308 }
6309 dev->irq = pci_dev->irq;
6310
6311 IPW_DEBUG_INFO("Attempting to register device...\n");
6312
James Ketrenos2c86c272005-03-23 17:32:29 -06006313 printk(KERN_INFO DRV_NAME
6314 ": Detected Intel PRO/Wireless 2100 Network Connection\n");
6315
Stanislav Yakovlevaac495a2012-05-14 19:06:19 -04006316 err = ipw2100_up(priv, 1);
6317 if (err)
6318 goto fail;
6319
Ben Hutchingse19d8baf2012-01-22 03:11:12 +00006320 err = ipw2100_wdev_init(dev);
6321 if (err)
6322 goto fail;
6323 registered = 1;
6324
James Ketrenos2c86c272005-03-23 17:32:29 -06006325 /* Bring up the interface. Pre 0.46, after we registered the
6326 * network device we would call ipw2100_up. This introduced a race
6327 * condition with newer hotplug configurations (network was coming
6328 * up and making calls before the device was initialized).
Stanislav Yakovlevaac495a2012-05-14 19:06:19 -04006329 */
James Ketrenos2c86c272005-03-23 17:32:29 -06006330 err = register_netdev(dev);
6331 if (err) {
6332 printk(KERN_WARNING DRV_NAME
6333 "Error calling register_netdev.\n");
Zhu Yiefbd8092006-08-21 11:38:52 +08006334 goto fail;
James Ketrenos2c86c272005-03-23 17:32:29 -06006335 }
Ben Hutchingse19d8baf2012-01-22 03:11:12 +00006336 registered = 2;
Zhu Yiefbd8092006-08-21 11:38:52 +08006337
6338 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006339
6340 IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
6341
6342 /* perform this after register_netdev so that dev->name is set */
Jeff Garzikde897882006-10-01 07:31:09 -04006343 err = sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
6344 if (err)
6345 goto fail_unlock;
James Ketrenos2c86c272005-03-23 17:32:29 -06006346
6347 /* If the RF Kill switch is disabled, go ahead and complete the
6348 * startup sequence */
6349 if (!(priv->status & STATUS_RF_KILL_MASK)) {
6350 /* Enable the adapter - sends HOST_COMPLETE */
6351 if (ipw2100_enable_adapter(priv)) {
6352 printk(KERN_WARNING DRV_NAME
6353 ": %s: failed in call to enable adapter.\n",
6354 priv->net_dev->name);
6355 ipw2100_hw_stop_adapter(priv);
6356 err = -EIO;
6357 goto fail_unlock;
6358 }
6359
6360 /* Start a scan . . . */
6361 ipw2100_set_scan_options(priv);
6362 ipw2100_start_scan(priv);
6363 }
6364
6365 IPW_DEBUG_INFO("exit\n");
6366
6367 priv->status |= STATUS_INITIALIZED;
6368
Ingo Molnar752e3772006-02-28 07:20:54 +08006369 mutex_unlock(&priv->action_mutex);
Francois Romieu9b717072012-03-24 11:37:16 +01006370out:
6371 return err;
James Ketrenos2c86c272005-03-23 17:32:29 -06006372
James Ketrenosee8e3652005-09-14 09:47:29 -05006373 fail_unlock:
Ingo Molnar752e3772006-02-28 07:20:54 +08006374 mutex_unlock(&priv->action_mutex);
James Ketrenosee8e3652005-09-14 09:47:29 -05006375 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06006376 if (dev) {
Ben Hutchingse19d8baf2012-01-22 03:11:12 +00006377 if (registered >= 2)
James Ketrenos2c86c272005-03-23 17:32:29 -06006378 unregister_netdev(dev);
6379
Ben Hutchingse19d8baf2012-01-22 03:11:12 +00006380 if (registered) {
6381 wiphy_unregister(priv->ieee->wdev.wiphy);
6382 kfree(priv->ieee->bg_band.channels);
6383 }
6384
James Ketrenos2c86c272005-03-23 17:32:29 -06006385 ipw2100_hw_stop_adapter(priv);
6386
6387 ipw2100_disable_interrupts(priv);
6388
6389 if (dev->irq)
6390 free_irq(dev->irq, priv);
6391
Tejun Heobcb6d912011-01-26 12:12:50 +01006392 ipw2100_kill_works(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006393
6394 /* These are safe to call even if they weren't allocated */
6395 ipw2100_queues_free(priv);
James Ketrenosee8e3652005-09-14 09:47:29 -05006396 sysfs_remove_group(&pci_dev->dev.kobj,
6397 &ipw2100_attribute_group);
James Ketrenos2c86c272005-03-23 17:32:29 -06006398
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006399 free_libipw(dev, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006400 pci_set_drvdata(pci_dev, NULL);
6401 }
6402
Francois Romieu9b717072012-03-24 11:37:16 +01006403 pci_iounmap(pci_dev, ioaddr);
James Ketrenos2c86c272005-03-23 17:32:29 -06006404
6405 pci_release_regions(pci_dev);
6406 pci_disable_device(pci_dev);
Francois Romieu9b717072012-03-24 11:37:16 +01006407 goto out;
James Ketrenos2c86c272005-03-23 17:32:29 -06006408}
6409
Bill Pembertoneb9248e2012-12-03 09:56:32 -05006410static void ipw2100_pci_remove_one(struct pci_dev *pci_dev)
James Ketrenos2c86c272005-03-23 17:32:29 -06006411{
6412 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
Francois Romieu019d0772012-03-24 11:47:40 +01006413 struct net_device *dev = priv->net_dev;
James Ketrenos2c86c272005-03-23 17:32:29 -06006414
Francois Romieu019d0772012-03-24 11:47:40 +01006415 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006416
Francois Romieu019d0772012-03-24 11:47:40 +01006417 priv->status &= ~STATUS_INITIALIZED;
James Ketrenos2c86c272005-03-23 17:32:29 -06006418
Francois Romieu019d0772012-03-24 11:47:40 +01006419 sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
James Ketrenos2c86c272005-03-23 17:32:29 -06006420
6421#ifdef CONFIG_PM
Francois Romieu019d0772012-03-24 11:47:40 +01006422 if (ipw2100_firmware.version)
6423 ipw2100_release_firmware(priv, &ipw2100_firmware);
James Ketrenos2c86c272005-03-23 17:32:29 -06006424#endif
Francois Romieu019d0772012-03-24 11:47:40 +01006425 /* Take down the hardware */
6426 ipw2100_down(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006427
Francois Romieu019d0772012-03-24 11:47:40 +01006428 /* Release the mutex so that the network subsystem can
6429 * complete any needed calls into the driver... */
6430 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006431
Francois Romieu019d0772012-03-24 11:47:40 +01006432 /* Unregister the device first - this results in close()
6433 * being called if the device is open. If we free storage
6434 * first, then close() will crash.
6435 * FIXME: remove the comment above. */
6436 unregister_netdev(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006437
Francois Romieu019d0772012-03-24 11:47:40 +01006438 ipw2100_kill_works(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006439
Francois Romieu019d0772012-03-24 11:47:40 +01006440 ipw2100_queues_free(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006441
Francois Romieu019d0772012-03-24 11:47:40 +01006442 /* Free potential debugging firmware snapshot */
6443 ipw2100_snapshot_free(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006444
Francois Romieu019d0772012-03-24 11:47:40 +01006445 free_irq(dev->irq, priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006446
Francois Romieu019d0772012-03-24 11:47:40 +01006447 pci_iounmap(pci_dev, priv->ioaddr);
James Ketrenos2c86c272005-03-23 17:32:29 -06006448
Francois Romieu019d0772012-03-24 11:47:40 +01006449 /* wiphy_unregister needs to be here, before free_libipw */
6450 wiphy_unregister(priv->ieee->wdev.wiphy);
6451 kfree(priv->ieee->bg_band.channels);
6452 free_libipw(dev, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006453
6454 pci_release_regions(pci_dev);
6455 pci_disable_device(pci_dev);
6456
6457 IPW_DEBUG_INFO("exit\n");
6458}
6459
James Ketrenos2c86c272005-03-23 17:32:29 -06006460#ifdef CONFIG_PM
James Ketrenos2c86c272005-03-23 17:32:29 -06006461static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state)
James Ketrenos2c86c272005-03-23 17:32:29 -06006462{
6463 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6464 struct net_device *dev = priv->net_dev;
6465
James Ketrenosee8e3652005-09-14 09:47:29 -05006466 IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06006467
Ingo Molnar752e3772006-02-28 07:20:54 +08006468 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006469 if (priv->status & STATUS_INITIALIZED) {
6470 /* Take down the device; powers it off, etc. */
6471 ipw2100_down(priv);
6472 }
6473
6474 /* Remove the PRESENT state of the device */
6475 netif_device_detach(dev);
6476
James Ketrenos2c86c272005-03-23 17:32:29 -06006477 pci_save_state(pci_dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05006478 pci_disable_device(pci_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006479 pci_set_power_state(pci_dev, PCI_D3hot);
James Ketrenos2c86c272005-03-23 17:32:29 -06006480
Dan Williamsc3d72b92009-02-11 13:26:06 -05006481 priv->suspend_at = get_seconds();
6482
Ingo Molnar752e3772006-02-28 07:20:54 +08006483 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006484
6485 return 0;
6486}
6487
6488static int ipw2100_resume(struct pci_dev *pci_dev)
6489{
6490 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6491 struct net_device *dev = priv->net_dev;
John W. Linville02e0e5e2006-11-07 20:53:48 -05006492 int err;
James Ketrenos2c86c272005-03-23 17:32:29 -06006493 u32 val;
6494
6495 if (IPW2100_PM_DISABLED)
6496 return 0;
6497
Ingo Molnar752e3772006-02-28 07:20:54 +08006498 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006499
James Ketrenosee8e3652005-09-14 09:47:29 -05006500 IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06006501
James Ketrenos2c86c272005-03-23 17:32:29 -06006502 pci_set_power_state(pci_dev, PCI_D0);
John W. Linville02e0e5e2006-11-07 20:53:48 -05006503 err = pci_enable_device(pci_dev);
6504 if (err) {
6505 printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
6506 dev->name);
Julia Lawall80c42af2008-07-21 09:58:11 +02006507 mutex_unlock(&priv->action_mutex);
John W. Linville02e0e5e2006-11-07 20:53:48 -05006508 return err;
6509 }
James Ketrenos2c86c272005-03-23 17:32:29 -06006510 pci_restore_state(pci_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006511
6512 /*
6513 * Suspend/Resume resets the PCI configuration space, so we have to
6514 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
6515 * from interfering with C3 CPU state. pci_restore_state won't help
6516 * here since it only restores the first 64 bytes pci config header.
6517 */
6518 pci_read_config_dword(pci_dev, 0x40, &val);
6519 if ((val & 0x0000ff00) != 0)
6520 pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
6521
6522 /* Set the device back into the PRESENT state; this will also wake
6523 * the queue of needed */
6524 netif_device_attach(dev);
6525
Dan Williamsc3d72b92009-02-11 13:26:06 -05006526 priv->suspend_time = get_seconds() - priv->suspend_at;
6527
James Ketrenosee8e3652005-09-14 09:47:29 -05006528 /* Bring the device back up */
6529 if (!(priv->status & STATUS_RF_KILL_SW))
6530 ipw2100_up(priv, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006531
Ingo Molnar752e3772006-02-28 07:20:54 +08006532 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006533
6534 return 0;
6535}
6536#endif
6537
Zhu Yi52ce3e9a72009-12-02 14:24:37 +08006538static void ipw2100_shutdown(struct pci_dev *pci_dev)
6539{
6540 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6541
6542 /* Take down the device; powers it off, etc. */
6543 ipw2100_down(priv);
6544
6545 pci_disable_device(pci_dev);
6546}
6547
James Ketrenos2c86c272005-03-23 17:32:29 -06006548#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
6549
Alexey Dobriyana3aa1882010-01-07 11:58:11 +00006550static DEFINE_PCI_DEVICE_TABLE(ipw2100_pci_id_table) = {
James Ketrenosee8e3652005-09-14 09:47:29 -05006551 IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
6552 IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
6553 IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
6554 IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
6555 IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
6556 IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
6557 IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
6558 IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
6559 IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
6560 IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
6561 IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
6562 IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
6563 IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
James Ketrenos2c86c272005-03-23 17:32:29 -06006564
James Ketrenosee8e3652005-09-14 09:47:29 -05006565 IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
6566 IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
6567 IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
6568 IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
6569 IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006570
James Ketrenosee8e3652005-09-14 09:47:29 -05006571 IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
6572 IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
6573 IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
6574 IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
6575 IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
6576 IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
6577 IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
James Ketrenos2c86c272005-03-23 17:32:29 -06006578
James Ketrenosee8e3652005-09-14 09:47:29 -05006579 IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006580
James Ketrenosee8e3652005-09-14 09:47:29 -05006581 IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
6582 IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
6583 IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
6584 IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
6585 IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
6586 IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
6587 IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006588
James Ketrenosee8e3652005-09-14 09:47:29 -05006589 IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
6590 IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
6591 IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
6592 IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
6593 IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
6594 IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006595
James Ketrenosee8e3652005-09-14 09:47:29 -05006596 IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006597 {0,},
6598};
6599
6600MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table);
6601
6602static struct pci_driver ipw2100_pci_driver = {
6603 .name = DRV_NAME,
6604 .id_table = ipw2100_pci_id_table,
6605 .probe = ipw2100_pci_init_one,
Bill Pembertoneb9248e2012-12-03 09:56:32 -05006606 .remove = ipw2100_pci_remove_one,
James Ketrenos2c86c272005-03-23 17:32:29 -06006607#ifdef CONFIG_PM
6608 .suspend = ipw2100_suspend,
6609 .resume = ipw2100_resume,
6610#endif
Zhu Yi52ce3e9a72009-12-02 14:24:37 +08006611 .shutdown = ipw2100_shutdown,
James Ketrenos2c86c272005-03-23 17:32:29 -06006612};
6613
James Ketrenos2c86c272005-03-23 17:32:29 -06006614/**
6615 * Initialize the ipw2100 driver/module
6616 *
6617 * @returns 0 if ok, < 0 errno node con error.
6618 *
6619 * Note: we cannot init the /proc stuff until the PCI driver is there,
6620 * or we risk an unlikely race condition on someone accessing
6621 * uninitialized data in the PCI dev struct through /proc.
6622 */
6623static int __init ipw2100_init(void)
6624{
6625 int ret;
6626
6627 printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
6628 printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
6629
John W. Linville2f81b472010-08-11 16:11:00 -04006630 pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
6631 PM_QOS_DEFAULT_VALUE);
6632
Jeff Garzik29917622006-08-19 17:48:59 -04006633 ret = pci_register_driver(&ipw2100_pci_driver);
Jeff Garzikde897882006-10-01 07:31:09 -04006634 if (ret)
6635 goto out;
James Ketrenos2c86c272005-03-23 17:32:29 -06006636
Brice Goglin0f52bf92005-12-01 01:41:46 -08006637#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06006638 ipw2100_debug_level = debug;
Jeff Garzikde897882006-10-01 07:31:09 -04006639 ret = driver_create_file(&ipw2100_pci_driver.driver,
6640 &driver_attr_debug_level);
James Ketrenos2c86c272005-03-23 17:32:29 -06006641#endif
6642
Jeff Garzikde897882006-10-01 07:31:09 -04006643out:
James Ketrenos2c86c272005-03-23 17:32:29 -06006644 return ret;
6645}
6646
James Ketrenos2c86c272005-03-23 17:32:29 -06006647/**
6648 * Cleanup ipw2100 driver registration
6649 */
6650static void __exit ipw2100_exit(void)
6651{
6652 /* FIXME: IPG: check that we have no instances of the devices open */
Brice Goglin0f52bf92005-12-01 01:41:46 -08006653#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06006654 driver_remove_file(&ipw2100_pci_driver.driver,
6655 &driver_attr_debug_level);
6656#endif
6657 pci_unregister_driver(&ipw2100_pci_driver);
James Bottomley82f68252010-07-05 22:53:06 +02006658 pm_qos_remove_request(&ipw2100_pm_qos_req);
James Ketrenos2c86c272005-03-23 17:32:29 -06006659}
6660
6661module_init(ipw2100_init);
6662module_exit(ipw2100_exit);
6663
James Ketrenos2c86c272005-03-23 17:32:29 -06006664static int ipw2100_wx_get_name(struct net_device *dev,
6665 struct iw_request_info *info,
6666 union iwreq_data *wrqu, char *extra)
6667{
6668 /*
6669 * This can be called at any time. No action lock required
6670 */
6671
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006672 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006673 if (!(priv->status & STATUS_ASSOCIATED))
6674 strcpy(wrqu->name, "unassociated");
6675 else
6676 snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
6677
6678 IPW_DEBUG_WX("Name: %s\n", wrqu->name);
6679 return 0;
6680}
6681
James Ketrenos2c86c272005-03-23 17:32:29 -06006682static int ipw2100_wx_set_freq(struct net_device *dev,
6683 struct iw_request_info *info,
6684 union iwreq_data *wrqu, char *extra)
6685{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006686 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006687 struct iw_freq *fwrq = &wrqu->freq;
6688 int err = 0;
6689
6690 if (priv->ieee->iw_mode == IW_MODE_INFRA)
6691 return -EOPNOTSUPP;
6692
Ingo Molnar752e3772006-02-28 07:20:54 +08006693 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006694 if (!(priv->status & STATUS_INITIALIZED)) {
6695 err = -EIO;
6696 goto done;
6697 }
6698
6699 /* if setting by freq convert to channel */
6700 if (fwrq->e == 1) {
James Ketrenosee8e3652005-09-14 09:47:29 -05006701 if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006702 int f = fwrq->m / 100000;
6703 int c = 0;
6704
6705 while ((c < REG_MAX_CHANNEL) &&
6706 (f != ipw2100_frequencies[c]))
6707 c++;
6708
6709 /* hack to fall through */
6710 fwrq->e = 0;
6711 fwrq->m = c + 1;
6712 }
6713 }
6714
James Ketrenos82328352005-08-24 22:33:31 -05006715 if (fwrq->e > 0 || fwrq->m > 1000) {
6716 err = -EOPNOTSUPP;
6717 goto done;
6718 } else { /* Set the channel */
Frans Pop9fd1ea42010-03-24 19:46:31 +01006719 IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
James Ketrenos2c86c272005-03-23 17:32:29 -06006720 err = ipw2100_set_channel(priv, fwrq->m, 0);
6721 }
6722
James Ketrenosee8e3652005-09-14 09:47:29 -05006723 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006724 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006725 return err;
6726}
6727
James Ketrenos2c86c272005-03-23 17:32:29 -06006728static int ipw2100_wx_get_freq(struct net_device *dev,
6729 struct iw_request_info *info,
6730 union iwreq_data *wrqu, char *extra)
6731{
6732 /*
6733 * This can be called at any time. No action lock required
6734 */
6735
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006736 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006737
6738 wrqu->freq.e = 0;
6739
6740 /* If we are associated, trying to associate, or have a statically
6741 * configured CHANNEL then return that; otherwise return ANY */
6742 if (priv->config & CFG_STATIC_CHANNEL ||
6743 priv->status & STATUS_ASSOCIATED)
6744 wrqu->freq.m = priv->channel;
6745 else
6746 wrqu->freq.m = 0;
6747
Frans Pop9fd1ea42010-03-24 19:46:31 +01006748 IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
James Ketrenos2c86c272005-03-23 17:32:29 -06006749 return 0;
6750
6751}
6752
6753static int ipw2100_wx_set_mode(struct net_device *dev,
6754 struct iw_request_info *info,
6755 union iwreq_data *wrqu, char *extra)
6756{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006757 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006758 int err = 0;
6759
Frans Pop9fd1ea42010-03-24 19:46:31 +01006760 IPW_DEBUG_WX("SET Mode -> %d\n", wrqu->mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06006761
6762 if (wrqu->mode == priv->ieee->iw_mode)
6763 return 0;
6764
Ingo Molnar752e3772006-02-28 07:20:54 +08006765 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006766 if (!(priv->status & STATUS_INITIALIZED)) {
6767 err = -EIO;
6768 goto done;
6769 }
6770
6771 switch (wrqu->mode) {
6772#ifdef CONFIG_IPW2100_MONITOR
6773 case IW_MODE_MONITOR:
6774 err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
6775 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05006776#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06006777 case IW_MODE_ADHOC:
6778 err = ipw2100_switch_mode(priv, IW_MODE_ADHOC);
6779 break;
6780 case IW_MODE_INFRA:
6781 case IW_MODE_AUTO:
6782 default:
6783 err = ipw2100_switch_mode(priv, IW_MODE_INFRA);
6784 break;
6785 }
6786
James Ketrenosee8e3652005-09-14 09:47:29 -05006787 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006788 mutex_unlock(&priv->action_mutex);
James Ketrenosee8e3652005-09-14 09:47:29 -05006789 return err;
James Ketrenos2c86c272005-03-23 17:32:29 -06006790}
6791
6792static int ipw2100_wx_get_mode(struct net_device *dev,
6793 struct iw_request_info *info,
6794 union iwreq_data *wrqu, char *extra)
6795{
6796 /*
6797 * This can be called at any time. No action lock required
6798 */
6799
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006800 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006801
6802 wrqu->mode = priv->ieee->iw_mode;
6803 IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode);
6804
6805 return 0;
6806}
6807
James Ketrenos2c86c272005-03-23 17:32:29 -06006808#define POWER_MODES 5
6809
6810/* Values are in microsecond */
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006811static const s32 timeout_duration[POWER_MODES] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006812 350000,
6813 250000,
6814 75000,
6815 37000,
6816 25000,
6817};
6818
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006819static const s32 period_duration[POWER_MODES] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006820 400000,
6821 700000,
6822 1000000,
6823 1000000,
6824 1000000
6825};
6826
6827static int ipw2100_wx_get_range(struct net_device *dev,
6828 struct iw_request_info *info,
6829 union iwreq_data *wrqu, char *extra)
6830{
6831 /*
6832 * This can be called at any time. No action lock required
6833 */
6834
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006835 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006836 struct iw_range *range = (struct iw_range *)extra;
6837 u16 val;
6838 int i, level;
6839
6840 wrqu->data.length = sizeof(*range);
6841 memset(range, 0, sizeof(*range));
6842
6843 /* Let's try to keep this struct in the same order as in
6844 * linux/include/wireless.h
6845 */
6846
6847 /* TODO: See what values we can set, and remove the ones we can't
6848 * set, or fill them with some default data.
6849 */
6850
6851 /* ~5 Mb/s real (802.11b) */
6852 range->throughput = 5 * 1000 * 1000;
6853
James Ketrenosee8e3652005-09-14 09:47:29 -05006854// range->sensitivity; /* signal level threshold range */
James Ketrenos2c86c272005-03-23 17:32:29 -06006855
6856 range->max_qual.qual = 100;
6857 /* TODO: Find real max RSSI and stick here */
6858 range->max_qual.level = 0;
6859 range->max_qual.noise = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05006860 range->max_qual.updated = 7; /* Updated all three */
James Ketrenos2c86c272005-03-23 17:32:29 -06006861
James Ketrenosee8e3652005-09-14 09:47:29 -05006862 range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02006863 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
James Ketrenos2c86c272005-03-23 17:32:29 -06006864 range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
6865 range->avg_qual.noise = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05006866 range->avg_qual.updated = 7; /* Updated all three */
James Ketrenos2c86c272005-03-23 17:32:29 -06006867
6868 range->num_bitrates = RATE_COUNT;
6869
6870 for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
Stanislav Yakovlev4d94c152012-02-09 20:23:52 -05006871 range->bitrate[i] = ipw2100_bg_rates[i].bitrate * 100 * 1000;
James Ketrenos2c86c272005-03-23 17:32:29 -06006872 }
6873
6874 range->min_rts = MIN_RTS_THRESHOLD;
6875 range->max_rts = MAX_RTS_THRESHOLD;
6876 range->min_frag = MIN_FRAG_THRESHOLD;
6877 range->max_frag = MAX_FRAG_THRESHOLD;
6878
6879 range->min_pmp = period_duration[0]; /* Minimal PM period */
James Ketrenosee8e3652005-09-14 09:47:29 -05006880 range->max_pmp = period_duration[POWER_MODES - 1]; /* Maximal PM period */
6881 range->min_pmt = timeout_duration[POWER_MODES - 1]; /* Minimal PM timeout */
6882 range->max_pmt = timeout_duration[0]; /* Maximal PM timeout */
James Ketrenos2c86c272005-03-23 17:32:29 -06006883
James Ketrenosee8e3652005-09-14 09:47:29 -05006884 /* How to decode max/min PM period */
James Ketrenos2c86c272005-03-23 17:32:29 -06006885 range->pmp_flags = IW_POWER_PERIOD;
James Ketrenosee8e3652005-09-14 09:47:29 -05006886 /* How to decode max/min PM period */
James Ketrenos2c86c272005-03-23 17:32:29 -06006887 range->pmt_flags = IW_POWER_TIMEOUT;
6888 /* What PM options are supported */
6889 range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD;
6890
6891 range->encoding_size[0] = 5;
James Ketrenosee8e3652005-09-14 09:47:29 -05006892 range->encoding_size[1] = 13; /* Different token sizes */
6893 range->num_encoding_sizes = 2; /* Number of entry in the list */
6894 range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */
6895// range->encoding_login_index; /* token index for login token */
James Ketrenos2c86c272005-03-23 17:32:29 -06006896
6897 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
6898 range->txpower_capa = IW_TXPOW_DBM;
6899 range->num_txpower = IW_MAX_TXPOWER;
James Ketrenosee8e3652005-09-14 09:47:29 -05006900 for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16);
6901 i < IW_MAX_TXPOWER;
6902 i++, level -=
6903 ((IPW_TX_POWER_MAX_DBM -
6904 IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1))
James Ketrenos2c86c272005-03-23 17:32:29 -06006905 range->txpower[i] = level / 16;
6906 } else {
6907 range->txpower_capa = 0;
6908 range->num_txpower = 0;
6909 }
6910
James Ketrenos2c86c272005-03-23 17:32:29 -06006911 /* Set the Wireless Extension versions */
6912 range->we_version_compiled = WIRELESS_EXT;
Dan Williams166c3432006-01-09 11:04:31 -05006913 range->we_version_source = 18;
James Ketrenos2c86c272005-03-23 17:32:29 -06006914
James Ketrenosee8e3652005-09-14 09:47:29 -05006915// range->retry_capa; /* What retry options are supported */
6916// range->retry_flags; /* How to decode max/min retry limit */
6917// range->r_time_flags; /* How to decode max/min retry life */
6918// range->min_retry; /* Minimal number of retries */
6919// range->max_retry; /* Maximal number of retries */
6920// range->min_r_time; /* Minimal retry lifetime */
6921// range->max_r_time; /* Maximal retry lifetime */
James Ketrenos2c86c272005-03-23 17:32:29 -06006922
James Ketrenosee8e3652005-09-14 09:47:29 -05006923 range->num_channels = FREQ_COUNT;
James Ketrenos2c86c272005-03-23 17:32:29 -06006924
6925 val = 0;
6926 for (i = 0; i < FREQ_COUNT; i++) {
6927 // TODO: Include only legal frequencies for some countries
James Ketrenosee8e3652005-09-14 09:47:29 -05006928// if (local->channel_mask & (1 << i)) {
6929 range->freq[val].i = i + 1;
6930 range->freq[val].m = ipw2100_frequencies[i] * 100000;
6931 range->freq[val].e = 1;
6932 val++;
6933// }
James Ketrenos2c86c272005-03-23 17:32:29 -06006934 if (val == IW_MAX_FREQUENCIES)
James Ketrenosee8e3652005-09-14 09:47:29 -05006935 break;
James Ketrenos2c86c272005-03-23 17:32:29 -06006936 }
6937 range->num_frequency = val;
6938
James Ketrenoseaf8f53b2005-11-12 12:50:12 -06006939 /* Event capability (kernel + driver) */
6940 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
6941 IW_EVENT_CAPA_MASK(SIOCGIWAP));
6942 range->event_capa[1] = IW_EVENT_CAPA_K_1;
6943
Dan Williams166c3432006-01-09 11:04:31 -05006944 range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
6945 IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
6946
James Ketrenos2c86c272005-03-23 17:32:29 -06006947 IPW_DEBUG_WX("GET Range\n");
6948
6949 return 0;
6950}
6951
6952static int ipw2100_wx_set_wap(struct net_device *dev,
6953 struct iw_request_info *info,
6954 union iwreq_data *wrqu, char *extra)
6955{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006956 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006957 int err = 0;
6958
James Ketrenos2c86c272005-03-23 17:32:29 -06006959 // sanity checks
6960 if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
6961 return -EINVAL;
6962
Ingo Molnar752e3772006-02-28 07:20:54 +08006963 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006964 if (!(priv->status & STATUS_INITIALIZED)) {
6965 err = -EIO;
6966 goto done;
6967 }
6968
Wei Yongjun96e716b2012-08-23 14:53:24 +08006969 if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data) ||
6970 is_zero_ether_addr(wrqu->ap_addr.sa_data)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006971 /* we disable mandatory BSSID association */
6972 IPW_DEBUG_WX("exit - disable mandatory BSSID\n");
6973 priv->config &= ~CFG_STATIC_BSSID;
6974 err = ipw2100_set_mandatory_bssid(priv, NULL, 0);
6975 goto done;
6976 }
6977
6978 priv->config |= CFG_STATIC_BSSID;
6979 memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN);
6980
6981 err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
6982
Johannes Berge1749612008-10-27 15:59:26 -07006983 IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data);
James Ketrenos2c86c272005-03-23 17:32:29 -06006984
James Ketrenosee8e3652005-09-14 09:47:29 -05006985 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006986 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006987 return err;
6988}
6989
6990static int ipw2100_wx_get_wap(struct net_device *dev,
6991 struct iw_request_info *info,
6992 union iwreq_data *wrqu, char *extra)
6993{
6994 /*
6995 * This can be called at any time. No action lock required
6996 */
6997
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006998 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006999
7000 /* If we are associated, trying to associate, or have a statically
7001 * configured BSSID then return that; otherwise return ANY */
James Ketrenosee8e3652005-09-14 09:47:29 -05007002 if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007003 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
James Ketrenos82328352005-08-24 22:33:31 -05007004 memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06007005 } else
7006 memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
7007
Johannes Berge1749612008-10-27 15:59:26 -07007008 IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data);
James Ketrenos2c86c272005-03-23 17:32:29 -06007009 return 0;
7010}
7011
7012static int ipw2100_wx_set_essid(struct net_device *dev,
7013 struct iw_request_info *info,
7014 union iwreq_data *wrqu, char *extra)
7015{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007016 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05007017 char *essid = ""; /* ANY */
James Ketrenos2c86c272005-03-23 17:32:29 -06007018 int length = 0;
7019 int err = 0;
John W. Linville9387b7c2008-09-30 20:59:05 -04007020 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06007021
Ingo Molnar752e3772006-02-28 07:20:54 +08007022 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007023 if (!(priv->status & STATUS_INITIALIZED)) {
7024 err = -EIO;
7025 goto done;
7026 }
7027
7028 if (wrqu->essid.flags && wrqu->essid.length) {
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007029 length = wrqu->essid.length;
James Ketrenos2c86c272005-03-23 17:32:29 -06007030 essid = extra;
7031 }
7032
7033 if (length == 0) {
7034 IPW_DEBUG_WX("Setting ESSID to ANY\n");
7035 priv->config &= ~CFG_STATIC_ESSID;
7036 err = ipw2100_set_essid(priv, NULL, 0, 0);
7037 goto done;
7038 }
7039
7040 length = min(length, IW_ESSID_MAX_SIZE);
7041
7042 priv->config |= CFG_STATIC_ESSID;
7043
7044 if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
7045 IPW_DEBUG_WX("ESSID set to current ESSID.\n");
7046 err = 0;
7047 goto done;
7048 }
7049
John W. Linville9387b7c2008-09-30 20:59:05 -04007050 IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
7051 print_ssid(ssid, essid, length), length);
James Ketrenos2c86c272005-03-23 17:32:29 -06007052
7053 priv->essid_len = length;
7054 memcpy(priv->essid, essid, priv->essid_len);
7055
7056 err = ipw2100_set_essid(priv, essid, length, 0);
7057
James Ketrenosee8e3652005-09-14 09:47:29 -05007058 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007059 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007060 return err;
7061}
7062
7063static int ipw2100_wx_get_essid(struct net_device *dev,
7064 struct iw_request_info *info,
7065 union iwreq_data *wrqu, char *extra)
7066{
7067 /*
7068 * This can be called at any time. No action lock required
7069 */
7070
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007071 struct ipw2100_priv *priv = libipw_priv(dev);
John W. Linville9387b7c2008-09-30 20:59:05 -04007072 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06007073
7074 /* If we are associated, trying to associate, or have a statically
7075 * configured ESSID then return that; otherwise return ANY */
James Ketrenosee8e3652005-09-14 09:47:29 -05007076 if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007077 IPW_DEBUG_WX("Getting essid: '%s'\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04007078 print_ssid(ssid, priv->essid, priv->essid_len));
James Ketrenos2c86c272005-03-23 17:32:29 -06007079 memcpy(extra, priv->essid, priv->essid_len);
7080 wrqu->essid.length = priv->essid_len;
James Ketrenosee8e3652005-09-14 09:47:29 -05007081 wrqu->essid.flags = 1; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007082 } else {
7083 IPW_DEBUG_WX("Getting essid: ANY\n");
7084 wrqu->essid.length = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05007085 wrqu->essid.flags = 0; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007086 }
7087
7088 return 0;
7089}
7090
7091static int ipw2100_wx_set_nick(struct net_device *dev,
7092 struct iw_request_info *info,
7093 union iwreq_data *wrqu, char *extra)
7094{
7095 /*
7096 * This can be called at any time. No action lock required
7097 */
7098
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007099 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007100
7101 if (wrqu->data.length > IW_ESSID_MAX_SIZE)
7102 return -E2BIG;
7103
James Ketrenosee8e3652005-09-14 09:47:29 -05007104 wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
James Ketrenos2c86c272005-03-23 17:32:29 -06007105 memset(priv->nick, 0, sizeof(priv->nick));
James Ketrenosee8e3652005-09-14 09:47:29 -05007106 memcpy(priv->nick, extra, wrqu->data.length);
James Ketrenos2c86c272005-03-23 17:32:29 -06007107
Frans Pop9fd1ea42010-03-24 19:46:31 +01007108 IPW_DEBUG_WX("SET Nickname -> %s\n", priv->nick);
James Ketrenos2c86c272005-03-23 17:32:29 -06007109
7110 return 0;
7111}
7112
7113static int ipw2100_wx_get_nick(struct net_device *dev,
7114 struct iw_request_info *info,
7115 union iwreq_data *wrqu, char *extra)
7116{
7117 /*
7118 * This can be called at any time. No action lock required
7119 */
7120
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007121 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007122
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007123 wrqu->data.length = strlen(priv->nick);
James Ketrenos2c86c272005-03-23 17:32:29 -06007124 memcpy(extra, priv->nick, wrqu->data.length);
James Ketrenosee8e3652005-09-14 09:47:29 -05007125 wrqu->data.flags = 1; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007126
Frans Pop9fd1ea42010-03-24 19:46:31 +01007127 IPW_DEBUG_WX("GET Nickname -> %s\n", extra);
James Ketrenos2c86c272005-03-23 17:32:29 -06007128
7129 return 0;
7130}
7131
7132static int ipw2100_wx_set_rate(struct net_device *dev,
7133 struct iw_request_info *info,
7134 union iwreq_data *wrqu, char *extra)
7135{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007136 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007137 u32 target_rate = wrqu->bitrate.value;
7138 u32 rate;
7139 int err = 0;
7140
Ingo Molnar752e3772006-02-28 07:20:54 +08007141 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007142 if (!(priv->status & STATUS_INITIALIZED)) {
7143 err = -EIO;
7144 goto done;
7145 }
7146
7147 rate = 0;
7148
7149 if (target_rate == 1000000 ||
7150 (!wrqu->bitrate.fixed && target_rate > 1000000))
7151 rate |= TX_RATE_1_MBIT;
7152 if (target_rate == 2000000 ||
7153 (!wrqu->bitrate.fixed && target_rate > 2000000))
7154 rate |= TX_RATE_2_MBIT;
7155 if (target_rate == 5500000 ||
7156 (!wrqu->bitrate.fixed && target_rate > 5500000))
7157 rate |= TX_RATE_5_5_MBIT;
7158 if (target_rate == 11000000 ||
7159 (!wrqu->bitrate.fixed && target_rate > 11000000))
7160 rate |= TX_RATE_11_MBIT;
7161 if (rate == 0)
7162 rate = DEFAULT_TX_RATES;
7163
7164 err = ipw2100_set_tx_rates(priv, rate, 0);
7165
Frans Pop9fd1ea42010-03-24 19:46:31 +01007166 IPW_DEBUG_WX("SET Rate -> %04X\n", rate);
James Ketrenosee8e3652005-09-14 09:47:29 -05007167 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007168 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007169 return err;
7170}
7171
James Ketrenos2c86c272005-03-23 17:32:29 -06007172static int ipw2100_wx_get_rate(struct net_device *dev,
7173 struct iw_request_info *info,
7174 union iwreq_data *wrqu, char *extra)
7175{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007176 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007177 int val;
Hannes Ederb9da9e92009-02-14 11:50:26 +00007178 unsigned int len = sizeof(val);
James Ketrenos2c86c272005-03-23 17:32:29 -06007179 int err = 0;
7180
7181 if (!(priv->status & STATUS_ENABLED) ||
7182 priv->status & STATUS_RF_KILL_MASK ||
7183 !(priv->status & STATUS_ASSOCIATED)) {
7184 wrqu->bitrate.value = 0;
7185 return 0;
7186 }
7187
Ingo Molnar752e3772006-02-28 07:20:54 +08007188 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007189 if (!(priv->status & STATUS_INITIALIZED)) {
7190 err = -EIO;
7191 goto done;
7192 }
7193
7194 err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len);
7195 if (err) {
7196 IPW_DEBUG_WX("failed querying ordinals.\n");
Julia Lawall80c42af2008-07-21 09:58:11 +02007197 goto done;
James Ketrenos2c86c272005-03-23 17:32:29 -06007198 }
7199
7200 switch (val & TX_RATE_MASK) {
7201 case TX_RATE_1_MBIT:
7202 wrqu->bitrate.value = 1000000;
7203 break;
7204 case TX_RATE_2_MBIT:
7205 wrqu->bitrate.value = 2000000;
7206 break;
7207 case TX_RATE_5_5_MBIT:
7208 wrqu->bitrate.value = 5500000;
7209 break;
7210 case TX_RATE_11_MBIT:
7211 wrqu->bitrate.value = 11000000;
7212 break;
7213 default:
7214 wrqu->bitrate.value = 0;
7215 }
7216
Frans Pop9fd1ea42010-03-24 19:46:31 +01007217 IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007218
James Ketrenosee8e3652005-09-14 09:47:29 -05007219 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007220 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007221 return err;
7222}
7223
7224static int ipw2100_wx_set_rts(struct net_device *dev,
7225 struct iw_request_info *info,
7226 union iwreq_data *wrqu, char *extra)
7227{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007228 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007229 int value, err;
7230
7231 /* Auto RTS not yet supported */
7232 if (wrqu->rts.fixed == 0)
7233 return -EINVAL;
7234
Ingo Molnar752e3772006-02-28 07:20:54 +08007235 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007236 if (!(priv->status & STATUS_INITIALIZED)) {
7237 err = -EIO;
7238 goto done;
7239 }
7240
7241 if (wrqu->rts.disabled)
7242 value = priv->rts_threshold | RTS_DISABLED;
7243 else {
James Ketrenosee8e3652005-09-14 09:47:29 -05007244 if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007245 err = -EINVAL;
7246 goto done;
7247 }
7248 value = wrqu->rts.value;
7249 }
7250
7251 err = ipw2100_set_rts_threshold(priv, value);
7252
Frans Pop9fd1ea42010-03-24 19:46:31 +01007253 IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X\n", value);
James Ketrenosee8e3652005-09-14 09:47:29 -05007254 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007255 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007256 return err;
7257}
7258
7259static int ipw2100_wx_get_rts(struct net_device *dev,
7260 struct iw_request_info *info,
7261 union iwreq_data *wrqu, char *extra)
7262{
7263 /*
7264 * This can be called at any time. No action lock required
7265 */
7266
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007267 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007268
7269 wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
James Ketrenosee8e3652005-09-14 09:47:29 -05007270 wrqu->rts.fixed = 1; /* no auto select */
James Ketrenos2c86c272005-03-23 17:32:29 -06007271
7272 /* If RTS is set to the default value, then it is disabled */
7273 wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
7274
Frans Pop9fd1ea42010-03-24 19:46:31 +01007275 IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X\n", wrqu->rts.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007276
7277 return 0;
7278}
7279
7280static int ipw2100_wx_set_txpow(struct net_device *dev,
7281 struct iw_request_info *info,
7282 union iwreq_data *wrqu, char *extra)
7283{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007284 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007285 int err = 0, value;
Zhu Yib6e4da72006-01-24 13:49:32 +08007286
7287 if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled))
7288 return -EINPROGRESS;
James Ketrenos2c86c272005-03-23 17:32:29 -06007289
7290 if (priv->ieee->iw_mode != IW_MODE_ADHOC)
Zhu Yib6e4da72006-01-24 13:49:32 +08007291 return 0;
7292
7293 if ((wrqu->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
James Ketrenos2c86c272005-03-23 17:32:29 -06007294 return -EINVAL;
7295
Zhu Yib6e4da72006-01-24 13:49:32 +08007296 if (wrqu->txpower.fixed == 0)
James Ketrenos2c86c272005-03-23 17:32:29 -06007297 value = IPW_TX_POWER_DEFAULT;
7298 else {
7299 if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM ||
7300 wrqu->txpower.value > IPW_TX_POWER_MAX_DBM)
7301 return -EINVAL;
7302
Liu Hongf75459e2005-07-13 12:29:21 -05007303 value = wrqu->txpower.value;
James Ketrenos2c86c272005-03-23 17:32:29 -06007304 }
7305
Ingo Molnar752e3772006-02-28 07:20:54 +08007306 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007307 if (!(priv->status & STATUS_INITIALIZED)) {
7308 err = -EIO;
7309 goto done;
7310 }
7311
7312 err = ipw2100_set_tx_power(priv, value);
7313
Frans Pop9fd1ea42010-03-24 19:46:31 +01007314 IPW_DEBUG_WX("SET TX Power -> %d\n", value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007315
James Ketrenosee8e3652005-09-14 09:47:29 -05007316 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007317 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007318 return err;
7319}
7320
7321static int ipw2100_wx_get_txpow(struct net_device *dev,
7322 struct iw_request_info *info,
7323 union iwreq_data *wrqu, char *extra)
7324{
7325 /*
7326 * This can be called at any time. No action lock required
7327 */
7328
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007329 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007330
Zhu Yib6e4da72006-01-24 13:49:32 +08007331 wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06007332
7333 if (priv->tx_power == IPW_TX_POWER_DEFAULT) {
Zhu Yib6e4da72006-01-24 13:49:32 +08007334 wrqu->txpower.fixed = 0;
7335 wrqu->txpower.value = IPW_TX_POWER_MAX_DBM;
James Ketrenos2c86c272005-03-23 17:32:29 -06007336 } else {
Zhu Yib6e4da72006-01-24 13:49:32 +08007337 wrqu->txpower.fixed = 1;
7338 wrqu->txpower.value = priv->tx_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06007339 }
7340
Zhu Yib6e4da72006-01-24 13:49:32 +08007341 wrqu->txpower.flags = IW_TXPOW_DBM;
James Ketrenos2c86c272005-03-23 17:32:29 -06007342
Frans Pop9fd1ea42010-03-24 19:46:31 +01007343 IPW_DEBUG_WX("GET TX Power -> %d\n", wrqu->txpower.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007344
7345 return 0;
7346}
7347
7348static int ipw2100_wx_set_frag(struct net_device *dev,
7349 struct iw_request_info *info,
7350 union iwreq_data *wrqu, char *extra)
7351{
7352 /*
7353 * This can be called at any time. No action lock required
7354 */
7355
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007356 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007357
7358 if (!wrqu->frag.fixed)
7359 return -EINVAL;
7360
7361 if (wrqu->frag.disabled) {
7362 priv->frag_threshold |= FRAG_DISABLED;
7363 priv->ieee->fts = DEFAULT_FTS;
7364 } else {
7365 if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
7366 wrqu->frag.value > MAX_FRAG_THRESHOLD)
7367 return -EINVAL;
7368
7369 priv->ieee->fts = wrqu->frag.value & ~0x1;
7370 priv->frag_threshold = priv->ieee->fts;
7371 }
7372
Frans Pop9fd1ea42010-03-24 19:46:31 +01007373 IPW_DEBUG_WX("SET Frag Threshold -> %d\n", priv->ieee->fts);
James Ketrenos2c86c272005-03-23 17:32:29 -06007374
7375 return 0;
7376}
7377
7378static int ipw2100_wx_get_frag(struct net_device *dev,
7379 struct iw_request_info *info,
7380 union iwreq_data *wrqu, char *extra)
7381{
7382 /*
7383 * This can be called at any time. No action lock required
7384 */
7385
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007386 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007387 wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED;
7388 wrqu->frag.fixed = 0; /* no auto select */
7389 wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
7390
Frans Pop9fd1ea42010-03-24 19:46:31 +01007391 IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007392
7393 return 0;
7394}
7395
7396static int ipw2100_wx_set_retry(struct net_device *dev,
7397 struct iw_request_info *info,
7398 union iwreq_data *wrqu, char *extra)
7399{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007400 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007401 int err = 0;
7402
James Ketrenosee8e3652005-09-14 09:47:29 -05007403 if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
James Ketrenos2c86c272005-03-23 17:32:29 -06007404 return -EINVAL;
7405
7406 if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
7407 return 0;
7408
Ingo Molnar752e3772006-02-28 07:20:54 +08007409 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007410 if (!(priv->status & STATUS_INITIALIZED)) {
7411 err = -EIO;
7412 goto done;
7413 }
7414
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007415 if (wrqu->retry.flags & IW_RETRY_SHORT) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007416 err = ipw2100_set_short_retry(priv, wrqu->retry.value);
Frans Pop9fd1ea42010-03-24 19:46:31 +01007417 IPW_DEBUG_WX("SET Short Retry Limit -> %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05007418 wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007419 goto done;
7420 }
7421
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007422 if (wrqu->retry.flags & IW_RETRY_LONG) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007423 err = ipw2100_set_long_retry(priv, wrqu->retry.value);
Frans Pop9fd1ea42010-03-24 19:46:31 +01007424 IPW_DEBUG_WX("SET Long Retry Limit -> %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05007425 wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007426 goto done;
7427 }
7428
7429 err = ipw2100_set_short_retry(priv, wrqu->retry.value);
7430 if (!err)
7431 err = ipw2100_set_long_retry(priv, wrqu->retry.value);
7432
Frans Pop9fd1ea42010-03-24 19:46:31 +01007433 IPW_DEBUG_WX("SET Both Retry Limits -> %d\n", wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007434
James Ketrenosee8e3652005-09-14 09:47:29 -05007435 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007436 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007437 return err;
7438}
7439
7440static int ipw2100_wx_get_retry(struct net_device *dev,
7441 struct iw_request_info *info,
7442 union iwreq_data *wrqu, char *extra)
7443{
7444 /*
7445 * This can be called at any time. No action lock required
7446 */
7447
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007448 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007449
James Ketrenosee8e3652005-09-14 09:47:29 -05007450 wrqu->retry.disabled = 0; /* can't be disabled */
James Ketrenos2c86c272005-03-23 17:32:29 -06007451
James Ketrenosee8e3652005-09-14 09:47:29 -05007452 if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
James Ketrenos2c86c272005-03-23 17:32:29 -06007453 return -EINVAL;
7454
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007455 if (wrqu->retry.flags & IW_RETRY_LONG) {
7456 wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
James Ketrenos2c86c272005-03-23 17:32:29 -06007457 wrqu->retry.value = priv->long_retry_limit;
7458 } else {
7459 wrqu->retry.flags =
7460 (priv->short_retry_limit !=
7461 priv->long_retry_limit) ?
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007462 IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT;
James Ketrenos2c86c272005-03-23 17:32:29 -06007463
7464 wrqu->retry.value = priv->short_retry_limit;
7465 }
7466
Frans Pop9fd1ea42010-03-24 19:46:31 +01007467 IPW_DEBUG_WX("GET Retry -> %d\n", wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007468
7469 return 0;
7470}
7471
7472static int ipw2100_wx_set_scan(struct net_device *dev,
7473 struct iw_request_info *info,
7474 union iwreq_data *wrqu, char *extra)
7475{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007476 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007477 int err = 0;
7478
Ingo Molnar752e3772006-02-28 07:20:54 +08007479 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007480 if (!(priv->status & STATUS_INITIALIZED)) {
7481 err = -EIO;
7482 goto done;
7483 }
7484
7485 IPW_DEBUG_WX("Initiating scan...\n");
Dan Williamsd20c6782007-10-10 12:28:07 -04007486
7487 priv->user_requested_scan = 1;
James Ketrenosee8e3652005-09-14 09:47:29 -05007488 if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007489 IPW_DEBUG_WX("Start scan failed.\n");
7490
7491 /* TODO: Mark a scan as pending so when hardware initialized
7492 * a scan starts */
7493 }
7494
James Ketrenosee8e3652005-09-14 09:47:29 -05007495 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007496 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007497 return err;
7498}
7499
7500static int ipw2100_wx_get_scan(struct net_device *dev,
7501 struct iw_request_info *info,
7502 union iwreq_data *wrqu, char *extra)
7503{
7504 /*
7505 * This can be called at any time. No action lock required
7506 */
7507
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007508 struct ipw2100_priv *priv = libipw_priv(dev);
7509 return libipw_wx_get_scan(priv->ieee, info, wrqu, extra);
James Ketrenos2c86c272005-03-23 17:32:29 -06007510}
7511
James Ketrenos2c86c272005-03-23 17:32:29 -06007512/*
7513 * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c
7514 */
7515static int ipw2100_wx_set_encode(struct net_device *dev,
7516 struct iw_request_info *info,
7517 union iwreq_data *wrqu, char *key)
7518{
7519 /*
7520 * No check of STATUS_INITIALIZED required
7521 */
7522
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007523 struct ipw2100_priv *priv = libipw_priv(dev);
7524 return libipw_wx_set_encode(priv->ieee, info, wrqu, key);
James Ketrenos2c86c272005-03-23 17:32:29 -06007525}
7526
7527static int ipw2100_wx_get_encode(struct net_device *dev,
7528 struct iw_request_info *info,
7529 union iwreq_data *wrqu, char *key)
7530{
7531 /*
7532 * This can be called at any time. No action lock required
7533 */
7534
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007535 struct ipw2100_priv *priv = libipw_priv(dev);
7536 return libipw_wx_get_encode(priv->ieee, info, wrqu, key);
James Ketrenos2c86c272005-03-23 17:32:29 -06007537}
7538
7539static int ipw2100_wx_set_power(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05007540 struct iw_request_info *info,
7541 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007542{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007543 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007544 int err = 0;
7545
Ingo Molnar752e3772006-02-28 07:20:54 +08007546 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007547 if (!(priv->status & STATUS_INITIALIZED)) {
7548 err = -EIO;
7549 goto done;
7550 }
7551
7552 if (wrqu->power.disabled) {
7553 priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
7554 err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
7555 IPW_DEBUG_WX("SET Power Management Mode -> off\n");
7556 goto done;
7557 }
7558
7559 switch (wrqu->power.flags & IW_POWER_MODE) {
James Ketrenosee8e3652005-09-14 09:47:29 -05007560 case IW_POWER_ON: /* If not specified */
7561 case IW_POWER_MODE: /* If set all mask */
Jean Delvarec03983a2007-10-19 23:22:55 +02007562 case IW_POWER_ALL_R: /* If explicitly state all */
James Ketrenos2c86c272005-03-23 17:32:29 -06007563 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05007564 default: /* Otherwise we don't support it */
James Ketrenos2c86c272005-03-23 17:32:29 -06007565 IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
7566 wrqu->power.flags);
7567 err = -EOPNOTSUPP;
7568 goto done;
7569 }
7570
7571 /* If the user hasn't specified a power management mode yet, default
7572 * to BATTERY */
7573 priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
7574 err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
7575
James Ketrenosee8e3652005-09-14 09:47:29 -05007576 IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06007577
James Ketrenosee8e3652005-09-14 09:47:29 -05007578 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007579 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007580 return err;
7581
7582}
7583
7584static int ipw2100_wx_get_power(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05007585 struct iw_request_info *info,
7586 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007587{
7588 /*
7589 * This can be called at any time. No action lock required
7590 */
7591
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007592 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007593
James Ketrenos82328352005-08-24 22:33:31 -05007594 if (!(priv->power_mode & IPW_POWER_ENABLED))
James Ketrenos2c86c272005-03-23 17:32:29 -06007595 wrqu->power.disabled = 1;
James Ketrenos82328352005-08-24 22:33:31 -05007596 else {
James Ketrenos2c86c272005-03-23 17:32:29 -06007597 wrqu->power.disabled = 0;
7598 wrqu->power.flags = 0;
7599 }
7600
7601 IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
7602
7603 return 0;
7604}
7605
James Ketrenos82328352005-08-24 22:33:31 -05007606/*
7607 * WE-18 WPA support
7608 */
7609
7610/* SIOCSIWGENIE */
7611static int ipw2100_wx_set_genie(struct net_device *dev,
7612 struct iw_request_info *info,
7613 union iwreq_data *wrqu, char *extra)
7614{
7615
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007616 struct ipw2100_priv *priv = libipw_priv(dev);
7617 struct libipw_device *ieee = priv->ieee;
James Ketrenos82328352005-08-24 22:33:31 -05007618 u8 *buf;
7619
7620 if (!ieee->wpa_enabled)
7621 return -EOPNOTSUPP;
7622
7623 if (wrqu->data.length > MAX_WPA_IE_LEN ||
7624 (wrqu->data.length && extra == NULL))
7625 return -EINVAL;
7626
7627 if (wrqu->data.length) {
Eric Sesterhennc3a9392e2006-10-23 22:20:15 +02007628 buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
James Ketrenos82328352005-08-24 22:33:31 -05007629 if (buf == NULL)
7630 return -ENOMEM;
7631
James Ketrenos82328352005-08-24 22:33:31 -05007632 kfree(ieee->wpa_ie);
7633 ieee->wpa_ie = buf;
7634 ieee->wpa_ie_len = wrqu->data.length;
7635 } else {
7636 kfree(ieee->wpa_ie);
7637 ieee->wpa_ie = NULL;
7638 ieee->wpa_ie_len = 0;
7639 }
7640
7641 ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
7642
7643 return 0;
7644}
7645
7646/* SIOCGIWGENIE */
7647static int ipw2100_wx_get_genie(struct net_device *dev,
7648 struct iw_request_info *info,
7649 union iwreq_data *wrqu, char *extra)
7650{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007651 struct ipw2100_priv *priv = libipw_priv(dev);
7652 struct libipw_device *ieee = priv->ieee;
James Ketrenos82328352005-08-24 22:33:31 -05007653
7654 if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
7655 wrqu->data.length = 0;
7656 return 0;
7657 }
7658
7659 if (wrqu->data.length < ieee->wpa_ie_len)
7660 return -E2BIG;
7661
7662 wrqu->data.length = ieee->wpa_ie_len;
7663 memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
7664
7665 return 0;
7666}
7667
7668/* SIOCSIWAUTH */
7669static int ipw2100_wx_set_auth(struct net_device *dev,
7670 struct iw_request_info *info,
7671 union iwreq_data *wrqu, char *extra)
7672{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007673 struct ipw2100_priv *priv = libipw_priv(dev);
7674 struct libipw_device *ieee = priv->ieee;
James Ketrenos82328352005-08-24 22:33:31 -05007675 struct iw_param *param = &wrqu->param;
John W. Linville274bfb82008-10-29 11:35:05 -04007676 struct lib80211_crypt_data *crypt;
James Ketrenos82328352005-08-24 22:33:31 -05007677 unsigned long flags;
7678 int ret = 0;
7679
7680 switch (param->flags & IW_AUTH_INDEX) {
7681 case IW_AUTH_WPA_VERSION:
7682 case IW_AUTH_CIPHER_PAIRWISE:
7683 case IW_AUTH_CIPHER_GROUP:
7684 case IW_AUTH_KEY_MGMT:
7685 /*
7686 * ipw2200 does not use these parameters
7687 */
7688 break;
7689
7690 case IW_AUTH_TKIP_COUNTERMEASURES:
John W. Linville274bfb82008-10-29 11:35:05 -04007691 crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
James Ketrenos991d1cc2005-10-13 09:26:48 +00007692 if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
James Ketrenos82328352005-08-24 22:33:31 -05007693 break;
James Ketrenos82328352005-08-24 22:33:31 -05007694
7695 flags = crypt->ops->get_flags(crypt->priv);
7696
7697 if (param->value)
7698 flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
7699 else
7700 flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
7701
7702 crypt->ops->set_flags(flags, crypt->priv);
7703
7704 break;
7705
7706 case IW_AUTH_DROP_UNENCRYPTED:{
7707 /* HACK:
7708 *
7709 * wpa_supplicant calls set_wpa_enabled when the driver
7710 * is loaded and unloaded, regardless of if WPA is being
7711 * used. No other calls are made which can be used to
7712 * determine if encryption will be used or not prior to
7713 * association being expected. If encryption is not being
7714 * used, drop_unencrypted is set to false, else true -- we
7715 * can use this to determine if the CAP_PRIVACY_ON bit should
7716 * be set.
7717 */
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007718 struct libipw_security sec = {
James Ketrenos82328352005-08-24 22:33:31 -05007719 .flags = SEC_ENABLED,
7720 .enabled = param->value,
7721 };
7722 priv->ieee->drop_unencrypted = param->value;
7723 /* We only change SEC_LEVEL for open mode. Others
7724 * are set by ipw_wpa_set_encryption.
7725 */
7726 if (!param->value) {
7727 sec.flags |= SEC_LEVEL;
7728 sec.level = SEC_LEVEL_0;
7729 } else {
7730 sec.flags |= SEC_LEVEL;
7731 sec.level = SEC_LEVEL_1;
7732 }
7733 if (priv->ieee->set_security)
7734 priv->ieee->set_security(priv->ieee->dev, &sec);
7735 break;
7736 }
7737
7738 case IW_AUTH_80211_AUTH_ALG:
7739 ret = ipw2100_wpa_set_auth_algs(priv, param->value);
7740 break;
7741
7742 case IW_AUTH_WPA_ENABLED:
7743 ret = ipw2100_wpa_enable(priv, param->value);
7744 break;
7745
7746 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
7747 ieee->ieee802_1x = param->value;
7748 break;
7749
7750 //case IW_AUTH_ROAMING_CONTROL:
7751 case IW_AUTH_PRIVACY_INVOKED:
7752 ieee->privacy_invoked = param->value;
7753 break;
7754
7755 default:
7756 return -EOPNOTSUPP;
7757 }
7758 return ret;
7759}
7760
7761/* SIOCGIWAUTH */
7762static int ipw2100_wx_get_auth(struct net_device *dev,
7763 struct iw_request_info *info,
7764 union iwreq_data *wrqu, char *extra)
7765{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007766 struct ipw2100_priv *priv = libipw_priv(dev);
7767 struct libipw_device *ieee = priv->ieee;
John W. Linville274bfb82008-10-29 11:35:05 -04007768 struct lib80211_crypt_data *crypt;
James Ketrenos82328352005-08-24 22:33:31 -05007769 struct iw_param *param = &wrqu->param;
7770 int ret = 0;
7771
7772 switch (param->flags & IW_AUTH_INDEX) {
7773 case IW_AUTH_WPA_VERSION:
7774 case IW_AUTH_CIPHER_PAIRWISE:
7775 case IW_AUTH_CIPHER_GROUP:
7776 case IW_AUTH_KEY_MGMT:
7777 /*
7778 * wpa_supplicant will control these internally
7779 */
7780 ret = -EOPNOTSUPP;
7781 break;
7782
7783 case IW_AUTH_TKIP_COUNTERMEASURES:
John W. Linville274bfb82008-10-29 11:35:05 -04007784 crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
James Ketrenos82328352005-08-24 22:33:31 -05007785 if (!crypt || !crypt->ops->get_flags) {
7786 IPW_DEBUG_WARNING("Can't get TKIP countermeasures: "
7787 "crypt not set!\n");
7788 break;
7789 }
7790
7791 param->value = (crypt->ops->get_flags(crypt->priv) &
7792 IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
7793
7794 break;
7795
7796 case IW_AUTH_DROP_UNENCRYPTED:
7797 param->value = ieee->drop_unencrypted;
7798 break;
7799
7800 case IW_AUTH_80211_AUTH_ALG:
25b645b2005-07-12 15:45:30 -05007801 param->value = priv->ieee->sec.auth_mode;
James Ketrenos82328352005-08-24 22:33:31 -05007802 break;
7803
7804 case IW_AUTH_WPA_ENABLED:
7805 param->value = ieee->wpa_enabled;
7806 break;
7807
7808 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
7809 param->value = ieee->ieee802_1x;
7810 break;
7811
7812 case IW_AUTH_ROAMING_CONTROL:
7813 case IW_AUTH_PRIVACY_INVOKED:
7814 param->value = ieee->privacy_invoked;
7815 break;
7816
7817 default:
7818 return -EOPNOTSUPP;
7819 }
7820 return 0;
7821}
7822
7823/* SIOCSIWENCODEEXT */
7824static int ipw2100_wx_set_encodeext(struct net_device *dev,
7825 struct iw_request_info *info,
7826 union iwreq_data *wrqu, char *extra)
7827{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007828 struct ipw2100_priv *priv = libipw_priv(dev);
7829 return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra);
James Ketrenos82328352005-08-24 22:33:31 -05007830}
7831
7832/* SIOCGIWENCODEEXT */
7833static int ipw2100_wx_get_encodeext(struct net_device *dev,
7834 struct iw_request_info *info,
7835 union iwreq_data *wrqu, char *extra)
7836{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007837 struct ipw2100_priv *priv = libipw_priv(dev);
7838 return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra);
James Ketrenos82328352005-08-24 22:33:31 -05007839}
7840
7841/* SIOCSIWMLME */
7842static int ipw2100_wx_set_mlme(struct net_device *dev,
7843 struct iw_request_info *info,
7844 union iwreq_data *wrqu, char *extra)
7845{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007846 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos82328352005-08-24 22:33:31 -05007847 struct iw_mlme *mlme = (struct iw_mlme *)extra;
Al Viro1edd3a52007-12-21 00:15:18 -05007848 __le16 reason;
James Ketrenos82328352005-08-24 22:33:31 -05007849
7850 reason = cpu_to_le16(mlme->reason_code);
7851
7852 switch (mlme->cmd) {
7853 case IW_MLME_DEAUTH:
7854 // silently ignore
7855 break;
7856
7857 case IW_MLME_DISASSOC:
7858 ipw2100_disassociate_bssid(priv);
7859 break;
7860
7861 default:
7862 return -EOPNOTSUPP;
7863 }
7864 return 0;
7865}
James Ketrenos2c86c272005-03-23 17:32:29 -06007866
7867/*
7868 *
7869 * IWPRIV handlers
7870 *
7871 */
7872#ifdef CONFIG_IPW2100_MONITOR
7873static int ipw2100_wx_set_promisc(struct net_device *dev,
7874 struct iw_request_info *info,
7875 union iwreq_data *wrqu, char *extra)
7876{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007877 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007878 int *parms = (int *)extra;
7879 int enable = (parms[0] > 0);
7880 int err = 0;
7881
Ingo Molnar752e3772006-02-28 07:20:54 +08007882 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007883 if (!(priv->status & STATUS_INITIALIZED)) {
7884 err = -EIO;
7885 goto done;
7886 }
7887
7888 if (enable) {
7889 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
7890 err = ipw2100_set_channel(priv, parms[1], 0);
7891 goto done;
7892 }
7893 priv->channel = parms[1];
7894 err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
7895 } else {
7896 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
7897 err = ipw2100_switch_mode(priv, priv->last_mode);
7898 }
James Ketrenosee8e3652005-09-14 09:47:29 -05007899 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007900 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007901 return err;
7902}
7903
7904static int ipw2100_wx_reset(struct net_device *dev,
7905 struct iw_request_info *info,
7906 union iwreq_data *wrqu, char *extra)
7907{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007908 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007909 if (priv->status & STATUS_INITIALIZED)
7910 schedule_reset(priv);
7911 return 0;
7912}
7913
7914#endif
7915
7916static int ipw2100_wx_set_powermode(struct net_device *dev,
7917 struct iw_request_info *info,
7918 union iwreq_data *wrqu, char *extra)
7919{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007920 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007921 int err = 0, mode = *(int *)extra;
7922
Ingo Molnar752e3772006-02-28 07:20:54 +08007923 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007924 if (!(priv->status & STATUS_INITIALIZED)) {
7925 err = -EIO;
7926 goto done;
7927 }
7928
Zhu Yi9f3b2412007-07-12 16:09:24 +08007929 if ((mode < 0) || (mode > POWER_MODES))
James Ketrenos2c86c272005-03-23 17:32:29 -06007930 mode = IPW_POWER_AUTO;
7931
Zhu Yi9f3b2412007-07-12 16:09:24 +08007932 if (IPW_POWER_LEVEL(priv->power_mode) != mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06007933 err = ipw2100_set_power_mode(priv, mode);
James Ketrenosee8e3652005-09-14 09:47:29 -05007934 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007935 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007936 return err;
7937}
7938
7939#define MAX_POWER_STRING 80
7940static int ipw2100_wx_get_powermode(struct net_device *dev,
7941 struct iw_request_info *info,
7942 union iwreq_data *wrqu, char *extra)
7943{
7944 /*
7945 * This can be called at any time. No action lock required
7946 */
7947
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007948 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007949 int level = IPW_POWER_LEVEL(priv->power_mode);
7950 s32 timeout, period;
7951
7952 if (!(priv->power_mode & IPW_POWER_ENABLED)) {
7953 snprintf(extra, MAX_POWER_STRING,
7954 "Power save level: %d (Off)", level);
7955 } else {
7956 switch (level) {
7957 case IPW_POWER_MODE_CAM:
7958 snprintf(extra, MAX_POWER_STRING,
7959 "Power save level: %d (None)", level);
7960 break;
7961 case IPW_POWER_AUTO:
James Ketrenosee8e3652005-09-14 09:47:29 -05007962 snprintf(extra, MAX_POWER_STRING,
Zhu Yi9f3b2412007-07-12 16:09:24 +08007963 "Power save level: %d (Auto)", level);
James Ketrenos2c86c272005-03-23 17:32:29 -06007964 break;
7965 default:
7966 timeout = timeout_duration[level - 1] / 1000;
7967 period = period_duration[level - 1] / 1000;
7968 snprintf(extra, MAX_POWER_STRING,
7969 "Power save level: %d "
7970 "(Timeout %dms, Period %dms)",
7971 level, timeout, period);
7972 }
7973 }
7974
7975 wrqu->data.length = strlen(extra) + 1;
7976
7977 return 0;
7978}
7979
James Ketrenos2c86c272005-03-23 17:32:29 -06007980static int ipw2100_wx_set_preamble(struct net_device *dev,
7981 struct iw_request_info *info,
7982 union iwreq_data *wrqu, char *extra)
7983{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007984 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007985 int err, mode = *(int *)extra;
7986
Ingo Molnar752e3772006-02-28 07:20:54 +08007987 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007988 if (!(priv->status & STATUS_INITIALIZED)) {
7989 err = -EIO;
7990 goto done;
7991 }
7992
7993 if (mode == 1)
7994 priv->config |= CFG_LONG_PREAMBLE;
7995 else if (mode == 0)
7996 priv->config &= ~CFG_LONG_PREAMBLE;
7997 else {
7998 err = -EINVAL;
7999 goto done;
8000 }
8001
8002 err = ipw2100_system_config(priv, 0);
8003
James Ketrenosee8e3652005-09-14 09:47:29 -05008004 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08008005 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008006 return err;
8007}
8008
8009static int ipw2100_wx_get_preamble(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05008010 struct iw_request_info *info,
8011 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06008012{
8013 /*
8014 * This can be called at any time. No action lock required
8015 */
8016
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008017 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008018
8019 if (priv->config & CFG_LONG_PREAMBLE)
8020 snprintf(wrqu->name, IFNAMSIZ, "long (1)");
8021 else
8022 snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
8023
8024 return 0;
8025}
8026
James Ketrenos82328352005-08-24 22:33:31 -05008027#ifdef CONFIG_IPW2100_MONITOR
8028static int ipw2100_wx_set_crc_check(struct net_device *dev,
8029 struct iw_request_info *info,
8030 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06008031{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008032 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos82328352005-08-24 22:33:31 -05008033 int err, mode = *(int *)extra;
8034
Ingo Molnar752e3772006-02-28 07:20:54 +08008035 mutex_lock(&priv->action_mutex);
James Ketrenos82328352005-08-24 22:33:31 -05008036 if (!(priv->status & STATUS_INITIALIZED)) {
8037 err = -EIO;
8038 goto done;
8039 }
8040
8041 if (mode == 1)
8042 priv->config |= CFG_CRC_CHECK;
8043 else if (mode == 0)
8044 priv->config &= ~CFG_CRC_CHECK;
8045 else {
8046 err = -EINVAL;
8047 goto done;
8048 }
8049 err = 0;
8050
8051 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08008052 mutex_unlock(&priv->action_mutex);
James Ketrenos82328352005-08-24 22:33:31 -05008053 return err;
8054}
8055
8056static int ipw2100_wx_get_crc_check(struct net_device *dev,
8057 struct iw_request_info *info,
8058 union iwreq_data *wrqu, char *extra)
8059{
8060 /*
8061 * This can be called at any time. No action lock required
8062 */
8063
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008064 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos82328352005-08-24 22:33:31 -05008065
8066 if (priv->config & CFG_CRC_CHECK)
8067 snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)");
8068 else
8069 snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)");
8070
8071 return 0;
8072}
8073#endif /* CONFIG_IPW2100_MONITOR */
8074
James Ketrenosee8e3652005-09-14 09:47:29 -05008075static iw_handler ipw2100_wx_handlers[] = {
Stanislav Yakovlev06d9b6a2012-02-23 17:31:24 -05008076 IW_HANDLER(SIOCGIWNAME, ipw2100_wx_get_name),
8077 IW_HANDLER(SIOCSIWFREQ, ipw2100_wx_set_freq),
8078 IW_HANDLER(SIOCGIWFREQ, ipw2100_wx_get_freq),
8079 IW_HANDLER(SIOCSIWMODE, ipw2100_wx_set_mode),
8080 IW_HANDLER(SIOCGIWMODE, ipw2100_wx_get_mode),
8081 IW_HANDLER(SIOCGIWRANGE, ipw2100_wx_get_range),
8082 IW_HANDLER(SIOCSIWAP, ipw2100_wx_set_wap),
8083 IW_HANDLER(SIOCGIWAP, ipw2100_wx_get_wap),
8084 IW_HANDLER(SIOCSIWMLME, ipw2100_wx_set_mlme),
8085 IW_HANDLER(SIOCSIWSCAN, ipw2100_wx_set_scan),
8086 IW_HANDLER(SIOCGIWSCAN, ipw2100_wx_get_scan),
8087 IW_HANDLER(SIOCSIWESSID, ipw2100_wx_set_essid),
8088 IW_HANDLER(SIOCGIWESSID, ipw2100_wx_get_essid),
8089 IW_HANDLER(SIOCSIWNICKN, ipw2100_wx_set_nick),
8090 IW_HANDLER(SIOCGIWNICKN, ipw2100_wx_get_nick),
8091 IW_HANDLER(SIOCSIWRATE, ipw2100_wx_set_rate),
8092 IW_HANDLER(SIOCGIWRATE, ipw2100_wx_get_rate),
8093 IW_HANDLER(SIOCSIWRTS, ipw2100_wx_set_rts),
8094 IW_HANDLER(SIOCGIWRTS, ipw2100_wx_get_rts),
8095 IW_HANDLER(SIOCSIWFRAG, ipw2100_wx_set_frag),
8096 IW_HANDLER(SIOCGIWFRAG, ipw2100_wx_get_frag),
8097 IW_HANDLER(SIOCSIWTXPOW, ipw2100_wx_set_txpow),
8098 IW_HANDLER(SIOCGIWTXPOW, ipw2100_wx_get_txpow),
8099 IW_HANDLER(SIOCSIWRETRY, ipw2100_wx_set_retry),
8100 IW_HANDLER(SIOCGIWRETRY, ipw2100_wx_get_retry),
8101 IW_HANDLER(SIOCSIWENCODE, ipw2100_wx_set_encode),
8102 IW_HANDLER(SIOCGIWENCODE, ipw2100_wx_get_encode),
8103 IW_HANDLER(SIOCSIWPOWER, ipw2100_wx_set_power),
8104 IW_HANDLER(SIOCGIWPOWER, ipw2100_wx_get_power),
8105 IW_HANDLER(SIOCSIWGENIE, ipw2100_wx_set_genie),
8106 IW_HANDLER(SIOCGIWGENIE, ipw2100_wx_get_genie),
8107 IW_HANDLER(SIOCSIWAUTH, ipw2100_wx_set_auth),
8108 IW_HANDLER(SIOCGIWAUTH, ipw2100_wx_get_auth),
8109 IW_HANDLER(SIOCSIWENCODEEXT, ipw2100_wx_set_encodeext),
8110 IW_HANDLER(SIOCGIWENCODEEXT, ipw2100_wx_get_encodeext),
James Ketrenos2c86c272005-03-23 17:32:29 -06008111};
8112
8113#define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV
8114#define IPW2100_PRIV_RESET SIOCIWFIRSTPRIV+1
8115#define IPW2100_PRIV_SET_POWER SIOCIWFIRSTPRIV+2
8116#define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3
8117#define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4
8118#define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5
James Ketrenos82328352005-08-24 22:33:31 -05008119#define IPW2100_PRIV_SET_CRC_CHECK SIOCIWFIRSTPRIV+6
8120#define IPW2100_PRIV_GET_CRC_CHECK SIOCIWFIRSTPRIV+7
James Ketrenos2c86c272005-03-23 17:32:29 -06008121
8122static const struct iw_priv_args ipw2100_private_args[] = {
8123
8124#ifdef CONFIG_IPW2100_MONITOR
8125 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008126 IPW2100_PRIV_SET_MONITOR,
8127 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008128 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008129 IPW2100_PRIV_RESET,
8130 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
8131#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008132
8133 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008134 IPW2100_PRIV_SET_POWER,
8135 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008136 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008137 IPW2100_PRIV_GET_POWER,
8138 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING,
8139 "get_power"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008140 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008141 IPW2100_PRIV_SET_LONGPREAMBLE,
8142 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008143 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008144 IPW2100_PRIV_GET_LONGPREAMBLE,
8145 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"},
James Ketrenos82328352005-08-24 22:33:31 -05008146#ifdef CONFIG_IPW2100_MONITOR
8147 {
8148 IPW2100_PRIV_SET_CRC_CHECK,
8149 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"},
8150 {
8151 IPW2100_PRIV_GET_CRC_CHECK,
8152 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"},
8153#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008154};
8155
8156static iw_handler ipw2100_private_handler[] = {
8157#ifdef CONFIG_IPW2100_MONITOR
8158 ipw2100_wx_set_promisc,
8159 ipw2100_wx_reset,
James Ketrenosee8e3652005-09-14 09:47:29 -05008160#else /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008161 NULL,
8162 NULL,
James Ketrenosee8e3652005-09-14 09:47:29 -05008163#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008164 ipw2100_wx_set_powermode,
8165 ipw2100_wx_get_powermode,
8166 ipw2100_wx_set_preamble,
8167 ipw2100_wx_get_preamble,
James Ketrenos82328352005-08-24 22:33:31 -05008168#ifdef CONFIG_IPW2100_MONITOR
8169 ipw2100_wx_set_crc_check,
8170 ipw2100_wx_get_crc_check,
8171#else /* CONFIG_IPW2100_MONITOR */
8172 NULL,
8173 NULL,
8174#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008175};
8176
James Ketrenos2c86c272005-03-23 17:32:29 -06008177/*
8178 * Get wireless statistics.
8179 * Called by /proc/net/wireless
8180 * Also called by SIOCGIWSTATS
8181 */
James Ketrenosee8e3652005-09-14 09:47:29 -05008182static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
James Ketrenos2c86c272005-03-23 17:32:29 -06008183{
8184 enum {
8185 POOR = 30,
8186 FAIR = 60,
8187 GOOD = 80,
8188 VERY_GOOD = 90,
8189 EXCELLENT = 95,
8190 PERFECT = 100
8191 };
8192 int rssi_qual;
8193 int tx_qual;
8194 int beacon_qual;
Reinette Chatre21f8a732009-08-18 10:25:05 -07008195 int quality;
James Ketrenos2c86c272005-03-23 17:32:29 -06008196
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008197 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008198 struct iw_statistics *wstats;
Reinette Chatre21f8a732009-08-18 10:25:05 -07008199 u32 rssi, tx_retries, missed_beacons, tx_failures;
James Ketrenos2c86c272005-03-23 17:32:29 -06008200 u32 ord_len = sizeof(u32);
8201
8202 if (!priv)
James Ketrenosee8e3652005-09-14 09:47:29 -05008203 return (struct iw_statistics *)NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06008204
8205 wstats = &priv->wstats;
8206
8207 /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
8208 * ipw2100_wx_wireless_stats seems to be called before fw is
8209 * initialized. STATUS_ASSOCIATED will only be set if the hw is up
8210 * and associated; if not associcated, the values are all meaningless
8211 * anyway, so set them all to NULL and INVALID */
8212 if (!(priv->status & STATUS_ASSOCIATED)) {
8213 wstats->miss.beacon = 0;
8214 wstats->discard.retries = 0;
8215 wstats->qual.qual = 0;
8216 wstats->qual.level = 0;
8217 wstats->qual.noise = 0;
8218 wstats->qual.updated = 7;
8219 wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
James Ketrenosee8e3652005-09-14 09:47:29 -05008220 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
James Ketrenos2c86c272005-03-23 17:32:29 -06008221 return wstats;
8222 }
8223
8224 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS,
8225 &missed_beacons, &ord_len))
8226 goto fail_get_ordinal;
8227
James Ketrenosee8e3652005-09-14 09:47:29 -05008228 /* If we don't have a connection the quality and level is 0 */
James Ketrenos2c86c272005-03-23 17:32:29 -06008229 if (!(priv->status & STATUS_ASSOCIATED)) {
8230 wstats->qual.qual = 0;
8231 wstats->qual.level = 0;
8232 } else {
8233 if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR,
8234 &rssi, &ord_len))
8235 goto fail_get_ordinal;
8236 wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
8237 if (rssi < 10)
8238 rssi_qual = rssi * POOR / 10;
8239 else if (rssi < 15)
8240 rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR;
8241 else if (rssi < 20)
8242 rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR;
8243 else if (rssi < 30)
8244 rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008245 10 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008246 else
8247 rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008248 10 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008249
8250 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES,
8251 &tx_retries, &ord_len))
8252 goto fail_get_ordinal;
8253
8254 if (tx_retries > 75)
8255 tx_qual = (90 - tx_retries) * POOR / 15;
8256 else if (tx_retries > 70)
8257 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
8258 else if (tx_retries > 65)
8259 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
8260 else if (tx_retries > 50)
8261 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008262 15 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008263 else
8264 tx_qual = (50 - tx_retries) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008265 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008266
8267 if (missed_beacons > 50)
8268 beacon_qual = (60 - missed_beacons) * POOR / 10;
8269 else if (missed_beacons > 40)
8270 beacon_qual = (50 - missed_beacons) * (FAIR - POOR) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008271 10 + POOR;
James Ketrenos2c86c272005-03-23 17:32:29 -06008272 else if (missed_beacons > 32)
8273 beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008274 18 + FAIR;
James Ketrenos2c86c272005-03-23 17:32:29 -06008275 else if (missed_beacons > 20)
8276 beacon_qual = (32 - missed_beacons) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008277 (VERY_GOOD - GOOD) / 20 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008278 else
8279 beacon_qual = (20 - missed_beacons) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008280 (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008281
Reinette Chatre21f8a732009-08-18 10:25:05 -07008282 quality = min(tx_qual, rssi_qual);
8283 quality = min(beacon_qual, quality);
James Ketrenos2c86c272005-03-23 17:32:29 -06008284
Brice Goglin0f52bf92005-12-01 01:41:46 -08008285#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06008286 if (beacon_qual == quality)
8287 IPW_DEBUG_WX("Quality clamped by Missed Beacons\n");
8288 else if (tx_qual == quality)
8289 IPW_DEBUG_WX("Quality clamped by Tx Retries\n");
8290 else if (quality != 100)
8291 IPW_DEBUG_WX("Quality clamped by Signal Strength\n");
8292 else
8293 IPW_DEBUG_WX("Quality not clamped.\n");
8294#endif
8295
8296 wstats->qual.qual = quality;
8297 wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
8298 }
8299
8300 wstats->qual.noise = 0;
8301 wstats->qual.updated = 7;
8302 wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
8303
James Ketrenosee8e3652005-09-14 09:47:29 -05008304 /* FIXME: this is percent and not a # */
James Ketrenos2c86c272005-03-23 17:32:29 -06008305 wstats->miss.beacon = missed_beacons;
8306
8307 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES,
8308 &tx_failures, &ord_len))
8309 goto fail_get_ordinal;
8310 wstats->discard.retries = tx_failures;
8311
8312 return wstats;
8313
James Ketrenosee8e3652005-09-14 09:47:29 -05008314 fail_get_ordinal:
James Ketrenos2c86c272005-03-23 17:32:29 -06008315 IPW_DEBUG_WX("failed querying ordinals.\n");
8316
James Ketrenosee8e3652005-09-14 09:47:29 -05008317 return (struct iw_statistics *)NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06008318}
8319
James Ketrenoseaf8f53b2005-11-12 12:50:12 -06008320static struct iw_handler_def ipw2100_wx_handler_def = {
8321 .standard = ipw2100_wx_handlers,
Denis Chengff8ac602007-09-02 18:30:18 +08008322 .num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
8323 .num_private = ARRAY_SIZE(ipw2100_private_handler),
8324 .num_private_args = ARRAY_SIZE(ipw2100_private_args),
James Ketrenoseaf8f53b2005-11-12 12:50:12 -06008325 .private = (iw_handler *) ipw2100_private_handler,
8326 .private_args = (struct iw_priv_args *)ipw2100_private_args,
8327 .get_wireless_stats = ipw2100_wx_wireless_stats,
8328};
8329
David Howellsc4028952006-11-22 14:57:56 +00008330static void ipw2100_wx_event_work(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06008331{
David Howellsc4028952006-11-22 14:57:56 +00008332 struct ipw2100_priv *priv =
8333 container_of(work, struct ipw2100_priv, wx_event_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06008334 union iwreq_data wrqu;
Hannes Ederb9da9e92009-02-14 11:50:26 +00008335 unsigned int len = ETH_ALEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06008336
8337 if (priv->status & STATUS_STOPPING)
8338 return;
8339
Ingo Molnar752e3772006-02-28 07:20:54 +08008340 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008341
8342 IPW_DEBUG_WX("enter\n");
8343
Ingo Molnar752e3772006-02-28 07:20:54 +08008344 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008345
8346 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
8347
8348 /* Fetch BSSID from the hardware */
8349 if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) ||
8350 priv->status & STATUS_RF_KILL_MASK ||
8351 ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
James Ketrenosee8e3652005-09-14 09:47:29 -05008352 &priv->bssid, &len)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06008353 memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
8354 } else {
8355 /* We now have the BSSID, so can finish setting to the full
8356 * associated state */
8357 memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
James Ketrenos82328352005-08-24 22:33:31 -05008358 memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06008359 priv->status &= ~STATUS_ASSOCIATING;
8360 priv->status |= STATUS_ASSOCIATED;
8361 netif_carrier_on(priv->net_dev);
James Ketrenos82328352005-08-24 22:33:31 -05008362 netif_wake_queue(priv->net_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008363 }
8364
8365 if (!(priv->status & STATUS_ASSOCIATED)) {
8366 IPW_DEBUG_WX("Configuring ESSID\n");
Ingo Molnar752e3772006-02-28 07:20:54 +08008367 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008368 /* This is a disassociation event, so kick the firmware to
8369 * look for another AP */
8370 if (priv->config & CFG_STATIC_ESSID)
James Ketrenosee8e3652005-09-14 09:47:29 -05008371 ipw2100_set_essid(priv, priv->essid, priv->essid_len,
8372 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06008373 else
8374 ipw2100_set_essid(priv, NULL, 0, 0);
Ingo Molnar752e3772006-02-28 07:20:54 +08008375 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008376 }
8377
8378 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
8379}
8380
8381#define IPW2100_FW_MAJOR_VERSION 1
8382#define IPW2100_FW_MINOR_VERSION 3
8383
8384#define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8)
8385#define IPW2100_FW_MAJOR(x) (x & 0xff)
8386
8387#define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \
8388 IPW2100_FW_MAJOR_VERSION)
8389
8390#define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \
8391"." __stringify(IPW2100_FW_MINOR_VERSION)
8392
8393#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw"
8394
James Ketrenos2c86c272005-03-23 17:32:29 -06008395/*
8396
8397BINARY FIRMWARE HEADER FORMAT
8398
8399offset length desc
84000 2 version
84012 2 mode == 0:BSS,1:IBSS,2:MONITOR
84024 4 fw_len
84038 4 uc_len
8404C fw_len firmware data
840512 + fw_len uc_len microcode data
8406
8407*/
8408
8409struct ipw2100_fw_header {
8410 short version;
8411 short mode;
8412 unsigned int fw_size;
8413 unsigned int uc_size;
Eric Dumazetba2d3582010-06-02 18:10:09 +00008414} __packed;
James Ketrenos2c86c272005-03-23 17:32:29 -06008415
James Ketrenos2c86c272005-03-23 17:32:29 -06008416static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
8417{
8418 struct ipw2100_fw_header *h =
James Ketrenosee8e3652005-09-14 09:47:29 -05008419 (struct ipw2100_fw_header *)fw->fw_entry->data;
James Ketrenos2c86c272005-03-23 17:32:29 -06008420
8421 if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008422 printk(KERN_WARNING DRV_NAME ": Firmware image not compatible "
James Ketrenos2c86c272005-03-23 17:32:29 -06008423 "(detected version id of %u). "
8424 "See Documentation/networking/README.ipw2100\n",
8425 h->version);
8426 return 1;
8427 }
8428
8429 fw->version = h->version;
8430 fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header);
8431 fw->fw.size = h->fw_size;
8432 fw->uc.data = fw->fw.data + h->fw_size;
8433 fw->uc.size = h->uc_size;
8434
8435 return 0;
8436}
8437
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008438static int ipw2100_get_firmware(struct ipw2100_priv *priv,
8439 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008440{
8441 char *fw_name;
8442 int rc;
8443
8444 IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05008445 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06008446
8447 switch (priv->ieee->iw_mode) {
8448 case IW_MODE_ADHOC:
8449 fw_name = IPW2100_FW_NAME("-i");
8450 break;
8451#ifdef CONFIG_IPW2100_MONITOR
8452 case IW_MODE_MONITOR:
8453 fw_name = IPW2100_FW_NAME("-p");
8454 break;
8455#endif
8456 case IW_MODE_INFRA:
8457 default:
8458 fw_name = IPW2100_FW_NAME("");
8459 break;
8460 }
8461
8462 rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev);
8463
8464 if (rc < 0) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008465 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06008466 "%s: Firmware '%s' not available or load failed.\n",
8467 priv->net_dev->name, fw_name);
8468 return rc;
8469 }
Jiri Bencaaa4d302005-06-07 14:58:41 +02008470 IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data,
James Ketrenosee8e3652005-09-14 09:47:29 -05008471 fw->fw_entry->size);
James Ketrenos2c86c272005-03-23 17:32:29 -06008472
8473 ipw2100_mod_firmware_load(fw);
8474
8475 return 0;
8476}
8477
Ben Hutchingsa278ea32009-11-07 21:58:47 +00008478MODULE_FIRMWARE(IPW2100_FW_NAME("-i"));
8479#ifdef CONFIG_IPW2100_MONITOR
8480MODULE_FIRMWARE(IPW2100_FW_NAME("-p"));
8481#endif
8482MODULE_FIRMWARE(IPW2100_FW_NAME(""));
8483
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008484static void ipw2100_release_firmware(struct ipw2100_priv *priv,
8485 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008486{
8487 fw->version = 0;
Jesper Juhle3e07e02012-04-09 22:52:34 +02008488 release_firmware(fw->fw_entry);
James Ketrenos2c86c272005-03-23 17:32:29 -06008489 fw->fw_entry = NULL;
8490}
8491
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008492static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
8493 size_t max)
James Ketrenos2c86c272005-03-23 17:32:29 -06008494{
8495 char ver[MAX_FW_VERSION_LEN];
8496 u32 len = MAX_FW_VERSION_LEN;
8497 u32 tmp;
8498 int i;
8499 /* firmware version is an ascii string (max len of 14) */
James Ketrenosee8e3652005-09-14 09:47:29 -05008500 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len))
James Ketrenos2c86c272005-03-23 17:32:29 -06008501 return -EIO;
8502 tmp = max;
8503 if (len >= max)
8504 len = max - 1;
8505 for (i = 0; i < len; i++)
8506 buf[i] = ver[i];
8507 buf[i] = '\0';
8508 return tmp;
8509}
8510
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008511static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
8512 size_t max)
James Ketrenos2c86c272005-03-23 17:32:29 -06008513{
8514 u32 ver;
8515 u32 len = sizeof(ver);
8516 /* microcode version is a 32 bit integer */
James Ketrenosee8e3652005-09-14 09:47:29 -05008517 if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len))
James Ketrenos2c86c272005-03-23 17:32:29 -06008518 return -EIO;
8519 return snprintf(buf, max, "%08X", ver);
8520}
8521
8522/*
8523 * On exit, the firmware will have been freed from the fw list
8524 */
James Ketrenosee8e3652005-09-14 09:47:29 -05008525static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008526{
8527 /* firmware is constructed of N contiguous entries, each entry is
8528 * structured as:
8529 *
8530 * offset sie desc
8531 * 0 4 address to write to
8532 * 4 2 length of data run
James Ketrenosee8e3652005-09-14 09:47:29 -05008533 * 6 length data
James Ketrenos2c86c272005-03-23 17:32:29 -06008534 */
8535 unsigned int addr;
8536 unsigned short len;
8537
8538 const unsigned char *firmware_data = fw->fw.data;
8539 unsigned int firmware_data_left = fw->fw.size;
8540
8541 while (firmware_data_left > 0) {
James Ketrenosee8e3652005-09-14 09:47:29 -05008542 addr = *(u32 *) (firmware_data);
8543 firmware_data += 4;
James Ketrenos2c86c272005-03-23 17:32:29 -06008544 firmware_data_left -= 4;
8545
James Ketrenosee8e3652005-09-14 09:47:29 -05008546 len = *(u16 *) (firmware_data);
8547 firmware_data += 2;
James Ketrenos2c86c272005-03-23 17:32:29 -06008548 firmware_data_left -= 2;
8549
8550 if (len > 32) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008551 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06008552 "Invalid firmware run-length of %d bytes\n",
8553 len);
8554 return -EINVAL;
8555 }
8556
8557 write_nic_memory(priv->net_dev, addr, len, firmware_data);
James Ketrenosee8e3652005-09-14 09:47:29 -05008558 firmware_data += len;
James Ketrenos2c86c272005-03-23 17:32:29 -06008559 firmware_data_left -= len;
8560 }
8561
8562 return 0;
8563}
8564
8565struct symbol_alive_response {
8566 u8 cmd_id;
8567 u8 seq_num;
8568 u8 ucode_rev;
8569 u8 eeprom_valid;
8570 u16 valid_flags;
8571 u8 IEEE_addr[6];
8572 u16 flags;
8573 u16 pcb_rev;
8574 u16 clock_settle_time; // 1us LSB
8575 u16 powerup_settle_time; // 1us LSB
8576 u16 hop_settle_time; // 1us LSB
8577 u8 date[3]; // month, day, year
8578 u8 time[2]; // hours, minutes
8579 u8 ucode_valid;
8580};
8581
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008582static int ipw2100_ucode_download(struct ipw2100_priv *priv,
8583 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008584{
8585 struct net_device *dev = priv->net_dev;
8586 const unsigned char *microcode_data = fw->uc.data;
8587 unsigned int microcode_data_left = fw->uc.size;
Francois Romieu9b717072012-03-24 11:37:16 +01008588 void __iomem *reg = priv->ioaddr;
James Ketrenos2c86c272005-03-23 17:32:29 -06008589
8590 struct symbol_alive_response response;
8591 int i, j;
8592 u8 data;
8593
8594 /* Symbol control */
8595 write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008596 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008597 write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008598 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008599
8600 /* HW config */
8601 write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008602 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008603 write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008604 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008605
8606 /* EN_CS_ACCESS bit to reset control store pointer */
8607 write_nic_byte(dev, 0x210000, 0x40);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008608 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008609 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008610 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008611 write_nic_byte(dev, 0x210000, 0x40);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008612 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008613
8614 /* copy microcode from buffer into Symbol */
8615
8616 while (microcode_data_left > 0) {
8617 write_nic_byte(dev, 0x210010, *microcode_data++);
8618 write_nic_byte(dev, 0x210010, *microcode_data++);
8619 microcode_data_left -= 2;
8620 }
8621
8622 /* EN_CS_ACCESS bit to reset the control store pointer */
8623 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008624 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008625
8626 /* Enable System (Reg 0)
8627 * first enable causes garbage in RX FIFO */
8628 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008629 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008630 write_nic_byte(dev, 0x210000, 0x80);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008631 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008632
8633 /* Reset External Baseband Reg */
8634 write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008635 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008636 write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008637 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008638
8639 /* HW Config (Reg 5) */
8640 write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008641 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008642 write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008643 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008644
8645 /* Enable System (Reg 0)
8646 * second enable should be OK */
8647 write_nic_byte(dev, 0x210000, 0x00); // clear enable system
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008648 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008649 write_nic_byte(dev, 0x210000, 0x80); // set enable system
8650
8651 /* check Symbol is enabled - upped this from 5 as it wasn't always
8652 * catching the update */
8653 for (i = 0; i < 10; i++) {
8654 udelay(10);
8655
8656 /* check Dino is enabled bit */
8657 read_nic_byte(dev, 0x210000, &data);
8658 if (data & 0x1)
8659 break;
8660 }
8661
8662 if (i == 10) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008663 printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06008664 dev->name);
8665 return -EIO;
8666 }
8667
8668 /* Get Symbol alive response */
8669 for (i = 0; i < 30; i++) {
8670 /* Read alive response structure */
8671 for (j = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05008672 j < (sizeof(struct symbol_alive_response) >> 1); j++)
8673 read_nic_word(dev, 0x210004, ((u16 *) & response) + j);
James Ketrenos2c86c272005-03-23 17:32:29 -06008674
James Ketrenosee8e3652005-09-14 09:47:29 -05008675 if ((response.cmd_id == 1) && (response.ucode_valid == 0x1))
James Ketrenos2c86c272005-03-23 17:32:29 -06008676 break;
8677 udelay(10);
8678 }
8679
8680 if (i == 30) {
James Ketrenosee8e3652005-09-14 09:47:29 -05008681 printk(KERN_ERR DRV_NAME
8682 ": %s: No response from Symbol - hw not alive\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06008683 dev->name);
James Ketrenosee8e3652005-09-14 09:47:29 -05008684 printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response));
James Ketrenos2c86c272005-03-23 17:32:29 -06008685 return -EIO;
8686 }
8687
8688 return 0;
8689}