blob: ddf340f914da3b4a61118d60ee0f7c3519bd99af [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"
169
Zhu Yicc8279f2006-02-21 18:46:15 +0800170#define IPW2100_VERSION "git-1.2.2"
James Ketrenos2c86c272005-03-23 17:32:29 -0600171
172#define DRV_NAME "ipw2100"
173#define DRV_VERSION IPW2100_VERSION
174#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver"
Zhu Yi171e7b22006-02-15 07:17:56 +0800175#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
James Ketrenos2c86c272005-03-23 17:32:29 -0600176
Jean Pihetcc749982011-08-25 15:35:12 +0200177static struct pm_qos_request ipw2100_pm_qos_req;
Mark Grossed771342010-05-06 01:59:26 +0200178
James Ketrenos2c86c272005-03-23 17:32:29 -0600179/* Debugging stuff */
Brice Goglin0f52bf92005-12-01 01:41:46 -0800180#ifdef CONFIG_IPW2100_DEBUG
Robert P. J. Dayae800312007-01-31 02:39:40 -0500181#define IPW2100_RX_DEBUG /* Reception debugging */
James Ketrenos2c86c272005-03-23 17:32:29 -0600182#endif
183
184MODULE_DESCRIPTION(DRV_DESCRIPTION);
185MODULE_VERSION(DRV_VERSION);
186MODULE_AUTHOR(DRV_COPYRIGHT);
187MODULE_LICENSE("GPL");
188
189static int debug = 0;
Reinette Chatre21f8a732009-08-18 10:25:05 -0700190static int network_mode = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -0600191static int channel = 0;
Tim Gardner5c7f9b72008-10-14 10:38:03 -0600192static int associate = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -0600193static int disable = 0;
194#ifdef CONFIG_PM
195static struct ipw2100_fw ipw2100_firmware;
196#endif
197
198#include <linux/moduleparam.h>
199module_param(debug, int, 0444);
Reinette Chatre21f8a732009-08-18 10:25:05 -0700200module_param_named(mode, network_mode, int, 0444);
James Ketrenos2c86c272005-03-23 17:32:29 -0600201module_param(channel, int, 0444);
202module_param(associate, int, 0444);
203module_param(disable, int, 0444);
204
205MODULE_PARM_DESC(debug, "debug level");
206MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
207MODULE_PARM_DESC(channel, "channel");
Tim Gardner5c7f9b72008-10-14 10:38:03 -0600208MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
James Ketrenos2c86c272005-03-23 17:32:29 -0600209MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
210
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400211static u32 ipw2100_debug_level = IPW_DL_NONE;
212
Brice Goglin0f52bf92005-12-01 01:41:46 -0800213#ifdef CONFIG_IPW2100_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400214#define IPW_DEBUG(level, message...) \
215do { \
216 if (ipw2100_debug_level & (level)) { \
217 printk(KERN_DEBUG "ipw2100: %c %s ", \
Harvey Harrisonc94c93d2008-07-28 23:01:34 -0700218 in_interrupt() ? 'I' : 'U', __func__); \
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400219 printk(message); \
220 } \
221} while (0)
222#else
223#define IPW_DEBUG(level, message...) do {} while (0)
Brice Goglin0f52bf92005-12-01 01:41:46 -0800224#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -0600225
Brice Goglin0f52bf92005-12-01 01:41:46 -0800226#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -0600227static const char *command_types[] = {
228 "undefined",
James Ketrenosee8e3652005-09-14 09:47:29 -0500229 "unused", /* HOST_ATTENTION */
James Ketrenos2c86c272005-03-23 17:32:29 -0600230 "HOST_COMPLETE",
James Ketrenosee8e3652005-09-14 09:47:29 -0500231 "unused", /* SLEEP */
232 "unused", /* HOST_POWER_DOWN */
James Ketrenos2c86c272005-03-23 17:32:29 -0600233 "unused",
234 "SYSTEM_CONFIG",
James Ketrenosee8e3652005-09-14 09:47:29 -0500235 "unused", /* SET_IMR */
James Ketrenos2c86c272005-03-23 17:32:29 -0600236 "SSID",
237 "MANDATORY_BSSID",
238 "AUTHENTICATION_TYPE",
239 "ADAPTER_ADDRESS",
240 "PORT_TYPE",
241 "INTERNATIONAL_MODE",
242 "CHANNEL",
243 "RTS_THRESHOLD",
244 "FRAG_THRESHOLD",
245 "POWER_MODE",
246 "TX_RATES",
247 "BASIC_TX_RATES",
248 "WEP_KEY_INFO",
249 "unused",
250 "unused",
251 "unused",
252 "unused",
253 "WEP_KEY_INDEX",
254 "WEP_FLAGS",
255 "ADD_MULTICAST",
256 "CLEAR_ALL_MULTICAST",
257 "BEACON_INTERVAL",
258 "ATIM_WINDOW",
259 "CLEAR_STATISTICS",
260 "undefined",
261 "undefined",
262 "undefined",
263 "undefined",
264 "TX_POWER_INDEX",
265 "undefined",
266 "undefined",
267 "undefined",
268 "undefined",
269 "undefined",
270 "undefined",
271 "BROADCAST_SCAN",
272 "CARD_DISABLE",
273 "PREFERRED_BSSID",
274 "SET_SCAN_OPTIONS",
275 "SCAN_DWELL_TIME",
276 "SWEEP_TABLE",
277 "AP_OR_STATION_TABLE",
278 "GROUP_ORDINALS",
279 "SHORT_RETRY_LIMIT",
280 "LONG_RETRY_LIMIT",
James Ketrenosee8e3652005-09-14 09:47:29 -0500281 "unused", /* SAVE_CALIBRATION */
282 "unused", /* RESTORE_CALIBRATION */
James Ketrenos2c86c272005-03-23 17:32:29 -0600283 "undefined",
284 "undefined",
285 "undefined",
286 "HOST_PRE_POWER_DOWN",
James Ketrenosee8e3652005-09-14 09:47:29 -0500287 "unused", /* HOST_INTERRUPT_COALESCING */
James Ketrenos2c86c272005-03-23 17:32:29 -0600288 "undefined",
289 "CARD_DISABLE_PHY_OFF",
Jean Delvare96a95c12011-07-06 00:27:06 +0200290 "MSDU_TX_RATES",
James Ketrenos2c86c272005-03-23 17:32:29 -0600291 "undefined",
292 "SET_STATION_STAT_BITS",
293 "CLEAR_STATIONS_STAT_BITS",
294 "LEAP_ROGUE_MODE",
295 "SET_SECURITY_INFORMATION",
296 "DISASSOCIATION_BSSID",
297 "SET_WPA_ASS_IE"
298};
299#endif
300
Matthew Garrettc26409a2009-11-11 14:36:30 -0500301static const long ipw2100_frequencies[] = {
302 2412, 2417, 2422, 2427,
303 2432, 2437, 2442, 2447,
304 2452, 2457, 2462, 2467,
305 2472, 2484
306};
307
308#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies)
309
Matthew Garrettc26409a2009-11-11 14:36:30 -0500310static struct ieee80211_rate ipw2100_bg_rates[] = {
311 { .bitrate = 10 },
312 { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
313 { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
314 { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
315};
316
Stanislav Yakovlev4d94c152012-02-09 20:23:52 -0500317#define RATE_COUNT ARRAY_SIZE(ipw2100_bg_rates)
Matthew Garrettc26409a2009-11-11 14:36:30 -0500318
James Ketrenos2c86c272005-03-23 17:32:29 -0600319/* Pre-decl until we get the code solid and then we can clean it up */
Jiri Benc19f7f742005-08-25 20:02:10 -0400320static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
321static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
James Ketrenos2c86c272005-03-23 17:32:29 -0600322static int ipw2100_adapter_setup(struct ipw2100_priv *priv);
323
324static void ipw2100_queues_initialize(struct ipw2100_priv *priv);
325static void ipw2100_queues_free(struct ipw2100_priv *priv);
326static int ipw2100_queues_allocate(struct ipw2100_priv *priv);
327
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400328static int ipw2100_fw_download(struct ipw2100_priv *priv,
329 struct ipw2100_fw *fw);
330static int ipw2100_get_firmware(struct ipw2100_priv *priv,
331 struct ipw2100_fw *fw);
332static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
333 size_t max);
334static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
335 size_t max);
336static void ipw2100_release_firmware(struct ipw2100_priv *priv,
337 struct ipw2100_fw *fw);
338static int ipw2100_ucode_download(struct ipw2100_priv *priv,
339 struct ipw2100_fw *fw);
David Howellsc4028952006-11-22 14:57:56 +0000340static void ipw2100_wx_event_work(struct work_struct *work);
James Ketrenosee8e3652005-09-14 09:47:29 -0500341static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev);
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400342static struct iw_handler_def ipw2100_wx_handler_def;
343
James Ketrenosee8e3652005-09-14 09:47:29 -0500344static inline void read_register(struct net_device *dev, u32 reg, u32 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600345{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100346 *val = readl((void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600347 IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
348}
349
350static inline void write_register(struct net_device *dev, u32 reg, u32 val)
351{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100352 writel(val, (void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600353 IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
354}
355
James Ketrenosee8e3652005-09-14 09:47:29 -0500356static inline void read_register_word(struct net_device *dev, u32 reg,
357 u16 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600358{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100359 *val = readw((void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600360 IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
361}
362
James Ketrenosee8e3652005-09-14 09:47:29 -0500363static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600364{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100365 *val = readb((void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600366 IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
367}
368
369static inline void write_register_word(struct net_device *dev, u32 reg, u16 val)
370{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100371 writew(val, (void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600372 IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
373}
374
James Ketrenos2c86c272005-03-23 17:32:29 -0600375static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
376{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100377 writeb(val, (void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600378 IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
379}
380
James Ketrenosee8e3652005-09-14 09:47:29 -0500381static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600382{
383 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
384 addr & IPW_REG_INDIRECT_ADDR_MASK);
385 read_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
386}
387
388static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val)
389{
390 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
391 addr & IPW_REG_INDIRECT_ADDR_MASK);
392 write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
393}
394
James Ketrenosee8e3652005-09-14 09:47:29 -0500395static inline void read_nic_word(struct net_device *dev, u32 addr, u16 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600396{
397 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
398 addr & IPW_REG_INDIRECT_ADDR_MASK);
399 read_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
400}
401
402static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val)
403{
404 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
405 addr & IPW_REG_INDIRECT_ADDR_MASK);
406 write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
407}
408
James Ketrenosee8e3652005-09-14 09:47:29 -0500409static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600410{
411 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
412 addr & IPW_REG_INDIRECT_ADDR_MASK);
413 read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
414}
415
416static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val)
417{
418 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
419 addr & IPW_REG_INDIRECT_ADDR_MASK);
420 write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
421}
422
423static inline void write_nic_auto_inc_address(struct net_device *dev, u32 addr)
424{
425 write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
426 addr & IPW_REG_INDIRECT_ADDR_MASK);
427}
428
429static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val)
430{
431 write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val);
432}
433
Arjan van de Ven858119e2006-01-14 13:20:43 -0800434static void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
James Ketrenosee8e3652005-09-14 09:47:29 -0500435 const u8 * buf)
James Ketrenos2c86c272005-03-23 17:32:29 -0600436{
437 u32 aligned_addr;
438 u32 aligned_len;
439 u32 dif_len;
440 u32 i;
441
442 /* read first nibble byte by byte */
443 aligned_addr = addr & (~0x3);
444 dif_len = addr - aligned_addr;
445 if (dif_len) {
446 /* Start reading at aligned_addr + dif_len */
447 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
448 aligned_addr);
449 for (i = dif_len; i < 4; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500450 write_register_byte(dev,
451 IPW_REG_INDIRECT_ACCESS_DATA + i,
452 *buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600453
454 len -= dif_len;
455 aligned_addr += 4;
456 }
457
458 /* read DWs through autoincrement registers */
James Ketrenosee8e3652005-09-14 09:47:29 -0500459 write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600460 aligned_len = len & (~0x3);
461 for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
James Ketrenosee8e3652005-09-14 09:47:29 -0500462 write_register(dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *) buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600463
464 /* copy the last nibble */
465 dif_len = len - aligned_len;
466 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
467 for (i = 0; i < dif_len; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500468 write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
469 *buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600470}
471
Arjan van de Ven858119e2006-01-14 13:20:43 -0800472static void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
James Ketrenosee8e3652005-09-14 09:47:29 -0500473 u8 * buf)
James Ketrenos2c86c272005-03-23 17:32:29 -0600474{
475 u32 aligned_addr;
476 u32 aligned_len;
477 u32 dif_len;
478 u32 i;
479
480 /* read first nibble byte by byte */
481 aligned_addr = addr & (~0x3);
482 dif_len = addr - aligned_addr;
483 if (dif_len) {
484 /* Start reading at aligned_addr + dif_len */
485 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
486 aligned_addr);
487 for (i = dif_len; i < 4; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500488 read_register_byte(dev,
489 IPW_REG_INDIRECT_ACCESS_DATA + i,
490 buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600491
492 len -= dif_len;
493 aligned_addr += 4;
494 }
495
496 /* read DWs through autoincrement registers */
James Ketrenosee8e3652005-09-14 09:47:29 -0500497 write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600498 aligned_len = len & (~0x3);
499 for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
James Ketrenosee8e3652005-09-14 09:47:29 -0500500 read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600501
502 /* copy the last nibble */
503 dif_len = len - aligned_len;
James Ketrenosee8e3652005-09-14 09:47:29 -0500504 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600505 for (i = 0; i < dif_len; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500506 read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600507}
508
509static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev)
510{
511 return (dev->base_addr &&
James Ketrenosee8e3652005-09-14 09:47:29 -0500512 (readl
513 ((void __iomem *)(dev->base_addr +
514 IPW_REG_DOA_DEBUG_AREA_START))
James Ketrenos2c86c272005-03-23 17:32:29 -0600515 == IPW_DATA_DOA_DEBUG_VALUE));
516}
517
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400518static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
James Ketrenosee8e3652005-09-14 09:47:29 -0500519 void *val, u32 * len)
James Ketrenos2c86c272005-03-23 17:32:29 -0600520{
521 struct ipw2100_ordinals *ordinals = &priv->ordinals;
522 u32 addr;
523 u32 field_info;
524 u16 field_len;
525 u16 field_count;
526 u32 total_length;
527
528 if (ordinals->table1_addr == 0) {
Jiri Benc797b4f72005-08-25 20:03:27 -0400529 printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals "
James Ketrenos2c86c272005-03-23 17:32:29 -0600530 "before they have been loaded.\n");
531 return -EINVAL;
532 }
533
534 if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
535 if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) {
536 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
537
Jiri Benc797b4f72005-08-25 20:03:27 -0400538 printk(KERN_WARNING DRV_NAME
Jiri Bencaaa4d302005-06-07 14:58:41 +0200539 ": ordinal buffer length too small, need %zd\n",
James Ketrenos2c86c272005-03-23 17:32:29 -0600540 IPW_ORD_TAB_1_ENTRY_SIZE);
541
542 return -EINVAL;
543 }
544
James Ketrenosee8e3652005-09-14 09:47:29 -0500545 read_nic_dword(priv->net_dev,
546 ordinals->table1_addr + (ord << 2), &addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600547 read_nic_dword(priv->net_dev, addr, val);
548
549 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
550
551 return 0;
552 }
553
554 if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) {
555
556 ord -= IPW_START_ORD_TAB_2;
557
558 /* get the address of statistic */
James Ketrenosee8e3652005-09-14 09:47:29 -0500559 read_nic_dword(priv->net_dev,
560 ordinals->table2_addr + (ord << 3), &addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600561
562 /* get the second DW of statistics ;
563 * two 16-bit words - first is length, second is count */
564 read_nic_dword(priv->net_dev,
565 ordinals->table2_addr + (ord << 3) + sizeof(u32),
566 &field_info);
567
568 /* get each entry length */
James Ketrenosee8e3652005-09-14 09:47:29 -0500569 field_len = *((u16 *) & field_info);
James Ketrenos2c86c272005-03-23 17:32:29 -0600570
571 /* get number of entries */
James Ketrenosee8e3652005-09-14 09:47:29 -0500572 field_count = *(((u16 *) & field_info) + 1);
James Ketrenos2c86c272005-03-23 17:32:29 -0600573
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200574 /* abort if no enough memory */
James Ketrenos2c86c272005-03-23 17:32:29 -0600575 total_length = field_len * field_count;
576 if (total_length > *len) {
577 *len = total_length;
578 return -EINVAL;
579 }
580
581 *len = total_length;
582 if (!total_length)
583 return 0;
584
585 /* read the ordinal data from the SRAM */
586 read_nic_memory(priv->net_dev, addr, total_length, val);
587
588 return 0;
589 }
590
Jiri Benc797b4f72005-08-25 20:03:27 -0400591 printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor "
James Ketrenos2c86c272005-03-23 17:32:29 -0600592 "in table 2\n", ord);
593
594 return -EINVAL;
595}
596
James Ketrenosee8e3652005-09-14 09:47:29 -0500597static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val,
598 u32 * len)
James Ketrenos2c86c272005-03-23 17:32:29 -0600599{
600 struct ipw2100_ordinals *ordinals = &priv->ordinals;
601 u32 addr;
602
603 if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
604 if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) {
605 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
606 IPW_DEBUG_INFO("wrong size\n");
607 return -EINVAL;
608 }
609
James Ketrenosee8e3652005-09-14 09:47:29 -0500610 read_nic_dword(priv->net_dev,
611 ordinals->table1_addr + (ord << 2), &addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600612
613 write_nic_dword(priv->net_dev, addr, *val);
614
615 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
616
617 return 0;
618 }
619
620 IPW_DEBUG_INFO("wrong table\n");
621 if (IS_ORDINAL_TABLE_TWO(ordinals, ord))
622 return -EINVAL;
623
624 return -EINVAL;
625}
626
627static char *snprint_line(char *buf, size_t count,
James Ketrenosee8e3652005-09-14 09:47:29 -0500628 const u8 * data, u32 len, u32 ofs)
James Ketrenos2c86c272005-03-23 17:32:29 -0600629{
630 int out, i, j, l;
631 char c;
632
633 out = snprintf(buf, count, "%08X", ofs);
634
635 for (l = 0, i = 0; i < 2; i++) {
636 out += snprintf(buf + out, count - out, " ");
637 for (j = 0; j < 8 && l < len; j++, l++)
638 out += snprintf(buf + out, count - out, "%02X ",
639 data[(i * 8 + j)]);
640 for (; j < 8; j++)
641 out += snprintf(buf + out, count - out, " ");
642 }
643
644 out += snprintf(buf + out, count - out, " ");
645 for (l = 0, i = 0; i < 2; i++) {
646 out += snprintf(buf + out, count - out, " ");
647 for (j = 0; j < 8 && l < len; j++, l++) {
648 c = data[(i * 8 + j)];
649 if (!isascii(c) || !isprint(c))
650 c = '.';
651
652 out += snprintf(buf + out, count - out, "%c", c);
653 }
654
655 for (; j < 8; j++)
656 out += snprintf(buf + out, count - out, " ");
657 }
658
659 return buf;
660}
661
James Ketrenosee8e3652005-09-14 09:47:29 -0500662static void printk_buf(int level, const u8 * data, u32 len)
James Ketrenos2c86c272005-03-23 17:32:29 -0600663{
664 char line[81];
665 u32 ofs = 0;
666 if (!(ipw2100_debug_level & level))
667 return;
668
669 while (len) {
670 printk(KERN_DEBUG "%s\n",
671 snprint_line(line, sizeof(line), &data[ofs],
672 min(len, 16U), ofs));
673 ofs += 16;
674 len -= min(len, 16U);
675 }
676}
677
James Ketrenos2c86c272005-03-23 17:32:29 -0600678#define MAX_RESET_BACKOFF 10
679
Arjan van de Ven858119e2006-01-14 13:20:43 -0800680static void schedule_reset(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -0600681{
682 unsigned long now = get_seconds();
683
684 /* If we haven't received a reset request within the backoff period,
685 * then we can reset the backoff interval so this reset occurs
686 * immediately */
687 if (priv->reset_backoff &&
688 (now - priv->last_reset > priv->reset_backoff))
689 priv->reset_backoff = 0;
690
691 priv->last_reset = get_seconds();
692
693 if (!(priv->status & STATUS_RESET_PENDING)) {
694 IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n",
695 priv->net_dev->name, priv->reset_backoff);
696 netif_carrier_off(priv->net_dev);
697 netif_stop_queue(priv->net_dev);
698 priv->status |= STATUS_RESET_PENDING;
699 if (priv->reset_backoff)
Tejun Heobcb6d912011-01-26 12:12:50 +0100700 schedule_delayed_work(&priv->reset_work,
701 priv->reset_backoff * HZ);
James Ketrenos2c86c272005-03-23 17:32:29 -0600702 else
Tejun Heobcb6d912011-01-26 12:12:50 +0100703 schedule_delayed_work(&priv->reset_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -0600704
705 if (priv->reset_backoff < MAX_RESET_BACKOFF)
706 priv->reset_backoff++;
707
708 wake_up_interruptible(&priv->wait_command_queue);
709 } else
710 IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n",
711 priv->net_dev->name);
712
713}
714
715#define HOST_COMPLETE_TIMEOUT (2 * HZ)
716static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
James Ketrenosee8e3652005-09-14 09:47:29 -0500717 struct host_command *cmd)
James Ketrenos2c86c272005-03-23 17:32:29 -0600718{
719 struct list_head *element;
720 struct ipw2100_tx_packet *packet;
721 unsigned long flags;
722 int err = 0;
723
724 IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
725 command_types[cmd->host_command], cmd->host_command,
726 cmd->host_command_length);
James Ketrenosee8e3652005-09-14 09:47:29 -0500727 printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters,
James Ketrenos2c86c272005-03-23 17:32:29 -0600728 cmd->host_command_length);
729
730 spin_lock_irqsave(&priv->low_lock, flags);
731
732 if (priv->fatal_error) {
James Ketrenosee8e3652005-09-14 09:47:29 -0500733 IPW_DEBUG_INFO
734 ("Attempt to send command while hardware in fatal error condition.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -0600735 err = -EIO;
736 goto fail_unlock;
737 }
738
739 if (!(priv->status & STATUS_RUNNING)) {
James Ketrenosee8e3652005-09-14 09:47:29 -0500740 IPW_DEBUG_INFO
741 ("Attempt to send command while hardware is not running.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -0600742 err = -EIO;
743 goto fail_unlock;
744 }
745
746 if (priv->status & STATUS_CMD_ACTIVE) {
James Ketrenosee8e3652005-09-14 09:47:29 -0500747 IPW_DEBUG_INFO
748 ("Attempt to send command while another command is pending.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -0600749 err = -EBUSY;
750 goto fail_unlock;
751 }
752
753 if (list_empty(&priv->msg_free_list)) {
754 IPW_DEBUG_INFO("no available msg buffers\n");
755 goto fail_unlock;
756 }
757
758 priv->status |= STATUS_CMD_ACTIVE;
759 priv->messages_sent++;
760
761 element = priv->msg_free_list.next;
762
763 packet = list_entry(element, struct ipw2100_tx_packet, list);
764 packet->jiffy_start = jiffies;
765
766 /* initialize the firmware command packet */
767 packet->info.c_struct.cmd->host_command_reg = cmd->host_command;
768 packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1;
James Ketrenosee8e3652005-09-14 09:47:29 -0500769 packet->info.c_struct.cmd->host_command_len_reg =
770 cmd->host_command_length;
James Ketrenos2c86c272005-03-23 17:32:29 -0600771 packet->info.c_struct.cmd->sequence = cmd->host_command_sequence;
772
773 memcpy(packet->info.c_struct.cmd->host_command_params_reg,
774 cmd->host_command_parameters,
775 sizeof(packet->info.c_struct.cmd->host_command_params_reg));
776
777 list_del(element);
778 DEC_STAT(&priv->msg_free_stat);
779
780 list_add_tail(element, &priv->msg_pend_list);
781 INC_STAT(&priv->msg_pend_stat);
782
Jiri Benc19f7f742005-08-25 20:02:10 -0400783 ipw2100_tx_send_commands(priv);
784 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -0600785
786 spin_unlock_irqrestore(&priv->low_lock, flags);
787
788 /*
789 * We must wait for this command to complete before another
790 * command can be sent... but if we wait more than 3 seconds
791 * then there is a problem.
792 */
793
James Ketrenosee8e3652005-09-14 09:47:29 -0500794 err =
795 wait_event_interruptible_timeout(priv->wait_command_queue,
796 !(priv->
797 status & STATUS_CMD_ACTIVE),
798 HOST_COMPLETE_TIMEOUT);
James Ketrenos2c86c272005-03-23 17:32:29 -0600799
800 if (err == 0) {
801 IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
James Ketrenos82328352005-08-24 22:33:31 -0500802 1000 * (HOST_COMPLETE_TIMEOUT / HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -0600803 priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT;
804 priv->status &= ~STATUS_CMD_ACTIVE;
805 schedule_reset(priv);
806 return -EIO;
807 }
808
809 if (priv->fatal_error) {
Jiri Benc797b4f72005-08-25 20:03:27 -0400810 printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n",
James Ketrenos2c86c272005-03-23 17:32:29 -0600811 priv->net_dev->name);
812 return -EIO;
813 }
814
815 /* !!!!! HACK TEST !!!!!
816 * When lots of debug trace statements are enabled, the driver
817 * doesn't seem to have as many firmware restart cycles...
818 *
819 * As a test, we're sticking in a 1/100s delay here */
Nishanth Aravamudan3173c892005-09-11 02:09:55 -0700820 schedule_timeout_uninterruptible(msecs_to_jiffies(10));
James Ketrenos2c86c272005-03-23 17:32:29 -0600821
822 return 0;
823
James Ketrenosee8e3652005-09-14 09:47:29 -0500824 fail_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -0600825 spin_unlock_irqrestore(&priv->low_lock, flags);
826
827 return err;
828}
829
James Ketrenos2c86c272005-03-23 17:32:29 -0600830/*
831 * Verify the values and data access of the hardware
832 * No locks needed or used. No functions called.
833 */
834static int ipw2100_verify(struct ipw2100_priv *priv)
835{
836 u32 data1, data2;
837 u32 address;
838
839 u32 val1 = 0x76543210;
840 u32 val2 = 0xFEDCBA98;
841
842 /* Domain 0 check - all values should be DOA_DEBUG */
843 for (address = IPW_REG_DOA_DEBUG_AREA_START;
James Ketrenosee8e3652005-09-14 09:47:29 -0500844 address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) {
James Ketrenos2c86c272005-03-23 17:32:29 -0600845 read_register(priv->net_dev, address, &data1);
846 if (data1 != IPW_DATA_DOA_DEBUG_VALUE)
847 return -EIO;
848 }
849
850 /* Domain 1 check - use arbitrary read/write compare */
851 for (address = 0; address < 5; address++) {
852 /* The memory area is not used now */
853 write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
854 val1);
855 write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
856 val2);
857 read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
858 &data1);
859 read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
860 &data2);
861 if (val1 == data1 && val2 == data2)
862 return 0;
863 }
864
865 return -EIO;
866}
867
868/*
869 *
870 * Loop until the CARD_DISABLED bit is the same value as the
871 * supplied parameter
872 *
873 * TODO: See if it would be more efficient to do a wait/wake
874 * cycle and have the completion event trigger the wakeup
875 *
876 */
877#define IPW_CARD_DISABLE_COMPLETE_WAIT 100 // 100 milli
878static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state)
879{
880 int i;
881 u32 card_state;
882 u32 len = sizeof(card_state);
883 int err;
884
885 for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) {
886 err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED,
887 &card_state, &len);
888 if (err) {
889 IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal "
890 "failed.\n");
891 return 0;
892 }
893
894 /* We'll break out if either the HW state says it is
895 * in the state we want, or if HOST_COMPLETE command
896 * finishes */
897 if ((card_state == state) ||
898 ((priv->status & STATUS_ENABLED) ?
899 IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) {
900 if (state == IPW_HW_STATE_ENABLED)
901 priv->status |= STATUS_ENABLED;
902 else
903 priv->status &= ~STATUS_ENABLED;
904
905 return 0;
906 }
907
908 udelay(50);
909 }
910
911 IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n",
912 state ? "DISABLED" : "ENABLED");
913 return -EIO;
914}
915
James Ketrenos2c86c272005-03-23 17:32:29 -0600916/*********************************************************************
917 Procedure : sw_reset_and_clock
918 Purpose : Asserts s/w reset, asserts clock initialization
919 and waits for clock stabilization
920 ********************************************************************/
921static int sw_reset_and_clock(struct ipw2100_priv *priv)
922{
923 int i;
924 u32 r;
925
926 // assert s/w reset
927 write_register(priv->net_dev, IPW_REG_RESET_REG,
928 IPW_AUX_HOST_RESET_REG_SW_RESET);
929
930 // wait for clock stabilization
931 for (i = 0; i < 1000; i++) {
932 udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY);
933
934 // check clock ready bit
935 read_register(priv->net_dev, IPW_REG_RESET_REG, &r);
936 if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET)
937 break;
938 }
939
940 if (i == 1000)
941 return -EIO; // TODO: better error value
942
943 /* set "initialization complete" bit to move adapter to
944 * D0 state */
945 write_register(priv->net_dev, IPW_REG_GP_CNTRL,
946 IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE);
947
948 /* wait for clock stabilization */
949 for (i = 0; i < 10000; i++) {
950 udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4);
951
952 /* check clock ready bit */
953 read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
954 if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY)
955 break;
956 }
957
958 if (i == 10000)
959 return -EIO; /* TODO: better error value */
960
James Ketrenos2c86c272005-03-23 17:32:29 -0600961 /* set D0 standby bit */
962 read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
963 write_register(priv->net_dev, IPW_REG_GP_CNTRL,
964 r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
James Ketrenos2c86c272005-03-23 17:32:29 -0600965
966 return 0;
967}
968
969/*********************************************************************
Pavel Machek8724a112005-06-20 14:28:43 -0700970 Procedure : ipw2100_download_firmware
James Ketrenos2c86c272005-03-23 17:32:29 -0600971 Purpose : Initiaze adapter after power on.
972 The sequence is:
973 1. assert s/w reset first!
974 2. awake clocks & wait for clock stabilization
975 3. hold ARC (don't ask me why...)
976 4. load Dino ucode and reset/clock init again
977 5. zero-out shared mem
978 6. download f/w
979 *******************************************************************/
980static int ipw2100_download_firmware(struct ipw2100_priv *priv)
981{
982 u32 address;
983 int err;
984
985#ifndef CONFIG_PM
986 /* Fetch the firmware and microcode */
987 struct ipw2100_fw ipw2100_firmware;
988#endif
989
990 if (priv->fatal_error) {
991 IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after "
James Ketrenosee8e3652005-09-14 09:47:29 -0500992 "fatal error %d. Interface must be brought down.\n",
993 priv->net_dev->name, priv->fatal_error);
James Ketrenos2c86c272005-03-23 17:32:29 -0600994 return -EINVAL;
995 }
James Ketrenos2c86c272005-03-23 17:32:29 -0600996#ifdef CONFIG_PM
997 if (!ipw2100_firmware.version) {
998 err = ipw2100_get_firmware(priv, &ipw2100_firmware);
999 if (err) {
1000 IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001001 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001002 priv->fatal_error = IPW2100_ERR_FW_LOAD;
1003 goto fail;
1004 }
1005 }
1006#else
1007 err = ipw2100_get_firmware(priv, &ipw2100_firmware);
1008 if (err) {
1009 IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001010 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001011 priv->fatal_error = IPW2100_ERR_FW_LOAD;
1012 goto fail;
1013 }
1014#endif
1015 priv->firmware_version = ipw2100_firmware.version;
1016
1017 /* s/w reset and clock stabilization */
1018 err = sw_reset_and_clock(priv);
1019 if (err) {
1020 IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001021 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001022 goto fail;
1023 }
1024
1025 err = ipw2100_verify(priv);
1026 if (err) {
1027 IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001028 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001029 goto fail;
1030 }
1031
1032 /* Hold ARC */
1033 write_nic_dword(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05001034 IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000);
James Ketrenos2c86c272005-03-23 17:32:29 -06001035
1036 /* allow ARC to run */
1037 write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
1038
1039 /* load microcode */
1040 err = ipw2100_ucode_download(priv, &ipw2100_firmware);
1041 if (err) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001042 printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001043 priv->net_dev->name, err);
1044 goto fail;
1045 }
1046
1047 /* release ARC */
1048 write_nic_dword(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05001049 IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000);
James Ketrenos2c86c272005-03-23 17:32:29 -06001050
1051 /* s/w reset and clock stabilization (again!!!) */
1052 err = sw_reset_and_clock(priv);
1053 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001054 printk(KERN_ERR DRV_NAME
1055 ": %s: sw_reset_and_clock failed: %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001056 priv->net_dev->name, err);
1057 goto fail;
1058 }
1059
1060 /* load f/w */
1061 err = ipw2100_fw_download(priv, &ipw2100_firmware);
1062 if (err) {
1063 IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001064 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001065 goto fail;
1066 }
James Ketrenos2c86c272005-03-23 17:32:29 -06001067#ifndef CONFIG_PM
1068 /*
1069 * When the .resume method of the driver is called, the other
1070 * part of the system, i.e. the ide driver could still stay in
1071 * the suspend stage. This prevents us from loading the firmware
1072 * from the disk. --YZ
1073 */
1074
1075 /* free any storage allocated for firmware image */
1076 ipw2100_release_firmware(priv, &ipw2100_firmware);
1077#endif
1078
1079 /* zero out Domain 1 area indirectly (Si requirement) */
1080 for (address = IPW_HOST_FW_SHARED_AREA0;
1081 address < IPW_HOST_FW_SHARED_AREA0_END; address += 4)
1082 write_nic_dword(priv->net_dev, address, 0);
1083 for (address = IPW_HOST_FW_SHARED_AREA1;
1084 address < IPW_HOST_FW_SHARED_AREA1_END; address += 4)
1085 write_nic_dword(priv->net_dev, address, 0);
1086 for (address = IPW_HOST_FW_SHARED_AREA2;
1087 address < IPW_HOST_FW_SHARED_AREA2_END; address += 4)
1088 write_nic_dword(priv->net_dev, address, 0);
1089 for (address = IPW_HOST_FW_SHARED_AREA3;
1090 address < IPW_HOST_FW_SHARED_AREA3_END; address += 4)
1091 write_nic_dword(priv->net_dev, address, 0);
1092 for (address = IPW_HOST_FW_INTERRUPT_AREA;
1093 address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4)
1094 write_nic_dword(priv->net_dev, address, 0);
1095
1096 return 0;
1097
James Ketrenosee8e3652005-09-14 09:47:29 -05001098 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06001099 ipw2100_release_firmware(priv, &ipw2100_firmware);
1100 return err;
1101}
1102
1103static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv)
1104{
1105 if (priv->status & STATUS_INT_ENABLED)
1106 return;
1107 priv->status |= STATUS_INT_ENABLED;
1108 write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK);
1109}
1110
1111static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv)
1112{
1113 if (!(priv->status & STATUS_INT_ENABLED))
1114 return;
1115 priv->status &= ~STATUS_INT_ENABLED;
1116 write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0);
1117}
1118
James Ketrenos2c86c272005-03-23 17:32:29 -06001119static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv)
1120{
1121 struct ipw2100_ordinals *ord = &priv->ordinals;
1122
1123 IPW_DEBUG_INFO("enter\n");
1124
1125 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1,
1126 &ord->table1_addr);
1127
1128 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2,
1129 &ord->table2_addr);
1130
1131 read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size);
1132 read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size);
1133
1134 ord->table2_size &= 0x0000FFFF;
1135
1136 IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size);
1137 IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size);
1138 IPW_DEBUG_INFO("exit\n");
1139}
1140
1141static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv)
1142{
1143 u32 reg = 0;
1144 /*
1145 * Set GPIO 3 writable by FW; GPIO 1 writable
1146 * by driver and enable clock
1147 */
1148 reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE |
1149 IPW_BIT_GPIO_LED_OFF);
1150 write_register(priv->net_dev, IPW_REG_GPIO, reg);
1151}
1152
Arjan van de Ven858119e2006-01-14 13:20:43 -08001153static int rf_kill_active(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06001154{
1155#define MAX_RF_KILL_CHECKS 5
1156#define RF_KILL_CHECK_DELAY 40
James Ketrenos2c86c272005-03-23 17:32:29 -06001157
1158 unsigned short value = 0;
1159 u32 reg = 0;
1160 int i;
1161
1162 if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
Matthew Garrettc26409a2009-11-11 14:36:30 -05001163 wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
James Ketrenos2c86c272005-03-23 17:32:29 -06001164 priv->status &= ~STATUS_RF_KILL_HW;
1165 return 0;
1166 }
1167
1168 for (i = 0; i < MAX_RF_KILL_CHECKS; i++) {
1169 udelay(RF_KILL_CHECK_DELAY);
1170 read_register(priv->net_dev, IPW_REG_GPIO, &reg);
1171 value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1);
1172 }
1173
Matthew Garrettc26409a2009-11-11 14:36:30 -05001174 if (value == 0) {
1175 wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
James Ketrenos2c86c272005-03-23 17:32:29 -06001176 priv->status |= STATUS_RF_KILL_HW;
Matthew Garrettc26409a2009-11-11 14:36:30 -05001177 } else {
1178 wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
James Ketrenos2c86c272005-03-23 17:32:29 -06001179 priv->status &= ~STATUS_RF_KILL_HW;
Matthew Garrettc26409a2009-11-11 14:36:30 -05001180 }
James Ketrenos2c86c272005-03-23 17:32:29 -06001181
1182 return (value == 0);
1183}
1184
1185static int ipw2100_get_hw_features(struct ipw2100_priv *priv)
1186{
1187 u32 addr, len;
1188 u32 val;
1189
1190 /*
1191 * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1
1192 */
1193 len = sizeof(addr);
James Ketrenosee8e3652005-09-14 09:47:29 -05001194 if (ipw2100_get_ordinal
1195 (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06001196 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001197 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06001198 return -EIO;
1199 }
1200
1201 IPW_DEBUG_INFO("EEPROM address: %08X\n", addr);
1202
1203 /*
1204 * EEPROM version is the byte at offset 0xfd in firmware
1205 * We read 4 bytes, then shift out the byte we actually want */
1206 read_nic_dword(priv->net_dev, addr + 0xFC, &val);
1207 priv->eeprom_version = (val >> 24) & 0xFF;
1208 IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version);
1209
James Ketrenosee8e3652005-09-14 09:47:29 -05001210 /*
James Ketrenos2c86c272005-03-23 17:32:29 -06001211 * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware
1212 *
1213 * notice that the EEPROM bit is reverse polarity, i.e.
1214 * bit = 0 signifies HW RF kill switch is supported
1215 * bit = 1 signifies HW RF kill switch is NOT supported
1216 */
1217 read_nic_dword(priv->net_dev, addr + 0x20, &val);
1218 if (!((val >> 24) & 0x01))
1219 priv->hw_features |= HW_FEATURE_RFKILL;
1220
1221 IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001222 (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not ");
James Ketrenos2c86c272005-03-23 17:32:29 -06001223
1224 return 0;
1225}
1226
1227/*
1228 * Start firmware execution after power on and intialization
1229 * The sequence is:
1230 * 1. Release ARC
1231 * 2. Wait for f/w initialization completes;
1232 */
1233static int ipw2100_start_adapter(struct ipw2100_priv *priv)
1234{
James Ketrenos2c86c272005-03-23 17:32:29 -06001235 int i;
1236 u32 inta, inta_mask, gpio;
1237
1238 IPW_DEBUG_INFO("enter\n");
1239
1240 if (priv->status & STATUS_RUNNING)
1241 return 0;
1242
1243 /*
1244 * Initialize the hw - drive adapter to DO state by setting
1245 * init_done bit. Wait for clk_ready bit and Download
1246 * fw & dino ucode
1247 */
1248 if (ipw2100_download_firmware(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001249 printk(KERN_ERR DRV_NAME
1250 ": %s: Failed to power on the adapter.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001251 priv->net_dev->name);
1252 return -EIO;
1253 }
1254
1255 /* Clear the Tx, Rx and Msg queues and the r/w indexes
1256 * in the firmware RBD and TBD ring queue */
1257 ipw2100_queues_initialize(priv);
1258
1259 ipw2100_hw_set_gpio(priv);
1260
1261 /* TODO -- Look at disabling interrupts here to make sure none
1262 * get fired during FW initialization */
1263
1264 /* Release ARC - clear reset bit */
1265 write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
1266
1267 /* wait for f/w intialization complete */
1268 IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n");
1269 i = 5000;
1270 do {
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001271 schedule_timeout_uninterruptible(msecs_to_jiffies(40));
James Ketrenos2c86c272005-03-23 17:32:29 -06001272 /* Todo... wait for sync command ... */
1273
1274 read_register(priv->net_dev, IPW_REG_INTA, &inta);
1275
1276 /* check "init done" bit */
1277 if (inta & IPW2100_INTA_FW_INIT_DONE) {
1278 /* reset "init done" bit */
1279 write_register(priv->net_dev, IPW_REG_INTA,
1280 IPW2100_INTA_FW_INIT_DONE);
1281 break;
1282 }
1283
1284 /* check error conditions : we check these after the firmware
1285 * check so that if there is an error, the interrupt handler
1286 * will see it and the adapter will be reset */
1287 if (inta &
1288 (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) {
1289 /* clear error conditions */
1290 write_register(priv->net_dev, IPW_REG_INTA,
1291 IPW2100_INTA_FATAL_ERROR |
1292 IPW2100_INTA_PARITY_ERROR);
1293 }
Roel Kluina2a1c3e2007-11-05 23:55:02 +01001294 } while (--i);
James Ketrenos2c86c272005-03-23 17:32:29 -06001295
1296 /* Clear out any pending INTAs since we aren't supposed to have
1297 * interrupts enabled at this point... */
1298 read_register(priv->net_dev, IPW_REG_INTA, &inta);
1299 read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
1300 inta &= IPW_INTERRUPT_MASK;
1301 /* Clear out any pending interrupts */
1302 if (inta & inta_mask)
1303 write_register(priv->net_dev, IPW_REG_INTA, inta);
1304
1305 IPW_DEBUG_FW("f/w initialization complete: %s\n",
1306 i ? "SUCCESS" : "FAILED");
1307
1308 if (!i) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001309 printk(KERN_WARNING DRV_NAME
1310 ": %s: Firmware did not initialize.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001311 priv->net_dev->name);
1312 return -EIO;
1313 }
1314
1315 /* allow firmware to write to GPIO1 & GPIO3 */
1316 read_register(priv->net_dev, IPW_REG_GPIO, &gpio);
1317
1318 gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK);
1319
1320 write_register(priv->net_dev, IPW_REG_GPIO, gpio);
1321
1322 /* Ready to receive commands */
1323 priv->status |= STATUS_RUNNING;
1324
1325 /* The adapter has been reset; we are not associated */
1326 priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
1327
1328 IPW_DEBUG_INFO("exit\n");
1329
1330 return 0;
1331}
1332
1333static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv)
1334{
1335 if (!priv->fatal_error)
1336 return;
1337
1338 priv->fatal_errors[priv->fatal_index++] = priv->fatal_error;
1339 priv->fatal_index %= IPW2100_ERROR_QUEUE;
1340 priv->fatal_error = 0;
1341}
1342
James Ketrenos2c86c272005-03-23 17:32:29 -06001343/* NOTE: Our interrupt is disabled when this method is called */
1344static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
1345{
1346 u32 reg;
1347 int i;
1348
1349 IPW_DEBUG_INFO("Power cycling the hardware.\n");
1350
1351 ipw2100_hw_set_gpio(priv);
1352
1353 /* Step 1. Stop Master Assert */
1354 write_register(priv->net_dev, IPW_REG_RESET_REG,
1355 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
1356
1357 /* Step 2. Wait for stop Master Assert
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02001358 * (not more than 50us, otherwise ret error */
James Ketrenos2c86c272005-03-23 17:32:29 -06001359 i = 5;
1360 do {
1361 udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
1362 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
1363
1364 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
1365 break;
Roel Kluina2a1c3e2007-11-05 23:55:02 +01001366 } while (--i);
James Ketrenos2c86c272005-03-23 17:32:29 -06001367
1368 priv->status &= ~STATUS_RESET_PENDING;
1369
1370 if (!i) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001371 IPW_DEBUG_INFO
1372 ("exit - waited too long for master assert stop\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06001373 return -EIO;
1374 }
1375
1376 write_register(priv->net_dev, IPW_REG_RESET_REG,
1377 IPW_AUX_HOST_RESET_REG_SW_RESET);
1378
James Ketrenos2c86c272005-03-23 17:32:29 -06001379 /* Reset any fatal_error conditions */
1380 ipw2100_reset_fatalerror(priv);
1381
1382 /* At this point, the adapter is now stopped and disabled */
1383 priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING |
1384 STATUS_ASSOCIATED | STATUS_ENABLED);
1385
1386 return 0;
1387}
1388
1389/*
Justin P. Mattock942a8492011-02-01 21:06:21 -08001390 * Send the CARD_DISABLE_PHY_OFF command to the card to disable it
James Ketrenos2c86c272005-03-23 17:32:29 -06001391 *
1392 * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent.
1393 *
1394 * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of
1395 * if STATUS_ASSN_LOST is sent.
1396 */
1397static int ipw2100_hw_phy_off(struct ipw2100_priv *priv)
1398{
1399
1400#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000)
1401
1402 struct host_command cmd = {
1403 .host_command = CARD_DISABLE_PHY_OFF,
1404 .host_command_sequence = 0,
1405 .host_command_length = 0,
1406 };
1407 int err, i;
1408 u32 val1, val2;
1409
1410 IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n");
1411
1412 /* Turn off the radio */
1413 err = ipw2100_hw_send_command(priv, &cmd);
1414 if (err)
1415 return err;
1416
1417 for (i = 0; i < 2500; i++) {
1418 read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1);
1419 read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2);
1420
1421 if ((val1 & IPW2100_CONTROL_PHY_OFF) &&
1422 (val2 & IPW2100_COMMAND_PHY_OFF))
1423 return 0;
1424
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001425 schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY);
James Ketrenos2c86c272005-03-23 17:32:29 -06001426 }
1427
1428 return -EIO;
1429}
1430
James Ketrenos2c86c272005-03-23 17:32:29 -06001431static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
1432{
1433 struct host_command cmd = {
1434 .host_command = HOST_COMPLETE,
1435 .host_command_sequence = 0,
1436 .host_command_length = 0
1437 };
1438 int err = 0;
1439
1440 IPW_DEBUG_HC("HOST_COMPLETE\n");
1441
1442 if (priv->status & STATUS_ENABLED)
1443 return 0;
1444
Ingo Molnar752e3772006-02-28 07:20:54 +08001445 mutex_lock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001446
1447 if (rf_kill_active(priv)) {
1448 IPW_DEBUG_HC("Command aborted due to RF kill active.\n");
1449 goto fail_up;
1450 }
1451
1452 err = ipw2100_hw_send_command(priv, &cmd);
1453 if (err) {
1454 IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n");
1455 goto fail_up;
1456 }
1457
1458 err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED);
1459 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001460 IPW_DEBUG_INFO("%s: card not responding to init command.\n",
1461 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001462 goto fail_up;
1463 }
1464
1465 if (priv->stop_hang_check) {
1466 priv->stop_hang_check = 0;
Tejun Heobcb6d912011-01-26 12:12:50 +01001467 schedule_delayed_work(&priv->hang_check, HZ / 2);
James Ketrenos2c86c272005-03-23 17:32:29 -06001468 }
1469
James Ketrenosee8e3652005-09-14 09:47:29 -05001470 fail_up:
Ingo Molnar752e3772006-02-28 07:20:54 +08001471 mutex_unlock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001472 return err;
1473}
1474
1475static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
1476{
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001477#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100))
James Ketrenos2c86c272005-03-23 17:32:29 -06001478
1479 struct host_command cmd = {
1480 .host_command = HOST_PRE_POWER_DOWN,
1481 .host_command_sequence = 0,
1482 .host_command_length = 0,
1483 };
1484 int err, i;
1485 u32 reg;
1486
1487 if (!(priv->status & STATUS_RUNNING))
1488 return 0;
1489
1490 priv->status |= STATUS_STOPPING;
1491
1492 /* We can only shut down the card if the firmware is operational. So,
1493 * if we haven't reset since a fatal_error, then we can not send the
1494 * shutdown commands. */
1495 if (!priv->fatal_error) {
1496 /* First, make sure the adapter is enabled so that the PHY_OFF
1497 * command can shut it down */
1498 ipw2100_enable_adapter(priv);
1499
1500 err = ipw2100_hw_phy_off(priv);
1501 if (err)
James Ketrenosee8e3652005-09-14 09:47:29 -05001502 printk(KERN_WARNING DRV_NAME
1503 ": Error disabling radio %d\n", err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001504
1505 /*
1506 * If in D0-standby mode going directly to D3 may cause a
1507 * PCI bus violation. Therefore we must change out of the D0
1508 * state.
1509 *
1510 * Sending the PREPARE_FOR_POWER_DOWN will restrict the
1511 * hardware from going into standby mode and will transition
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001512 * out of D0-standby if it is already in that state.
James Ketrenos2c86c272005-03-23 17:32:29 -06001513 *
1514 * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the
1515 * driver upon completion. Once received, the driver can
1516 * proceed to the D3 state.
1517 *
1518 * Prepare for power down command to fw. This command would
1519 * take HW out of D0-standby and prepare it for D3 state.
1520 *
1521 * Currently FW does not support event notification for this
1522 * event. Therefore, skip waiting for it. Just wait a fixed
1523 * 100ms
1524 */
1525 IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n");
1526
1527 err = ipw2100_hw_send_command(priv, &cmd);
1528 if (err)
Jiri Benc797b4f72005-08-25 20:03:27 -04001529 printk(KERN_WARNING DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06001530 "%s: Power down command failed: Error %d\n",
1531 priv->net_dev->name, err);
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001532 else
1533 schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY);
James Ketrenos2c86c272005-03-23 17:32:29 -06001534 }
1535
1536 priv->status &= ~STATUS_ENABLED;
1537
1538 /*
1539 * Set GPIO 3 writable by FW; GPIO 1 writable
1540 * by driver and enable clock
1541 */
1542 ipw2100_hw_set_gpio(priv);
1543
1544 /*
1545 * Power down adapter. Sequence:
1546 * 1. Stop master assert (RESET_REG[9]=1)
1547 * 2. Wait for stop master (RESET_REG[8]==1)
1548 * 3. S/w reset assert (RESET_REG[7] = 1)
1549 */
1550
1551 /* Stop master assert */
1552 write_register(priv->net_dev, IPW_REG_RESET_REG,
1553 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
1554
1555 /* wait stop master not more than 50 usec.
1556 * Otherwise return error. */
1557 for (i = 5; i > 0; i--) {
1558 udelay(10);
1559
1560 /* Check master stop bit */
1561 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
1562
1563 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
1564 break;
1565 }
1566
1567 if (i == 0)
Jiri Benc797b4f72005-08-25 20:03:27 -04001568 printk(KERN_WARNING DRV_NAME
James Ketrenos2c86c272005-03-23 17:32:29 -06001569 ": %s: Could now power down adapter.\n",
1570 priv->net_dev->name);
1571
1572 /* assert s/w reset */
1573 write_register(priv->net_dev, IPW_REG_RESET_REG,
1574 IPW_AUX_HOST_RESET_REG_SW_RESET);
1575
1576 priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING);
1577
1578 return 0;
1579}
1580
James Ketrenos2c86c272005-03-23 17:32:29 -06001581static int ipw2100_disable_adapter(struct ipw2100_priv *priv)
1582{
1583 struct host_command cmd = {
1584 .host_command = CARD_DISABLE,
1585 .host_command_sequence = 0,
1586 .host_command_length = 0
1587 };
1588 int err = 0;
1589
1590 IPW_DEBUG_HC("CARD_DISABLE\n");
1591
1592 if (!(priv->status & STATUS_ENABLED))
1593 return 0;
1594
1595 /* Make sure we clear the associated state */
1596 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1597
1598 if (!priv->stop_hang_check) {
1599 priv->stop_hang_check = 1;
1600 cancel_delayed_work(&priv->hang_check);
1601 }
1602
Ingo Molnar752e3772006-02-28 07:20:54 +08001603 mutex_lock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001604
1605 err = ipw2100_hw_send_command(priv, &cmd);
1606 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001607 printk(KERN_WARNING DRV_NAME
1608 ": exit - failed to send CARD_DISABLE command\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06001609 goto fail_up;
1610 }
1611
1612 err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED);
1613 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001614 printk(KERN_WARNING DRV_NAME
1615 ": exit - card failed to change to DISABLED\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06001616 goto fail_up;
1617 }
1618
1619 IPW_DEBUG_INFO("TODO: implement scan state machine\n");
1620
James Ketrenosee8e3652005-09-14 09:47:29 -05001621 fail_up:
Ingo Molnar752e3772006-02-28 07:20:54 +08001622 mutex_unlock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001623 return err;
1624}
1625
Jiri Bencc4aee8c2005-08-25 20:04:43 -04001626static int ipw2100_set_scan_options(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06001627{
1628 struct host_command cmd = {
1629 .host_command = SET_SCAN_OPTIONS,
1630 .host_command_sequence = 0,
1631 .host_command_length = 8
1632 };
1633 int err;
1634
1635 IPW_DEBUG_INFO("enter\n");
1636
1637 IPW_DEBUG_SCAN("setting scan options\n");
1638
1639 cmd.host_command_parameters[0] = 0;
1640
1641 if (!(priv->config & CFG_ASSOCIATE))
1642 cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE;
25b645b2005-07-12 15:45:30 -05001643 if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled)
James Ketrenos2c86c272005-03-23 17:32:29 -06001644 cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL;
1645 if (priv->config & CFG_PASSIVE_SCAN)
1646 cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE;
1647
1648 cmd.host_command_parameters[1] = priv->channel_mask;
1649
1650 err = ipw2100_hw_send_command(priv, &cmd);
1651
1652 IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n",
1653 cmd.host_command_parameters[0]);
1654
1655 return err;
1656}
1657
Jiri Bencc4aee8c2005-08-25 20:04:43 -04001658static int ipw2100_start_scan(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06001659{
1660 struct host_command cmd = {
1661 .host_command = BROADCAST_SCAN,
1662 .host_command_sequence = 0,
1663 .host_command_length = 4
1664 };
1665 int err;
1666
1667 IPW_DEBUG_HC("START_SCAN\n");
1668
1669 cmd.host_command_parameters[0] = 0;
1670
1671 /* No scanning if in monitor mode */
1672 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
1673 return 1;
1674
1675 if (priv->status & STATUS_SCANNING) {
1676 IPW_DEBUG_SCAN("Scan requested while already in scan...\n");
1677 return 0;
1678 }
1679
1680 IPW_DEBUG_INFO("enter\n");
1681
1682 /* Not clearing here; doing so makes iwlist always return nothing...
1683 *
1684 * We should modify the table logic to use aging tables vs. clearing
1685 * the table on each scan start.
1686 */
1687 IPW_DEBUG_SCAN("starting scan\n");
1688
1689 priv->status |= STATUS_SCANNING;
1690 err = ipw2100_hw_send_command(priv, &cmd);
1691 if (err)
1692 priv->status &= ~STATUS_SCANNING;
1693
1694 IPW_DEBUG_INFO("exit\n");
1695
1696 return err;
1697}
1698
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04001699static const struct libipw_geo ipw_geos[] = {
Zhu Yibe6b3b12006-01-24 13:49:08 +08001700 { /* Restricted */
1701 "---",
1702 .bg_channels = 14,
1703 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
1704 {2427, 4}, {2432, 5}, {2437, 6},
1705 {2442, 7}, {2447, 8}, {2452, 9},
1706 {2457, 10}, {2462, 11}, {2467, 12},
1707 {2472, 13}, {2484, 14}},
1708 },
1709};
1710
James Ketrenos2c86c272005-03-23 17:32:29 -06001711static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
1712{
1713 unsigned long flags;
1714 int rc = 0;
1715 u32 lock;
1716 u32 ord_len = sizeof(lock);
1717
Dan Williamsc3d72b92009-02-11 13:26:06 -05001718 /* Age scan list entries found before suspend */
1719 if (priv->suspend_time) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04001720 libipw_networks_age(priv->ieee, priv->suspend_time);
Dan Williamsc3d72b92009-02-11 13:26:06 -05001721 priv->suspend_time = 0;
1722 }
1723
1724 /* Quiet if manually disabled. */
James Ketrenos2c86c272005-03-23 17:32:29 -06001725 if (priv->status & STATUS_RF_KILL_SW) {
1726 IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "
1727 "switch\n", priv->net_dev->name);
1728 return 0;
1729 }
1730
Arjan van de Ven5c875792006-09-30 23:27:17 -07001731 /* the ipw2100 hardware really doesn't want power management delays
1732 * longer than 175usec
1733 */
James Bottomley82f68252010-07-05 22:53:06 +02001734 pm_qos_update_request(&ipw2100_pm_qos_req, 175);
Arjan van de Ven5c875792006-09-30 23:27:17 -07001735
James Ketrenos2c86c272005-03-23 17:32:29 -06001736 /* If the interrupt is enabled, turn it off... */
1737 spin_lock_irqsave(&priv->low_lock, flags);
1738 ipw2100_disable_interrupts(priv);
1739
1740 /* Reset any fatal_error conditions */
1741 ipw2100_reset_fatalerror(priv);
1742 spin_unlock_irqrestore(&priv->low_lock, flags);
1743
1744 if (priv->status & STATUS_POWERED ||
1745 (priv->status & STATUS_RESET_PENDING)) {
1746 /* Power cycle the card ... */
1747 if (ipw2100_power_cycle_adapter(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001748 printk(KERN_WARNING DRV_NAME
1749 ": %s: Could not cycle adapter.\n",
1750 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001751 rc = 1;
1752 goto exit;
1753 }
1754 } else
1755 priv->status |= STATUS_POWERED;
1756
Pavel Machek8724a112005-06-20 14:28:43 -07001757 /* Load the firmware, start the clocks, etc. */
James Ketrenos2c86c272005-03-23 17:32:29 -06001758 if (ipw2100_start_adapter(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001759 printk(KERN_ERR DRV_NAME
1760 ": %s: Failed to start the firmware.\n",
1761 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001762 rc = 1;
1763 goto exit;
1764 }
1765
1766 ipw2100_initialize_ordinals(priv);
1767
1768 /* Determine capabilities of this particular HW configuration */
1769 if (ipw2100_get_hw_features(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001770 printk(KERN_ERR DRV_NAME
1771 ": %s: Failed to determine HW features.\n",
1772 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001773 rc = 1;
1774 goto exit;
1775 }
1776
Zhu Yibe6b3b12006-01-24 13:49:08 +08001777 /* Initialize the geo */
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04001778 if (libipw_set_geo(priv->ieee, &ipw_geos[0])) {
Zhu Yibe6b3b12006-01-24 13:49:08 +08001779 printk(KERN_WARNING DRV_NAME "Could not set geo\n");
1780 return 0;
1781 }
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04001782 priv->ieee->freq_band = LIBIPW_24GHZ_BAND;
Zhu Yibe6b3b12006-01-24 13:49:08 +08001783
James Ketrenos2c86c272005-03-23 17:32:29 -06001784 lock = LOCK_NONE;
1785 if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001786 printk(KERN_ERR DRV_NAME
1787 ": %s: Failed to clear ordinal lock.\n",
1788 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001789 rc = 1;
1790 goto exit;
1791 }
1792
1793 priv->status &= ~STATUS_SCANNING;
1794
1795 if (rf_kill_active(priv)) {
1796 printk(KERN_INFO "%s: Radio is disabled by RF switch.\n",
1797 priv->net_dev->name);
1798
1799 if (priv->stop_rf_kill) {
1800 priv->stop_rf_kill = 0;
Tejun Heobcb6d912011-01-26 12:12:50 +01001801 schedule_delayed_work(&priv->rf_kill,
1802 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06001803 }
1804
1805 deferred = 1;
1806 }
1807
1808 /* Turn on the interrupt so that commands can be processed */
1809 ipw2100_enable_interrupts(priv);
1810
1811 /* Send all of the commands that must be sent prior to
1812 * HOST_COMPLETE */
1813 if (ipw2100_adapter_setup(priv)) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001814 printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001815 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001816 rc = 1;
1817 goto exit;
1818 }
1819
1820 if (!deferred) {
1821 /* Enable the adapter - sends HOST_COMPLETE */
1822 if (ipw2100_enable_adapter(priv)) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001823 printk(KERN_ERR DRV_NAME ": "
James Ketrenosee8e3652005-09-14 09:47:29 -05001824 "%s: failed in call to enable adapter.\n",
1825 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001826 ipw2100_hw_stop_adapter(priv);
1827 rc = 1;
1828 goto exit;
1829 }
1830
James Ketrenos2c86c272005-03-23 17:32:29 -06001831 /* Start a scan . . . */
1832 ipw2100_set_scan_options(priv);
1833 ipw2100_start_scan(priv);
1834 }
1835
James Ketrenosee8e3652005-09-14 09:47:29 -05001836 exit:
James Ketrenos2c86c272005-03-23 17:32:29 -06001837 return rc;
1838}
1839
James Ketrenos2c86c272005-03-23 17:32:29 -06001840static void ipw2100_down(struct ipw2100_priv *priv)
1841{
1842 unsigned long flags;
1843 union iwreq_data wrqu = {
1844 .ap_addr = {
James Ketrenosee8e3652005-09-14 09:47:29 -05001845 .sa_family = ARPHRD_ETHER}
James Ketrenos2c86c272005-03-23 17:32:29 -06001846 };
1847 int associated = priv->status & STATUS_ASSOCIATED;
1848
1849 /* Kill the RF switch timer */
1850 if (!priv->stop_rf_kill) {
1851 priv->stop_rf_kill = 1;
1852 cancel_delayed_work(&priv->rf_kill);
1853 }
1854
Nick Andrew44072452009-01-03 18:52:40 +11001855 /* Kill the firmware hang check timer */
James Ketrenos2c86c272005-03-23 17:32:29 -06001856 if (!priv->stop_hang_check) {
1857 priv->stop_hang_check = 1;
1858 cancel_delayed_work(&priv->hang_check);
1859 }
1860
1861 /* Kill any pending resets */
1862 if (priv->status & STATUS_RESET_PENDING)
1863 cancel_delayed_work(&priv->reset_work);
1864
1865 /* Make sure the interrupt is on so that FW commands will be
1866 * processed correctly */
1867 spin_lock_irqsave(&priv->low_lock, flags);
1868 ipw2100_enable_interrupts(priv);
1869 spin_unlock_irqrestore(&priv->low_lock, flags);
1870
1871 if (ipw2100_hw_stop_adapter(priv))
Jiri Benc797b4f72005-08-25 20:03:27 -04001872 printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001873 priv->net_dev->name);
1874
1875 /* Do not disable the interrupt until _after_ we disable
1876 * the adaptor. Otherwise the CARD_DISABLE command will never
1877 * be ack'd by the firmware */
1878 spin_lock_irqsave(&priv->low_lock, flags);
1879 ipw2100_disable_interrupts(priv);
1880 spin_unlock_irqrestore(&priv->low_lock, flags);
1881
James Bottomley82f68252010-07-05 22:53:06 +02001882 pm_qos_update_request(&ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
Arjan van de Ven5c875792006-09-30 23:27:17 -07001883
James Ketrenos2c86c272005-03-23 17:32:29 -06001884 /* We have to signal any supplicant if we are disassociating */
1885 if (associated)
1886 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
1887
1888 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1889 netif_carrier_off(priv->net_dev);
1890 netif_stop_queue(priv->net_dev);
1891}
1892
Matthew Garrettc26409a2009-11-11 14:36:30 -05001893/* Called by register_netdev() */
1894static int ipw2100_net_init(struct net_device *dev)
1895{
1896 struct ipw2100_priv *priv = libipw_priv(dev);
Stanislaw Gruszka7cabafc2011-09-14 16:47:50 +02001897
1898 return ipw2100_up(priv, 1);
1899}
1900
1901static int ipw2100_wdev_init(struct net_device *dev)
1902{
1903 struct ipw2100_priv *priv = libipw_priv(dev);
Matthew Garrettc26409a2009-11-11 14:36:30 -05001904 const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
1905 struct wireless_dev *wdev = &priv->ieee->wdev;
Matthew Garrettc26409a2009-11-11 14:36:30 -05001906 int i;
1907
Matthew Garrettc26409a2009-11-11 14:36:30 -05001908 memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
1909
1910 /* fill-out priv->ieee->bg_band */
1911 if (geo->bg_channels) {
1912 struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
1913
1914 bg_band->band = IEEE80211_BAND_2GHZ;
1915 bg_band->n_channels = geo->bg_channels;
Joe Perchesbaeb2ff2010-08-11 07:02:48 +00001916 bg_band->channels = kcalloc(geo->bg_channels,
1917 sizeof(struct ieee80211_channel),
1918 GFP_KERNEL);
Christoph Fritz93c05842010-08-03 12:54:20 +02001919 if (!bg_band->channels) {
1920 ipw2100_down(priv);
1921 return -ENOMEM;
1922 }
Matthew Garrettc26409a2009-11-11 14:36:30 -05001923 /* translate geo->bg to bg_band.channels */
1924 for (i = 0; i < geo->bg_channels; i++) {
1925 bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
1926 bg_band->channels[i].center_freq = geo->bg[i].freq;
1927 bg_band->channels[i].hw_value = geo->bg[i].channel;
1928 bg_band->channels[i].max_power = geo->bg[i].max_power;
1929 if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
1930 bg_band->channels[i].flags |=
1931 IEEE80211_CHAN_PASSIVE_SCAN;
1932 if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
1933 bg_band->channels[i].flags |=
1934 IEEE80211_CHAN_NO_IBSS;
1935 if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
1936 bg_band->channels[i].flags |=
1937 IEEE80211_CHAN_RADAR;
1938 /* No equivalent for LIBIPW_CH_80211H_RULES,
1939 LIBIPW_CH_UNIFORM_SPREADING, or
1940 LIBIPW_CH_B_ONLY... */
1941 }
1942 /* point at bitrate info */
1943 bg_band->bitrates = ipw2100_bg_rates;
1944 bg_band->n_bitrates = RATE_COUNT;
1945
1946 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band;
1947 }
1948
1949 set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
1950 if (wiphy_register(wdev->wiphy)) {
1951 ipw2100_down(priv);
1952 return -EIO;
1953 }
1954 return 0;
1955}
1956
David Howellsc4028952006-11-22 14:57:56 +00001957static void ipw2100_reset_adapter(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06001958{
David Howellsc4028952006-11-22 14:57:56 +00001959 struct ipw2100_priv *priv =
1960 container_of(work, struct ipw2100_priv, reset_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06001961 unsigned long flags;
1962 union iwreq_data wrqu = {
1963 .ap_addr = {
James Ketrenosee8e3652005-09-14 09:47:29 -05001964 .sa_family = ARPHRD_ETHER}
James Ketrenos2c86c272005-03-23 17:32:29 -06001965 };
1966 int associated = priv->status & STATUS_ASSOCIATED;
1967
1968 spin_lock_irqsave(&priv->low_lock, flags);
Zhu Yia1e695a2005-07-04 14:06:00 +08001969 IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001970 priv->resets++;
1971 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1972 priv->status |= STATUS_SECURITY_UPDATED;
1973
1974 /* Force a power cycle even if interface hasn't been opened
1975 * yet */
1976 cancel_delayed_work(&priv->reset_work);
1977 priv->status |= STATUS_RESET_PENDING;
1978 spin_unlock_irqrestore(&priv->low_lock, flags);
1979
Ingo Molnar752e3772006-02-28 07:20:54 +08001980 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001981 /* stop timed checks so that they don't interfere with reset */
1982 priv->stop_hang_check = 1;
1983 cancel_delayed_work(&priv->hang_check);
1984
1985 /* We have to signal any supplicant if we are disassociating */
1986 if (associated)
1987 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
1988
1989 ipw2100_up(priv, 0);
Ingo Molnar752e3772006-02-28 07:20:54 +08001990 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001991
1992}
1993
James Ketrenos2c86c272005-03-23 17:32:29 -06001994static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
1995{
1996
1997#define MAC_ASSOCIATION_READ_DELAY (HZ)
Hannes Ederb9da9e92009-02-14 11:50:26 +00001998 int ret;
1999 unsigned int len, essid_len;
James Ketrenos2c86c272005-03-23 17:32:29 -06002000 char essid[IW_ESSID_MAX_SIZE];
2001 u32 txrate;
2002 u32 chan;
2003 char *txratename;
James Ketrenosee8e3652005-09-14 09:47:29 -05002004 u8 bssid[ETH_ALEN];
John W. Linville9387b7c2008-09-30 20:59:05 -04002005 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002006
2007 /*
2008 * TBD: BSSID is usually 00:00:00:00:00:00 here and not
2009 * an actual MAC of the AP. Seems like FW sets this
2010 * address too late. Read it later and expose through
2011 * /proc or schedule a later task to query and update
2012 */
2013
2014 essid_len = IW_ESSID_MAX_SIZE;
2015 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID,
2016 essid, &essid_len);
2017 if (ret) {
2018 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002019 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06002020 return;
2021 }
2022
2023 len = sizeof(u32);
James Ketrenosee8e3652005-09-14 09:47:29 -05002024 ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002025 if (ret) {
2026 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002027 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06002028 return;
2029 }
2030
2031 len = sizeof(u32);
2032 ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len);
2033 if (ret) {
2034 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002035 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06002036 return;
2037 }
2038 len = ETH_ALEN;
James Ketrenosee8e3652005-09-14 09:47:29 -05002039 ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002040 if (ret) {
2041 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002042 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06002043 return;
2044 }
2045 memcpy(priv->ieee->bssid, bssid, ETH_ALEN);
2046
James Ketrenos2c86c272005-03-23 17:32:29 -06002047 switch (txrate) {
2048 case TX_RATE_1_MBIT:
2049 txratename = "1Mbps";
2050 break;
2051 case TX_RATE_2_MBIT:
2052 txratename = "2Mbsp";
2053 break;
2054 case TX_RATE_5_5_MBIT:
2055 txratename = "5.5Mbps";
2056 break;
2057 case TX_RATE_11_MBIT:
2058 txratename = "11Mbps";
2059 break;
2060 default:
2061 IPW_DEBUG_INFO("Unknown rate: %d\n", txrate);
2062 txratename = "unknown rate";
2063 break;
2064 }
2065
Johannes Berge1749612008-10-27 15:59:26 -07002066 IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04002067 priv->net_dev->name, print_ssid(ssid, essid, essid_len),
Johannes Berge1749612008-10-27 15:59:26 -07002068 txratename, chan, bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002069
2070 /* now we copy read ssid into dev */
2071 if (!(priv->config & CFG_STATIC_ESSID)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002072 priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002073 memcpy(priv->essid, essid, priv->essid_len);
2074 }
2075 priv->channel = chan;
2076 memcpy(priv->bssid, bssid, ETH_ALEN);
2077
2078 priv->status |= STATUS_ASSOCIATING;
2079 priv->connect_start = get_seconds();
2080
Tejun Heobcb6d912011-01-26 12:12:50 +01002081 schedule_delayed_work(&priv->wx_event_work, HZ / 10);
James Ketrenos2c86c272005-03-23 17:32:29 -06002082}
2083
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002084static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
2085 int length, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06002086{
2087 int ssid_len = min(length, IW_ESSID_MAX_SIZE);
2088 struct host_command cmd = {
2089 .host_command = SSID,
2090 .host_command_sequence = 0,
2091 .host_command_length = ssid_len
2092 };
2093 int err;
John W. Linville9387b7c2008-09-30 20:59:05 -04002094 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002095
John W. Linville9387b7c2008-09-30 20:59:05 -04002096 IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len));
James Ketrenos2c86c272005-03-23 17:32:29 -06002097
2098 if (ssid_len)
James Ketrenos82328352005-08-24 22:33:31 -05002099 memcpy(cmd.host_command_parameters, essid, ssid_len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002100
2101 if (!batch_mode) {
2102 err = ipw2100_disable_adapter(priv);
2103 if (err)
2104 return err;
2105 }
2106
2107 /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to
2108 * disable auto association -- so we cheat by setting a bogus SSID */
2109 if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) {
2110 int i;
James Ketrenosee8e3652005-09-14 09:47:29 -05002111 u8 *bogus = (u8 *) cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06002112 for (i = 0; i < IW_ESSID_MAX_SIZE; i++)
2113 bogus[i] = 0x18 + i;
2114 cmd.host_command_length = IW_ESSID_MAX_SIZE;
2115 }
2116
2117 /* NOTE: We always send the SSID command even if the provided ESSID is
2118 * the same as what we currently think is set. */
2119
2120 err = ipw2100_hw_send_command(priv, &cmd);
2121 if (!err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002122 memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002123 memcpy(priv->essid, essid, ssid_len);
2124 priv->essid_len = ssid_len;
2125 }
2126
2127 if (!batch_mode) {
2128 if (ipw2100_enable_adapter(priv))
2129 err = -EIO;
2130 }
2131
2132 return err;
2133}
2134
2135static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
2136{
John W. Linville9387b7c2008-09-30 20:59:05 -04002137 DECLARE_SSID_BUF(ssid);
2138
James Ketrenos2c86c272005-03-23 17:32:29 -06002139 IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
Frans Pop9fd1ea42010-03-24 19:46:31 +01002140 "disassociated: '%s' %pM\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04002141 print_ssid(ssid, priv->essid, priv->essid_len),
Johannes Berge1749612008-10-27 15:59:26 -07002142 priv->bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002143
2144 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
2145
2146 if (priv->status & STATUS_STOPPING) {
2147 IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n");
2148 return;
2149 }
2150
2151 memset(priv->bssid, 0, ETH_ALEN);
2152 memset(priv->ieee->bssid, 0, ETH_ALEN);
2153
2154 netif_carrier_off(priv->net_dev);
2155 netif_stop_queue(priv->net_dev);
2156
2157 if (!(priv->status & STATUS_RUNNING))
2158 return;
2159
2160 if (priv->status & STATUS_SECURITY_UPDATED)
Tejun Heobcb6d912011-01-26 12:12:50 +01002161 schedule_delayed_work(&priv->security_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06002162
Tejun Heobcb6d912011-01-26 12:12:50 +01002163 schedule_delayed_work(&priv->wx_event_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06002164}
2165
2166static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
2167{
2168 IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002169 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002170
2171 /* RF_KILL is now enabled (else we wouldn't be here) */
Matthew Garrettc26409a2009-11-11 14:36:30 -05002172 wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
James Ketrenos2c86c272005-03-23 17:32:29 -06002173 priv->status |= STATUS_RF_KILL_HW;
2174
James Ketrenos2c86c272005-03-23 17:32:29 -06002175 /* Make sure the RF Kill check timer is running */
2176 priv->stop_rf_kill = 0;
2177 cancel_delayed_work(&priv->rf_kill);
Tejun Heobcb6d912011-01-26 12:12:50 +01002178 schedule_delayed_work(&priv->rf_kill, round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06002179}
2180
Dan Williamsd20c6782007-10-10 12:28:07 -04002181static void send_scan_event(void *data)
2182{
2183 struct ipw2100_priv *priv = data;
2184 union iwreq_data wrqu;
2185
2186 wrqu.data.length = 0;
2187 wrqu.data.flags = 0;
2188 wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
2189}
2190
2191static void ipw2100_scan_event_later(struct work_struct *work)
2192{
2193 send_scan_event(container_of(work, struct ipw2100_priv,
2194 scan_event_later.work));
2195}
2196
2197static void ipw2100_scan_event_now(struct work_struct *work)
2198{
2199 send_scan_event(container_of(work, struct ipw2100_priv,
2200 scan_event_now));
2201}
2202
James Ketrenos2c86c272005-03-23 17:32:29 -06002203static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
2204{
2205 IPW_DEBUG_SCAN("scan complete\n");
2206 /* Age the scan results... */
2207 priv->ieee->scans++;
2208 priv->status &= ~STATUS_SCANNING;
Dan Williamsd20c6782007-10-10 12:28:07 -04002209
2210 /* Only userspace-requested scan completion events go out immediately */
2211 if (!priv->user_requested_scan) {
2212 if (!delayed_work_pending(&priv->scan_event_later))
Tejun Heobcb6d912011-01-26 12:12:50 +01002213 schedule_delayed_work(&priv->scan_event_later,
2214 round_jiffies_relative(msecs_to_jiffies(4000)));
Dan Williamsd20c6782007-10-10 12:28:07 -04002215 } else {
2216 priv->user_requested_scan = 0;
2217 cancel_delayed_work(&priv->scan_event_later);
Tejun Heobcb6d912011-01-26 12:12:50 +01002218 schedule_work(&priv->scan_event_now);
Dan Williamsd20c6782007-10-10 12:28:07 -04002219 }
James Ketrenos2c86c272005-03-23 17:32:29 -06002220}
2221
Brice Goglin0f52bf92005-12-01 01:41:46 -08002222#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002223#define IPW2100_HANDLER(v, f) { v, f, # v }
2224struct ipw2100_status_indicator {
2225 int status;
James Ketrenosee8e3652005-09-14 09:47:29 -05002226 void (*cb) (struct ipw2100_priv * priv, u32 status);
James Ketrenos2c86c272005-03-23 17:32:29 -06002227 char *name;
2228};
2229#else
2230#define IPW2100_HANDLER(v, f) { v, f }
2231struct ipw2100_status_indicator {
2232 int status;
James Ketrenosee8e3652005-09-14 09:47:29 -05002233 void (*cb) (struct ipw2100_priv * priv, u32 status);
James Ketrenos2c86c272005-03-23 17:32:29 -06002234};
Brice Goglin0f52bf92005-12-01 01:41:46 -08002235#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -06002236
2237static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
2238{
2239 IPW_DEBUG_SCAN("Scanning...\n");
2240 priv->status |= STATUS_SCANNING;
2241}
2242
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002243static const struct ipw2100_status_indicator status_handlers[] = {
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002244 IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL),
2245 IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002246 IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated),
2247 IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002248 IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002249 IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002250 IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL),
2251 IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002252 IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002253 IPW2100_HANDLER(IPW_STATE_DISABLED, NULL),
2254 IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002255 IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002256 IPW2100_HANDLER(-1, NULL)
James Ketrenos2c86c272005-03-23 17:32:29 -06002257};
2258
James Ketrenos2c86c272005-03-23 17:32:29 -06002259static void isr_status_change(struct ipw2100_priv *priv, int status)
2260{
2261 int i;
2262
2263 if (status == IPW_STATE_SCANNING &&
2264 priv->status & STATUS_ASSOCIATED &&
2265 !(priv->status & STATUS_SCANNING)) {
2266 IPW_DEBUG_INFO("Scan detected while associated, with "
2267 "no scan request. Restarting firmware.\n");
2268
2269 /* Wake up any sleeping jobs */
2270 schedule_reset(priv);
2271 }
2272
2273 for (i = 0; status_handlers[i].status != -1; i++) {
2274 if (status == status_handlers[i].status) {
2275 IPW_DEBUG_NOTIF("Status change: %s\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002276 status_handlers[i].name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002277 if (status_handlers[i].cb)
2278 status_handlers[i].cb(priv, status);
2279 priv->wstats.status = status;
2280 return;
2281 }
2282 }
2283
2284 IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);
2285}
2286
James Ketrenosee8e3652005-09-14 09:47:29 -05002287static void isr_rx_complete_command(struct ipw2100_priv *priv,
2288 struct ipw2100_cmd_header *cmd)
James Ketrenos2c86c272005-03-23 17:32:29 -06002289{
Brice Goglin0f52bf92005-12-01 01:41:46 -08002290#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002291 if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
2292 IPW_DEBUG_HC("Command completed '%s (%d)'\n",
2293 command_types[cmd->host_command_reg],
2294 cmd->host_command_reg);
2295 }
2296#endif
2297 if (cmd->host_command_reg == HOST_COMPLETE)
2298 priv->status |= STATUS_ENABLED;
2299
2300 if (cmd->host_command_reg == CARD_DISABLE)
2301 priv->status &= ~STATUS_ENABLED;
2302
2303 priv->status &= ~STATUS_CMD_ACTIVE;
2304
2305 wake_up_interruptible(&priv->wait_command_queue);
2306}
2307
Brice Goglin0f52bf92005-12-01 01:41:46 -08002308#ifdef CONFIG_IPW2100_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002309static const char *frame_types[] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06002310 "COMMAND_STATUS_VAL",
2311 "STATUS_CHANGE_VAL",
2312 "P80211_DATA_VAL",
2313 "P8023_DATA_VAL",
2314 "HOST_NOTIFICATION_VAL"
2315};
2316#endif
2317
Arjan van de Ven858119e2006-01-14 13:20:43 -08002318static int ipw2100_alloc_skb(struct ipw2100_priv *priv,
James Ketrenosee8e3652005-09-14 09:47:29 -05002319 struct ipw2100_rx_packet *packet)
James Ketrenos2c86c272005-03-23 17:32:29 -06002320{
2321 packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
2322 if (!packet->skb)
2323 return -ENOMEM;
2324
2325 packet->rxp = (struct ipw2100_rx *)packet->skb->data;
2326 packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data,
2327 sizeof(struct ipw2100_rx),
2328 PCI_DMA_FROMDEVICE);
2329 /* NOTE: pci_map_single does not return an error code, and 0 is a valid
2330 * dma_addr */
2331
2332 return 0;
2333}
2334
James Ketrenos2c86c272005-03-23 17:32:29 -06002335#define SEARCH_ERROR 0xffffffff
2336#define SEARCH_FAIL 0xfffffffe
2337#define SEARCH_SUCCESS 0xfffffff0
2338#define SEARCH_DISCARD 0
2339#define SEARCH_SNAPSHOT 1
2340
2341#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
Zhu Yi3c5eca52006-01-24 13:49:26 +08002342static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
2343{
2344 int i;
2345 if (!priv->snapshot[0])
2346 return;
2347 for (i = 0; i < 0x30; i++)
2348 kfree(priv->snapshot[i]);
2349 priv->snapshot[0] = NULL;
2350}
2351
Robert P. J. Dayae800312007-01-31 02:39:40 -05002352#ifdef IPW2100_DEBUG_C3
Arjan van de Ven858119e2006-01-14 13:20:43 -08002353static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002354{
2355 int i;
2356 if (priv->snapshot[0])
2357 return 1;
2358 for (i = 0; i < 0x30; i++) {
Robert P. J. Day5cbded52006-12-13 00:35:56 -08002359 priv->snapshot[i] = kmalloc(0x1000, GFP_ATOMIC);
James Ketrenos2c86c272005-03-23 17:32:29 -06002360 if (!priv->snapshot[i]) {
2361 IPW_DEBUG_INFO("%s: Error allocating snapshot "
James Ketrenosee8e3652005-09-14 09:47:29 -05002362 "buffer %d\n", priv->net_dev->name, i);
James Ketrenos2c86c272005-03-23 17:32:29 -06002363 while (i > 0)
2364 kfree(priv->snapshot[--i]);
2365 priv->snapshot[0] = NULL;
2366 return 0;
2367 }
2368 }
2369
2370 return 1;
2371}
2372
Arjan van de Ven858119e2006-01-14 13:20:43 -08002373static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
James Ketrenos2c86c272005-03-23 17:32:29 -06002374 size_t len, int mode)
2375{
2376 u32 i, j;
2377 u32 tmp;
2378 u8 *s, *d;
2379 u32 ret;
2380
2381 s = in_buf;
2382 if (mode == SEARCH_SNAPSHOT) {
2383 if (!ipw2100_snapshot_alloc(priv))
2384 mode = SEARCH_DISCARD;
2385 }
2386
2387 for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) {
2388 read_nic_dword(priv->net_dev, i, &tmp);
2389 if (mode == SEARCH_SNAPSHOT)
James Ketrenosee8e3652005-09-14 09:47:29 -05002390 *(u32 *) SNAPSHOT_ADDR(i) = tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06002391 if (ret == SEARCH_FAIL) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002392 d = (u8 *) & tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06002393 for (j = 0; j < 4; j++) {
2394 if (*s != *d) {
2395 s = in_buf;
2396 continue;
2397 }
2398
2399 s++;
2400 d++;
2401
2402 if ((s - in_buf) == len)
2403 ret = (i + j) - len + 1;
2404 }
2405 } else if (mode == SEARCH_DISCARD)
2406 return ret;
2407 }
2408
2409 return ret;
2410}
Zhu Yi3c5eca52006-01-24 13:49:26 +08002411#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06002412
2413/*
2414 *
2415 * 0) Disconnect the SKB from the firmware (just unmap)
2416 * 1) Pack the ETH header into the SKB
2417 * 2) Pass the SKB to the network stack
2418 *
2419 * When packet is provided by the firmware, it contains the following:
2420 *
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002421 * . libipw_hdr
2422 * . libipw_snap_hdr
James Ketrenos2c86c272005-03-23 17:32:29 -06002423 *
2424 * The size of the constructed ethernet
2425 *
2426 */
Robert P. J. Dayae800312007-01-31 02:39:40 -05002427#ifdef IPW2100_RX_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002428static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
James Ketrenos2c86c272005-03-23 17:32:29 -06002429#endif
2430
Arjan van de Ven858119e2006-01-14 13:20:43 -08002431static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
James Ketrenos2c86c272005-03-23 17:32:29 -06002432{
Robert P. J. Dayae800312007-01-31 02:39:40 -05002433#ifdef IPW2100_DEBUG_C3
James Ketrenos2c86c272005-03-23 17:32:29 -06002434 struct ipw2100_status *status = &priv->status_queue.drv[i];
2435 u32 match, reg;
2436 int j;
2437#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06002438
Zhu Yia1e695a2005-07-04 14:06:00 +08002439 IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n",
2440 i * sizeof(struct ipw2100_status));
James Ketrenos2c86c272005-03-23 17:32:29 -06002441
Robert P. J. Dayae800312007-01-31 02:39:40 -05002442#ifdef IPW2100_DEBUG_C3
Nick Andrew877d0312009-01-26 11:06:57 +01002443 /* Halt the firmware so we can get a good image */
James Ketrenos2c86c272005-03-23 17:32:29 -06002444 write_register(priv->net_dev, IPW_REG_RESET_REG,
2445 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
2446 j = 5;
2447 do {
2448 udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
2449 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
2450
2451 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
2452 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05002453 } while (j--);
James Ketrenos2c86c272005-03-23 17:32:29 -06002454
James Ketrenosee8e3652005-09-14 09:47:29 -05002455 match = ipw2100_match_buf(priv, (u8 *) status,
James Ketrenos2c86c272005-03-23 17:32:29 -06002456 sizeof(struct ipw2100_status),
2457 SEARCH_SNAPSHOT);
2458 if (match < SEARCH_SUCCESS)
2459 IPW_DEBUG_INFO("%s: DMA status match in Firmware at "
2460 "offset 0x%06X, length %d:\n",
2461 priv->net_dev->name, match,
2462 sizeof(struct ipw2100_status));
2463 else
2464 IPW_DEBUG_INFO("%s: No DMA status match in "
2465 "Firmware.\n", priv->net_dev->name);
2466
James Ketrenosee8e3652005-09-14 09:47:29 -05002467 printk_buf((u8 *) priv->status_queue.drv,
James Ketrenos2c86c272005-03-23 17:32:29 -06002468 sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);
2469#endif
2470
2471 priv->fatal_error = IPW2100_ERR_C3_CORRUPTION;
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002472 priv->net_dev->stats.rx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002473 schedule_reset(priv);
2474}
2475
Arjan van de Ven858119e2006-01-14 13:20:43 -08002476static void isr_rx(struct ipw2100_priv *priv, int i,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002477 struct libipw_rx_stats *stats)
James Ketrenos2c86c272005-03-23 17:32:29 -06002478{
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002479 struct net_device *dev = priv->net_dev;
James Ketrenos2c86c272005-03-23 17:32:29 -06002480 struct ipw2100_status *status = &priv->status_queue.drv[i];
2481 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
2482
2483 IPW_DEBUG_RX("Handler...\n");
2484
2485 if (unlikely(status->frame_size > skb_tailroom(packet->skb))) {
2486 IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
2487 " Dropping.\n",
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002488 dev->name,
James Ketrenos2c86c272005-03-23 17:32:29 -06002489 status->frame_size, skb_tailroom(packet->skb));
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002490 dev->stats.rx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002491 return;
2492 }
2493
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002494 if (unlikely(!netif_running(dev))) {
2495 dev->stats.rx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002496 priv->wstats.discard.misc++;
2497 IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
2498 return;
2499 }
James Ketrenos2c86c272005-03-23 17:32:29 -06002500
2501 if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
James Ketrenosee8e3652005-09-14 09:47:29 -05002502 !(priv->status & STATUS_ASSOCIATED))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002503 IPW_DEBUG_DROP("Dropping packet while not associated.\n");
2504 priv->wstats.discard.misc++;
2505 return;
2506 }
2507
James Ketrenos2c86c272005-03-23 17:32:29 -06002508 pci_unmap_single(priv->pci_dev,
2509 packet->dma_addr,
James Ketrenosee8e3652005-09-14 09:47:29 -05002510 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002511
2512 skb_put(packet->skb, status->frame_size);
2513
Robert P. J. Dayae800312007-01-31 02:39:40 -05002514#ifdef IPW2100_RX_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002515 /* Make a copy of the frame so we can dump it to the logs if
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002516 * libipw_rx fails */
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03002517 skb_copy_from_linear_data(packet->skb, packet_data,
2518 min_t(u32, status->frame_size,
2519 IPW_RX_NIC_BUFFER_LENGTH));
James Ketrenos2c86c272005-03-23 17:32:29 -06002520#endif
2521
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002522 if (!libipw_rx(priv->ieee, packet->skb, stats)) {
Robert P. J. Dayae800312007-01-31 02:39:40 -05002523#ifdef IPW2100_RX_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002524 IPW_DEBUG_DROP("%s: Non consumed packet:\n",
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002525 dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002526 printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
2527#endif
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002528 dev->stats.rx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002529
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002530 /* libipw_rx failed, so it didn't free the SKB */
James Ketrenos2c86c272005-03-23 17:32:29 -06002531 dev_kfree_skb_any(packet->skb);
2532 packet->skb = NULL;
2533 }
2534
2535 /* We need to allocate a new SKB and attach it to the RDB. */
2536 if (unlikely(ipw2100_alloc_skb(priv, packet))) {
Jiri Benc797b4f72005-08-25 20:03:27 -04002537 printk(KERN_WARNING DRV_NAME ": "
James Ketrenosee8e3652005-09-14 09:47:29 -05002538 "%s: Unable to allocate SKB onto RBD ring - disabling "
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002539 "adapter.\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002540 /* TODO: schedule adapter shutdown */
2541 IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
2542 }
2543
2544 /* Update the RDB entry */
2545 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
2546}
2547
Stefan Rompf15745a72006-02-21 18:36:17 +08002548#ifdef CONFIG_IPW2100_MONITOR
2549
2550static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002551 struct libipw_rx_stats *stats)
Stefan Rompf15745a72006-02-21 18:36:17 +08002552{
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002553 struct net_device *dev = priv->net_dev;
Stefan Rompf15745a72006-02-21 18:36:17 +08002554 struct ipw2100_status *status = &priv->status_queue.drv[i];
2555 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
2556
Stefan Rompf15745a72006-02-21 18:36:17 +08002557 /* Magic struct that slots into the radiotap header -- no reason
2558 * to build this manually element by element, we can write it much
2559 * more efficiently than we can parse it. ORDER MATTERS HERE */
2560 struct ipw_rt_hdr {
2561 struct ieee80211_radiotap_header rt_hdr;
2562 s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
2563 } *ipw_rt;
2564
Zhu Yicae16292006-02-21 18:41:14 +08002565 IPW_DEBUG_RX("Handler...\n");
2566
2567 if (unlikely(status->frame_size > skb_tailroom(packet->skb) -
2568 sizeof(struct ipw_rt_hdr))) {
Stefan Rompf15745a72006-02-21 18:36:17 +08002569 IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
2570 " Dropping.\n",
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002571 dev->name,
Zhu Yicae16292006-02-21 18:41:14 +08002572 status->frame_size,
2573 skb_tailroom(packet->skb));
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002574 dev->stats.rx_errors++;
Stefan Rompf15745a72006-02-21 18:36:17 +08002575 return;
2576 }
2577
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002578 if (unlikely(!netif_running(dev))) {
2579 dev->stats.rx_errors++;
Stefan Rompf15745a72006-02-21 18:36:17 +08002580 priv->wstats.discard.misc++;
2581 IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
2582 return;
2583 }
2584
2585 if (unlikely(priv->config & CFG_CRC_CHECK &&
2586 status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
2587 IPW_DEBUG_RX("CRC error in packet. Dropping.\n");
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002588 dev->stats.rx_errors++;
Stefan Rompf15745a72006-02-21 18:36:17 +08002589 return;
2590 }
2591
Zhu Yicae16292006-02-21 18:41:14 +08002592 pci_unmap_single(priv->pci_dev, packet->dma_addr,
Stefan Rompf15745a72006-02-21 18:36:17 +08002593 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
2594 memmove(packet->skb->data + sizeof(struct ipw_rt_hdr),
2595 packet->skb->data, status->frame_size);
2596
2597 ipw_rt = (struct ipw_rt_hdr *) packet->skb->data;
2598
2599 ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
2600 ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
Al Viro1edd3a52007-12-21 00:15:18 -05002601 ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total hdr+data */
Stefan Rompf15745a72006-02-21 18:36:17 +08002602
Al Viro1edd3a52007-12-21 00:15:18 -05002603 ipw_rt->rt_hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
Stefan Rompf15745a72006-02-21 18:36:17 +08002604
2605 ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM;
2606
2607 skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr));
2608
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002609 if (!libipw_rx(priv->ieee, packet->skb, stats)) {
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002610 dev->stats.rx_errors++;
Stefan Rompf15745a72006-02-21 18:36:17 +08002611
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002612 /* libipw_rx failed, so it didn't free the SKB */
Stefan Rompf15745a72006-02-21 18:36:17 +08002613 dev_kfree_skb_any(packet->skb);
2614 packet->skb = NULL;
2615 }
2616
2617 /* We need to allocate a new SKB and attach it to the RDB. */
2618 if (unlikely(ipw2100_alloc_skb(priv, packet))) {
2619 IPW_DEBUG_WARNING(
2620 "%s: Unable to allocate SKB onto RBD ring - disabling "
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002621 "adapter.\n", dev->name);
Stefan Rompf15745a72006-02-21 18:36:17 +08002622 /* TODO: schedule adapter shutdown */
2623 IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
2624 }
2625
2626 /* Update the RDB entry */
2627 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
2628}
2629
2630#endif
2631
Arjan van de Ven858119e2006-01-14 13:20:43 -08002632static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
James Ketrenos2c86c272005-03-23 17:32:29 -06002633{
2634 struct ipw2100_status *status = &priv->status_queue.drv[i];
2635 struct ipw2100_rx *u = priv->rx_buffers[i].rxp;
2636 u16 frame_type = status->status_fields & STATUS_TYPE_MASK;
2637
2638 switch (frame_type) {
2639 case COMMAND_STATUS_VAL:
2640 return (status->frame_size != sizeof(u->rx_data.command));
2641 case STATUS_CHANGE_VAL:
2642 return (status->frame_size != sizeof(u->rx_data.status));
2643 case HOST_NOTIFICATION_VAL:
2644 return (status->frame_size < sizeof(u->rx_data.notification));
2645 case P80211_DATA_VAL:
2646 case P8023_DATA_VAL:
2647#ifdef CONFIG_IPW2100_MONITOR
2648 return 0;
2649#else
Al Viro1edd3a52007-12-21 00:15:18 -05002650 switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002651 case IEEE80211_FTYPE_MGMT:
2652 case IEEE80211_FTYPE_CTL:
2653 return 0;
2654 case IEEE80211_FTYPE_DATA:
2655 return (status->frame_size >
2656 IPW_MAX_802_11_PAYLOAD_LENGTH);
2657 }
2658#endif
2659 }
2660
2661 return 1;
2662}
2663
2664/*
2665 * ipw2100 interrupts are disabled at this point, and the ISR
2666 * is the only code that calls this method. So, we do not need
2667 * to play with any locks.
2668 *
2669 * RX Queue works as follows:
2670 *
2671 * Read index - firmware places packet in entry identified by the
2672 * Read index and advances Read index. In this manner,
2673 * Read index will always point to the next packet to
2674 * be filled--but not yet valid.
2675 *
2676 * Write index - driver fills this entry with an unused RBD entry.
2677 * This entry has not filled by the firmware yet.
2678 *
2679 * In between the W and R indexes are the RBDs that have been received
2680 * but not yet processed.
2681 *
2682 * The process of handling packets will start at WRITE + 1 and advance
2683 * until it reaches the READ index.
2684 *
2685 * The WRITE index is cached in the variable 'priv->rx_queue.next'.
2686 *
2687 */
Arjan van de Ven858119e2006-01-14 13:20:43 -08002688static void __ipw2100_rx_process(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002689{
2690 struct ipw2100_bd_queue *rxq = &priv->rx_queue;
2691 struct ipw2100_status_queue *sq = &priv->status_queue;
2692 struct ipw2100_rx_packet *packet;
2693 u16 frame_type;
2694 u32 r, w, i, s;
2695 struct ipw2100_rx *u;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002696 struct libipw_rx_stats stats = {
James Ketrenos2c86c272005-03-23 17:32:29 -06002697 .mac_time = jiffies,
2698 };
2699
2700 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r);
2701 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w);
2702
2703 if (r >= rxq->entries) {
2704 IPW_DEBUG_RX("exit - bad read index\n");
2705 return;
2706 }
2707
2708 i = (rxq->next + 1) % rxq->entries;
2709 s = i;
2710 while (i != r) {
2711 /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n",
2712 r, rxq->next, i); */
2713
2714 packet = &priv->rx_buffers[i];
2715
James Ketrenos2c86c272005-03-23 17:32:29 -06002716 /* Sync the DMA for the RX buffer so CPU is sure to get
2717 * the correct values */
2718 pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr,
2719 sizeof(struct ipw2100_rx),
2720 PCI_DMA_FROMDEVICE);
2721
2722 if (unlikely(ipw2100_corruption_check(priv, i))) {
2723 ipw2100_corruption_detected(priv, i);
2724 goto increment;
2725 }
2726
2727 u = packet->rxp;
James Ketrenosee8e3652005-09-14 09:47:29 -05002728 frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK;
James Ketrenos2c86c272005-03-23 17:32:29 -06002729 stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM;
2730 stats.len = sq->drv[i].frame_size;
2731
2732 stats.mask = 0;
2733 if (stats.rssi != 0)
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002734 stats.mask |= LIBIPW_STATMASK_RSSI;
2735 stats.freq = LIBIPW_24GHZ_BAND;
James Ketrenos2c86c272005-03-23 17:32:29 -06002736
James Ketrenosee8e3652005-09-14 09:47:29 -05002737 IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n",
2738 priv->net_dev->name, frame_types[frame_type],
2739 stats.len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002740
2741 switch (frame_type) {
2742 case COMMAND_STATUS_VAL:
2743 /* Reset Rx watchdog */
James Ketrenosee8e3652005-09-14 09:47:29 -05002744 isr_rx_complete_command(priv, &u->rx_data.command);
James Ketrenos2c86c272005-03-23 17:32:29 -06002745 break;
2746
2747 case STATUS_CHANGE_VAL:
2748 isr_status_change(priv, u->rx_data.status);
2749 break;
2750
2751 case P80211_DATA_VAL:
2752 case P8023_DATA_VAL:
2753#ifdef CONFIG_IPW2100_MONITOR
2754 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
Stefan Rompf15745a72006-02-21 18:36:17 +08002755 isr_rx_monitor(priv, i, &stats);
James Ketrenos2c86c272005-03-23 17:32:29 -06002756 break;
2757 }
2758#endif
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002759 if (stats.len < sizeof(struct libipw_hdr_3addr))
James Ketrenos2c86c272005-03-23 17:32:29 -06002760 break;
Al Viro1edd3a52007-12-21 00:15:18 -05002761 switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002762 case IEEE80211_FTYPE_MGMT:
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002763 libipw_rx_mgt(priv->ieee,
James Ketrenosee8e3652005-09-14 09:47:29 -05002764 &u->rx_data.header, &stats);
James Ketrenos2c86c272005-03-23 17:32:29 -06002765 break;
2766
2767 case IEEE80211_FTYPE_CTL:
2768 break;
2769
2770 case IEEE80211_FTYPE_DATA:
2771 isr_rx(priv, i, &stats);
2772 break;
2773
2774 }
2775 break;
2776 }
2777
James Ketrenosee8e3652005-09-14 09:47:29 -05002778 increment:
James Ketrenos2c86c272005-03-23 17:32:29 -06002779 /* clear status field associated with this RBD */
2780 rxq->drv[i].status.info.field = 0;
2781
2782 i = (i + 1) % rxq->entries;
2783 }
2784
2785 if (i != s) {
2786 /* backtrack one entry, wrapping to end if at 0 */
2787 rxq->next = (i ? i : rxq->entries) - 1;
2788
2789 write_register(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05002790 IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next);
James Ketrenos2c86c272005-03-23 17:32:29 -06002791 }
2792}
2793
James Ketrenos2c86c272005-03-23 17:32:29 -06002794/*
2795 * __ipw2100_tx_process
2796 *
2797 * This routine will determine whether the next packet on
2798 * the fw_pend_list has been processed by the firmware yet.
2799 *
2800 * If not, then it does nothing and returns.
2801 *
2802 * If so, then it removes the item from the fw_pend_list, frees
2803 * any associated storage, and places the item back on the
2804 * free list of its source (either msg_free_list or tx_free_list)
2805 *
2806 * TX Queue works as follows:
2807 *
2808 * Read index - points to the next TBD that the firmware will
2809 * process. The firmware will read the data, and once
2810 * done processing, it will advance the Read index.
2811 *
2812 * Write index - driver fills this entry with an constructed TBD
2813 * entry. The Write index is not advanced until the
2814 * packet has been configured.
2815 *
2816 * In between the W and R indexes are the TBDs that have NOT been
2817 * processed. Lagging behind the R index are packets that have
2818 * been processed but have not been freed by the driver.
2819 *
2820 * In order to free old storage, an internal index will be maintained
2821 * that points to the next packet to be freed. When all used
2822 * packets have been freed, the oldest index will be the same as the
2823 * firmware's read index.
2824 *
2825 * The OLDEST index is cached in the variable 'priv->tx_queue.oldest'
2826 *
2827 * Because the TBD structure can not contain arbitrary data, the
2828 * driver must keep an internal queue of cached allocations such that
2829 * it can put that data back into the tx_free_list and msg_free_list
2830 * for use by future command and data packets.
2831 *
2832 */
Arjan van de Ven858119e2006-01-14 13:20:43 -08002833static int __ipw2100_tx_process(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002834{
2835 struct ipw2100_bd_queue *txq = &priv->tx_queue;
James Ketrenosee8e3652005-09-14 09:47:29 -05002836 struct ipw2100_bd *tbd;
James Ketrenos2c86c272005-03-23 17:32:29 -06002837 struct list_head *element;
2838 struct ipw2100_tx_packet *packet;
2839 int descriptors_used;
2840 int e, i;
2841 u32 r, w, frag_num = 0;
2842
2843 if (list_empty(&priv->fw_pend_list))
2844 return 0;
2845
2846 element = priv->fw_pend_list.next;
2847
2848 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenosee8e3652005-09-14 09:47:29 -05002849 tbd = &txq->drv[packet->index];
James Ketrenos2c86c272005-03-23 17:32:29 -06002850
2851 /* Determine how many TBD entries must be finished... */
2852 switch (packet->type) {
2853 case COMMAND:
2854 /* COMMAND uses only one slot; don't advance */
2855 descriptors_used = 1;
2856 e = txq->oldest;
2857 break;
2858
2859 case DATA:
2860 /* DATA uses two slots; advance and loop position. */
2861 descriptors_used = tbd->num_fragments;
James Ketrenosee8e3652005-09-14 09:47:29 -05002862 frag_num = tbd->num_fragments - 1;
James Ketrenos2c86c272005-03-23 17:32:29 -06002863 e = txq->oldest + frag_num;
2864 e %= txq->entries;
2865 break;
2866
2867 default:
Jiri Benc797b4f72005-08-25 20:03:27 -04002868 printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002869 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002870 return 0;
2871 }
2872
2873 /* if the last TBD is not done by NIC yet, then packet is
2874 * not ready to be released.
2875 *
2876 */
2877 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
2878 &r);
2879 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
2880 &w);
2881 if (w != txq->next)
Jiri Benc797b4f72005-08-25 20:03:27 -04002882 printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06002883 priv->net_dev->name);
2884
James Ketrenosee8e3652005-09-14 09:47:29 -05002885 /*
James Ketrenos2c86c272005-03-23 17:32:29 -06002886 * txq->next is the index of the last packet written txq->oldest is
2887 * the index of the r is the index of the next packet to be read by
2888 * firmware
2889 */
2890
James Ketrenos2c86c272005-03-23 17:32:29 -06002891 /*
2892 * Quick graphic to help you visualize the following
2893 * if / else statement
2894 *
2895 * ===>| s---->|===============
2896 * e>|
2897 * | a | b | c | d | e | f | g | h | i | j | k | l
2898 * r---->|
2899 * w
2900 *
2901 * w - updated by driver
2902 * r - updated by firmware
2903 * s - start of oldest BD entry (txq->oldest)
2904 * e - end of oldest BD entry
2905 *
2906 */
2907 if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) {
2908 IPW_DEBUG_TX("exit - no processed packets ready to release.\n");
2909 return 0;
2910 }
2911
2912 list_del(element);
2913 DEC_STAT(&priv->fw_pend_stat);
2914
Brice Goglin0f52bf92005-12-01 01:41:46 -08002915#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002916 {
Reinette Chatre21f8a732009-08-18 10:25:05 -07002917 i = txq->oldest;
James Ketrenosee8e3652005-09-14 09:47:29 -05002918 IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
2919 &txq->drv[i],
2920 (u32) (txq->nic + i * sizeof(struct ipw2100_bd)),
2921 txq->drv[i].host_addr, txq->drv[i].buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002922
2923 if (packet->type == DATA) {
2924 i = (i + 1) % txq->entries;
2925
James Ketrenosee8e3652005-09-14 09:47:29 -05002926 IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
2927 &txq->drv[i],
2928 (u32) (txq->nic + i *
2929 sizeof(struct ipw2100_bd)),
2930 (u32) txq->drv[i].host_addr,
2931 txq->drv[i].buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002932 }
2933 }
2934#endif
2935
2936 switch (packet->type) {
2937 case DATA:
2938 if (txq->drv[txq->oldest].status.info.fields.txType != 0)
Jiri Benc797b4f72005-08-25 20:03:27 -04002939 printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
James Ketrenos2c86c272005-03-23 17:32:29 -06002940 "Expecting DATA TBD but pulled "
2941 "something else: ids %d=%d.\n",
2942 priv->net_dev->name, txq->oldest, packet->index);
2943
2944 /* DATA packet; we have to unmap and free the SKB */
James Ketrenos2c86c272005-03-23 17:32:29 -06002945 for (i = 0; i < frag_num; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002946 tbd = &txq->drv[(packet->index + 1 + i) % txq->entries];
James Ketrenos2c86c272005-03-23 17:32:29 -06002947
James Ketrenosee8e3652005-09-14 09:47:29 -05002948 IPW_DEBUG_TX("TX%d P=%08x L=%d\n",
2949 (packet->index + 1 + i) % txq->entries,
2950 tbd->host_addr, tbd->buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002951
2952 pci_unmap_single(priv->pci_dev,
2953 tbd->host_addr,
James Ketrenosee8e3652005-09-14 09:47:29 -05002954 tbd->buf_length, PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002955 }
2956
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002957 libipw_txb_free(packet->info.d_struct.txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06002958 packet->info.d_struct.txb = NULL;
2959
2960 list_add_tail(element, &priv->tx_free_list);
2961 INC_STAT(&priv->tx_free_stat);
2962
2963 /* We have a free slot in the Tx queue, so wake up the
2964 * transmit layer if it is stopped. */
James Ketrenos82328352005-08-24 22:33:31 -05002965 if (priv->status & STATUS_ASSOCIATED)
James Ketrenos2c86c272005-03-23 17:32:29 -06002966 netif_wake_queue(priv->net_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06002967
2968 /* A packet was processed by the hardware, so update the
2969 * watchdog */
2970 priv->net_dev->trans_start = jiffies;
2971
2972 break;
2973
2974 case COMMAND:
2975 if (txq->drv[txq->oldest].status.info.fields.txType != 1)
Jiri Benc797b4f72005-08-25 20:03:27 -04002976 printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
James Ketrenos2c86c272005-03-23 17:32:29 -06002977 "Expecting COMMAND TBD but pulled "
2978 "something else: ids %d=%d.\n",
2979 priv->net_dev->name, txq->oldest, packet->index);
2980
Brice Goglin0f52bf92005-12-01 01:41:46 -08002981#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002982 if (packet->info.c_struct.cmd->host_command_reg <
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02002983 ARRAY_SIZE(command_types))
James Ketrenosee8e3652005-09-14 09:47:29 -05002984 IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n",
2985 command_types[packet->info.c_struct.cmd->
2986 host_command_reg],
2987 packet->info.c_struct.cmd->
2988 host_command_reg,
2989 packet->info.c_struct.cmd->cmd_status_reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06002990#endif
2991
2992 list_add_tail(element, &priv->msg_free_list);
2993 INC_STAT(&priv->msg_free_stat);
2994 break;
2995 }
2996
2997 /* advance oldest used TBD pointer to start of next entry */
2998 txq->oldest = (e + 1) % txq->entries;
2999 /* increase available TBDs number */
3000 txq->available += descriptors_used;
3001 SET_STAT(&priv->txq_stat, txq->available);
3002
3003 IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003004 jiffies - packet->jiffy_start);
James Ketrenos2c86c272005-03-23 17:32:29 -06003005
3006 return (!list_empty(&priv->fw_pend_list));
3007}
3008
James Ketrenos2c86c272005-03-23 17:32:29 -06003009static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
3010{
3011 int i = 0;
3012
James Ketrenosee8e3652005-09-14 09:47:29 -05003013 while (__ipw2100_tx_process(priv) && i < 200)
3014 i++;
James Ketrenos2c86c272005-03-23 17:32:29 -06003015
3016 if (i == 200) {
Jiri Benc19f7f742005-08-25 20:02:10 -04003017 printk(KERN_WARNING DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06003018 "%s: Driver is running slow (%d iters).\n",
3019 priv->net_dev->name, i);
3020 }
3021}
3022
Jiri Benc19f7f742005-08-25 20:02:10 -04003023static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06003024{
3025 struct list_head *element;
3026 struct ipw2100_tx_packet *packet;
3027 struct ipw2100_bd_queue *txq = &priv->tx_queue;
3028 struct ipw2100_bd *tbd;
3029 int next = txq->next;
3030
3031 while (!list_empty(&priv->msg_pend_list)) {
3032 /* if there isn't enough space in TBD queue, then
3033 * don't stuff a new one in.
3034 * NOTE: 3 are needed as a command will take one,
3035 * and there is a minimum of 2 that must be
3036 * maintained between the r and w indexes
3037 */
3038 if (txq->available <= 3) {
3039 IPW_DEBUG_TX("no room in tx_queue\n");
3040 break;
3041 }
3042
3043 element = priv->msg_pend_list.next;
3044 list_del(element);
3045 DEC_STAT(&priv->msg_pend_stat);
3046
James Ketrenosee8e3652005-09-14 09:47:29 -05003047 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06003048
John W. Linvilleaa0d52c2010-08-10 13:08:11 -04003049 IPW_DEBUG_TX("using TBD at virt=%p, phys=%04X\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003050 &txq->drv[txq->next],
John W. Linvilleaa0d52c2010-08-10 13:08:11 -04003051 (u32) (txq->nic + txq->next *
James Ketrenosee8e3652005-09-14 09:47:29 -05003052 sizeof(struct ipw2100_bd)));
James Ketrenos2c86c272005-03-23 17:32:29 -06003053
3054 packet->index = txq->next;
3055
3056 tbd = &txq->drv[txq->next];
3057
3058 /* initialize TBD */
3059 tbd->host_addr = packet->info.c_struct.cmd_phys;
3060 tbd->buf_length = sizeof(struct ipw2100_cmd_header);
3061 /* not marking number of fragments causes problems
3062 * with f/w debug version */
3063 tbd->num_fragments = 1;
3064 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003065 IPW_BD_STATUS_TX_FRAME_COMMAND |
3066 IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06003067
3068 /* update TBD queue counters */
3069 txq->next++;
3070 txq->next %= txq->entries;
3071 txq->available--;
3072 DEC_STAT(&priv->txq_stat);
3073
3074 list_add_tail(element, &priv->fw_pend_list);
3075 INC_STAT(&priv->fw_pend_stat);
3076 }
3077
3078 if (txq->next != next) {
3079 /* kick off the DMA by notifying firmware the
3080 * write index has moved; make sure TBD stores are sync'd */
3081 wmb();
3082 write_register(priv->net_dev,
3083 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
3084 txq->next);
3085 }
3086}
3087
James Ketrenos2c86c272005-03-23 17:32:29 -06003088/*
Jiri Benc19f7f742005-08-25 20:02:10 -04003089 * ipw2100_tx_send_data
James Ketrenos2c86c272005-03-23 17:32:29 -06003090 *
3091 */
Jiri Benc19f7f742005-08-25 20:02:10 -04003092static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06003093{
3094 struct list_head *element;
3095 struct ipw2100_tx_packet *packet;
3096 struct ipw2100_bd_queue *txq = &priv->tx_queue;
3097 struct ipw2100_bd *tbd;
3098 int next = txq->next;
James Ketrenosee8e3652005-09-14 09:47:29 -05003099 int i = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06003100 struct ipw2100_data_header *ipw_hdr;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003101 struct libipw_hdr_3addr *hdr;
James Ketrenos2c86c272005-03-23 17:32:29 -06003102
3103 while (!list_empty(&priv->tx_pend_list)) {
3104 /* if there isn't enough space in TBD queue, then
3105 * don't stuff a new one in.
3106 * NOTE: 4 are needed as a data will take two,
3107 * and there is a minimum of 2 that must be
3108 * maintained between the r and w indexes
3109 */
3110 element = priv->tx_pend_list.next;
James Ketrenosee8e3652005-09-14 09:47:29 -05003111 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06003112
3113 if (unlikely(1 + packet->info.d_struct.txb->nr_frags >
3114 IPW_MAX_BDS)) {
3115 /* TODO: Support merging buffers if more than
3116 * IPW_MAX_BDS are used */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02003117 IPW_DEBUG_INFO("%s: Maximum BD threshold exceeded. "
James Ketrenosee8e3652005-09-14 09:47:29 -05003118 "Increase fragmentation level.\n",
3119 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003120 }
3121
James Ketrenosee8e3652005-09-14 09:47:29 -05003122 if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003123 IPW_DEBUG_TX("no room in tx_queue\n");
3124 break;
3125 }
3126
3127 list_del(element);
3128 DEC_STAT(&priv->tx_pend_stat);
3129
3130 tbd = &txq->drv[txq->next];
3131
3132 packet->index = txq->next;
3133
3134 ipw_hdr = packet->info.d_struct.data;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003135 hdr = (struct libipw_hdr_3addr *)packet->info.d_struct.txb->
James Ketrenosee8e3652005-09-14 09:47:29 -05003136 fragments[0]->data;
James Ketrenos2c86c272005-03-23 17:32:29 -06003137
3138 if (priv->ieee->iw_mode == IW_MODE_INFRA) {
3139 /* To DS: Addr1 = BSSID, Addr2 = SA,
3140 Addr3 = DA */
3141 memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
3142 memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN);
3143 } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
3144 /* not From/To DS: Addr1 = DA, Addr2 = SA,
3145 Addr3 = BSSID */
3146 memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
3147 memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN);
3148 }
3149
3150 ipw_hdr->host_command_reg = SEND;
3151 ipw_hdr->host_command_reg1 = 0;
3152
3153 /* For now we only support host based encryption */
3154 ipw_hdr->needs_encryption = 0;
3155 ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted;
3156 if (packet->info.d_struct.txb->nr_frags > 1)
3157 ipw_hdr->fragment_size =
James Ketrenosee8e3652005-09-14 09:47:29 -05003158 packet->info.d_struct.txb->frag_size -
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003159 LIBIPW_3ADDR_LEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06003160 else
3161 ipw_hdr->fragment_size = 0;
3162
3163 tbd->host_addr = packet->info.d_struct.data_phys;
3164 tbd->buf_length = sizeof(struct ipw2100_data_header);
3165 tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags;
3166 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003167 IPW_BD_STATUS_TX_FRAME_802_3 |
3168 IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
James Ketrenos2c86c272005-03-23 17:32:29 -06003169 txq->next++;
3170 txq->next %= txq->entries;
3171
James Ketrenosee8e3652005-09-14 09:47:29 -05003172 IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n",
3173 packet->index, tbd->host_addr, tbd->buf_length);
Brice Goglin0f52bf92005-12-01 01:41:46 -08003174#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06003175 if (packet->info.d_struct.txb->nr_frags > 1)
3176 IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
3177 packet->info.d_struct.txb->nr_frags);
3178#endif
3179
James Ketrenosee8e3652005-09-14 09:47:29 -05003180 for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
3181 tbd = &txq->drv[txq->next];
James Ketrenos2c86c272005-03-23 17:32:29 -06003182 if (i == packet->info.d_struct.txb->nr_frags - 1)
3183 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003184 IPW_BD_STATUS_TX_FRAME_802_3 |
3185 IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06003186 else
3187 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003188 IPW_BD_STATUS_TX_FRAME_802_3 |
3189 IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
James Ketrenos2c86c272005-03-23 17:32:29 -06003190
3191 tbd->buf_length = packet->info.d_struct.txb->
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003192 fragments[i]->len - LIBIPW_3ADDR_LEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06003193
James Ketrenosee8e3652005-09-14 09:47:29 -05003194 tbd->host_addr = pci_map_single(priv->pci_dev,
3195 packet->info.d_struct.
3196 txb->fragments[i]->
3197 data +
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003198 LIBIPW_3ADDR_LEN,
James Ketrenosee8e3652005-09-14 09:47:29 -05003199 tbd->buf_length,
3200 PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003201
James Ketrenosee8e3652005-09-14 09:47:29 -05003202 IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n",
3203 txq->next, tbd->host_addr,
3204 tbd->buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06003205
James Ketrenosee8e3652005-09-14 09:47:29 -05003206 pci_dma_sync_single_for_device(priv->pci_dev,
3207 tbd->host_addr,
3208 tbd->buf_length,
3209 PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003210
3211 txq->next++;
3212 txq->next %= txq->entries;
James Ketrenosee8e3652005-09-14 09:47:29 -05003213 }
James Ketrenos2c86c272005-03-23 17:32:29 -06003214
3215 txq->available -= 1 + packet->info.d_struct.txb->nr_frags;
3216 SET_STAT(&priv->txq_stat, txq->available);
3217
3218 list_add_tail(element, &priv->fw_pend_list);
3219 INC_STAT(&priv->fw_pend_stat);
3220 }
3221
3222 if (txq->next != next) {
3223 /* kick off the DMA by notifying firmware the
3224 * write index has moved; make sure TBD stores are sync'd */
3225 write_register(priv->net_dev,
3226 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
3227 txq->next);
3228 }
James Ketrenos2c86c272005-03-23 17:32:29 -06003229}
3230
3231static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
3232{
3233 struct net_device *dev = priv->net_dev;
3234 unsigned long flags;
3235 u32 inta, tmp;
3236
3237 spin_lock_irqsave(&priv->low_lock, flags);
3238 ipw2100_disable_interrupts(priv);
3239
3240 read_register(dev, IPW_REG_INTA, &inta);
3241
3242 IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n",
3243 (unsigned long)inta & IPW_INTERRUPT_MASK);
3244
3245 priv->in_isr++;
3246 priv->interrupts++;
3247
3248 /* We do not loop and keep polling for more interrupts as this
3249 * is frowned upon and doesn't play nicely with other potentially
3250 * chained IRQs */
3251 IPW_DEBUG_ISR("INTA: 0x%08lX\n",
3252 (unsigned long)inta & IPW_INTERRUPT_MASK);
3253
3254 if (inta & IPW2100_INTA_FATAL_ERROR) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003255 printk(KERN_WARNING DRV_NAME
James Ketrenosee8e3652005-09-14 09:47:29 -05003256 ": Fatal interrupt. Scheduling firmware restart.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003257 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003258 write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003259
3260 read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error);
3261 IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n",
3262 priv->net_dev->name, priv->fatal_error);
3263
3264 read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp);
3265 IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n",
3266 priv->net_dev->name, tmp);
3267
3268 /* Wake up any sleeping jobs */
3269 schedule_reset(priv);
3270 }
3271
3272 if (inta & IPW2100_INTA_PARITY_ERROR) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003273 printk(KERN_ERR DRV_NAME
Frans Pop9fd1ea42010-03-24 19:46:31 +01003274 ": ***** PARITY ERROR INTERRUPT !!!!\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003275 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003276 write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003277 }
3278
3279 if (inta & IPW2100_INTA_RX_TRANSFER) {
3280 IPW_DEBUG_ISR("RX interrupt\n");
3281
3282 priv->rx_interrupts++;
3283
James Ketrenosee8e3652005-09-14 09:47:29 -05003284 write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER);
James Ketrenos2c86c272005-03-23 17:32:29 -06003285
3286 __ipw2100_rx_process(priv);
3287 __ipw2100_tx_complete(priv);
3288 }
3289
3290 if (inta & IPW2100_INTA_TX_TRANSFER) {
3291 IPW_DEBUG_ISR("TX interrupt\n");
3292
3293 priv->tx_interrupts++;
3294
James Ketrenosee8e3652005-09-14 09:47:29 -05003295 write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER);
James Ketrenos2c86c272005-03-23 17:32:29 -06003296
3297 __ipw2100_tx_complete(priv);
Jiri Benc19f7f742005-08-25 20:02:10 -04003298 ipw2100_tx_send_commands(priv);
3299 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06003300 }
3301
3302 if (inta & IPW2100_INTA_TX_COMPLETE) {
3303 IPW_DEBUG_ISR("TX complete\n");
3304 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003305 write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003306
3307 __ipw2100_tx_complete(priv);
3308 }
3309
3310 if (inta & IPW2100_INTA_EVENT_INTERRUPT) {
3311 /* ipw2100_handle_event(dev); */
3312 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003313 write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT);
James Ketrenos2c86c272005-03-23 17:32:29 -06003314 }
3315
3316 if (inta & IPW2100_INTA_FW_INIT_DONE) {
3317 IPW_DEBUG_ISR("FW init done interrupt\n");
3318 priv->inta_other++;
3319
3320 read_register(dev, IPW_REG_INTA, &tmp);
3321 if (tmp & (IPW2100_INTA_FATAL_ERROR |
3322 IPW2100_INTA_PARITY_ERROR)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003323 write_register(dev, IPW_REG_INTA,
3324 IPW2100_INTA_FATAL_ERROR |
3325 IPW2100_INTA_PARITY_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003326 }
3327
James Ketrenosee8e3652005-09-14 09:47:29 -05003328 write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003329 }
3330
3331 if (inta & IPW2100_INTA_STATUS_CHANGE) {
3332 IPW_DEBUG_ISR("Status change interrupt\n");
3333 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003334 write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003335 }
3336
3337 if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) {
3338 IPW_DEBUG_ISR("slave host mode interrupt\n");
3339 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003340 write_register(dev, IPW_REG_INTA,
3341 IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003342 }
3343
3344 priv->in_isr--;
3345 ipw2100_enable_interrupts(priv);
3346
3347 spin_unlock_irqrestore(&priv->low_lock, flags);
3348
3349 IPW_DEBUG_ISR("exit\n");
3350}
3351
David Howells7d12e782006-10-05 14:55:46 +01003352static irqreturn_t ipw2100_interrupt(int irq, void *data)
James Ketrenos2c86c272005-03-23 17:32:29 -06003353{
3354 struct ipw2100_priv *priv = data;
3355 u32 inta, inta_mask;
3356
3357 if (!data)
3358 return IRQ_NONE;
3359
James Ketrenosee8e3652005-09-14 09:47:29 -05003360 spin_lock(&priv->low_lock);
James Ketrenos2c86c272005-03-23 17:32:29 -06003361
3362 /* We check to see if we should be ignoring interrupts before
3363 * we touch the hardware. During ucode load if we try and handle
3364 * an interrupt we can cause keyboard problems as well as cause
3365 * the ucode to fail to initialize */
3366 if (!(priv->status & STATUS_INT_ENABLED)) {
3367 /* Shared IRQ */
3368 goto none;
3369 }
3370
3371 read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
3372 read_register(priv->net_dev, IPW_REG_INTA, &inta);
3373
3374 if (inta == 0xFFFFFFFF) {
3375 /* Hardware disappeared */
Jiri Benc797b4f72005-08-25 20:03:27 -04003376 printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003377 goto none;
3378 }
3379
3380 inta &= IPW_INTERRUPT_MASK;
3381
3382 if (!(inta & inta_mask)) {
3383 /* Shared interrupt */
3384 goto none;
3385 }
3386
3387 /* We disable the hardware interrupt here just to prevent unneeded
3388 * calls to be made. We disable this again within the actual
3389 * work tasklet, so if another part of the code re-enables the
3390 * interrupt, that is fine */
3391 ipw2100_disable_interrupts(priv);
3392
3393 tasklet_schedule(&priv->irq_tasklet);
James Ketrenosee8e3652005-09-14 09:47:29 -05003394 spin_unlock(&priv->low_lock);
James Ketrenos2c86c272005-03-23 17:32:29 -06003395
3396 return IRQ_HANDLED;
James Ketrenosee8e3652005-09-14 09:47:29 -05003397 none:
James Ketrenos2c86c272005-03-23 17:32:29 -06003398 spin_unlock(&priv->low_lock);
3399 return IRQ_NONE;
3400}
3401
Stephen Hemmingerd0cf9c02009-08-31 19:50:57 +00003402static netdev_tx_t ipw2100_tx(struct libipw_txb *txb,
3403 struct net_device *dev, int pri)
James Ketrenos2c86c272005-03-23 17:32:29 -06003404{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003405 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06003406 struct list_head *element;
3407 struct ipw2100_tx_packet *packet;
3408 unsigned long flags;
3409
3410 spin_lock_irqsave(&priv->low_lock, flags);
3411
3412 if (!(priv->status & STATUS_ASSOCIATED)) {
3413 IPW_DEBUG_INFO("Can not transmit when not connected.\n");
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00003414 priv->net_dev->stats.tx_carrier_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06003415 netif_stop_queue(dev);
3416 goto fail_unlock;
3417 }
3418
3419 if (list_empty(&priv->tx_free_list))
3420 goto fail_unlock;
3421
3422 element = priv->tx_free_list.next;
3423 packet = list_entry(element, struct ipw2100_tx_packet, list);
3424
3425 packet->info.d_struct.txb = txb;
3426
James Ketrenosee8e3652005-09-14 09:47:29 -05003427 IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len);
3428 printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len);
James Ketrenos2c86c272005-03-23 17:32:29 -06003429
3430 packet->jiffy_start = jiffies;
3431
3432 list_del(element);
3433 DEC_STAT(&priv->tx_free_stat);
3434
3435 list_add_tail(element, &priv->tx_pend_list);
3436 INC_STAT(&priv->tx_pend_stat);
3437
Jiri Benc19f7f742005-08-25 20:02:10 -04003438 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06003439
3440 spin_unlock_irqrestore(&priv->low_lock, flags);
Stephen Hemmingerd0cf9c02009-08-31 19:50:57 +00003441 return NETDEV_TX_OK;
James Ketrenos2c86c272005-03-23 17:32:29 -06003442
Stephen Hemmingerd0cf9c02009-08-31 19:50:57 +00003443fail_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -06003444 netif_stop_queue(dev);
3445 spin_unlock_irqrestore(&priv->low_lock, flags);
Stephen Hemmingerd0cf9c02009-08-31 19:50:57 +00003446 return NETDEV_TX_BUSY;
James Ketrenos2c86c272005-03-23 17:32:29 -06003447}
3448
James Ketrenos2c86c272005-03-23 17:32:29 -06003449static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
3450{
3451 int i, j, err = -EINVAL;
3452 void *v;
3453 dma_addr_t p;
3454
James Ketrenosee8e3652005-09-14 09:47:29 -05003455 priv->msg_buffers =
Joe Perchesefe4c452010-05-31 20:23:15 -07003456 kmalloc(IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet),
3457 GFP_KERNEL);
James Ketrenos2c86c272005-03-23 17:32:29 -06003458 if (!priv->msg_buffers) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003459 printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg "
James Ketrenos2c86c272005-03-23 17:32:29 -06003460 "buffers.\n", priv->net_dev->name);
3461 return -ENOMEM;
3462 }
3463
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,
3779 "channels suported by country"),
3780 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
James Ketrenosee8e3652005-09-14 09:47:29 -05004068 printk(KERN_INFO "%s: Reseting 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;
4321 cancel_delayed_work(&priv->rf_kill);
Tejun Heobcb6d912011-01-26 12:12:50 +01004322 schedule_delayed_work(&priv->rf_kill,
4323 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06004324 } else
4325 schedule_reset(priv);
4326 }
4327
Ingo Molnar752e3772006-02-28 07:20:54 +08004328 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06004329 return 1;
4330}
4331
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004332static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004333 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004334{
4335 struct ipw2100_priv *priv = dev_get_drvdata(d);
4336 ipw_radio_kill_sw(priv, buf[0] == '1');
4337 return count;
4338}
James Ketrenos2c86c272005-03-23 17:32:29 -06004339
James Ketrenosee8e3652005-09-14 09:47:29 -05004340static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
James Ketrenos2c86c272005-03-23 17:32:29 -06004341
4342static struct attribute *ipw2100_sysfs_entries[] = {
4343 &dev_attr_hardware.attr,
4344 &dev_attr_registers.attr,
4345 &dev_attr_ordinals.attr,
4346 &dev_attr_pci.attr,
4347 &dev_attr_stats.attr,
4348 &dev_attr_internals.attr,
4349 &dev_attr_bssinfo.attr,
4350 &dev_attr_memory.attr,
4351 &dev_attr_scan_age.attr,
4352 &dev_attr_fatal_error.attr,
4353 &dev_attr_rf_kill.attr,
4354 &dev_attr_cfg.attr,
4355 &dev_attr_status.attr,
4356 &dev_attr_capability.attr,
4357 NULL,
4358};
4359
4360static struct attribute_group ipw2100_attribute_group = {
4361 .attrs = ipw2100_sysfs_entries,
4362};
4363
James Ketrenos2c86c272005-03-23 17:32:29 -06004364static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
4365{
4366 struct ipw2100_status_queue *q = &priv->status_queue;
4367
4368 IPW_DEBUG_INFO("enter\n");
4369
4370 q->size = entries * sizeof(struct ipw2100_status);
James Ketrenosee8e3652005-09-14 09:47:29 -05004371 q->drv =
4372 (struct ipw2100_status *)pci_alloc_consistent(priv->pci_dev,
4373 q->size, &q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004374 if (!q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004375 IPW_DEBUG_WARNING("Can not allocate status queue.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06004376 return -ENOMEM;
4377 }
4378
4379 memset(q->drv, 0, q->size);
4380
4381 IPW_DEBUG_INFO("exit\n");
4382
4383 return 0;
4384}
4385
4386static void status_queue_free(struct ipw2100_priv *priv)
4387{
4388 IPW_DEBUG_INFO("enter\n");
4389
4390 if (priv->status_queue.drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004391 pci_free_consistent(priv->pci_dev, priv->status_queue.size,
4392 priv->status_queue.drv,
4393 priv->status_queue.nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004394 priv->status_queue.drv = NULL;
4395 }
4396
4397 IPW_DEBUG_INFO("exit\n");
4398}
4399
4400static int bd_queue_allocate(struct ipw2100_priv *priv,
4401 struct ipw2100_bd_queue *q, int entries)
4402{
4403 IPW_DEBUG_INFO("enter\n");
4404
4405 memset(q, 0, sizeof(struct ipw2100_bd_queue));
4406
4407 q->entries = entries;
4408 q->size = entries * sizeof(struct ipw2100_bd);
4409 q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic);
4410 if (!q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004411 IPW_DEBUG_INFO
4412 ("can't allocate shared memory for buffer descriptors\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06004413 return -ENOMEM;
4414 }
4415 memset(q->drv, 0, q->size);
4416
4417 IPW_DEBUG_INFO("exit\n");
4418
4419 return 0;
4420}
4421
James Ketrenosee8e3652005-09-14 09:47:29 -05004422static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q)
James Ketrenos2c86c272005-03-23 17:32:29 -06004423{
4424 IPW_DEBUG_INFO("enter\n");
4425
4426 if (!q)
4427 return;
4428
4429 if (q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004430 pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004431 q->drv = NULL;
4432 }
4433
4434 IPW_DEBUG_INFO("exit\n");
4435}
4436
James Ketrenosee8e3652005-09-14 09:47:29 -05004437static void bd_queue_initialize(struct ipw2100_priv *priv,
4438 struct ipw2100_bd_queue *q, u32 base, u32 size,
4439 u32 r, u32 w)
James Ketrenos2c86c272005-03-23 17:32:29 -06004440{
4441 IPW_DEBUG_INFO("enter\n");
4442
James Ketrenosee8e3652005-09-14 09:47:29 -05004443 IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv,
4444 (u32) q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004445
4446 write_register(priv->net_dev, base, q->nic);
4447 write_register(priv->net_dev, size, q->entries);
4448 write_register(priv->net_dev, r, q->oldest);
4449 write_register(priv->net_dev, w, q->next);
4450
4451 IPW_DEBUG_INFO("exit\n");
4452}
4453
Tejun Heobcb6d912011-01-26 12:12:50 +01004454static void ipw2100_kill_works(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06004455{
Tejun Heobcb6d912011-01-26 12:12:50 +01004456 priv->stop_rf_kill = 1;
4457 priv->stop_hang_check = 1;
4458 cancel_delayed_work_sync(&priv->reset_work);
4459 cancel_delayed_work_sync(&priv->security_work);
4460 cancel_delayed_work_sync(&priv->wx_event_work);
4461 cancel_delayed_work_sync(&priv->hang_check);
4462 cancel_delayed_work_sync(&priv->rf_kill);
4463 cancel_work_sync(&priv->scan_event_now);
4464 cancel_delayed_work_sync(&priv->scan_event_later);
James Ketrenos2c86c272005-03-23 17:32:29 -06004465}
4466
4467static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
4468{
4469 int i, j, err = -EINVAL;
4470 void *v;
4471 dma_addr_t p;
4472
4473 IPW_DEBUG_INFO("enter\n");
4474
4475 err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH);
4476 if (err) {
4477 IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05004478 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004479 return err;
4480 }
4481
James Ketrenosee8e3652005-09-14 09:47:29 -05004482 priv->tx_buffers =
Joe Perchesefe4c452010-05-31 20:23:15 -07004483 kmalloc(TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet),
4484 GFP_ATOMIC);
James Ketrenos2c86c272005-03-23 17:32:29 -06004485 if (!priv->tx_buffers) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004486 printk(KERN_ERR DRV_NAME
4487 ": %s: alloc failed form tx buffers.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06004488 priv->net_dev->name);
4489 bd_queue_free(priv, &priv->tx_queue);
4490 return -ENOMEM;
4491 }
4492
4493 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004494 v = pci_alloc_consistent(priv->pci_dev,
4495 sizeof(struct ipw2100_data_header),
4496 &p);
James Ketrenos2c86c272005-03-23 17:32:29 -06004497 if (!v) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004498 printk(KERN_ERR DRV_NAME
4499 ": %s: PCI alloc failed for tx " "buffers.\n",
4500 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004501 err = -ENOMEM;
4502 break;
4503 }
4504
4505 priv->tx_buffers[i].type = DATA;
James Ketrenosee8e3652005-09-14 09:47:29 -05004506 priv->tx_buffers[i].info.d_struct.data =
4507 (struct ipw2100_data_header *)v;
James Ketrenos2c86c272005-03-23 17:32:29 -06004508 priv->tx_buffers[i].info.d_struct.data_phys = p;
4509 priv->tx_buffers[i].info.d_struct.txb = NULL;
4510 }
4511
4512 if (i == TX_PENDED_QUEUE_LENGTH)
4513 return 0;
4514
4515 for (j = 0; j < i; j++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004516 pci_free_consistent(priv->pci_dev,
4517 sizeof(struct ipw2100_data_header),
4518 priv->tx_buffers[j].info.d_struct.data,
4519 priv->tx_buffers[j].info.d_struct.
4520 data_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06004521 }
4522
4523 kfree(priv->tx_buffers);
4524 priv->tx_buffers = NULL;
4525
4526 return err;
4527}
4528
4529static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
4530{
4531 int i;
4532
4533 IPW_DEBUG_INFO("enter\n");
4534
4535 /*
4536 * reinitialize packet info lists
4537 */
4538 INIT_LIST_HEAD(&priv->fw_pend_list);
4539 INIT_STAT(&priv->fw_pend_stat);
4540
4541 /*
4542 * reinitialize lists
4543 */
4544 INIT_LIST_HEAD(&priv->tx_pend_list);
4545 INIT_LIST_HEAD(&priv->tx_free_list);
4546 INIT_STAT(&priv->tx_pend_stat);
4547 INIT_STAT(&priv->tx_free_stat);
4548
4549 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
4550 /* We simply drop any SKBs that have been queued for
4551 * transmit */
4552 if (priv->tx_buffers[i].info.d_struct.txb) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04004553 libipw_txb_free(priv->tx_buffers[i].info.d_struct.
James Ketrenosee8e3652005-09-14 09:47:29 -05004554 txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06004555 priv->tx_buffers[i].info.d_struct.txb = NULL;
4556 }
4557
4558 list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list);
4559 }
4560
4561 SET_STAT(&priv->tx_free_stat, i);
4562
4563 priv->tx_queue.oldest = 0;
4564 priv->tx_queue.available = priv->tx_queue.entries;
4565 priv->tx_queue.next = 0;
4566 INIT_STAT(&priv->txq_stat);
4567 SET_STAT(&priv->txq_stat, priv->tx_queue.available);
4568
4569 bd_queue_initialize(priv, &priv->tx_queue,
4570 IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE,
4571 IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE,
4572 IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
4573 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX);
4574
4575 IPW_DEBUG_INFO("exit\n");
4576
4577}
4578
4579static void ipw2100_tx_free(struct ipw2100_priv *priv)
4580{
4581 int i;
4582
4583 IPW_DEBUG_INFO("enter\n");
4584
4585 bd_queue_free(priv, &priv->tx_queue);
4586
4587 if (!priv->tx_buffers)
4588 return;
4589
4590 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
4591 if (priv->tx_buffers[i].info.d_struct.txb) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04004592 libipw_txb_free(priv->tx_buffers[i].info.d_struct.
James Ketrenosee8e3652005-09-14 09:47:29 -05004593 txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06004594 priv->tx_buffers[i].info.d_struct.txb = NULL;
4595 }
4596 if (priv->tx_buffers[i].info.d_struct.data)
James Ketrenosee8e3652005-09-14 09:47:29 -05004597 pci_free_consistent(priv->pci_dev,
4598 sizeof(struct ipw2100_data_header),
4599 priv->tx_buffers[i].info.d_struct.
4600 data,
4601 priv->tx_buffers[i].info.d_struct.
4602 data_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06004603 }
4604
4605 kfree(priv->tx_buffers);
4606 priv->tx_buffers = NULL;
4607
4608 IPW_DEBUG_INFO("exit\n");
4609}
4610
James Ketrenos2c86c272005-03-23 17:32:29 -06004611static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
4612{
4613 int i, j, err = -EINVAL;
4614
4615 IPW_DEBUG_INFO("enter\n");
4616
4617 err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH);
4618 if (err) {
4619 IPW_DEBUG_INFO("failed bd_queue_allocate\n");
4620 return err;
4621 }
4622
4623 err = status_queue_allocate(priv, RX_QUEUE_LENGTH);
4624 if (err) {
4625 IPW_DEBUG_INFO("failed status_queue_allocate\n");
4626 bd_queue_free(priv, &priv->rx_queue);
4627 return err;
4628 }
4629
4630 /*
4631 * allocate packets
4632 */
Joe Perchesefe4c452010-05-31 20:23:15 -07004633 priv->rx_buffers = kmalloc(RX_QUEUE_LENGTH *
4634 sizeof(struct ipw2100_rx_packet),
4635 GFP_KERNEL);
James Ketrenos2c86c272005-03-23 17:32:29 -06004636 if (!priv->rx_buffers) {
4637 IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
4638
4639 bd_queue_free(priv, &priv->rx_queue);
4640
4641 status_queue_free(priv);
4642
4643 return -ENOMEM;
4644 }
4645
4646 for (i = 0; i < RX_QUEUE_LENGTH; i++) {
4647 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
4648
4649 err = ipw2100_alloc_skb(priv, packet);
4650 if (unlikely(err)) {
4651 err = -ENOMEM;
4652 break;
4653 }
4654
4655 /* The BD holds the cache aligned address */
4656 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
4657 priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH;
4658 priv->status_queue.drv[i].status_fields = 0;
4659 }
4660
4661 if (i == RX_QUEUE_LENGTH)
4662 return 0;
4663
4664 for (j = 0; j < i; j++) {
4665 pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr,
4666 sizeof(struct ipw2100_rx_packet),
4667 PCI_DMA_FROMDEVICE);
4668 dev_kfree_skb(priv->rx_buffers[j].skb);
4669 }
4670
4671 kfree(priv->rx_buffers);
4672 priv->rx_buffers = NULL;
4673
4674 bd_queue_free(priv, &priv->rx_queue);
4675
4676 status_queue_free(priv);
4677
4678 return err;
4679}
4680
4681static void ipw2100_rx_initialize(struct ipw2100_priv *priv)
4682{
4683 IPW_DEBUG_INFO("enter\n");
4684
4685 priv->rx_queue.oldest = 0;
4686 priv->rx_queue.available = priv->rx_queue.entries - 1;
4687 priv->rx_queue.next = priv->rx_queue.entries - 1;
4688
4689 INIT_STAT(&priv->rxq_stat);
4690 SET_STAT(&priv->rxq_stat, priv->rx_queue.available);
4691
4692 bd_queue_initialize(priv, &priv->rx_queue,
4693 IPW_MEM_HOST_SHARED_RX_BD_BASE,
4694 IPW_MEM_HOST_SHARED_RX_BD_SIZE,
4695 IPW_MEM_HOST_SHARED_RX_READ_INDEX,
4696 IPW_MEM_HOST_SHARED_RX_WRITE_INDEX);
4697
4698 /* set up the status queue */
4699 write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE,
4700 priv->status_queue.nic);
4701
4702 IPW_DEBUG_INFO("exit\n");
4703}
4704
4705static void ipw2100_rx_free(struct ipw2100_priv *priv)
4706{
4707 int i;
4708
4709 IPW_DEBUG_INFO("enter\n");
4710
4711 bd_queue_free(priv, &priv->rx_queue);
4712 status_queue_free(priv);
4713
4714 if (!priv->rx_buffers)
4715 return;
4716
4717 for (i = 0; i < RX_QUEUE_LENGTH; i++) {
4718 if (priv->rx_buffers[i].rxp) {
4719 pci_unmap_single(priv->pci_dev,
4720 priv->rx_buffers[i].dma_addr,
4721 sizeof(struct ipw2100_rx),
4722 PCI_DMA_FROMDEVICE);
4723 dev_kfree_skb(priv->rx_buffers[i].skb);
4724 }
4725 }
4726
4727 kfree(priv->rx_buffers);
4728 priv->rx_buffers = NULL;
4729
4730 IPW_DEBUG_INFO("exit\n");
4731}
4732
4733static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
4734{
4735 u32 length = ETH_ALEN;
Joe Perches0795af52007-10-03 17:59:30 -07004736 u8 addr[ETH_ALEN];
James Ketrenos2c86c272005-03-23 17:32:29 -06004737
4738 int err;
4739
Joe Perches0795af52007-10-03 17:59:30 -07004740 err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
James Ketrenos2c86c272005-03-23 17:32:29 -06004741 if (err) {
4742 IPW_DEBUG_INFO("MAC address read failed\n");
4743 return -EIO;
4744 }
James Ketrenos2c86c272005-03-23 17:32:29 -06004745
Joe Perches0795af52007-10-03 17:59:30 -07004746 memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN);
Johannes Berge1749612008-10-27 15:59:26 -07004747 IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06004748
4749 return 0;
4750}
4751
4752/********************************************************************
4753 *
4754 * Firmware Commands
4755 *
4756 ********************************************************************/
4757
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004758static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004759{
4760 struct host_command cmd = {
4761 .host_command = ADAPTER_ADDRESS,
4762 .host_command_sequence = 0,
4763 .host_command_length = ETH_ALEN
4764 };
4765 int err;
4766
4767 IPW_DEBUG_HC("SET_MAC_ADDRESS\n");
4768
4769 IPW_DEBUG_INFO("enter\n");
4770
4771 if (priv->config & CFG_CUSTOM_MAC) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004772 memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06004773 memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
4774 } else
4775 memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr,
4776 ETH_ALEN);
4777
4778 err = ipw2100_hw_send_command(priv, &cmd);
4779
4780 IPW_DEBUG_INFO("exit\n");
4781 return err;
4782}
4783
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004784static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type,
James Ketrenos2c86c272005-03-23 17:32:29 -06004785 int batch_mode)
4786{
4787 struct host_command cmd = {
4788 .host_command = PORT_TYPE,
4789 .host_command_sequence = 0,
4790 .host_command_length = sizeof(u32)
4791 };
4792 int err;
4793
4794 switch (port_type) {
4795 case IW_MODE_INFRA:
4796 cmd.host_command_parameters[0] = IPW_BSS;
4797 break;
4798 case IW_MODE_ADHOC:
4799 cmd.host_command_parameters[0] = IPW_IBSS;
4800 break;
4801 }
4802
4803 IPW_DEBUG_HC("PORT_TYPE: %s\n",
4804 port_type == IPW_IBSS ? "Ad-Hoc" : "Managed");
4805
4806 if (!batch_mode) {
4807 err = ipw2100_disable_adapter(priv);
4808 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004809 printk(KERN_ERR DRV_NAME
4810 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06004811 priv->net_dev->name, err);
4812 return err;
4813 }
4814 }
4815
4816 /* send cmd to firmware */
4817 err = ipw2100_hw_send_command(priv, &cmd);
4818
4819 if (!batch_mode)
4820 ipw2100_enable_adapter(priv);
4821
4822 return err;
4823}
4824
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004825static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
4826 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004827{
4828 struct host_command cmd = {
4829 .host_command = CHANNEL,
4830 .host_command_sequence = 0,
4831 .host_command_length = sizeof(u32)
4832 };
4833 int err;
4834
4835 cmd.host_command_parameters[0] = channel;
4836
4837 IPW_DEBUG_HC("CHANNEL: %d\n", channel);
4838
4839 /* If BSS then we don't support channel selection */
4840 if (priv->ieee->iw_mode == IW_MODE_INFRA)
4841 return 0;
4842
4843 if ((channel != 0) &&
4844 ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL)))
4845 return -EINVAL;
4846
4847 if (!batch_mode) {
4848 err = ipw2100_disable_adapter(priv);
4849 if (err)
4850 return err;
4851 }
4852
4853 err = ipw2100_hw_send_command(priv, &cmd);
4854 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004855 IPW_DEBUG_INFO("Failed to set channel to %d", channel);
James Ketrenos2c86c272005-03-23 17:32:29 -06004856 return err;
4857 }
4858
4859 if (channel)
4860 priv->config |= CFG_STATIC_CHANNEL;
4861 else
4862 priv->config &= ~CFG_STATIC_CHANNEL;
4863
4864 priv->channel = channel;
4865
4866 if (!batch_mode) {
4867 err = ipw2100_enable_adapter(priv);
4868 if (err)
4869 return err;
4870 }
4871
4872 return 0;
4873}
4874
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004875static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004876{
4877 struct host_command cmd = {
4878 .host_command = SYSTEM_CONFIG,
4879 .host_command_sequence = 0,
4880 .host_command_length = 12,
4881 };
4882 u32 ibss_mask, len = sizeof(u32);
4883 int err;
4884
4885 /* Set system configuration */
4886
4887 if (!batch_mode) {
4888 err = ipw2100_disable_adapter(priv);
4889 if (err)
4890 return err;
4891 }
4892
4893 if (priv->ieee->iw_mode == IW_MODE_ADHOC)
4894 cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START;
4895
4896 cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK |
James Ketrenosee8e3652005-09-14 09:47:29 -05004897 IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06004898
4899 if (!(priv->config & CFG_LONG_PREAMBLE))
4900 cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO;
4901
4902 err = ipw2100_get_ordinal(priv,
4903 IPW_ORD_EEPROM_IBSS_11B_CHANNELS,
James Ketrenosee8e3652005-09-14 09:47:29 -05004904 &ibss_mask, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06004905 if (err)
4906 ibss_mask = IPW_IBSS_11B_DEFAULT_MASK;
4907
4908 cmd.host_command_parameters[1] = REG_CHANNEL_MASK;
4909 cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask;
4910
4911 /* 11b only */
James Ketrenosee8e3652005-09-14 09:47:29 -05004912 /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */
James Ketrenos2c86c272005-03-23 17:32:29 -06004913
4914 err = ipw2100_hw_send_command(priv, &cmd);
4915 if (err)
4916 return err;
4917
4918/* If IPv6 is configured in the kernel then we don't want to filter out all
4919 * of the multicast packets as IPv6 needs some. */
4920#if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE)
4921 cmd.host_command = ADD_MULTICAST;
4922 cmd.host_command_sequence = 0;
4923 cmd.host_command_length = 0;
4924
4925 ipw2100_hw_send_command(priv, &cmd);
4926#endif
4927 if (!batch_mode) {
4928 err = ipw2100_enable_adapter(priv);
4929 if (err)
4930 return err;
4931 }
4932
4933 return 0;
4934}
4935
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004936static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate,
4937 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004938{
4939 struct host_command cmd = {
4940 .host_command = BASIC_TX_RATES,
4941 .host_command_sequence = 0,
4942 .host_command_length = 4
4943 };
4944 int err;
4945
4946 cmd.host_command_parameters[0] = rate & TX_RATE_MASK;
4947
4948 if (!batch_mode) {
4949 err = ipw2100_disable_adapter(priv);
4950 if (err)
4951 return err;
4952 }
4953
4954 /* Set BASIC TX Rate first */
4955 ipw2100_hw_send_command(priv, &cmd);
4956
4957 /* Set TX Rate */
4958 cmd.host_command = TX_RATES;
4959 ipw2100_hw_send_command(priv, &cmd);
4960
4961 /* Set MSDU TX Rate */
4962 cmd.host_command = MSDU_TX_RATES;
4963 ipw2100_hw_send_command(priv, &cmd);
4964
4965 if (!batch_mode) {
4966 err = ipw2100_enable_adapter(priv);
4967 if (err)
4968 return err;
4969 }
4970
4971 priv->tx_rates = rate;
4972
4973 return 0;
4974}
4975
James Ketrenosee8e3652005-09-14 09:47:29 -05004976static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
James Ketrenos2c86c272005-03-23 17:32:29 -06004977{
4978 struct host_command cmd = {
4979 .host_command = POWER_MODE,
4980 .host_command_sequence = 0,
4981 .host_command_length = 4
4982 };
4983 int err;
4984
4985 cmd.host_command_parameters[0] = power_level;
4986
4987 err = ipw2100_hw_send_command(priv, &cmd);
4988 if (err)
4989 return err;
4990
4991 if (power_level == IPW_POWER_MODE_CAM)
4992 priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
4993 else
4994 priv->power_mode = IPW_POWER_ENABLED | power_level;
4995
Robert P. J. Dayae800312007-01-31 02:39:40 -05004996#ifdef IPW2100_TX_POWER
James Ketrenosee8e3652005-09-14 09:47:29 -05004997 if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
James Ketrenos2c86c272005-03-23 17:32:29 -06004998 /* Set beacon interval */
4999 cmd.host_command = TX_POWER_INDEX;
James Ketrenosee8e3652005-09-14 09:47:29 -05005000 cmd.host_command_parameters[0] = (u32) priv->adhoc_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06005001
5002 err = ipw2100_hw_send_command(priv, &cmd);
5003 if (err)
5004 return err;
5005 }
5006#endif
5007
5008 return 0;
5009}
5010
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005011static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold)
James Ketrenos2c86c272005-03-23 17:32:29 -06005012{
5013 struct host_command cmd = {
5014 .host_command = RTS_THRESHOLD,
5015 .host_command_sequence = 0,
5016 .host_command_length = 4
5017 };
5018 int err;
5019
5020 if (threshold & RTS_DISABLED)
5021 cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD;
5022 else
5023 cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED;
5024
5025 err = ipw2100_hw_send_command(priv, &cmd);
5026 if (err)
5027 return err;
5028
5029 priv->rts_threshold = threshold;
5030
5031 return 0;
5032}
5033
5034#if 0
5035int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv,
5036 u32 threshold, int batch_mode)
5037{
5038 struct host_command cmd = {
5039 .host_command = FRAG_THRESHOLD,
5040 .host_command_sequence = 0,
5041 .host_command_length = 4,
5042 .host_command_parameters[0] = 0,
5043 };
5044 int err;
5045
5046 if (!batch_mode) {
5047 err = ipw2100_disable_adapter(priv);
5048 if (err)
5049 return err;
5050 }
5051
5052 if (threshold == 0)
5053 threshold = DEFAULT_FRAG_THRESHOLD;
5054 else {
5055 threshold = max(threshold, MIN_FRAG_THRESHOLD);
5056 threshold = min(threshold, MAX_FRAG_THRESHOLD);
5057 }
5058
5059 cmd.host_command_parameters[0] = threshold;
5060
5061 IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold);
5062
5063 err = ipw2100_hw_send_command(priv, &cmd);
5064
5065 if (!batch_mode)
5066 ipw2100_enable_adapter(priv);
5067
5068 if (!err)
5069 priv->frag_threshold = threshold;
5070
5071 return err;
5072}
5073#endif
5074
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005075static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry)
James Ketrenos2c86c272005-03-23 17:32:29 -06005076{
5077 struct host_command cmd = {
5078 .host_command = SHORT_RETRY_LIMIT,
5079 .host_command_sequence = 0,
5080 .host_command_length = 4
5081 };
5082 int err;
5083
5084 cmd.host_command_parameters[0] = retry;
5085
5086 err = ipw2100_hw_send_command(priv, &cmd);
5087 if (err)
5088 return err;
5089
5090 priv->short_retry_limit = retry;
5091
5092 return 0;
5093}
5094
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005095static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry)
James Ketrenos2c86c272005-03-23 17:32:29 -06005096{
5097 struct host_command cmd = {
5098 .host_command = LONG_RETRY_LIMIT,
5099 .host_command_sequence = 0,
5100 .host_command_length = 4
5101 };
5102 int err;
5103
5104 cmd.host_command_parameters[0] = retry;
5105
5106 err = ipw2100_hw_send_command(priv, &cmd);
5107 if (err)
5108 return err;
5109
5110 priv->long_retry_limit = retry;
5111
5112 return 0;
5113}
5114
James Ketrenosee8e3652005-09-14 09:47:29 -05005115static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005116 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005117{
5118 struct host_command cmd = {
5119 .host_command = MANDATORY_BSSID,
5120 .host_command_sequence = 0,
5121 .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN
5122 };
5123 int err;
5124
Brice Goglin0f52bf92005-12-01 01:41:46 -08005125#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06005126 if (bssid != NULL)
Johannes Berge1749612008-10-27 15:59:26 -07005127 IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06005128 else
5129 IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
5130#endif
5131 /* if BSSID is empty then we disable mandatory bssid mode */
5132 if (bssid != NULL)
James Ketrenos82328352005-08-24 22:33:31 -05005133 memcpy(cmd.host_command_parameters, bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06005134
5135 if (!batch_mode) {
5136 err = ipw2100_disable_adapter(priv);
5137 if (err)
5138 return err;
5139 }
5140
5141 err = ipw2100_hw_send_command(priv, &cmd);
5142
5143 if (!batch_mode)
5144 ipw2100_enable_adapter(priv);
5145
5146 return err;
5147}
5148
James Ketrenos2c86c272005-03-23 17:32:29 -06005149static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
5150{
5151 struct host_command cmd = {
5152 .host_command = DISASSOCIATION_BSSID,
5153 .host_command_sequence = 0,
5154 .host_command_length = ETH_ALEN
5155 };
5156 int err;
5157 int len;
5158
5159 IPW_DEBUG_HC("DISASSOCIATION_BSSID\n");
5160
5161 len = ETH_ALEN;
5162 /* The Firmware currently ignores the BSSID and just disassociates from
5163 * the currently associated AP -- but in the off chance that a future
5164 * firmware does use the BSSID provided here, we go ahead and try and
5165 * set it to the currently associated AP's BSSID */
5166 memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN);
5167
5168 err = ipw2100_hw_send_command(priv, &cmd);
5169
5170 return err;
5171}
James Ketrenos2c86c272005-03-23 17:32:29 -06005172
5173static int ipw2100_set_wpa_ie(struct ipw2100_priv *,
5174 struct ipw2100_wpa_assoc_frame *, int)
James Ketrenosee8e3652005-09-14 09:47:29 -05005175 __attribute__ ((unused));
James Ketrenos2c86c272005-03-23 17:32:29 -06005176
5177static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv,
5178 struct ipw2100_wpa_assoc_frame *wpa_frame,
5179 int batch_mode)
5180{
5181 struct host_command cmd = {
5182 .host_command = SET_WPA_IE,
5183 .host_command_sequence = 0,
5184 .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame),
5185 };
5186 int err;
5187
5188 IPW_DEBUG_HC("SET_WPA_IE\n");
5189
5190 if (!batch_mode) {
5191 err = ipw2100_disable_adapter(priv);
5192 if (err)
5193 return err;
5194 }
5195
5196 memcpy(cmd.host_command_parameters, wpa_frame,
5197 sizeof(struct ipw2100_wpa_assoc_frame));
5198
5199 err = ipw2100_hw_send_command(priv, &cmd);
5200
5201 if (!batch_mode) {
5202 if (ipw2100_enable_adapter(priv))
5203 err = -EIO;
5204 }
5205
5206 return err;
5207}
5208
5209struct security_info_params {
5210 u32 allowed_ciphers;
5211 u16 version;
5212 u8 auth_mode;
5213 u8 replay_counters_number;
5214 u8 unicast_using_group;
Eric Dumazetba2d3582010-06-02 18:10:09 +00005215} __packed;
James Ketrenos2c86c272005-03-23 17:32:29 -06005216
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005217static int ipw2100_set_security_information(struct ipw2100_priv *priv,
5218 int auth_mode,
5219 int security_level,
5220 int unicast_using_group,
5221 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005222{
5223 struct host_command cmd = {
5224 .host_command = SET_SECURITY_INFORMATION,
5225 .host_command_sequence = 0,
5226 .host_command_length = sizeof(struct security_info_params)
5227 };
5228 struct security_info_params *security =
James Ketrenosee8e3652005-09-14 09:47:29 -05005229 (struct security_info_params *)&cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06005230 int err;
5231 memset(security, 0, sizeof(*security));
5232
5233 /* If shared key AP authentication is turned on, then we need to
5234 * configure the firmware to try and use it.
5235 *
5236 * Actual data encryption/decryption is handled by the host. */
5237 security->auth_mode = auth_mode;
5238 security->unicast_using_group = unicast_using_group;
5239
5240 switch (security_level) {
5241 default:
5242 case SEC_LEVEL_0:
5243 security->allowed_ciphers = IPW_NONE_CIPHER;
5244 break;
5245 case SEC_LEVEL_1:
5246 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005247 IPW_WEP104_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005248 break;
5249 case SEC_LEVEL_2:
5250 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005251 IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005252 break;
5253 case SEC_LEVEL_2_CKIP:
5254 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005255 IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005256 break;
5257 case SEC_LEVEL_3:
5258 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005259 IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005260 break;
5261 }
5262
James Ketrenosee8e3652005-09-14 09:47:29 -05005263 IPW_DEBUG_HC
5264 ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
5265 security->auth_mode, security->allowed_ciphers, security_level);
James Ketrenos2c86c272005-03-23 17:32:29 -06005266
5267 security->replay_counters_number = 0;
5268
5269 if (!batch_mode) {
5270 err = ipw2100_disable_adapter(priv);
5271 if (err)
5272 return err;
5273 }
5274
5275 err = ipw2100_hw_send_command(priv, &cmd);
5276
5277 if (!batch_mode)
5278 ipw2100_enable_adapter(priv);
5279
5280 return err;
5281}
5282
James Ketrenosee8e3652005-09-14 09:47:29 -05005283static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power)
James Ketrenos2c86c272005-03-23 17:32:29 -06005284{
5285 struct host_command cmd = {
5286 .host_command = TX_POWER_INDEX,
5287 .host_command_sequence = 0,
5288 .host_command_length = 4
5289 };
5290 int err = 0;
Zhu Yi3173ca02006-01-24 13:49:01 +08005291 u32 tmp = tx_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06005292
Liu Hongf75459e2005-07-13 12:29:21 -05005293 if (tx_power != IPW_TX_POWER_DEFAULT)
Zhu Yi3173ca02006-01-24 13:49:01 +08005294 tmp = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 /
5295 (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
Liu Hongf75459e2005-07-13 12:29:21 -05005296
Zhu Yi3173ca02006-01-24 13:49:01 +08005297 cmd.host_command_parameters[0] = tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06005298
5299 if (priv->ieee->iw_mode == IW_MODE_ADHOC)
5300 err = ipw2100_hw_send_command(priv, &cmd);
5301 if (!err)
5302 priv->tx_power = tx_power;
5303
5304 return 0;
5305}
5306
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005307static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv,
5308 u32 interval, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005309{
5310 struct host_command cmd = {
5311 .host_command = BEACON_INTERVAL,
5312 .host_command_sequence = 0,
5313 .host_command_length = 4
5314 };
5315 int err;
5316
5317 cmd.host_command_parameters[0] = interval;
5318
5319 IPW_DEBUG_INFO("enter\n");
5320
5321 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
5322 if (!batch_mode) {
5323 err = ipw2100_disable_adapter(priv);
5324 if (err)
5325 return err;
5326 }
5327
5328 ipw2100_hw_send_command(priv, &cmd);
5329
5330 if (!batch_mode) {
5331 err = ipw2100_enable_adapter(priv);
5332 if (err)
5333 return err;
5334 }
5335 }
5336
5337 IPW_DEBUG_INFO("exit\n");
5338
5339 return 0;
5340}
5341
Hannes Edera3d1fd22008-12-26 00:14:41 -08005342static void ipw2100_queues_initialize(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005343{
5344 ipw2100_tx_initialize(priv);
5345 ipw2100_rx_initialize(priv);
5346 ipw2100_msg_initialize(priv);
5347}
5348
Hannes Edera3d1fd22008-12-26 00:14:41 -08005349static void ipw2100_queues_free(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005350{
5351 ipw2100_tx_free(priv);
5352 ipw2100_rx_free(priv);
5353 ipw2100_msg_free(priv);
5354}
5355
Hannes Edera3d1fd22008-12-26 00:14:41 -08005356static int ipw2100_queues_allocate(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005357{
5358 if (ipw2100_tx_allocate(priv) ||
James Ketrenosee8e3652005-09-14 09:47:29 -05005359 ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv))
James Ketrenos2c86c272005-03-23 17:32:29 -06005360 goto fail;
5361
5362 return 0;
5363
James Ketrenosee8e3652005-09-14 09:47:29 -05005364 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06005365 ipw2100_tx_free(priv);
5366 ipw2100_rx_free(priv);
5367 ipw2100_msg_free(priv);
5368 return -ENOMEM;
5369}
5370
5371#define IPW_PRIVACY_CAPABLE 0x0008
5372
5373static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags,
5374 int batch_mode)
5375{
5376 struct host_command cmd = {
5377 .host_command = WEP_FLAGS,
5378 .host_command_sequence = 0,
5379 .host_command_length = 4
5380 };
5381 int err;
5382
5383 cmd.host_command_parameters[0] = flags;
5384
5385 IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags);
5386
5387 if (!batch_mode) {
5388 err = ipw2100_disable_adapter(priv);
5389 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005390 printk(KERN_ERR DRV_NAME
5391 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005392 priv->net_dev->name, err);
5393 return err;
5394 }
5395 }
5396
5397 /* send cmd to firmware */
5398 err = ipw2100_hw_send_command(priv, &cmd);
5399
5400 if (!batch_mode)
5401 ipw2100_enable_adapter(priv);
5402
5403 return err;
5404}
5405
5406struct ipw2100_wep_key {
5407 u8 idx;
5408 u8 len;
5409 u8 key[13];
5410};
5411
5412/* Macros to ease up priting WEP keys */
5413#define WEP_FMT_64 "%02X%02X%02X%02X-%02X"
5414#define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X"
5415#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4]
5416#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]
5417
James Ketrenos2c86c272005-03-23 17:32:29 -06005418/**
5419 * Set a the wep key
5420 *
5421 * @priv: struct to work on
5422 * @idx: index of the key we want to set
5423 * @key: ptr to the key data to set
5424 * @len: length of the buffer at @key
5425 * @batch_mode: FIXME perform the operation in batch mode, not
5426 * disabling the device.
5427 *
5428 * @returns 0 if OK, < 0 errno code on error.
5429 *
5430 * Fill out a command structure with the new wep key, length an
5431 * index and send it down the wire.
5432 */
5433static int ipw2100_set_key(struct ipw2100_priv *priv,
5434 int idx, char *key, int len, int batch_mode)
5435{
5436 int keylen = len ? (len <= 5 ? 5 : 13) : 0;
5437 struct host_command cmd = {
5438 .host_command = WEP_KEY_INFO,
5439 .host_command_sequence = 0,
5440 .host_command_length = sizeof(struct ipw2100_wep_key),
5441 };
James Ketrenosee8e3652005-09-14 09:47:29 -05005442 struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06005443 int err;
5444
5445 IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005446 idx, keylen, len);
James Ketrenos2c86c272005-03-23 17:32:29 -06005447
5448 /* NOTE: We don't check cached values in case the firmware was reset
Adrian Bunk80f72282006-06-30 18:27:16 +02005449 * or some other problem is occurring. If the user is setting the key,
James Ketrenos2c86c272005-03-23 17:32:29 -06005450 * then we push the change */
5451
5452 wep_key->idx = idx;
5453 wep_key->len = keylen;
5454
5455 if (keylen) {
5456 memcpy(wep_key->key, key, len);
5457 memset(wep_key->key + len, 0, keylen - len);
5458 }
5459
5460 /* Will be optimized out on debug not being configured in */
5461 if (keylen == 0)
5462 IPW_DEBUG_WEP("%s: Clearing key %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005463 priv->net_dev->name, wep_key->idx);
James Ketrenos2c86c272005-03-23 17:32:29 -06005464 else if (keylen == 5)
5465 IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005466 priv->net_dev->name, wep_key->idx, wep_key->len,
5467 WEP_STR_64(wep_key->key));
James Ketrenos2c86c272005-03-23 17:32:29 -06005468 else
5469 IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128
James Ketrenosee8e3652005-09-14 09:47:29 -05005470 "\n",
5471 priv->net_dev->name, wep_key->idx, wep_key->len,
5472 WEP_STR_128(wep_key->key));
James Ketrenos2c86c272005-03-23 17:32:29 -06005473
5474 if (!batch_mode) {
5475 err = ipw2100_disable_adapter(priv);
5476 /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */
5477 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005478 printk(KERN_ERR DRV_NAME
5479 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005480 priv->net_dev->name, err);
5481 return err;
5482 }
5483 }
5484
5485 /* send cmd to firmware */
5486 err = ipw2100_hw_send_command(priv, &cmd);
5487
5488 if (!batch_mode) {
5489 int err2 = ipw2100_enable_adapter(priv);
5490 if (err == 0)
5491 err = err2;
5492 }
5493 return err;
5494}
5495
5496static int ipw2100_set_key_index(struct ipw2100_priv *priv,
5497 int idx, int batch_mode)
5498{
5499 struct host_command cmd = {
5500 .host_command = WEP_KEY_INDEX,
5501 .host_command_sequence = 0,
5502 .host_command_length = 4,
James Ketrenosee8e3652005-09-14 09:47:29 -05005503 .host_command_parameters = {idx},
James Ketrenos2c86c272005-03-23 17:32:29 -06005504 };
5505 int err;
5506
5507 IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx);
5508
5509 if (idx < 0 || idx > 3)
5510 return -EINVAL;
5511
5512 if (!batch_mode) {
5513 err = ipw2100_disable_adapter(priv);
5514 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005515 printk(KERN_ERR DRV_NAME
5516 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005517 priv->net_dev->name, err);
5518 return err;
5519 }
5520 }
5521
5522 /* send cmd to firmware */
5523 err = ipw2100_hw_send_command(priv, &cmd);
5524
5525 if (!batch_mode)
5526 ipw2100_enable_adapter(priv);
5527
5528 return err;
5529}
5530
James Ketrenosee8e3652005-09-14 09:47:29 -05005531static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005532{
5533 int i, err, auth_mode, sec_level, use_group;
5534
5535 if (!(priv->status & STATUS_RUNNING))
5536 return 0;
5537
5538 if (!batch_mode) {
5539 err = ipw2100_disable_adapter(priv);
5540 if (err)
5541 return err;
5542 }
5543
25b645b2005-07-12 15:45:30 -05005544 if (!priv->ieee->sec.enabled) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005545 err =
5546 ipw2100_set_security_information(priv, IPW_AUTH_OPEN,
5547 SEC_LEVEL_0, 0, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005548 } else {
5549 auth_mode = IPW_AUTH_OPEN;
Zhu Yicbbdd032006-01-24 13:48:53 +08005550 if (priv->ieee->sec.flags & SEC_AUTH_MODE) {
5551 if (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)
5552 auth_mode = IPW_AUTH_SHARED;
5553 else if (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)
5554 auth_mode = IPW_AUTH_LEAP_CISCO_ID;
5555 }
James Ketrenos2c86c272005-03-23 17:32:29 -06005556
5557 sec_level = SEC_LEVEL_0;
25b645b2005-07-12 15:45:30 -05005558 if (priv->ieee->sec.flags & SEC_LEVEL)
5559 sec_level = priv->ieee->sec.level;
James Ketrenos2c86c272005-03-23 17:32:29 -06005560
5561 use_group = 0;
25b645b2005-07-12 15:45:30 -05005562 if (priv->ieee->sec.flags & SEC_UNICAST_GROUP)
5563 use_group = priv->ieee->sec.unicast_uses_group;
James Ketrenos2c86c272005-03-23 17:32:29 -06005564
James Ketrenosee8e3652005-09-14 09:47:29 -05005565 err =
5566 ipw2100_set_security_information(priv, auth_mode, sec_level,
5567 use_group, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005568 }
5569
5570 if (err)
5571 goto exit;
5572
25b645b2005-07-12 15:45:30 -05005573 if (priv->ieee->sec.enabled) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005574 for (i = 0; i < 4; i++) {
25b645b2005-07-12 15:45:30 -05005575 if (!(priv->ieee->sec.flags & (1 << i))) {
5576 memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN);
5577 priv->ieee->sec.key_sizes[i] = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005578 } else {
5579 err = ipw2100_set_key(priv, i,
25b645b2005-07-12 15:45:30 -05005580 priv->ieee->sec.keys[i],
5581 priv->ieee->sec.
5582 key_sizes[i], 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005583 if (err)
5584 goto exit;
5585 }
5586 }
5587
John W. Linville274bfb82008-10-29 11:35:05 -04005588 ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005589 }
5590
5591 /* Always enable privacy so the Host can filter WEP packets if
5592 * encrypted data is sent up */
James Ketrenosee8e3652005-09-14 09:47:29 -05005593 err =
5594 ipw2100_set_wep_flags(priv,
25b645b2005-07-12 15:45:30 -05005595 priv->ieee->sec.
5596 enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005597 if (err)
5598 goto exit;
5599
5600 priv->status &= ~STATUS_SECURITY_UPDATED;
5601
James Ketrenosee8e3652005-09-14 09:47:29 -05005602 exit:
James Ketrenos2c86c272005-03-23 17:32:29 -06005603 if (!batch_mode)
5604 ipw2100_enable_adapter(priv);
5605
5606 return err;
5607}
5608
David Howellsc4028952006-11-22 14:57:56 +00005609static void ipw2100_security_work(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06005610{
David Howellsc4028952006-11-22 14:57:56 +00005611 struct ipw2100_priv *priv =
5612 container_of(work, struct ipw2100_priv, security_work.work);
5613
James Ketrenos2c86c272005-03-23 17:32:29 -06005614 /* If we happen to have reconnected before we get a chance to
5615 * process this, then update the security settings--which causes
5616 * a disassociation to occur */
5617 if (!(priv->status & STATUS_ASSOCIATED) &&
5618 priv->status & STATUS_SECURITY_UPDATED)
5619 ipw2100_configure_security(priv, 0);
5620}
5621
5622static void shim__set_security(struct net_device *dev,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005623 struct libipw_security *sec)
James Ketrenos2c86c272005-03-23 17:32:29 -06005624{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005625 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005626 int i, force_update = 0;
5627
Ingo Molnar752e3772006-02-28 07:20:54 +08005628 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005629 if (!(priv->status & STATUS_INITIALIZED))
5630 goto done;
5631
5632 for (i = 0; i < 4; i++) {
5633 if (sec->flags & (1 << i)) {
25b645b2005-07-12 15:45:30 -05005634 priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
James Ketrenos2c86c272005-03-23 17:32:29 -06005635 if (sec->key_sizes[i] == 0)
25b645b2005-07-12 15:45:30 -05005636 priv->ieee->sec.flags &= ~(1 << i);
James Ketrenos2c86c272005-03-23 17:32:29 -06005637 else
25b645b2005-07-12 15:45:30 -05005638 memcpy(priv->ieee->sec.keys[i], sec->keys[i],
James Ketrenos2c86c272005-03-23 17:32:29 -06005639 sec->key_sizes[i]);
Hong Liu054b08d2005-08-25 17:45:49 +08005640 if (sec->level == SEC_LEVEL_1) {
5641 priv->ieee->sec.flags |= (1 << i);
5642 priv->status |= STATUS_SECURITY_UPDATED;
5643 } else
5644 priv->ieee->sec.flags &= ~(1 << i);
James Ketrenos2c86c272005-03-23 17:32:29 -06005645 }
5646 }
5647
5648 if ((sec->flags & SEC_ACTIVE_KEY) &&
25b645b2005-07-12 15:45:30 -05005649 priv->ieee->sec.active_key != sec->active_key) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005650 if (sec->active_key <= 3) {
25b645b2005-07-12 15:45:30 -05005651 priv->ieee->sec.active_key = sec->active_key;
5652 priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
James Ketrenos2c86c272005-03-23 17:32:29 -06005653 } else
25b645b2005-07-12 15:45:30 -05005654 priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
James Ketrenos2c86c272005-03-23 17:32:29 -06005655
5656 priv->status |= STATUS_SECURITY_UPDATED;
5657 }
5658
5659 if ((sec->flags & SEC_AUTH_MODE) &&
25b645b2005-07-12 15:45:30 -05005660 (priv->ieee->sec.auth_mode != sec->auth_mode)) {
5661 priv->ieee->sec.auth_mode = sec->auth_mode;
5662 priv->ieee->sec.flags |= SEC_AUTH_MODE;
James Ketrenos2c86c272005-03-23 17:32:29 -06005663 priv->status |= STATUS_SECURITY_UPDATED;
5664 }
5665
25b645b2005-07-12 15:45:30 -05005666 if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
5667 priv->ieee->sec.flags |= SEC_ENABLED;
5668 priv->ieee->sec.enabled = sec->enabled;
James Ketrenos2c86c272005-03-23 17:32:29 -06005669 priv->status |= STATUS_SECURITY_UPDATED;
5670 force_update = 1;
5671 }
5672
25b645b2005-07-12 15:45:30 -05005673 if (sec->flags & SEC_ENCRYPT)
5674 priv->ieee->sec.encrypt = sec->encrypt;
5675
5676 if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
5677 priv->ieee->sec.level = sec->level;
5678 priv->ieee->sec.flags |= SEC_LEVEL;
James Ketrenos2c86c272005-03-23 17:32:29 -06005679 priv->status |= STATUS_SECURITY_UPDATED;
5680 }
5681
5682 IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n",
25b645b2005-07-12 15:45:30 -05005683 priv->ieee->sec.flags & (1 << 8) ? '1' : '0',
5684 priv->ieee->sec.flags & (1 << 7) ? '1' : '0',
5685 priv->ieee->sec.flags & (1 << 6) ? '1' : '0',
5686 priv->ieee->sec.flags & (1 << 5) ? '1' : '0',
5687 priv->ieee->sec.flags & (1 << 4) ? '1' : '0',
5688 priv->ieee->sec.flags & (1 << 3) ? '1' : '0',
5689 priv->ieee->sec.flags & (1 << 2) ? '1' : '0',
5690 priv->ieee->sec.flags & (1 << 1) ? '1' : '0',
5691 priv->ieee->sec.flags & (1 << 0) ? '1' : '0');
James Ketrenos2c86c272005-03-23 17:32:29 -06005692
5693/* As a temporary work around to enable WPA until we figure out why
5694 * wpa_supplicant toggles the security capability of the driver, which
5695 * forces a disassocation with force_update...
5696 *
5697 * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/
5698 if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
5699 ipw2100_configure_security(priv, 0);
James Ketrenosee8e3652005-09-14 09:47:29 -05005700 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08005701 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005702}
5703
5704static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
5705{
5706 int err;
5707 int batch_mode = 1;
5708 u8 *bssid;
5709
5710 IPW_DEBUG_INFO("enter\n");
5711
5712 err = ipw2100_disable_adapter(priv);
5713 if (err)
5714 return err;
5715#ifdef CONFIG_IPW2100_MONITOR
5716 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
5717 err = ipw2100_set_channel(priv, priv->channel, batch_mode);
5718 if (err)
5719 return err;
5720
5721 IPW_DEBUG_INFO("exit\n");
5722
5723 return 0;
5724 }
James Ketrenosee8e3652005-09-14 09:47:29 -05005725#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06005726
5727 err = ipw2100_read_mac_address(priv);
5728 if (err)
5729 return -EIO;
5730
5731 err = ipw2100_set_mac_address(priv, batch_mode);
5732 if (err)
5733 return err;
5734
5735 err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode);
5736 if (err)
5737 return err;
5738
5739 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
5740 err = ipw2100_set_channel(priv, priv->channel, batch_mode);
5741 if (err)
5742 return err;
5743 }
5744
James Ketrenosee8e3652005-09-14 09:47:29 -05005745 err = ipw2100_system_config(priv, batch_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06005746 if (err)
5747 return err;
5748
5749 err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode);
5750 if (err)
5751 return err;
5752
5753 /* Default to power mode OFF */
5754 err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
5755 if (err)
5756 return err;
5757
5758 err = ipw2100_set_rts_threshold(priv, priv->rts_threshold);
5759 if (err)
5760 return err;
5761
5762 if (priv->config & CFG_STATIC_BSSID)
5763 bssid = priv->bssid;
5764 else
5765 bssid = NULL;
5766 err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode);
5767 if (err)
5768 return err;
5769
5770 if (priv->config & CFG_STATIC_ESSID)
5771 err = ipw2100_set_essid(priv, priv->essid, priv->essid_len,
5772 batch_mode);
5773 else
5774 err = ipw2100_set_essid(priv, NULL, 0, batch_mode);
5775 if (err)
5776 return err;
5777
5778 err = ipw2100_configure_security(priv, batch_mode);
5779 if (err)
5780 return err;
5781
5782 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005783 err =
5784 ipw2100_set_ibss_beacon_interval(priv,
5785 priv->beacon_interval,
5786 batch_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06005787 if (err)
5788 return err;
5789
5790 err = ipw2100_set_tx_power(priv, priv->tx_power);
5791 if (err)
5792 return err;
5793 }
5794
5795 /*
James Ketrenosee8e3652005-09-14 09:47:29 -05005796 err = ipw2100_set_fragmentation_threshold(
5797 priv, priv->frag_threshold, batch_mode);
5798 if (err)
5799 return err;
5800 */
James Ketrenos2c86c272005-03-23 17:32:29 -06005801
5802 IPW_DEBUG_INFO("exit\n");
5803
5804 return 0;
5805}
5806
James Ketrenos2c86c272005-03-23 17:32:29 -06005807/*************************************************************************
5808 *
5809 * EXTERNALLY CALLED METHODS
5810 *
5811 *************************************************************************/
5812
5813/* This method is called by the network layer -- not to be confused with
5814 * ipw2100_set_mac_address() declared above called by this driver (and this
5815 * method as well) to talk to the firmware */
5816static int ipw2100_set_address(struct net_device *dev, void *p)
5817{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005818 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005819 struct sockaddr *addr = p;
5820 int err = 0;
5821
5822 if (!is_valid_ether_addr(addr->sa_data))
5823 return -EADDRNOTAVAIL;
5824
Ingo Molnar752e3772006-02-28 07:20:54 +08005825 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005826
5827 priv->config |= CFG_CUSTOM_MAC;
5828 memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
5829
5830 err = ipw2100_set_mac_address(priv, 0);
5831 if (err)
5832 goto done;
5833
5834 priv->reset_backoff = 0;
Ingo Molnar752e3772006-02-28 07:20:54 +08005835 mutex_unlock(&priv->action_mutex);
David Howellsc4028952006-11-22 14:57:56 +00005836 ipw2100_reset_adapter(&priv->reset_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06005837 return 0;
5838
James Ketrenosee8e3652005-09-14 09:47:29 -05005839 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08005840 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005841 return err;
5842}
5843
5844static int ipw2100_open(struct net_device *dev)
5845{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005846 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005847 unsigned long flags;
5848 IPW_DEBUG_INFO("dev->open\n");
5849
5850 spin_lock_irqsave(&priv->low_lock, flags);
Jiri Benc3ce329c2005-08-25 20:07:01 -04005851 if (priv->status & STATUS_ASSOCIATED) {
5852 netif_carrier_on(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005853 netif_start_queue(dev);
Jiri Benc3ce329c2005-08-25 20:07:01 -04005854 }
James Ketrenos2c86c272005-03-23 17:32:29 -06005855 spin_unlock_irqrestore(&priv->low_lock, flags);
5856
5857 return 0;
5858}
5859
5860static int ipw2100_close(struct net_device *dev)
5861{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005862 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005863 unsigned long flags;
5864 struct list_head *element;
5865 struct ipw2100_tx_packet *packet;
5866
5867 IPW_DEBUG_INFO("enter\n");
5868
5869 spin_lock_irqsave(&priv->low_lock, flags);
5870
5871 if (priv->status & STATUS_ASSOCIATED)
5872 netif_carrier_off(dev);
5873 netif_stop_queue(dev);
5874
5875 /* Flush the TX queue ... */
5876 while (!list_empty(&priv->tx_pend_list)) {
5877 element = priv->tx_pend_list.next;
James Ketrenosee8e3652005-09-14 09:47:29 -05005878 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06005879
5880 list_del(element);
5881 DEC_STAT(&priv->tx_pend_stat);
5882
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005883 libipw_txb_free(packet->info.d_struct.txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06005884 packet->info.d_struct.txb = NULL;
5885
5886 list_add_tail(element, &priv->tx_free_list);
5887 INC_STAT(&priv->tx_free_stat);
5888 }
5889 spin_unlock_irqrestore(&priv->low_lock, flags);
5890
5891 IPW_DEBUG_INFO("exit\n");
5892
5893 return 0;
5894}
5895
James Ketrenos2c86c272005-03-23 17:32:29 -06005896/*
5897 * TODO: Fix this function... its just wrong
5898 */
5899static void ipw2100_tx_timeout(struct net_device *dev)
5900{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005901 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005902
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00005903 dev->stats.tx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06005904
5905#ifdef CONFIG_IPW2100_MONITOR
5906 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
5907 return;
5908#endif
5909
5910 IPW_DEBUG_INFO("%s: TX timed out. Scheduling firmware restart.\n",
5911 dev->name);
5912 schedule_reset(priv);
5913}
5914
James Ketrenosee8e3652005-09-14 09:47:29 -05005915static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value)
5916{
James Ketrenos82328352005-08-24 22:33:31 -05005917 /* This is called when wpa_supplicant loads and closes the driver
5918 * interface. */
5919 priv->ieee->wpa_enabled = value;
5920 return 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005921}
5922
James Ketrenosee8e3652005-09-14 09:47:29 -05005923static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value)
5924{
James Ketrenos2c86c272005-03-23 17:32:29 -06005925
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005926 struct libipw_device *ieee = priv->ieee;
5927 struct libipw_security sec = {
James Ketrenos2c86c272005-03-23 17:32:29 -06005928 .flags = SEC_AUTH_MODE,
5929 };
5930 int ret = 0;
5931
James Ketrenos82328352005-08-24 22:33:31 -05005932 if (value & IW_AUTH_ALG_SHARED_KEY) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005933 sec.auth_mode = WLAN_AUTH_SHARED_KEY;
5934 ieee->open_wep = 0;
James Ketrenos82328352005-08-24 22:33:31 -05005935 } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005936 sec.auth_mode = WLAN_AUTH_OPEN;
5937 ieee->open_wep = 1;
Zhu Yicbbdd032006-01-24 13:48:53 +08005938 } else if (value & IW_AUTH_ALG_LEAP) {
5939 sec.auth_mode = WLAN_AUTH_LEAP;
5940 ieee->open_wep = 1;
James Ketrenos82328352005-08-24 22:33:31 -05005941 } else
5942 return -EINVAL;
James Ketrenos2c86c272005-03-23 17:32:29 -06005943
5944 if (ieee->set_security)
5945 ieee->set_security(ieee->dev, &sec);
5946 else
5947 ret = -EOPNOTSUPP;
5948
5949 return ret;
5950}
5951
Adrian Bunk3c398b82006-01-21 01:36:36 +01005952static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
5953 char *wpa_ie, int wpa_ie_len)
James Ketrenosee8e3652005-09-14 09:47:29 -05005954{
James Ketrenos2c86c272005-03-23 17:32:29 -06005955
5956 struct ipw2100_wpa_assoc_frame frame;
5957
5958 frame.fixed_ie_mask = 0;
5959
5960 /* copy WPA IE */
5961 memcpy(frame.var_ie, wpa_ie, wpa_ie_len);
5962 frame.var_ie_len = wpa_ie_len;
5963
5964 /* make sure WPA is enabled */
5965 ipw2100_wpa_enable(priv, 1);
5966 ipw2100_set_wpa_ie(priv, &frame, 0);
5967}
5968
James Ketrenos2c86c272005-03-23 17:32:29 -06005969static void ipw_ethtool_get_drvinfo(struct net_device *dev,
5970 struct ethtool_drvinfo *info)
5971{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005972 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005973 char fw_ver[64], ucode_ver[64];
5974
Rick Jones1f80c232011-11-15 10:40:49 -08005975 strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
5976 strlcpy(info->version, DRV_VERSION, sizeof(info->version));
James Ketrenos2c86c272005-03-23 17:32:29 -06005977
5978 ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver));
5979 ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver));
5980
5981 snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s",
5982 fw_ver, priv->eeprom_version, ucode_ver);
5983
Rick Jones1f80c232011-11-15 10:40:49 -08005984 strlcpy(info->bus_info, pci_name(priv->pci_dev),
5985 sizeof(info->bus_info));
James Ketrenos2c86c272005-03-23 17:32:29 -06005986}
5987
5988static u32 ipw2100_ethtool_get_link(struct net_device *dev)
5989{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005990 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05005991 return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005992}
5993
Jeff Garzik7282d492006-09-13 14:30:00 -04005994static const struct ethtool_ops ipw2100_ethtool_ops = {
James Ketrenosee8e3652005-09-14 09:47:29 -05005995 .get_link = ipw2100_ethtool_get_link,
5996 .get_drvinfo = ipw_ethtool_get_drvinfo,
James Ketrenos2c86c272005-03-23 17:32:29 -06005997};
5998
David Howellsc4028952006-11-22 14:57:56 +00005999static void ipw2100_hang_check(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06006000{
David Howellsc4028952006-11-22 14:57:56 +00006001 struct ipw2100_priv *priv =
6002 container_of(work, struct ipw2100_priv, hang_check.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06006003 unsigned long flags;
6004 u32 rtc = 0xa5a5a5a5;
6005 u32 len = sizeof(rtc);
6006 int restart = 0;
6007
6008 spin_lock_irqsave(&priv->low_lock, flags);
6009
6010 if (priv->fatal_error != 0) {
6011 /* If fatal_error is set then we need to restart */
6012 IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n",
6013 priv->net_dev->name);
6014
6015 restart = 1;
6016 } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) ||
6017 (rtc == priv->last_rtc)) {
6018 /* Check if firmware is hung */
6019 IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n",
6020 priv->net_dev->name);
6021
6022 restart = 1;
6023 }
6024
6025 if (restart) {
6026 /* Kill timer */
6027 priv->stop_hang_check = 1;
6028 priv->hangs++;
6029
6030 /* Restart the NIC */
6031 schedule_reset(priv);
6032 }
6033
6034 priv->last_rtc = rtc;
6035
6036 if (!priv->stop_hang_check)
Tejun Heobcb6d912011-01-26 12:12:50 +01006037 schedule_delayed_work(&priv->hang_check, HZ / 2);
James Ketrenos2c86c272005-03-23 17:32:29 -06006038
6039 spin_unlock_irqrestore(&priv->low_lock, flags);
6040}
6041
David Howellsc4028952006-11-22 14:57:56 +00006042static void ipw2100_rf_kill(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06006043{
David Howellsc4028952006-11-22 14:57:56 +00006044 struct ipw2100_priv *priv =
6045 container_of(work, struct ipw2100_priv, rf_kill.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06006046 unsigned long flags;
6047
6048 spin_lock_irqsave(&priv->low_lock, flags);
6049
6050 if (rf_kill_active(priv)) {
6051 IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
6052 if (!priv->stop_rf_kill)
Tejun Heobcb6d912011-01-26 12:12:50 +01006053 schedule_delayed_work(&priv->rf_kill,
6054 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06006055 goto exit_unlock;
6056 }
6057
6058 /* RF Kill is now disabled, so bring the device back up */
6059
6060 if (!(priv->status & STATUS_RF_KILL_MASK)) {
6061 IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
6062 "device\n");
6063 schedule_reset(priv);
6064 } else
6065 IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
6066 "enabled\n");
6067
James Ketrenosee8e3652005-09-14 09:47:29 -05006068 exit_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -06006069 spin_unlock_irqrestore(&priv->low_lock, flags);
6070}
6071
6072static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
6073
Stephen Hemminger3e47fce2009-03-20 19:36:40 +00006074static const struct net_device_ops ipw2100_netdev_ops = {
6075 .ndo_open = ipw2100_open,
6076 .ndo_stop = ipw2100_close,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006077 .ndo_start_xmit = libipw_xmit,
6078 .ndo_change_mtu = libipw_change_mtu,
Stephen Hemminger3e47fce2009-03-20 19:36:40 +00006079 .ndo_init = ipw2100_net_init,
6080 .ndo_tx_timeout = ipw2100_tx_timeout,
6081 .ndo_set_mac_address = ipw2100_set_address,
6082 .ndo_validate_addr = eth_validate_addr,
6083};
6084
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006085/* Look into using netdev destructor to shutdown libipw? */
James Ketrenos2c86c272005-03-23 17:32:29 -06006086
James Ketrenosee8e3652005-09-14 09:47:29 -05006087static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
6088 void __iomem * base_addr,
6089 unsigned long mem_start,
6090 unsigned long mem_len)
James Ketrenos2c86c272005-03-23 17:32:29 -06006091{
6092 struct ipw2100_priv *priv;
6093 struct net_device *dev;
6094
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006095 dev = alloc_libipw(sizeof(struct ipw2100_priv), 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006096 if (!dev)
6097 return NULL;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006098 priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006099 priv->ieee = netdev_priv(dev);
6100 priv->pci_dev = pci_dev;
6101 priv->net_dev = dev;
6102
6103 priv->ieee->hard_start_xmit = ipw2100_tx;
6104 priv->ieee->set_security = shim__set_security;
6105
James Ketrenos82328352005-08-24 22:33:31 -05006106 priv->ieee->perfect_rssi = -20;
6107 priv->ieee->worst_rssi = -85;
6108
Stephen Hemminger3e47fce2009-03-20 19:36:40 +00006109 dev->netdev_ops = &ipw2100_netdev_ops;
James Ketrenos2c86c272005-03-23 17:32:29 -06006110 dev->ethtool_ops = &ipw2100_ethtool_ops;
James Ketrenos2c86c272005-03-23 17:32:29 -06006111 dev->wireless_handlers = &ipw2100_wx_handler_def;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006112 priv->wireless_data.libipw = priv->ieee;
James Ketrenoseaf8f532005-11-12 12:50:12 -06006113 dev->wireless_data = &priv->wireless_data;
James Ketrenosee8e3652005-09-14 09:47:29 -05006114 dev->watchdog_timeo = 3 * HZ;
James Ketrenos2c86c272005-03-23 17:32:29 -06006115 dev->irq = 0;
6116
6117 dev->base_addr = (unsigned long)base_addr;
6118 dev->mem_start = mem_start;
6119 dev->mem_end = dev->mem_start + mem_len - 1;
6120
6121 /* NOTE: We don't use the wireless_handlers hook
6122 * in dev as the system will start throwing WX requests
6123 * to us before we're actually initialized and it just
6124 * ends up causing problems. So, we just handle
6125 * the WX extensions through the ipw2100_ioctl interface */
6126
Jean Delvarec03983a2007-10-19 23:22:55 +02006127 /* memset() puts everything to 0, so we only have explicitly set
James Ketrenos2c86c272005-03-23 17:32:29 -06006128 * those values that need to be something else */
6129
6130 /* If power management is turned on, default to AUTO mode */
6131 priv->power_mode = IPW_POWER_AUTO;
6132
James Ketrenos82328352005-08-24 22:33:31 -05006133#ifdef CONFIG_IPW2100_MONITOR
6134 priv->config |= CFG_CRC_CHECK;
6135#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06006136 priv->ieee->wpa_enabled = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06006137 priv->ieee->drop_unencrypted = 0;
6138 priv->ieee->privacy_invoked = 0;
6139 priv->ieee->ieee802_1x = 1;
James Ketrenos2c86c272005-03-23 17:32:29 -06006140
6141 /* Set module parameters */
Reinette Chatre21f8a732009-08-18 10:25:05 -07006142 switch (network_mode) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006143 case 1:
6144 priv->ieee->iw_mode = IW_MODE_ADHOC;
6145 break;
6146#ifdef CONFIG_IPW2100_MONITOR
6147 case 2:
6148 priv->ieee->iw_mode = IW_MODE_MONITOR;
6149 break;
6150#endif
6151 default:
6152 case 0:
6153 priv->ieee->iw_mode = IW_MODE_INFRA;
6154 break;
6155 }
6156
6157 if (disable == 1)
6158 priv->status |= STATUS_RF_KILL_SW;
6159
6160 if (channel != 0 &&
James Ketrenosee8e3652005-09-14 09:47:29 -05006161 ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006162 priv->config |= CFG_STATIC_CHANNEL;
6163 priv->channel = channel;
6164 }
6165
6166 if (associate)
6167 priv->config |= CFG_ASSOCIATE;
6168
6169 priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
6170 priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
6171 priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
6172 priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED;
6173 priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED;
6174 priv->tx_power = IPW_TX_POWER_DEFAULT;
6175 priv->tx_rates = DEFAULT_TX_RATES;
6176
6177 strcpy(priv->nick, "ipw2100");
6178
6179 spin_lock_init(&priv->low_lock);
Ingo Molnar752e3772006-02-28 07:20:54 +08006180 mutex_init(&priv->action_mutex);
6181 mutex_init(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006182
6183 init_waitqueue_head(&priv->wait_command_queue);
6184
6185 netif_carrier_off(dev);
6186
6187 INIT_LIST_HEAD(&priv->msg_free_list);
6188 INIT_LIST_HEAD(&priv->msg_pend_list);
6189 INIT_STAT(&priv->msg_free_stat);
6190 INIT_STAT(&priv->msg_pend_stat);
6191
6192 INIT_LIST_HEAD(&priv->tx_free_list);
6193 INIT_LIST_HEAD(&priv->tx_pend_list);
6194 INIT_STAT(&priv->tx_free_stat);
6195 INIT_STAT(&priv->tx_pend_stat);
6196
6197 INIT_LIST_HEAD(&priv->fw_pend_list);
6198 INIT_STAT(&priv->fw_pend_stat);
6199
David Howellsc4028952006-11-22 14:57:56 +00006200 INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter);
6201 INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work);
6202 INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
6203 INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
6204 INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
Dan Williamsd20c6782007-10-10 12:28:07 -04006205 INIT_WORK(&priv->scan_event_now, ipw2100_scan_event_now);
6206 INIT_DELAYED_WORK(&priv->scan_event_later, ipw2100_scan_event_later);
James Ketrenos2c86c272005-03-23 17:32:29 -06006207
6208 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
6209 ipw2100_irq_tasklet, (unsigned long)priv);
6210
6211 /* NOTE: We do not start the deferred work for status checks yet */
6212 priv->stop_rf_kill = 1;
6213 priv->stop_hang_check = 1;
6214
6215 return dev;
6216}
6217
James Ketrenos2c86c272005-03-23 17:32:29 -06006218static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
6219 const struct pci_device_id *ent)
6220{
6221 unsigned long mem_start, mem_len, mem_flags;
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01006222 void __iomem *base_addr = NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06006223 struct net_device *dev = NULL;
6224 struct ipw2100_priv *priv = NULL;
6225 int err = 0;
6226 int registered = 0;
6227 u32 val;
6228
6229 IPW_DEBUG_INFO("enter\n");
6230
6231 mem_start = pci_resource_start(pci_dev, 0);
6232 mem_len = pci_resource_len(pci_dev, 0);
6233 mem_flags = pci_resource_flags(pci_dev, 0);
6234
6235 if ((mem_flags & IORESOURCE_MEM) != IORESOURCE_MEM) {
6236 IPW_DEBUG_INFO("weird - resource type is not memory\n");
6237 err = -ENODEV;
6238 goto fail;
6239 }
6240
6241 base_addr = ioremap_nocache(mem_start, mem_len);
6242 if (!base_addr) {
6243 printk(KERN_WARNING DRV_NAME
6244 "Error calling ioremap_nocache.\n");
6245 err = -EIO;
6246 goto fail;
6247 }
6248
6249 /* allocate and initialize our net_device */
6250 dev = ipw2100_alloc_device(pci_dev, base_addr, mem_start, mem_len);
6251 if (!dev) {
6252 printk(KERN_WARNING DRV_NAME
6253 "Error calling ipw2100_alloc_device.\n");
6254 err = -ENOMEM;
6255 goto fail;
6256 }
6257
6258 /* set up PCI mappings for device */
6259 err = pci_enable_device(pci_dev);
6260 if (err) {
6261 printk(KERN_WARNING DRV_NAME
6262 "Error calling pci_enable_device.\n");
6263 return err;
6264 }
6265
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006266 priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006267
6268 pci_set_master(pci_dev);
6269 pci_set_drvdata(pci_dev, priv);
6270
Yang Hongyang284901a2009-04-06 19:01:15 -07006271 err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
James Ketrenos2c86c272005-03-23 17:32:29 -06006272 if (err) {
6273 printk(KERN_WARNING DRV_NAME
6274 "Error calling pci_set_dma_mask.\n");
6275 pci_disable_device(pci_dev);
6276 return err;
6277 }
6278
6279 err = pci_request_regions(pci_dev, DRV_NAME);
6280 if (err) {
6281 printk(KERN_WARNING DRV_NAME
6282 "Error calling pci_request_regions.\n");
6283 pci_disable_device(pci_dev);
6284 return err;
6285 }
6286
James Ketrenosee8e3652005-09-14 09:47:29 -05006287 /* We disable the RETRY_TIMEOUT register (0x41) to keep
James Ketrenos2c86c272005-03-23 17:32:29 -06006288 * PCI Tx retries from interfering with C3 CPU state */
6289 pci_read_config_dword(pci_dev, 0x40, &val);
6290 if ((val & 0x0000ff00) != 0)
6291 pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
6292
Pavel Machek8724a112005-06-20 14:28:43 -07006293 pci_set_power_state(pci_dev, PCI_D0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006294
6295 if (!ipw2100_hw_is_adapter_in_system(dev)) {
6296 printk(KERN_WARNING DRV_NAME
6297 "Device not found via register read.\n");
6298 err = -ENODEV;
6299 goto fail;
6300 }
6301
6302 SET_NETDEV_DEV(dev, &pci_dev->dev);
6303
6304 /* Force interrupts to be shut off on the device */
6305 priv->status |= STATUS_INT_ENABLED;
6306 ipw2100_disable_interrupts(priv);
6307
6308 /* Allocate and initialize the Tx/Rx queues and lists */
6309 if (ipw2100_queues_allocate(priv)) {
6310 printk(KERN_WARNING DRV_NAME
Zhu Yi90c009a2006-12-05 14:41:32 +08006311 "Error calling ipw2100_queues_allocate.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06006312 err = -ENOMEM;
6313 goto fail;
6314 }
6315 ipw2100_queues_initialize(priv);
6316
6317 err = request_irq(pci_dev->irq,
Thomas Gleixner1fb9df52006-07-01 19:29:39 -07006318 ipw2100_interrupt, IRQF_SHARED, dev->name, priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006319 if (err) {
6320 printk(KERN_WARNING DRV_NAME
James Ketrenosee8e3652005-09-14 09:47:29 -05006321 "Error calling request_irq: %d.\n", pci_dev->irq);
James Ketrenos2c86c272005-03-23 17:32:29 -06006322 goto fail;
6323 }
6324 dev->irq = pci_dev->irq;
6325
6326 IPW_DEBUG_INFO("Attempting to register device...\n");
6327
James Ketrenos2c86c272005-03-23 17:32:29 -06006328 printk(KERN_INFO DRV_NAME
6329 ": Detected Intel PRO/Wireless 2100 Network Connection\n");
6330
6331 /* Bring up the interface. Pre 0.46, after we registered the
6332 * network device we would call ipw2100_up. This introduced a race
6333 * condition with newer hotplug configurations (network was coming
6334 * up and making calls before the device was initialized).
6335 *
6336 * If we called ipw2100_up before we registered the device, then the
6337 * device name wasn't registered. So, we instead use the net_dev->init
6338 * member to call a function that then just turns and calls ipw2100_up.
6339 * net_dev->init is called after name allocation but before the
6340 * notifier chain is called */
James Ketrenos2c86c272005-03-23 17:32:29 -06006341 err = register_netdev(dev);
6342 if (err) {
6343 printk(KERN_WARNING DRV_NAME
6344 "Error calling register_netdev.\n");
Zhu Yiefbd8092006-08-21 11:38:52 +08006345 goto fail;
James Ketrenos2c86c272005-03-23 17:32:29 -06006346 }
Stanislaw Gruszka7cabafc2011-09-14 16:47:50 +02006347 registered = 1;
6348
6349 err = ipw2100_wdev_init(dev);
6350 if (err)
6351 goto fail;
Zhu Yiefbd8092006-08-21 11:38:52 +08006352
6353 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006354
6355 IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
6356
6357 /* perform this after register_netdev so that dev->name is set */
Jeff Garzikde897882006-10-01 07:31:09 -04006358 err = sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
6359 if (err)
6360 goto fail_unlock;
James Ketrenos2c86c272005-03-23 17:32:29 -06006361
6362 /* If the RF Kill switch is disabled, go ahead and complete the
6363 * startup sequence */
6364 if (!(priv->status & STATUS_RF_KILL_MASK)) {
6365 /* Enable the adapter - sends HOST_COMPLETE */
6366 if (ipw2100_enable_adapter(priv)) {
6367 printk(KERN_WARNING DRV_NAME
6368 ": %s: failed in call to enable adapter.\n",
6369 priv->net_dev->name);
6370 ipw2100_hw_stop_adapter(priv);
6371 err = -EIO;
6372 goto fail_unlock;
6373 }
6374
6375 /* Start a scan . . . */
6376 ipw2100_set_scan_options(priv);
6377 ipw2100_start_scan(priv);
6378 }
6379
6380 IPW_DEBUG_INFO("exit\n");
6381
6382 priv->status |= STATUS_INITIALIZED;
6383
Ingo Molnar752e3772006-02-28 07:20:54 +08006384 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006385
6386 return 0;
6387
James Ketrenosee8e3652005-09-14 09:47:29 -05006388 fail_unlock:
Ingo Molnar752e3772006-02-28 07:20:54 +08006389 mutex_unlock(&priv->action_mutex);
Stanislaw Gruszka7cabafc2011-09-14 16:47:50 +02006390 wiphy_unregister(priv->ieee->wdev.wiphy);
6391 kfree(priv->ieee->bg_band.channels);
James Ketrenosee8e3652005-09-14 09:47:29 -05006392 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06006393 if (dev) {
John W. Linville143d40f2009-11-06 12:58:20 -05006394 if (registered)
James Ketrenos2c86c272005-03-23 17:32:29 -06006395 unregister_netdev(dev);
6396
6397 ipw2100_hw_stop_adapter(priv);
6398
6399 ipw2100_disable_interrupts(priv);
6400
6401 if (dev->irq)
6402 free_irq(dev->irq, priv);
6403
Tejun Heobcb6d912011-01-26 12:12:50 +01006404 ipw2100_kill_works(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006405
6406 /* These are safe to call even if they weren't allocated */
6407 ipw2100_queues_free(priv);
James Ketrenosee8e3652005-09-14 09:47:29 -05006408 sysfs_remove_group(&pci_dev->dev.kobj,
6409 &ipw2100_attribute_group);
James Ketrenos2c86c272005-03-23 17:32:29 -06006410
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006411 free_libipw(dev, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006412 pci_set_drvdata(pci_dev, NULL);
6413 }
6414
6415 if (base_addr)
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01006416 iounmap(base_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06006417
6418 pci_release_regions(pci_dev);
6419 pci_disable_device(pci_dev);
6420
6421 return err;
6422}
6423
6424static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
6425{
6426 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6427 struct net_device *dev;
6428
6429 if (priv) {
Ingo Molnar752e3772006-02-28 07:20:54 +08006430 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006431
6432 priv->status &= ~STATUS_INITIALIZED;
6433
6434 dev = priv->net_dev;
James Ketrenosee8e3652005-09-14 09:47:29 -05006435 sysfs_remove_group(&pci_dev->dev.kobj,
6436 &ipw2100_attribute_group);
James Ketrenos2c86c272005-03-23 17:32:29 -06006437
6438#ifdef CONFIG_PM
6439 if (ipw2100_firmware.version)
6440 ipw2100_release_firmware(priv, &ipw2100_firmware);
6441#endif
6442 /* Take down the hardware */
6443 ipw2100_down(priv);
6444
Ingo Molnar752e3772006-02-28 07:20:54 +08006445 /* Release the mutex so that the network subsystem can
James Ketrenos2c86c272005-03-23 17:32:29 -06006446 * complete any needed calls into the driver... */
Ingo Molnar752e3772006-02-28 07:20:54 +08006447 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006448
6449 /* Unregister the device first - this results in close()
6450 * being called if the device is open. If we free storage
6451 * first, then close() will crash. */
6452 unregister_netdev(dev);
6453
Tejun Heobcb6d912011-01-26 12:12:50 +01006454 ipw2100_kill_works(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006455
6456 ipw2100_queues_free(priv);
6457
6458 /* Free potential debugging firmware snapshot */
6459 ipw2100_snapshot_free(priv);
6460
6461 if (dev->irq)
6462 free_irq(dev->irq, priv);
6463
6464 if (dev->base_addr)
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01006465 iounmap((void __iomem *)dev->base_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06006466
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006467 /* wiphy_unregister needs to be here, before free_libipw */
Matthew Garrettc26409a2009-11-11 14:36:30 -05006468 wiphy_unregister(priv->ieee->wdev.wiphy);
6469 kfree(priv->ieee->bg_band.channels);
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006470 free_libipw(dev, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006471 }
6472
6473 pci_release_regions(pci_dev);
6474 pci_disable_device(pci_dev);
6475
6476 IPW_DEBUG_INFO("exit\n");
6477}
6478
James Ketrenos2c86c272005-03-23 17:32:29 -06006479#ifdef CONFIG_PM
James Ketrenos2c86c272005-03-23 17:32:29 -06006480static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state)
James Ketrenos2c86c272005-03-23 17:32:29 -06006481{
6482 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6483 struct net_device *dev = priv->net_dev;
6484
James Ketrenosee8e3652005-09-14 09:47:29 -05006485 IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06006486
Ingo Molnar752e3772006-02-28 07:20:54 +08006487 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006488 if (priv->status & STATUS_INITIALIZED) {
6489 /* Take down the device; powers it off, etc. */
6490 ipw2100_down(priv);
6491 }
6492
6493 /* Remove the PRESENT state of the device */
6494 netif_device_detach(dev);
6495
James Ketrenos2c86c272005-03-23 17:32:29 -06006496 pci_save_state(pci_dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05006497 pci_disable_device(pci_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006498 pci_set_power_state(pci_dev, PCI_D3hot);
James Ketrenos2c86c272005-03-23 17:32:29 -06006499
Dan Williamsc3d72b92009-02-11 13:26:06 -05006500 priv->suspend_at = get_seconds();
6501
Ingo Molnar752e3772006-02-28 07:20:54 +08006502 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006503
6504 return 0;
6505}
6506
6507static int ipw2100_resume(struct pci_dev *pci_dev)
6508{
6509 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6510 struct net_device *dev = priv->net_dev;
John W. Linville02e0e5e2006-11-07 20:53:48 -05006511 int err;
James Ketrenos2c86c272005-03-23 17:32:29 -06006512 u32 val;
6513
6514 if (IPW2100_PM_DISABLED)
6515 return 0;
6516
Ingo Molnar752e3772006-02-28 07:20:54 +08006517 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006518
James Ketrenosee8e3652005-09-14 09:47:29 -05006519 IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06006520
James Ketrenos2c86c272005-03-23 17:32:29 -06006521 pci_set_power_state(pci_dev, PCI_D0);
John W. Linville02e0e5e2006-11-07 20:53:48 -05006522 err = pci_enable_device(pci_dev);
6523 if (err) {
6524 printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
6525 dev->name);
Julia Lawall80c42af2008-07-21 09:58:11 +02006526 mutex_unlock(&priv->action_mutex);
John W. Linville02e0e5e2006-11-07 20:53:48 -05006527 return err;
6528 }
James Ketrenos2c86c272005-03-23 17:32:29 -06006529 pci_restore_state(pci_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006530
6531 /*
6532 * Suspend/Resume resets the PCI configuration space, so we have to
6533 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
6534 * from interfering with C3 CPU state. pci_restore_state won't help
6535 * here since it only restores the first 64 bytes pci config header.
6536 */
6537 pci_read_config_dword(pci_dev, 0x40, &val);
6538 if ((val & 0x0000ff00) != 0)
6539 pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
6540
6541 /* Set the device back into the PRESENT state; this will also wake
6542 * the queue of needed */
6543 netif_device_attach(dev);
6544
Dan Williamsc3d72b92009-02-11 13:26:06 -05006545 priv->suspend_time = get_seconds() - priv->suspend_at;
6546
James Ketrenosee8e3652005-09-14 09:47:29 -05006547 /* Bring the device back up */
6548 if (!(priv->status & STATUS_RF_KILL_SW))
6549 ipw2100_up(priv, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006550
Ingo Molnar752e3772006-02-28 07:20:54 +08006551 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006552
6553 return 0;
6554}
6555#endif
6556
Zhu Yi52ce3e9a72009-12-02 14:24:37 +08006557static void ipw2100_shutdown(struct pci_dev *pci_dev)
6558{
6559 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6560
6561 /* Take down the device; powers it off, etc. */
6562 ipw2100_down(priv);
6563
6564 pci_disable_device(pci_dev);
6565}
6566
James Ketrenos2c86c272005-03-23 17:32:29 -06006567#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
6568
Alexey Dobriyana3aa1882010-01-07 11:58:11 +00006569static DEFINE_PCI_DEVICE_TABLE(ipw2100_pci_id_table) = {
James Ketrenosee8e3652005-09-14 09:47:29 -05006570 IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
6571 IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
6572 IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
6573 IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
6574 IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
6575 IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
6576 IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
6577 IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
6578 IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
6579 IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
6580 IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
6581 IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
6582 IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
James Ketrenos2c86c272005-03-23 17:32:29 -06006583
James Ketrenosee8e3652005-09-14 09:47:29 -05006584 IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
6585 IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
6586 IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
6587 IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
6588 IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006589
James Ketrenosee8e3652005-09-14 09:47:29 -05006590 IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
6591 IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
6592 IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
6593 IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
6594 IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
6595 IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
6596 IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
James Ketrenos2c86c272005-03-23 17:32:29 -06006597
James Ketrenosee8e3652005-09-14 09:47:29 -05006598 IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006599
James Ketrenosee8e3652005-09-14 09:47:29 -05006600 IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
6601 IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
6602 IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
6603 IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
6604 IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
6605 IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
6606 IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006607
James Ketrenosee8e3652005-09-14 09:47:29 -05006608 IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
6609 IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
6610 IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
6611 IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
6612 IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
6613 IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006614
James Ketrenosee8e3652005-09-14 09:47:29 -05006615 IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006616 {0,},
6617};
6618
6619MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table);
6620
6621static struct pci_driver ipw2100_pci_driver = {
6622 .name = DRV_NAME,
6623 .id_table = ipw2100_pci_id_table,
6624 .probe = ipw2100_pci_init_one,
6625 .remove = __devexit_p(ipw2100_pci_remove_one),
6626#ifdef CONFIG_PM
6627 .suspend = ipw2100_suspend,
6628 .resume = ipw2100_resume,
6629#endif
Zhu Yi52ce3e9a72009-12-02 14:24:37 +08006630 .shutdown = ipw2100_shutdown,
James Ketrenos2c86c272005-03-23 17:32:29 -06006631};
6632
James Ketrenos2c86c272005-03-23 17:32:29 -06006633/**
6634 * Initialize the ipw2100 driver/module
6635 *
6636 * @returns 0 if ok, < 0 errno node con error.
6637 *
6638 * Note: we cannot init the /proc stuff until the PCI driver is there,
6639 * or we risk an unlikely race condition on someone accessing
6640 * uninitialized data in the PCI dev struct through /proc.
6641 */
6642static int __init ipw2100_init(void)
6643{
6644 int ret;
6645
6646 printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
6647 printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
6648
John W. Linville2f81b472010-08-11 16:11:00 -04006649 pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
6650 PM_QOS_DEFAULT_VALUE);
6651
Jeff Garzik29917622006-08-19 17:48:59 -04006652 ret = pci_register_driver(&ipw2100_pci_driver);
Jeff Garzikde897882006-10-01 07:31:09 -04006653 if (ret)
6654 goto out;
James Ketrenos2c86c272005-03-23 17:32:29 -06006655
Brice Goglin0f52bf92005-12-01 01:41:46 -08006656#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06006657 ipw2100_debug_level = debug;
Jeff Garzikde897882006-10-01 07:31:09 -04006658 ret = driver_create_file(&ipw2100_pci_driver.driver,
6659 &driver_attr_debug_level);
James Ketrenos2c86c272005-03-23 17:32:29 -06006660#endif
6661
Jeff Garzikde897882006-10-01 07:31:09 -04006662out:
James Ketrenos2c86c272005-03-23 17:32:29 -06006663 return ret;
6664}
6665
James Ketrenos2c86c272005-03-23 17:32:29 -06006666/**
6667 * Cleanup ipw2100 driver registration
6668 */
6669static void __exit ipw2100_exit(void)
6670{
6671 /* FIXME: IPG: check that we have no instances of the devices open */
Brice Goglin0f52bf92005-12-01 01:41:46 -08006672#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06006673 driver_remove_file(&ipw2100_pci_driver.driver,
6674 &driver_attr_debug_level);
6675#endif
6676 pci_unregister_driver(&ipw2100_pci_driver);
James Bottomley82f68252010-07-05 22:53:06 +02006677 pm_qos_remove_request(&ipw2100_pm_qos_req);
James Ketrenos2c86c272005-03-23 17:32:29 -06006678}
6679
6680module_init(ipw2100_init);
6681module_exit(ipw2100_exit);
6682
James Ketrenos2c86c272005-03-23 17:32:29 -06006683static int ipw2100_wx_get_name(struct net_device *dev,
6684 struct iw_request_info *info,
6685 union iwreq_data *wrqu, char *extra)
6686{
6687 /*
6688 * This can be called at any time. No action lock required
6689 */
6690
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006691 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006692 if (!(priv->status & STATUS_ASSOCIATED))
6693 strcpy(wrqu->name, "unassociated");
6694 else
6695 snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
6696
6697 IPW_DEBUG_WX("Name: %s\n", wrqu->name);
6698 return 0;
6699}
6700
James Ketrenos2c86c272005-03-23 17:32:29 -06006701static int ipw2100_wx_set_freq(struct net_device *dev,
6702 struct iw_request_info *info,
6703 union iwreq_data *wrqu, char *extra)
6704{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006705 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006706 struct iw_freq *fwrq = &wrqu->freq;
6707 int err = 0;
6708
6709 if (priv->ieee->iw_mode == IW_MODE_INFRA)
6710 return -EOPNOTSUPP;
6711
Ingo Molnar752e3772006-02-28 07:20:54 +08006712 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006713 if (!(priv->status & STATUS_INITIALIZED)) {
6714 err = -EIO;
6715 goto done;
6716 }
6717
6718 /* if setting by freq convert to channel */
6719 if (fwrq->e == 1) {
James Ketrenosee8e3652005-09-14 09:47:29 -05006720 if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006721 int f = fwrq->m / 100000;
6722 int c = 0;
6723
6724 while ((c < REG_MAX_CHANNEL) &&
6725 (f != ipw2100_frequencies[c]))
6726 c++;
6727
6728 /* hack to fall through */
6729 fwrq->e = 0;
6730 fwrq->m = c + 1;
6731 }
6732 }
6733
James Ketrenos82328352005-08-24 22:33:31 -05006734 if (fwrq->e > 0 || fwrq->m > 1000) {
6735 err = -EOPNOTSUPP;
6736 goto done;
6737 } else { /* Set the channel */
Frans Pop9fd1ea42010-03-24 19:46:31 +01006738 IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
James Ketrenos2c86c272005-03-23 17:32:29 -06006739 err = ipw2100_set_channel(priv, fwrq->m, 0);
6740 }
6741
James Ketrenosee8e3652005-09-14 09:47:29 -05006742 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006743 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006744 return err;
6745}
6746
James Ketrenos2c86c272005-03-23 17:32:29 -06006747static int ipw2100_wx_get_freq(struct net_device *dev,
6748 struct iw_request_info *info,
6749 union iwreq_data *wrqu, char *extra)
6750{
6751 /*
6752 * This can be called at any time. No action lock required
6753 */
6754
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006755 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006756
6757 wrqu->freq.e = 0;
6758
6759 /* If we are associated, trying to associate, or have a statically
6760 * configured CHANNEL then return that; otherwise return ANY */
6761 if (priv->config & CFG_STATIC_CHANNEL ||
6762 priv->status & STATUS_ASSOCIATED)
6763 wrqu->freq.m = priv->channel;
6764 else
6765 wrqu->freq.m = 0;
6766
Frans Pop9fd1ea42010-03-24 19:46:31 +01006767 IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
James Ketrenos2c86c272005-03-23 17:32:29 -06006768 return 0;
6769
6770}
6771
6772static int ipw2100_wx_set_mode(struct net_device *dev,
6773 struct iw_request_info *info,
6774 union iwreq_data *wrqu, char *extra)
6775{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006776 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006777 int err = 0;
6778
Frans Pop9fd1ea42010-03-24 19:46:31 +01006779 IPW_DEBUG_WX("SET Mode -> %d\n", wrqu->mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06006780
6781 if (wrqu->mode == priv->ieee->iw_mode)
6782 return 0;
6783
Ingo Molnar752e3772006-02-28 07:20:54 +08006784 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006785 if (!(priv->status & STATUS_INITIALIZED)) {
6786 err = -EIO;
6787 goto done;
6788 }
6789
6790 switch (wrqu->mode) {
6791#ifdef CONFIG_IPW2100_MONITOR
6792 case IW_MODE_MONITOR:
6793 err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
6794 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05006795#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06006796 case IW_MODE_ADHOC:
6797 err = ipw2100_switch_mode(priv, IW_MODE_ADHOC);
6798 break;
6799 case IW_MODE_INFRA:
6800 case IW_MODE_AUTO:
6801 default:
6802 err = ipw2100_switch_mode(priv, IW_MODE_INFRA);
6803 break;
6804 }
6805
James Ketrenosee8e3652005-09-14 09:47:29 -05006806 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006807 mutex_unlock(&priv->action_mutex);
James Ketrenosee8e3652005-09-14 09:47:29 -05006808 return err;
James Ketrenos2c86c272005-03-23 17:32:29 -06006809}
6810
6811static int ipw2100_wx_get_mode(struct net_device *dev,
6812 struct iw_request_info *info,
6813 union iwreq_data *wrqu, char *extra)
6814{
6815 /*
6816 * This can be called at any time. No action lock required
6817 */
6818
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006819 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006820
6821 wrqu->mode = priv->ieee->iw_mode;
6822 IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode);
6823
6824 return 0;
6825}
6826
James Ketrenos2c86c272005-03-23 17:32:29 -06006827#define POWER_MODES 5
6828
6829/* Values are in microsecond */
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006830static const s32 timeout_duration[POWER_MODES] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006831 350000,
6832 250000,
6833 75000,
6834 37000,
6835 25000,
6836};
6837
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006838static const s32 period_duration[POWER_MODES] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006839 400000,
6840 700000,
6841 1000000,
6842 1000000,
6843 1000000
6844};
6845
6846static int ipw2100_wx_get_range(struct net_device *dev,
6847 struct iw_request_info *info,
6848 union iwreq_data *wrqu, char *extra)
6849{
6850 /*
6851 * This can be called at any time. No action lock required
6852 */
6853
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006854 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006855 struct iw_range *range = (struct iw_range *)extra;
6856 u16 val;
6857 int i, level;
6858
6859 wrqu->data.length = sizeof(*range);
6860 memset(range, 0, sizeof(*range));
6861
6862 /* Let's try to keep this struct in the same order as in
6863 * linux/include/wireless.h
6864 */
6865
6866 /* TODO: See what values we can set, and remove the ones we can't
6867 * set, or fill them with some default data.
6868 */
6869
6870 /* ~5 Mb/s real (802.11b) */
6871 range->throughput = 5 * 1000 * 1000;
6872
James Ketrenosee8e3652005-09-14 09:47:29 -05006873// range->sensitivity; /* signal level threshold range */
James Ketrenos2c86c272005-03-23 17:32:29 -06006874
6875 range->max_qual.qual = 100;
6876 /* TODO: Find real max RSSI and stick here */
6877 range->max_qual.level = 0;
6878 range->max_qual.noise = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05006879 range->max_qual.updated = 7; /* Updated all three */
James Ketrenos2c86c272005-03-23 17:32:29 -06006880
James Ketrenosee8e3652005-09-14 09:47:29 -05006881 range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02006882 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
James Ketrenos2c86c272005-03-23 17:32:29 -06006883 range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
6884 range->avg_qual.noise = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05006885 range->avg_qual.updated = 7; /* Updated all three */
James Ketrenos2c86c272005-03-23 17:32:29 -06006886
6887 range->num_bitrates = RATE_COUNT;
6888
6889 for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
Stanislav Yakovlev4d94c152012-02-09 20:23:52 -05006890 range->bitrate[i] = ipw2100_bg_rates[i].bitrate * 100 * 1000;
James Ketrenos2c86c272005-03-23 17:32:29 -06006891 }
6892
6893 range->min_rts = MIN_RTS_THRESHOLD;
6894 range->max_rts = MAX_RTS_THRESHOLD;
6895 range->min_frag = MIN_FRAG_THRESHOLD;
6896 range->max_frag = MAX_FRAG_THRESHOLD;
6897
6898 range->min_pmp = period_duration[0]; /* Minimal PM period */
James Ketrenosee8e3652005-09-14 09:47:29 -05006899 range->max_pmp = period_duration[POWER_MODES - 1]; /* Maximal PM period */
6900 range->min_pmt = timeout_duration[POWER_MODES - 1]; /* Minimal PM timeout */
6901 range->max_pmt = timeout_duration[0]; /* Maximal PM timeout */
James Ketrenos2c86c272005-03-23 17:32:29 -06006902
James Ketrenosee8e3652005-09-14 09:47:29 -05006903 /* How to decode max/min PM period */
James Ketrenos2c86c272005-03-23 17:32:29 -06006904 range->pmp_flags = IW_POWER_PERIOD;
James Ketrenosee8e3652005-09-14 09:47:29 -05006905 /* How to decode max/min PM period */
James Ketrenos2c86c272005-03-23 17:32:29 -06006906 range->pmt_flags = IW_POWER_TIMEOUT;
6907 /* What PM options are supported */
6908 range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD;
6909
6910 range->encoding_size[0] = 5;
James Ketrenosee8e3652005-09-14 09:47:29 -05006911 range->encoding_size[1] = 13; /* Different token sizes */
6912 range->num_encoding_sizes = 2; /* Number of entry in the list */
6913 range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */
6914// range->encoding_login_index; /* token index for login token */
James Ketrenos2c86c272005-03-23 17:32:29 -06006915
6916 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
6917 range->txpower_capa = IW_TXPOW_DBM;
6918 range->num_txpower = IW_MAX_TXPOWER;
James Ketrenosee8e3652005-09-14 09:47:29 -05006919 for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16);
6920 i < IW_MAX_TXPOWER;
6921 i++, level -=
6922 ((IPW_TX_POWER_MAX_DBM -
6923 IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1))
James Ketrenos2c86c272005-03-23 17:32:29 -06006924 range->txpower[i] = level / 16;
6925 } else {
6926 range->txpower_capa = 0;
6927 range->num_txpower = 0;
6928 }
6929
James Ketrenos2c86c272005-03-23 17:32:29 -06006930 /* Set the Wireless Extension versions */
6931 range->we_version_compiled = WIRELESS_EXT;
Dan Williams166c3432006-01-09 11:04:31 -05006932 range->we_version_source = 18;
James Ketrenos2c86c272005-03-23 17:32:29 -06006933
James Ketrenosee8e3652005-09-14 09:47:29 -05006934// range->retry_capa; /* What retry options are supported */
6935// range->retry_flags; /* How to decode max/min retry limit */
6936// range->r_time_flags; /* How to decode max/min retry life */
6937// range->min_retry; /* Minimal number of retries */
6938// range->max_retry; /* Maximal number of retries */
6939// range->min_r_time; /* Minimal retry lifetime */
6940// range->max_r_time; /* Maximal retry lifetime */
James Ketrenos2c86c272005-03-23 17:32:29 -06006941
James Ketrenosee8e3652005-09-14 09:47:29 -05006942 range->num_channels = FREQ_COUNT;
James Ketrenos2c86c272005-03-23 17:32:29 -06006943
6944 val = 0;
6945 for (i = 0; i < FREQ_COUNT; i++) {
6946 // TODO: Include only legal frequencies for some countries
James Ketrenosee8e3652005-09-14 09:47:29 -05006947// if (local->channel_mask & (1 << i)) {
6948 range->freq[val].i = i + 1;
6949 range->freq[val].m = ipw2100_frequencies[i] * 100000;
6950 range->freq[val].e = 1;
6951 val++;
6952// }
James Ketrenos2c86c272005-03-23 17:32:29 -06006953 if (val == IW_MAX_FREQUENCIES)
James Ketrenosee8e3652005-09-14 09:47:29 -05006954 break;
James Ketrenos2c86c272005-03-23 17:32:29 -06006955 }
6956 range->num_frequency = val;
6957
James Ketrenoseaf8f532005-11-12 12:50:12 -06006958 /* Event capability (kernel + driver) */
6959 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
6960 IW_EVENT_CAPA_MASK(SIOCGIWAP));
6961 range->event_capa[1] = IW_EVENT_CAPA_K_1;
6962
Dan Williams166c3432006-01-09 11:04:31 -05006963 range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
6964 IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
6965
James Ketrenos2c86c272005-03-23 17:32:29 -06006966 IPW_DEBUG_WX("GET Range\n");
6967
6968 return 0;
6969}
6970
6971static int ipw2100_wx_set_wap(struct net_device *dev,
6972 struct iw_request_info *info,
6973 union iwreq_data *wrqu, char *extra)
6974{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006975 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006976 int err = 0;
6977
6978 static const unsigned char any[] = {
6979 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
6980 };
6981 static const unsigned char off[] = {
6982 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6983 };
6984
6985 // sanity checks
6986 if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
6987 return -EINVAL;
6988
Ingo Molnar752e3772006-02-28 07:20:54 +08006989 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006990 if (!(priv->status & STATUS_INITIALIZED)) {
6991 err = -EIO;
6992 goto done;
6993 }
6994
6995 if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
6996 !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
6997 /* we disable mandatory BSSID association */
6998 IPW_DEBUG_WX("exit - disable mandatory BSSID\n");
6999 priv->config &= ~CFG_STATIC_BSSID;
7000 err = ipw2100_set_mandatory_bssid(priv, NULL, 0);
7001 goto done;
7002 }
7003
7004 priv->config |= CFG_STATIC_BSSID;
7005 memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN);
7006
7007 err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
7008
Johannes Berge1749612008-10-27 15:59:26 -07007009 IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data);
James Ketrenos2c86c272005-03-23 17:32:29 -06007010
James Ketrenosee8e3652005-09-14 09:47:29 -05007011 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007012 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007013 return err;
7014}
7015
7016static int ipw2100_wx_get_wap(struct net_device *dev,
7017 struct iw_request_info *info,
7018 union iwreq_data *wrqu, char *extra)
7019{
7020 /*
7021 * This can be called at any time. No action lock required
7022 */
7023
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007024 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007025
7026 /* If we are associated, trying to associate, or have a statically
7027 * configured BSSID then return that; otherwise return ANY */
James Ketrenosee8e3652005-09-14 09:47:29 -05007028 if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007029 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
James Ketrenos82328352005-08-24 22:33:31 -05007030 memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06007031 } else
7032 memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
7033
Johannes Berge1749612008-10-27 15:59:26 -07007034 IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data);
James Ketrenos2c86c272005-03-23 17:32:29 -06007035 return 0;
7036}
7037
7038static int ipw2100_wx_set_essid(struct net_device *dev,
7039 struct iw_request_info *info,
7040 union iwreq_data *wrqu, char *extra)
7041{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007042 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05007043 char *essid = ""; /* ANY */
James Ketrenos2c86c272005-03-23 17:32:29 -06007044 int length = 0;
7045 int err = 0;
John W. Linville9387b7c2008-09-30 20:59:05 -04007046 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06007047
Ingo Molnar752e3772006-02-28 07:20:54 +08007048 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007049 if (!(priv->status & STATUS_INITIALIZED)) {
7050 err = -EIO;
7051 goto done;
7052 }
7053
7054 if (wrqu->essid.flags && wrqu->essid.length) {
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007055 length = wrqu->essid.length;
James Ketrenos2c86c272005-03-23 17:32:29 -06007056 essid = extra;
7057 }
7058
7059 if (length == 0) {
7060 IPW_DEBUG_WX("Setting ESSID to ANY\n");
7061 priv->config &= ~CFG_STATIC_ESSID;
7062 err = ipw2100_set_essid(priv, NULL, 0, 0);
7063 goto done;
7064 }
7065
7066 length = min(length, IW_ESSID_MAX_SIZE);
7067
7068 priv->config |= CFG_STATIC_ESSID;
7069
7070 if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
7071 IPW_DEBUG_WX("ESSID set to current ESSID.\n");
7072 err = 0;
7073 goto done;
7074 }
7075
John W. Linville9387b7c2008-09-30 20:59:05 -04007076 IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
7077 print_ssid(ssid, essid, length), length);
James Ketrenos2c86c272005-03-23 17:32:29 -06007078
7079 priv->essid_len = length;
7080 memcpy(priv->essid, essid, priv->essid_len);
7081
7082 err = ipw2100_set_essid(priv, essid, length, 0);
7083
James Ketrenosee8e3652005-09-14 09:47:29 -05007084 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007085 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007086 return err;
7087}
7088
7089static int ipw2100_wx_get_essid(struct net_device *dev,
7090 struct iw_request_info *info,
7091 union iwreq_data *wrqu, char *extra)
7092{
7093 /*
7094 * This can be called at any time. No action lock required
7095 */
7096
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007097 struct ipw2100_priv *priv = libipw_priv(dev);
John W. Linville9387b7c2008-09-30 20:59:05 -04007098 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06007099
7100 /* If we are associated, trying to associate, or have a statically
7101 * configured ESSID then return that; otherwise return ANY */
James Ketrenosee8e3652005-09-14 09:47:29 -05007102 if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007103 IPW_DEBUG_WX("Getting essid: '%s'\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04007104 print_ssid(ssid, priv->essid, priv->essid_len));
James Ketrenos2c86c272005-03-23 17:32:29 -06007105 memcpy(extra, priv->essid, priv->essid_len);
7106 wrqu->essid.length = priv->essid_len;
James Ketrenosee8e3652005-09-14 09:47:29 -05007107 wrqu->essid.flags = 1; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007108 } else {
7109 IPW_DEBUG_WX("Getting essid: ANY\n");
7110 wrqu->essid.length = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05007111 wrqu->essid.flags = 0; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007112 }
7113
7114 return 0;
7115}
7116
7117static int ipw2100_wx_set_nick(struct net_device *dev,
7118 struct iw_request_info *info,
7119 union iwreq_data *wrqu, char *extra)
7120{
7121 /*
7122 * This can be called at any time. No action lock required
7123 */
7124
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007125 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007126
7127 if (wrqu->data.length > IW_ESSID_MAX_SIZE)
7128 return -E2BIG;
7129
James Ketrenosee8e3652005-09-14 09:47:29 -05007130 wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
James Ketrenos2c86c272005-03-23 17:32:29 -06007131 memset(priv->nick, 0, sizeof(priv->nick));
James Ketrenosee8e3652005-09-14 09:47:29 -05007132 memcpy(priv->nick, extra, wrqu->data.length);
James Ketrenos2c86c272005-03-23 17:32:29 -06007133
Frans Pop9fd1ea42010-03-24 19:46:31 +01007134 IPW_DEBUG_WX("SET Nickname -> %s\n", priv->nick);
James Ketrenos2c86c272005-03-23 17:32:29 -06007135
7136 return 0;
7137}
7138
7139static int ipw2100_wx_get_nick(struct net_device *dev,
7140 struct iw_request_info *info,
7141 union iwreq_data *wrqu, char *extra)
7142{
7143 /*
7144 * This can be called at any time. No action lock required
7145 */
7146
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007147 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007148
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007149 wrqu->data.length = strlen(priv->nick);
James Ketrenos2c86c272005-03-23 17:32:29 -06007150 memcpy(extra, priv->nick, wrqu->data.length);
James Ketrenosee8e3652005-09-14 09:47:29 -05007151 wrqu->data.flags = 1; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007152
Frans Pop9fd1ea42010-03-24 19:46:31 +01007153 IPW_DEBUG_WX("GET Nickname -> %s\n", extra);
James Ketrenos2c86c272005-03-23 17:32:29 -06007154
7155 return 0;
7156}
7157
7158static int ipw2100_wx_set_rate(struct net_device *dev,
7159 struct iw_request_info *info,
7160 union iwreq_data *wrqu, char *extra)
7161{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007162 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007163 u32 target_rate = wrqu->bitrate.value;
7164 u32 rate;
7165 int err = 0;
7166
Ingo Molnar752e3772006-02-28 07:20:54 +08007167 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007168 if (!(priv->status & STATUS_INITIALIZED)) {
7169 err = -EIO;
7170 goto done;
7171 }
7172
7173 rate = 0;
7174
7175 if (target_rate == 1000000 ||
7176 (!wrqu->bitrate.fixed && target_rate > 1000000))
7177 rate |= TX_RATE_1_MBIT;
7178 if (target_rate == 2000000 ||
7179 (!wrqu->bitrate.fixed && target_rate > 2000000))
7180 rate |= TX_RATE_2_MBIT;
7181 if (target_rate == 5500000 ||
7182 (!wrqu->bitrate.fixed && target_rate > 5500000))
7183 rate |= TX_RATE_5_5_MBIT;
7184 if (target_rate == 11000000 ||
7185 (!wrqu->bitrate.fixed && target_rate > 11000000))
7186 rate |= TX_RATE_11_MBIT;
7187 if (rate == 0)
7188 rate = DEFAULT_TX_RATES;
7189
7190 err = ipw2100_set_tx_rates(priv, rate, 0);
7191
Frans Pop9fd1ea42010-03-24 19:46:31 +01007192 IPW_DEBUG_WX("SET Rate -> %04X\n", rate);
James Ketrenosee8e3652005-09-14 09:47:29 -05007193 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007194 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007195 return err;
7196}
7197
James Ketrenos2c86c272005-03-23 17:32:29 -06007198static int ipw2100_wx_get_rate(struct net_device *dev,
7199 struct iw_request_info *info,
7200 union iwreq_data *wrqu, char *extra)
7201{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007202 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007203 int val;
Hannes Ederb9da9e92009-02-14 11:50:26 +00007204 unsigned int len = sizeof(val);
James Ketrenos2c86c272005-03-23 17:32:29 -06007205 int err = 0;
7206
7207 if (!(priv->status & STATUS_ENABLED) ||
7208 priv->status & STATUS_RF_KILL_MASK ||
7209 !(priv->status & STATUS_ASSOCIATED)) {
7210 wrqu->bitrate.value = 0;
7211 return 0;
7212 }
7213
Ingo Molnar752e3772006-02-28 07:20:54 +08007214 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007215 if (!(priv->status & STATUS_INITIALIZED)) {
7216 err = -EIO;
7217 goto done;
7218 }
7219
7220 err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len);
7221 if (err) {
7222 IPW_DEBUG_WX("failed querying ordinals.\n");
Julia Lawall80c42af2008-07-21 09:58:11 +02007223 goto done;
James Ketrenos2c86c272005-03-23 17:32:29 -06007224 }
7225
7226 switch (val & TX_RATE_MASK) {
7227 case TX_RATE_1_MBIT:
7228 wrqu->bitrate.value = 1000000;
7229 break;
7230 case TX_RATE_2_MBIT:
7231 wrqu->bitrate.value = 2000000;
7232 break;
7233 case TX_RATE_5_5_MBIT:
7234 wrqu->bitrate.value = 5500000;
7235 break;
7236 case TX_RATE_11_MBIT:
7237 wrqu->bitrate.value = 11000000;
7238 break;
7239 default:
7240 wrqu->bitrate.value = 0;
7241 }
7242
Frans Pop9fd1ea42010-03-24 19:46:31 +01007243 IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007244
James Ketrenosee8e3652005-09-14 09:47:29 -05007245 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007246 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007247 return err;
7248}
7249
7250static int ipw2100_wx_set_rts(struct net_device *dev,
7251 struct iw_request_info *info,
7252 union iwreq_data *wrqu, char *extra)
7253{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007254 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007255 int value, err;
7256
7257 /* Auto RTS not yet supported */
7258 if (wrqu->rts.fixed == 0)
7259 return -EINVAL;
7260
Ingo Molnar752e3772006-02-28 07:20:54 +08007261 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007262 if (!(priv->status & STATUS_INITIALIZED)) {
7263 err = -EIO;
7264 goto done;
7265 }
7266
7267 if (wrqu->rts.disabled)
7268 value = priv->rts_threshold | RTS_DISABLED;
7269 else {
James Ketrenosee8e3652005-09-14 09:47:29 -05007270 if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007271 err = -EINVAL;
7272 goto done;
7273 }
7274 value = wrqu->rts.value;
7275 }
7276
7277 err = ipw2100_set_rts_threshold(priv, value);
7278
Frans Pop9fd1ea42010-03-24 19:46:31 +01007279 IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X\n", value);
James Ketrenosee8e3652005-09-14 09:47:29 -05007280 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007281 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007282 return err;
7283}
7284
7285static int ipw2100_wx_get_rts(struct net_device *dev,
7286 struct iw_request_info *info,
7287 union iwreq_data *wrqu, char *extra)
7288{
7289 /*
7290 * This can be called at any time. No action lock required
7291 */
7292
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007293 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007294
7295 wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
James Ketrenosee8e3652005-09-14 09:47:29 -05007296 wrqu->rts.fixed = 1; /* no auto select */
James Ketrenos2c86c272005-03-23 17:32:29 -06007297
7298 /* If RTS is set to the default value, then it is disabled */
7299 wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
7300
Frans Pop9fd1ea42010-03-24 19:46:31 +01007301 IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X\n", wrqu->rts.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007302
7303 return 0;
7304}
7305
7306static int ipw2100_wx_set_txpow(struct net_device *dev,
7307 struct iw_request_info *info,
7308 union iwreq_data *wrqu, char *extra)
7309{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007310 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007311 int err = 0, value;
Zhu Yib6e4da72006-01-24 13:49:32 +08007312
7313 if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled))
7314 return -EINPROGRESS;
James Ketrenos2c86c272005-03-23 17:32:29 -06007315
7316 if (priv->ieee->iw_mode != IW_MODE_ADHOC)
Zhu Yib6e4da72006-01-24 13:49:32 +08007317 return 0;
7318
7319 if ((wrqu->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
James Ketrenos2c86c272005-03-23 17:32:29 -06007320 return -EINVAL;
7321
Zhu Yib6e4da72006-01-24 13:49:32 +08007322 if (wrqu->txpower.fixed == 0)
James Ketrenos2c86c272005-03-23 17:32:29 -06007323 value = IPW_TX_POWER_DEFAULT;
7324 else {
7325 if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM ||
7326 wrqu->txpower.value > IPW_TX_POWER_MAX_DBM)
7327 return -EINVAL;
7328
Liu Hongf75459e2005-07-13 12:29:21 -05007329 value = wrqu->txpower.value;
James Ketrenos2c86c272005-03-23 17:32:29 -06007330 }
7331
Ingo Molnar752e3772006-02-28 07:20:54 +08007332 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007333 if (!(priv->status & STATUS_INITIALIZED)) {
7334 err = -EIO;
7335 goto done;
7336 }
7337
7338 err = ipw2100_set_tx_power(priv, value);
7339
Frans Pop9fd1ea42010-03-24 19:46:31 +01007340 IPW_DEBUG_WX("SET TX Power -> %d\n", value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007341
James Ketrenosee8e3652005-09-14 09:47:29 -05007342 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007343 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007344 return err;
7345}
7346
7347static int ipw2100_wx_get_txpow(struct net_device *dev,
7348 struct iw_request_info *info,
7349 union iwreq_data *wrqu, char *extra)
7350{
7351 /*
7352 * This can be called at any time. No action lock required
7353 */
7354
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007355 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007356
Zhu Yib6e4da72006-01-24 13:49:32 +08007357 wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06007358
7359 if (priv->tx_power == IPW_TX_POWER_DEFAULT) {
Zhu Yib6e4da72006-01-24 13:49:32 +08007360 wrqu->txpower.fixed = 0;
7361 wrqu->txpower.value = IPW_TX_POWER_MAX_DBM;
James Ketrenos2c86c272005-03-23 17:32:29 -06007362 } else {
Zhu Yib6e4da72006-01-24 13:49:32 +08007363 wrqu->txpower.fixed = 1;
7364 wrqu->txpower.value = priv->tx_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06007365 }
7366
Zhu Yib6e4da72006-01-24 13:49:32 +08007367 wrqu->txpower.flags = IW_TXPOW_DBM;
James Ketrenos2c86c272005-03-23 17:32:29 -06007368
Frans Pop9fd1ea42010-03-24 19:46:31 +01007369 IPW_DEBUG_WX("GET TX Power -> %d\n", wrqu->txpower.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007370
7371 return 0;
7372}
7373
7374static int ipw2100_wx_set_frag(struct net_device *dev,
7375 struct iw_request_info *info,
7376 union iwreq_data *wrqu, char *extra)
7377{
7378 /*
7379 * This can be called at any time. No action lock required
7380 */
7381
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007382 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007383
7384 if (!wrqu->frag.fixed)
7385 return -EINVAL;
7386
7387 if (wrqu->frag.disabled) {
7388 priv->frag_threshold |= FRAG_DISABLED;
7389 priv->ieee->fts = DEFAULT_FTS;
7390 } else {
7391 if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
7392 wrqu->frag.value > MAX_FRAG_THRESHOLD)
7393 return -EINVAL;
7394
7395 priv->ieee->fts = wrqu->frag.value & ~0x1;
7396 priv->frag_threshold = priv->ieee->fts;
7397 }
7398
Frans Pop9fd1ea42010-03-24 19:46:31 +01007399 IPW_DEBUG_WX("SET Frag Threshold -> %d\n", priv->ieee->fts);
James Ketrenos2c86c272005-03-23 17:32:29 -06007400
7401 return 0;
7402}
7403
7404static int ipw2100_wx_get_frag(struct net_device *dev,
7405 struct iw_request_info *info,
7406 union iwreq_data *wrqu, char *extra)
7407{
7408 /*
7409 * This can be called at any time. No action lock required
7410 */
7411
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007412 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007413 wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED;
7414 wrqu->frag.fixed = 0; /* no auto select */
7415 wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
7416
Frans Pop9fd1ea42010-03-24 19:46:31 +01007417 IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007418
7419 return 0;
7420}
7421
7422static int ipw2100_wx_set_retry(struct net_device *dev,
7423 struct iw_request_info *info,
7424 union iwreq_data *wrqu, char *extra)
7425{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007426 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007427 int err = 0;
7428
James Ketrenosee8e3652005-09-14 09:47:29 -05007429 if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
James Ketrenos2c86c272005-03-23 17:32:29 -06007430 return -EINVAL;
7431
7432 if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
7433 return 0;
7434
Ingo Molnar752e3772006-02-28 07:20:54 +08007435 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007436 if (!(priv->status & STATUS_INITIALIZED)) {
7437 err = -EIO;
7438 goto done;
7439 }
7440
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007441 if (wrqu->retry.flags & IW_RETRY_SHORT) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007442 err = ipw2100_set_short_retry(priv, wrqu->retry.value);
Frans Pop9fd1ea42010-03-24 19:46:31 +01007443 IPW_DEBUG_WX("SET Short Retry Limit -> %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05007444 wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007445 goto done;
7446 }
7447
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007448 if (wrqu->retry.flags & IW_RETRY_LONG) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007449 err = ipw2100_set_long_retry(priv, wrqu->retry.value);
Frans Pop9fd1ea42010-03-24 19:46:31 +01007450 IPW_DEBUG_WX("SET Long Retry Limit -> %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05007451 wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007452 goto done;
7453 }
7454
7455 err = ipw2100_set_short_retry(priv, wrqu->retry.value);
7456 if (!err)
7457 err = ipw2100_set_long_retry(priv, wrqu->retry.value);
7458
Frans Pop9fd1ea42010-03-24 19:46:31 +01007459 IPW_DEBUG_WX("SET Both Retry Limits -> %d\n", wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007460
James Ketrenosee8e3652005-09-14 09:47:29 -05007461 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007462 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007463 return err;
7464}
7465
7466static int ipw2100_wx_get_retry(struct net_device *dev,
7467 struct iw_request_info *info,
7468 union iwreq_data *wrqu, char *extra)
7469{
7470 /*
7471 * This can be called at any time. No action lock required
7472 */
7473
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007474 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007475
James Ketrenosee8e3652005-09-14 09:47:29 -05007476 wrqu->retry.disabled = 0; /* can't be disabled */
James Ketrenos2c86c272005-03-23 17:32:29 -06007477
James Ketrenosee8e3652005-09-14 09:47:29 -05007478 if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
James Ketrenos2c86c272005-03-23 17:32:29 -06007479 return -EINVAL;
7480
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007481 if (wrqu->retry.flags & IW_RETRY_LONG) {
7482 wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
James Ketrenos2c86c272005-03-23 17:32:29 -06007483 wrqu->retry.value = priv->long_retry_limit;
7484 } else {
7485 wrqu->retry.flags =
7486 (priv->short_retry_limit !=
7487 priv->long_retry_limit) ?
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007488 IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT;
James Ketrenos2c86c272005-03-23 17:32:29 -06007489
7490 wrqu->retry.value = priv->short_retry_limit;
7491 }
7492
Frans Pop9fd1ea42010-03-24 19:46:31 +01007493 IPW_DEBUG_WX("GET Retry -> %d\n", wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007494
7495 return 0;
7496}
7497
7498static int ipw2100_wx_set_scan(struct net_device *dev,
7499 struct iw_request_info *info,
7500 union iwreq_data *wrqu, char *extra)
7501{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007502 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007503 int err = 0;
7504
Ingo Molnar752e3772006-02-28 07:20:54 +08007505 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007506 if (!(priv->status & STATUS_INITIALIZED)) {
7507 err = -EIO;
7508 goto done;
7509 }
7510
7511 IPW_DEBUG_WX("Initiating scan...\n");
Dan Williamsd20c6782007-10-10 12:28:07 -04007512
7513 priv->user_requested_scan = 1;
James Ketrenosee8e3652005-09-14 09:47:29 -05007514 if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007515 IPW_DEBUG_WX("Start scan failed.\n");
7516
7517 /* TODO: Mark a scan as pending so when hardware initialized
7518 * a scan starts */
7519 }
7520
James Ketrenosee8e3652005-09-14 09:47:29 -05007521 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007522 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007523 return err;
7524}
7525
7526static int ipw2100_wx_get_scan(struct net_device *dev,
7527 struct iw_request_info *info,
7528 union iwreq_data *wrqu, char *extra)
7529{
7530 /*
7531 * This can be called at any time. No action lock required
7532 */
7533
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007534 struct ipw2100_priv *priv = libipw_priv(dev);
7535 return libipw_wx_get_scan(priv->ieee, info, wrqu, extra);
James Ketrenos2c86c272005-03-23 17:32:29 -06007536}
7537
James Ketrenos2c86c272005-03-23 17:32:29 -06007538/*
7539 * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c
7540 */
7541static int ipw2100_wx_set_encode(struct net_device *dev,
7542 struct iw_request_info *info,
7543 union iwreq_data *wrqu, char *key)
7544{
7545 /*
7546 * No check of STATUS_INITIALIZED required
7547 */
7548
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007549 struct ipw2100_priv *priv = libipw_priv(dev);
7550 return libipw_wx_set_encode(priv->ieee, info, wrqu, key);
James Ketrenos2c86c272005-03-23 17:32:29 -06007551}
7552
7553static int ipw2100_wx_get_encode(struct net_device *dev,
7554 struct iw_request_info *info,
7555 union iwreq_data *wrqu, char *key)
7556{
7557 /*
7558 * This can be called at any time. No action lock required
7559 */
7560
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007561 struct ipw2100_priv *priv = libipw_priv(dev);
7562 return libipw_wx_get_encode(priv->ieee, info, wrqu, key);
James Ketrenos2c86c272005-03-23 17:32:29 -06007563}
7564
7565static int ipw2100_wx_set_power(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05007566 struct iw_request_info *info,
7567 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007568{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007569 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007570 int err = 0;
7571
Ingo Molnar752e3772006-02-28 07:20:54 +08007572 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007573 if (!(priv->status & STATUS_INITIALIZED)) {
7574 err = -EIO;
7575 goto done;
7576 }
7577
7578 if (wrqu->power.disabled) {
7579 priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
7580 err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
7581 IPW_DEBUG_WX("SET Power Management Mode -> off\n");
7582 goto done;
7583 }
7584
7585 switch (wrqu->power.flags & IW_POWER_MODE) {
James Ketrenosee8e3652005-09-14 09:47:29 -05007586 case IW_POWER_ON: /* If not specified */
7587 case IW_POWER_MODE: /* If set all mask */
Jean Delvarec03983a2007-10-19 23:22:55 +02007588 case IW_POWER_ALL_R: /* If explicitly state all */
James Ketrenos2c86c272005-03-23 17:32:29 -06007589 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05007590 default: /* Otherwise we don't support it */
James Ketrenos2c86c272005-03-23 17:32:29 -06007591 IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
7592 wrqu->power.flags);
7593 err = -EOPNOTSUPP;
7594 goto done;
7595 }
7596
7597 /* If the user hasn't specified a power management mode yet, default
7598 * to BATTERY */
7599 priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
7600 err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
7601
James Ketrenosee8e3652005-09-14 09:47:29 -05007602 IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06007603
James Ketrenosee8e3652005-09-14 09:47:29 -05007604 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007605 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007606 return err;
7607
7608}
7609
7610static int ipw2100_wx_get_power(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05007611 struct iw_request_info *info,
7612 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007613{
7614 /*
7615 * This can be called at any time. No action lock required
7616 */
7617
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007618 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007619
James Ketrenos82328352005-08-24 22:33:31 -05007620 if (!(priv->power_mode & IPW_POWER_ENABLED))
James Ketrenos2c86c272005-03-23 17:32:29 -06007621 wrqu->power.disabled = 1;
James Ketrenos82328352005-08-24 22:33:31 -05007622 else {
James Ketrenos2c86c272005-03-23 17:32:29 -06007623 wrqu->power.disabled = 0;
7624 wrqu->power.flags = 0;
7625 }
7626
7627 IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
7628
7629 return 0;
7630}
7631
James Ketrenos82328352005-08-24 22:33:31 -05007632/*
7633 * WE-18 WPA support
7634 */
7635
7636/* SIOCSIWGENIE */
7637static int ipw2100_wx_set_genie(struct net_device *dev,
7638 struct iw_request_info *info,
7639 union iwreq_data *wrqu, char *extra)
7640{
7641
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007642 struct ipw2100_priv *priv = libipw_priv(dev);
7643 struct libipw_device *ieee = priv->ieee;
James Ketrenos82328352005-08-24 22:33:31 -05007644 u8 *buf;
7645
7646 if (!ieee->wpa_enabled)
7647 return -EOPNOTSUPP;
7648
7649 if (wrqu->data.length > MAX_WPA_IE_LEN ||
7650 (wrqu->data.length && extra == NULL))
7651 return -EINVAL;
7652
7653 if (wrqu->data.length) {
Eric Sesterhennc3a93922006-10-23 22:20:15 +02007654 buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
James Ketrenos82328352005-08-24 22:33:31 -05007655 if (buf == NULL)
7656 return -ENOMEM;
7657
James Ketrenos82328352005-08-24 22:33:31 -05007658 kfree(ieee->wpa_ie);
7659 ieee->wpa_ie = buf;
7660 ieee->wpa_ie_len = wrqu->data.length;
7661 } else {
7662 kfree(ieee->wpa_ie);
7663 ieee->wpa_ie = NULL;
7664 ieee->wpa_ie_len = 0;
7665 }
7666
7667 ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
7668
7669 return 0;
7670}
7671
7672/* SIOCGIWGENIE */
7673static int ipw2100_wx_get_genie(struct net_device *dev,
7674 struct iw_request_info *info,
7675 union iwreq_data *wrqu, char *extra)
7676{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007677 struct ipw2100_priv *priv = libipw_priv(dev);
7678 struct libipw_device *ieee = priv->ieee;
James Ketrenos82328352005-08-24 22:33:31 -05007679
7680 if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
7681 wrqu->data.length = 0;
7682 return 0;
7683 }
7684
7685 if (wrqu->data.length < ieee->wpa_ie_len)
7686 return -E2BIG;
7687
7688 wrqu->data.length = ieee->wpa_ie_len;
7689 memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
7690
7691 return 0;
7692}
7693
7694/* SIOCSIWAUTH */
7695static int ipw2100_wx_set_auth(struct net_device *dev,
7696 struct iw_request_info *info,
7697 union iwreq_data *wrqu, char *extra)
7698{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007699 struct ipw2100_priv *priv = libipw_priv(dev);
7700 struct libipw_device *ieee = priv->ieee;
James Ketrenos82328352005-08-24 22:33:31 -05007701 struct iw_param *param = &wrqu->param;
John W. Linville274bfb82008-10-29 11:35:05 -04007702 struct lib80211_crypt_data *crypt;
James Ketrenos82328352005-08-24 22:33:31 -05007703 unsigned long flags;
7704 int ret = 0;
7705
7706 switch (param->flags & IW_AUTH_INDEX) {
7707 case IW_AUTH_WPA_VERSION:
7708 case IW_AUTH_CIPHER_PAIRWISE:
7709 case IW_AUTH_CIPHER_GROUP:
7710 case IW_AUTH_KEY_MGMT:
7711 /*
7712 * ipw2200 does not use these parameters
7713 */
7714 break;
7715
7716 case IW_AUTH_TKIP_COUNTERMEASURES:
John W. Linville274bfb82008-10-29 11:35:05 -04007717 crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
James Ketrenos991d1cc2005-10-13 09:26:48 +00007718 if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
James Ketrenos82328352005-08-24 22:33:31 -05007719 break;
James Ketrenos82328352005-08-24 22:33:31 -05007720
7721 flags = crypt->ops->get_flags(crypt->priv);
7722
7723 if (param->value)
7724 flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
7725 else
7726 flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
7727
7728 crypt->ops->set_flags(flags, crypt->priv);
7729
7730 break;
7731
7732 case IW_AUTH_DROP_UNENCRYPTED:{
7733 /* HACK:
7734 *
7735 * wpa_supplicant calls set_wpa_enabled when the driver
7736 * is loaded and unloaded, regardless of if WPA is being
7737 * used. No other calls are made which can be used to
7738 * determine if encryption will be used or not prior to
7739 * association being expected. If encryption is not being
7740 * used, drop_unencrypted is set to false, else true -- we
7741 * can use this to determine if the CAP_PRIVACY_ON bit should
7742 * be set.
7743 */
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007744 struct libipw_security sec = {
James Ketrenos82328352005-08-24 22:33:31 -05007745 .flags = SEC_ENABLED,
7746 .enabled = param->value,
7747 };
7748 priv->ieee->drop_unencrypted = param->value;
7749 /* We only change SEC_LEVEL for open mode. Others
7750 * are set by ipw_wpa_set_encryption.
7751 */
7752 if (!param->value) {
7753 sec.flags |= SEC_LEVEL;
7754 sec.level = SEC_LEVEL_0;
7755 } else {
7756 sec.flags |= SEC_LEVEL;
7757 sec.level = SEC_LEVEL_1;
7758 }
7759 if (priv->ieee->set_security)
7760 priv->ieee->set_security(priv->ieee->dev, &sec);
7761 break;
7762 }
7763
7764 case IW_AUTH_80211_AUTH_ALG:
7765 ret = ipw2100_wpa_set_auth_algs(priv, param->value);
7766 break;
7767
7768 case IW_AUTH_WPA_ENABLED:
7769 ret = ipw2100_wpa_enable(priv, param->value);
7770 break;
7771
7772 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
7773 ieee->ieee802_1x = param->value;
7774 break;
7775
7776 //case IW_AUTH_ROAMING_CONTROL:
7777 case IW_AUTH_PRIVACY_INVOKED:
7778 ieee->privacy_invoked = param->value;
7779 break;
7780
7781 default:
7782 return -EOPNOTSUPP;
7783 }
7784 return ret;
7785}
7786
7787/* SIOCGIWAUTH */
7788static int ipw2100_wx_get_auth(struct net_device *dev,
7789 struct iw_request_info *info,
7790 union iwreq_data *wrqu, char *extra)
7791{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007792 struct ipw2100_priv *priv = libipw_priv(dev);
7793 struct libipw_device *ieee = priv->ieee;
John W. Linville274bfb82008-10-29 11:35:05 -04007794 struct lib80211_crypt_data *crypt;
James Ketrenos82328352005-08-24 22:33:31 -05007795 struct iw_param *param = &wrqu->param;
7796 int ret = 0;
7797
7798 switch (param->flags & IW_AUTH_INDEX) {
7799 case IW_AUTH_WPA_VERSION:
7800 case IW_AUTH_CIPHER_PAIRWISE:
7801 case IW_AUTH_CIPHER_GROUP:
7802 case IW_AUTH_KEY_MGMT:
7803 /*
7804 * wpa_supplicant will control these internally
7805 */
7806 ret = -EOPNOTSUPP;
7807 break;
7808
7809 case IW_AUTH_TKIP_COUNTERMEASURES:
John W. Linville274bfb82008-10-29 11:35:05 -04007810 crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
James Ketrenos82328352005-08-24 22:33:31 -05007811 if (!crypt || !crypt->ops->get_flags) {
7812 IPW_DEBUG_WARNING("Can't get TKIP countermeasures: "
7813 "crypt not set!\n");
7814 break;
7815 }
7816
7817 param->value = (crypt->ops->get_flags(crypt->priv) &
7818 IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
7819
7820 break;
7821
7822 case IW_AUTH_DROP_UNENCRYPTED:
7823 param->value = ieee->drop_unencrypted;
7824 break;
7825
7826 case IW_AUTH_80211_AUTH_ALG:
25b645b2005-07-12 15:45:30 -05007827 param->value = priv->ieee->sec.auth_mode;
James Ketrenos82328352005-08-24 22:33:31 -05007828 break;
7829
7830 case IW_AUTH_WPA_ENABLED:
7831 param->value = ieee->wpa_enabled;
7832 break;
7833
7834 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
7835 param->value = ieee->ieee802_1x;
7836 break;
7837
7838 case IW_AUTH_ROAMING_CONTROL:
7839 case IW_AUTH_PRIVACY_INVOKED:
7840 param->value = ieee->privacy_invoked;
7841 break;
7842
7843 default:
7844 return -EOPNOTSUPP;
7845 }
7846 return 0;
7847}
7848
7849/* SIOCSIWENCODEEXT */
7850static int ipw2100_wx_set_encodeext(struct net_device *dev,
7851 struct iw_request_info *info,
7852 union iwreq_data *wrqu, char *extra)
7853{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007854 struct ipw2100_priv *priv = libipw_priv(dev);
7855 return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra);
James Ketrenos82328352005-08-24 22:33:31 -05007856}
7857
7858/* SIOCGIWENCODEEXT */
7859static int ipw2100_wx_get_encodeext(struct net_device *dev,
7860 struct iw_request_info *info,
7861 union iwreq_data *wrqu, char *extra)
7862{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007863 struct ipw2100_priv *priv = libipw_priv(dev);
7864 return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra);
James Ketrenos82328352005-08-24 22:33:31 -05007865}
7866
7867/* SIOCSIWMLME */
7868static int ipw2100_wx_set_mlme(struct net_device *dev,
7869 struct iw_request_info *info,
7870 union iwreq_data *wrqu, char *extra)
7871{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007872 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos82328352005-08-24 22:33:31 -05007873 struct iw_mlme *mlme = (struct iw_mlme *)extra;
Al Viro1edd3a52007-12-21 00:15:18 -05007874 __le16 reason;
James Ketrenos82328352005-08-24 22:33:31 -05007875
7876 reason = cpu_to_le16(mlme->reason_code);
7877
7878 switch (mlme->cmd) {
7879 case IW_MLME_DEAUTH:
7880 // silently ignore
7881 break;
7882
7883 case IW_MLME_DISASSOC:
7884 ipw2100_disassociate_bssid(priv);
7885 break;
7886
7887 default:
7888 return -EOPNOTSUPP;
7889 }
7890 return 0;
7891}
James Ketrenos2c86c272005-03-23 17:32:29 -06007892
7893/*
7894 *
7895 * IWPRIV handlers
7896 *
7897 */
7898#ifdef CONFIG_IPW2100_MONITOR
7899static int ipw2100_wx_set_promisc(struct net_device *dev,
7900 struct iw_request_info *info,
7901 union iwreq_data *wrqu, char *extra)
7902{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007903 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007904 int *parms = (int *)extra;
7905 int enable = (parms[0] > 0);
7906 int err = 0;
7907
Ingo Molnar752e3772006-02-28 07:20:54 +08007908 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007909 if (!(priv->status & STATUS_INITIALIZED)) {
7910 err = -EIO;
7911 goto done;
7912 }
7913
7914 if (enable) {
7915 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
7916 err = ipw2100_set_channel(priv, parms[1], 0);
7917 goto done;
7918 }
7919 priv->channel = parms[1];
7920 err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
7921 } else {
7922 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
7923 err = ipw2100_switch_mode(priv, priv->last_mode);
7924 }
James Ketrenosee8e3652005-09-14 09:47:29 -05007925 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007926 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007927 return err;
7928}
7929
7930static int ipw2100_wx_reset(struct net_device *dev,
7931 struct iw_request_info *info,
7932 union iwreq_data *wrqu, char *extra)
7933{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007934 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007935 if (priv->status & STATUS_INITIALIZED)
7936 schedule_reset(priv);
7937 return 0;
7938}
7939
7940#endif
7941
7942static int ipw2100_wx_set_powermode(struct net_device *dev,
7943 struct iw_request_info *info,
7944 union iwreq_data *wrqu, char *extra)
7945{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007946 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007947 int err = 0, mode = *(int *)extra;
7948
Ingo Molnar752e3772006-02-28 07:20:54 +08007949 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007950 if (!(priv->status & STATUS_INITIALIZED)) {
7951 err = -EIO;
7952 goto done;
7953 }
7954
Zhu Yi9f3b2412007-07-12 16:09:24 +08007955 if ((mode < 0) || (mode > POWER_MODES))
James Ketrenos2c86c272005-03-23 17:32:29 -06007956 mode = IPW_POWER_AUTO;
7957
Zhu Yi9f3b2412007-07-12 16:09:24 +08007958 if (IPW_POWER_LEVEL(priv->power_mode) != mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06007959 err = ipw2100_set_power_mode(priv, mode);
James Ketrenosee8e3652005-09-14 09:47:29 -05007960 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007961 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007962 return err;
7963}
7964
7965#define MAX_POWER_STRING 80
7966static int ipw2100_wx_get_powermode(struct net_device *dev,
7967 struct iw_request_info *info,
7968 union iwreq_data *wrqu, char *extra)
7969{
7970 /*
7971 * This can be called at any time. No action lock required
7972 */
7973
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007974 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007975 int level = IPW_POWER_LEVEL(priv->power_mode);
7976 s32 timeout, period;
7977
7978 if (!(priv->power_mode & IPW_POWER_ENABLED)) {
7979 snprintf(extra, MAX_POWER_STRING,
7980 "Power save level: %d (Off)", level);
7981 } else {
7982 switch (level) {
7983 case IPW_POWER_MODE_CAM:
7984 snprintf(extra, MAX_POWER_STRING,
7985 "Power save level: %d (None)", level);
7986 break;
7987 case IPW_POWER_AUTO:
James Ketrenosee8e3652005-09-14 09:47:29 -05007988 snprintf(extra, MAX_POWER_STRING,
Zhu Yi9f3b2412007-07-12 16:09:24 +08007989 "Power save level: %d (Auto)", level);
James Ketrenos2c86c272005-03-23 17:32:29 -06007990 break;
7991 default:
7992 timeout = timeout_duration[level - 1] / 1000;
7993 period = period_duration[level - 1] / 1000;
7994 snprintf(extra, MAX_POWER_STRING,
7995 "Power save level: %d "
7996 "(Timeout %dms, Period %dms)",
7997 level, timeout, period);
7998 }
7999 }
8000
8001 wrqu->data.length = strlen(extra) + 1;
8002
8003 return 0;
8004}
8005
James Ketrenos2c86c272005-03-23 17:32:29 -06008006static int ipw2100_wx_set_preamble(struct net_device *dev,
8007 struct iw_request_info *info,
8008 union iwreq_data *wrqu, char *extra)
8009{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008010 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008011 int err, mode = *(int *)extra;
8012
Ingo Molnar752e3772006-02-28 07:20:54 +08008013 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008014 if (!(priv->status & STATUS_INITIALIZED)) {
8015 err = -EIO;
8016 goto done;
8017 }
8018
8019 if (mode == 1)
8020 priv->config |= CFG_LONG_PREAMBLE;
8021 else if (mode == 0)
8022 priv->config &= ~CFG_LONG_PREAMBLE;
8023 else {
8024 err = -EINVAL;
8025 goto done;
8026 }
8027
8028 err = ipw2100_system_config(priv, 0);
8029
James Ketrenosee8e3652005-09-14 09:47:29 -05008030 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08008031 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008032 return err;
8033}
8034
8035static int ipw2100_wx_get_preamble(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05008036 struct iw_request_info *info,
8037 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06008038{
8039 /*
8040 * This can be called at any time. No action lock required
8041 */
8042
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008043 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008044
8045 if (priv->config & CFG_LONG_PREAMBLE)
8046 snprintf(wrqu->name, IFNAMSIZ, "long (1)");
8047 else
8048 snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
8049
8050 return 0;
8051}
8052
James Ketrenos82328352005-08-24 22:33:31 -05008053#ifdef CONFIG_IPW2100_MONITOR
8054static int ipw2100_wx_set_crc_check(struct net_device *dev,
8055 struct iw_request_info *info,
8056 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06008057{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008058 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos82328352005-08-24 22:33:31 -05008059 int err, mode = *(int *)extra;
8060
Ingo Molnar752e3772006-02-28 07:20:54 +08008061 mutex_lock(&priv->action_mutex);
James Ketrenos82328352005-08-24 22:33:31 -05008062 if (!(priv->status & STATUS_INITIALIZED)) {
8063 err = -EIO;
8064 goto done;
8065 }
8066
8067 if (mode == 1)
8068 priv->config |= CFG_CRC_CHECK;
8069 else if (mode == 0)
8070 priv->config &= ~CFG_CRC_CHECK;
8071 else {
8072 err = -EINVAL;
8073 goto done;
8074 }
8075 err = 0;
8076
8077 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08008078 mutex_unlock(&priv->action_mutex);
James Ketrenos82328352005-08-24 22:33:31 -05008079 return err;
8080}
8081
8082static int ipw2100_wx_get_crc_check(struct net_device *dev,
8083 struct iw_request_info *info,
8084 union iwreq_data *wrqu, char *extra)
8085{
8086 /*
8087 * This can be called at any time. No action lock required
8088 */
8089
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008090 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos82328352005-08-24 22:33:31 -05008091
8092 if (priv->config & CFG_CRC_CHECK)
8093 snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)");
8094 else
8095 snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)");
8096
8097 return 0;
8098}
8099#endif /* CONFIG_IPW2100_MONITOR */
8100
James Ketrenosee8e3652005-09-14 09:47:29 -05008101static iw_handler ipw2100_wx_handlers[] = {
Stanislav Yakovlev06d9b6a2012-02-23 17:31:24 -05008102 IW_HANDLER(SIOCGIWNAME, ipw2100_wx_get_name),
8103 IW_HANDLER(SIOCSIWFREQ, ipw2100_wx_set_freq),
8104 IW_HANDLER(SIOCGIWFREQ, ipw2100_wx_get_freq),
8105 IW_HANDLER(SIOCSIWMODE, ipw2100_wx_set_mode),
8106 IW_HANDLER(SIOCGIWMODE, ipw2100_wx_get_mode),
8107 IW_HANDLER(SIOCGIWRANGE, ipw2100_wx_get_range),
8108 IW_HANDLER(SIOCSIWAP, ipw2100_wx_set_wap),
8109 IW_HANDLER(SIOCGIWAP, ipw2100_wx_get_wap),
8110 IW_HANDLER(SIOCSIWMLME, ipw2100_wx_set_mlme),
8111 IW_HANDLER(SIOCSIWSCAN, ipw2100_wx_set_scan),
8112 IW_HANDLER(SIOCGIWSCAN, ipw2100_wx_get_scan),
8113 IW_HANDLER(SIOCSIWESSID, ipw2100_wx_set_essid),
8114 IW_HANDLER(SIOCGIWESSID, ipw2100_wx_get_essid),
8115 IW_HANDLER(SIOCSIWNICKN, ipw2100_wx_set_nick),
8116 IW_HANDLER(SIOCGIWNICKN, ipw2100_wx_get_nick),
8117 IW_HANDLER(SIOCSIWRATE, ipw2100_wx_set_rate),
8118 IW_HANDLER(SIOCGIWRATE, ipw2100_wx_get_rate),
8119 IW_HANDLER(SIOCSIWRTS, ipw2100_wx_set_rts),
8120 IW_HANDLER(SIOCGIWRTS, ipw2100_wx_get_rts),
8121 IW_HANDLER(SIOCSIWFRAG, ipw2100_wx_set_frag),
8122 IW_HANDLER(SIOCGIWFRAG, ipw2100_wx_get_frag),
8123 IW_HANDLER(SIOCSIWTXPOW, ipw2100_wx_set_txpow),
8124 IW_HANDLER(SIOCGIWTXPOW, ipw2100_wx_get_txpow),
8125 IW_HANDLER(SIOCSIWRETRY, ipw2100_wx_set_retry),
8126 IW_HANDLER(SIOCGIWRETRY, ipw2100_wx_get_retry),
8127 IW_HANDLER(SIOCSIWENCODE, ipw2100_wx_set_encode),
8128 IW_HANDLER(SIOCGIWENCODE, ipw2100_wx_get_encode),
8129 IW_HANDLER(SIOCSIWPOWER, ipw2100_wx_set_power),
8130 IW_HANDLER(SIOCGIWPOWER, ipw2100_wx_get_power),
8131 IW_HANDLER(SIOCSIWGENIE, ipw2100_wx_set_genie),
8132 IW_HANDLER(SIOCGIWGENIE, ipw2100_wx_get_genie),
8133 IW_HANDLER(SIOCSIWAUTH, ipw2100_wx_set_auth),
8134 IW_HANDLER(SIOCGIWAUTH, ipw2100_wx_get_auth),
8135 IW_HANDLER(SIOCSIWENCODEEXT, ipw2100_wx_set_encodeext),
8136 IW_HANDLER(SIOCGIWENCODEEXT, ipw2100_wx_get_encodeext),
James Ketrenos2c86c272005-03-23 17:32:29 -06008137};
8138
8139#define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV
8140#define IPW2100_PRIV_RESET SIOCIWFIRSTPRIV+1
8141#define IPW2100_PRIV_SET_POWER SIOCIWFIRSTPRIV+2
8142#define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3
8143#define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4
8144#define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5
James Ketrenos82328352005-08-24 22:33:31 -05008145#define IPW2100_PRIV_SET_CRC_CHECK SIOCIWFIRSTPRIV+6
8146#define IPW2100_PRIV_GET_CRC_CHECK SIOCIWFIRSTPRIV+7
James Ketrenos2c86c272005-03-23 17:32:29 -06008147
8148static const struct iw_priv_args ipw2100_private_args[] = {
8149
8150#ifdef CONFIG_IPW2100_MONITOR
8151 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008152 IPW2100_PRIV_SET_MONITOR,
8153 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008154 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008155 IPW2100_PRIV_RESET,
8156 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
8157#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008158
8159 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008160 IPW2100_PRIV_SET_POWER,
8161 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008162 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008163 IPW2100_PRIV_GET_POWER,
8164 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING,
8165 "get_power"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008166 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008167 IPW2100_PRIV_SET_LONGPREAMBLE,
8168 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008169 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008170 IPW2100_PRIV_GET_LONGPREAMBLE,
8171 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"},
James Ketrenos82328352005-08-24 22:33:31 -05008172#ifdef CONFIG_IPW2100_MONITOR
8173 {
8174 IPW2100_PRIV_SET_CRC_CHECK,
8175 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"},
8176 {
8177 IPW2100_PRIV_GET_CRC_CHECK,
8178 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"},
8179#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008180};
8181
8182static iw_handler ipw2100_private_handler[] = {
8183#ifdef CONFIG_IPW2100_MONITOR
8184 ipw2100_wx_set_promisc,
8185 ipw2100_wx_reset,
James Ketrenosee8e3652005-09-14 09:47:29 -05008186#else /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008187 NULL,
8188 NULL,
James Ketrenosee8e3652005-09-14 09:47:29 -05008189#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008190 ipw2100_wx_set_powermode,
8191 ipw2100_wx_get_powermode,
8192 ipw2100_wx_set_preamble,
8193 ipw2100_wx_get_preamble,
James Ketrenos82328352005-08-24 22:33:31 -05008194#ifdef CONFIG_IPW2100_MONITOR
8195 ipw2100_wx_set_crc_check,
8196 ipw2100_wx_get_crc_check,
8197#else /* CONFIG_IPW2100_MONITOR */
8198 NULL,
8199 NULL,
8200#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008201};
8202
James Ketrenos2c86c272005-03-23 17:32:29 -06008203/*
8204 * Get wireless statistics.
8205 * Called by /proc/net/wireless
8206 * Also called by SIOCGIWSTATS
8207 */
James Ketrenosee8e3652005-09-14 09:47:29 -05008208static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
James Ketrenos2c86c272005-03-23 17:32:29 -06008209{
8210 enum {
8211 POOR = 30,
8212 FAIR = 60,
8213 GOOD = 80,
8214 VERY_GOOD = 90,
8215 EXCELLENT = 95,
8216 PERFECT = 100
8217 };
8218 int rssi_qual;
8219 int tx_qual;
8220 int beacon_qual;
Reinette Chatre21f8a732009-08-18 10:25:05 -07008221 int quality;
James Ketrenos2c86c272005-03-23 17:32:29 -06008222
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008223 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008224 struct iw_statistics *wstats;
Reinette Chatre21f8a732009-08-18 10:25:05 -07008225 u32 rssi, tx_retries, missed_beacons, tx_failures;
James Ketrenos2c86c272005-03-23 17:32:29 -06008226 u32 ord_len = sizeof(u32);
8227
8228 if (!priv)
James Ketrenosee8e3652005-09-14 09:47:29 -05008229 return (struct iw_statistics *)NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06008230
8231 wstats = &priv->wstats;
8232
8233 /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
8234 * ipw2100_wx_wireless_stats seems to be called before fw is
8235 * initialized. STATUS_ASSOCIATED will only be set if the hw is up
8236 * and associated; if not associcated, the values are all meaningless
8237 * anyway, so set them all to NULL and INVALID */
8238 if (!(priv->status & STATUS_ASSOCIATED)) {
8239 wstats->miss.beacon = 0;
8240 wstats->discard.retries = 0;
8241 wstats->qual.qual = 0;
8242 wstats->qual.level = 0;
8243 wstats->qual.noise = 0;
8244 wstats->qual.updated = 7;
8245 wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
James Ketrenosee8e3652005-09-14 09:47:29 -05008246 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
James Ketrenos2c86c272005-03-23 17:32:29 -06008247 return wstats;
8248 }
8249
8250 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS,
8251 &missed_beacons, &ord_len))
8252 goto fail_get_ordinal;
8253
James Ketrenosee8e3652005-09-14 09:47:29 -05008254 /* If we don't have a connection the quality and level is 0 */
James Ketrenos2c86c272005-03-23 17:32:29 -06008255 if (!(priv->status & STATUS_ASSOCIATED)) {
8256 wstats->qual.qual = 0;
8257 wstats->qual.level = 0;
8258 } else {
8259 if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR,
8260 &rssi, &ord_len))
8261 goto fail_get_ordinal;
8262 wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
8263 if (rssi < 10)
8264 rssi_qual = rssi * POOR / 10;
8265 else if (rssi < 15)
8266 rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR;
8267 else if (rssi < 20)
8268 rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR;
8269 else if (rssi < 30)
8270 rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008271 10 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008272 else
8273 rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008274 10 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008275
8276 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES,
8277 &tx_retries, &ord_len))
8278 goto fail_get_ordinal;
8279
8280 if (tx_retries > 75)
8281 tx_qual = (90 - tx_retries) * POOR / 15;
8282 else if (tx_retries > 70)
8283 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
8284 else if (tx_retries > 65)
8285 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
8286 else if (tx_retries > 50)
8287 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008288 15 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008289 else
8290 tx_qual = (50 - tx_retries) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008291 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008292
8293 if (missed_beacons > 50)
8294 beacon_qual = (60 - missed_beacons) * POOR / 10;
8295 else if (missed_beacons > 40)
8296 beacon_qual = (50 - missed_beacons) * (FAIR - POOR) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008297 10 + POOR;
James Ketrenos2c86c272005-03-23 17:32:29 -06008298 else if (missed_beacons > 32)
8299 beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008300 18 + FAIR;
James Ketrenos2c86c272005-03-23 17:32:29 -06008301 else if (missed_beacons > 20)
8302 beacon_qual = (32 - missed_beacons) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008303 (VERY_GOOD - GOOD) / 20 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008304 else
8305 beacon_qual = (20 - missed_beacons) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008306 (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008307
Reinette Chatre21f8a732009-08-18 10:25:05 -07008308 quality = min(tx_qual, rssi_qual);
8309 quality = min(beacon_qual, quality);
James Ketrenos2c86c272005-03-23 17:32:29 -06008310
Brice Goglin0f52bf92005-12-01 01:41:46 -08008311#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06008312 if (beacon_qual == quality)
8313 IPW_DEBUG_WX("Quality clamped by Missed Beacons\n");
8314 else if (tx_qual == quality)
8315 IPW_DEBUG_WX("Quality clamped by Tx Retries\n");
8316 else if (quality != 100)
8317 IPW_DEBUG_WX("Quality clamped by Signal Strength\n");
8318 else
8319 IPW_DEBUG_WX("Quality not clamped.\n");
8320#endif
8321
8322 wstats->qual.qual = quality;
8323 wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
8324 }
8325
8326 wstats->qual.noise = 0;
8327 wstats->qual.updated = 7;
8328 wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
8329
James Ketrenosee8e3652005-09-14 09:47:29 -05008330 /* FIXME: this is percent and not a # */
James Ketrenos2c86c272005-03-23 17:32:29 -06008331 wstats->miss.beacon = missed_beacons;
8332
8333 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES,
8334 &tx_failures, &ord_len))
8335 goto fail_get_ordinal;
8336 wstats->discard.retries = tx_failures;
8337
8338 return wstats;
8339
James Ketrenosee8e3652005-09-14 09:47:29 -05008340 fail_get_ordinal:
James Ketrenos2c86c272005-03-23 17:32:29 -06008341 IPW_DEBUG_WX("failed querying ordinals.\n");
8342
James Ketrenosee8e3652005-09-14 09:47:29 -05008343 return (struct iw_statistics *)NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06008344}
8345
James Ketrenoseaf8f532005-11-12 12:50:12 -06008346static struct iw_handler_def ipw2100_wx_handler_def = {
8347 .standard = ipw2100_wx_handlers,
Denis Chengff8ac602007-09-02 18:30:18 +08008348 .num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
8349 .num_private = ARRAY_SIZE(ipw2100_private_handler),
8350 .num_private_args = ARRAY_SIZE(ipw2100_private_args),
James Ketrenoseaf8f532005-11-12 12:50:12 -06008351 .private = (iw_handler *) ipw2100_private_handler,
8352 .private_args = (struct iw_priv_args *)ipw2100_private_args,
8353 .get_wireless_stats = ipw2100_wx_wireless_stats,
8354};
8355
David Howellsc4028952006-11-22 14:57:56 +00008356static void ipw2100_wx_event_work(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06008357{
David Howellsc4028952006-11-22 14:57:56 +00008358 struct ipw2100_priv *priv =
8359 container_of(work, struct ipw2100_priv, wx_event_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06008360 union iwreq_data wrqu;
Hannes Ederb9da9e92009-02-14 11:50:26 +00008361 unsigned int len = ETH_ALEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06008362
8363 if (priv->status & STATUS_STOPPING)
8364 return;
8365
Ingo Molnar752e3772006-02-28 07:20:54 +08008366 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008367
8368 IPW_DEBUG_WX("enter\n");
8369
Ingo Molnar752e3772006-02-28 07:20:54 +08008370 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008371
8372 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
8373
8374 /* Fetch BSSID from the hardware */
8375 if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) ||
8376 priv->status & STATUS_RF_KILL_MASK ||
8377 ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
James Ketrenosee8e3652005-09-14 09:47:29 -05008378 &priv->bssid, &len)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06008379 memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
8380 } else {
8381 /* We now have the BSSID, so can finish setting to the full
8382 * associated state */
8383 memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
James Ketrenos82328352005-08-24 22:33:31 -05008384 memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06008385 priv->status &= ~STATUS_ASSOCIATING;
8386 priv->status |= STATUS_ASSOCIATED;
8387 netif_carrier_on(priv->net_dev);
James Ketrenos82328352005-08-24 22:33:31 -05008388 netif_wake_queue(priv->net_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008389 }
8390
8391 if (!(priv->status & STATUS_ASSOCIATED)) {
8392 IPW_DEBUG_WX("Configuring ESSID\n");
Ingo Molnar752e3772006-02-28 07:20:54 +08008393 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008394 /* This is a disassociation event, so kick the firmware to
8395 * look for another AP */
8396 if (priv->config & CFG_STATIC_ESSID)
James Ketrenosee8e3652005-09-14 09:47:29 -05008397 ipw2100_set_essid(priv, priv->essid, priv->essid_len,
8398 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06008399 else
8400 ipw2100_set_essid(priv, NULL, 0, 0);
Ingo Molnar752e3772006-02-28 07:20:54 +08008401 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008402 }
8403
8404 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
8405}
8406
8407#define IPW2100_FW_MAJOR_VERSION 1
8408#define IPW2100_FW_MINOR_VERSION 3
8409
8410#define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8)
8411#define IPW2100_FW_MAJOR(x) (x & 0xff)
8412
8413#define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \
8414 IPW2100_FW_MAJOR_VERSION)
8415
8416#define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \
8417"." __stringify(IPW2100_FW_MINOR_VERSION)
8418
8419#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw"
8420
James Ketrenos2c86c272005-03-23 17:32:29 -06008421/*
8422
8423BINARY FIRMWARE HEADER FORMAT
8424
8425offset length desc
84260 2 version
84272 2 mode == 0:BSS,1:IBSS,2:MONITOR
84284 4 fw_len
84298 4 uc_len
8430C fw_len firmware data
843112 + fw_len uc_len microcode data
8432
8433*/
8434
8435struct ipw2100_fw_header {
8436 short version;
8437 short mode;
8438 unsigned int fw_size;
8439 unsigned int uc_size;
Eric Dumazetba2d3582010-06-02 18:10:09 +00008440} __packed;
James Ketrenos2c86c272005-03-23 17:32:29 -06008441
James Ketrenos2c86c272005-03-23 17:32:29 -06008442static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
8443{
8444 struct ipw2100_fw_header *h =
James Ketrenosee8e3652005-09-14 09:47:29 -05008445 (struct ipw2100_fw_header *)fw->fw_entry->data;
James Ketrenos2c86c272005-03-23 17:32:29 -06008446
8447 if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008448 printk(KERN_WARNING DRV_NAME ": Firmware image not compatible "
James Ketrenos2c86c272005-03-23 17:32:29 -06008449 "(detected version id of %u). "
8450 "See Documentation/networking/README.ipw2100\n",
8451 h->version);
8452 return 1;
8453 }
8454
8455 fw->version = h->version;
8456 fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header);
8457 fw->fw.size = h->fw_size;
8458 fw->uc.data = fw->fw.data + h->fw_size;
8459 fw->uc.size = h->uc_size;
8460
8461 return 0;
8462}
8463
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008464static int ipw2100_get_firmware(struct ipw2100_priv *priv,
8465 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008466{
8467 char *fw_name;
8468 int rc;
8469
8470 IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05008471 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06008472
8473 switch (priv->ieee->iw_mode) {
8474 case IW_MODE_ADHOC:
8475 fw_name = IPW2100_FW_NAME("-i");
8476 break;
8477#ifdef CONFIG_IPW2100_MONITOR
8478 case IW_MODE_MONITOR:
8479 fw_name = IPW2100_FW_NAME("-p");
8480 break;
8481#endif
8482 case IW_MODE_INFRA:
8483 default:
8484 fw_name = IPW2100_FW_NAME("");
8485 break;
8486 }
8487
8488 rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev);
8489
8490 if (rc < 0) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008491 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06008492 "%s: Firmware '%s' not available or load failed.\n",
8493 priv->net_dev->name, fw_name);
8494 return rc;
8495 }
Jiri Bencaaa4d302005-06-07 14:58:41 +02008496 IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data,
James Ketrenosee8e3652005-09-14 09:47:29 -05008497 fw->fw_entry->size);
James Ketrenos2c86c272005-03-23 17:32:29 -06008498
8499 ipw2100_mod_firmware_load(fw);
8500
8501 return 0;
8502}
8503
Ben Hutchingsa278ea32009-11-07 21:58:47 +00008504MODULE_FIRMWARE(IPW2100_FW_NAME("-i"));
8505#ifdef CONFIG_IPW2100_MONITOR
8506MODULE_FIRMWARE(IPW2100_FW_NAME("-p"));
8507#endif
8508MODULE_FIRMWARE(IPW2100_FW_NAME(""));
8509
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008510static void ipw2100_release_firmware(struct ipw2100_priv *priv,
8511 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008512{
8513 fw->version = 0;
8514 if (fw->fw_entry)
8515 release_firmware(fw->fw_entry);
8516 fw->fw_entry = NULL;
8517}
8518
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008519static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
8520 size_t max)
James Ketrenos2c86c272005-03-23 17:32:29 -06008521{
8522 char ver[MAX_FW_VERSION_LEN];
8523 u32 len = MAX_FW_VERSION_LEN;
8524 u32 tmp;
8525 int i;
8526 /* firmware version is an ascii string (max len of 14) */
James Ketrenosee8e3652005-09-14 09:47:29 -05008527 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len))
James Ketrenos2c86c272005-03-23 17:32:29 -06008528 return -EIO;
8529 tmp = max;
8530 if (len >= max)
8531 len = max - 1;
8532 for (i = 0; i < len; i++)
8533 buf[i] = ver[i];
8534 buf[i] = '\0';
8535 return tmp;
8536}
8537
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008538static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
8539 size_t max)
James Ketrenos2c86c272005-03-23 17:32:29 -06008540{
8541 u32 ver;
8542 u32 len = sizeof(ver);
8543 /* microcode version is a 32 bit integer */
James Ketrenosee8e3652005-09-14 09:47:29 -05008544 if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len))
James Ketrenos2c86c272005-03-23 17:32:29 -06008545 return -EIO;
8546 return snprintf(buf, max, "%08X", ver);
8547}
8548
8549/*
8550 * On exit, the firmware will have been freed from the fw list
8551 */
James Ketrenosee8e3652005-09-14 09:47:29 -05008552static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008553{
8554 /* firmware is constructed of N contiguous entries, each entry is
8555 * structured as:
8556 *
8557 * offset sie desc
8558 * 0 4 address to write to
8559 * 4 2 length of data run
James Ketrenosee8e3652005-09-14 09:47:29 -05008560 * 6 length data
James Ketrenos2c86c272005-03-23 17:32:29 -06008561 */
8562 unsigned int addr;
8563 unsigned short len;
8564
8565 const unsigned char *firmware_data = fw->fw.data;
8566 unsigned int firmware_data_left = fw->fw.size;
8567
8568 while (firmware_data_left > 0) {
James Ketrenosee8e3652005-09-14 09:47:29 -05008569 addr = *(u32 *) (firmware_data);
8570 firmware_data += 4;
James Ketrenos2c86c272005-03-23 17:32:29 -06008571 firmware_data_left -= 4;
8572
James Ketrenosee8e3652005-09-14 09:47:29 -05008573 len = *(u16 *) (firmware_data);
8574 firmware_data += 2;
James Ketrenos2c86c272005-03-23 17:32:29 -06008575 firmware_data_left -= 2;
8576
8577 if (len > 32) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008578 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06008579 "Invalid firmware run-length of %d bytes\n",
8580 len);
8581 return -EINVAL;
8582 }
8583
8584 write_nic_memory(priv->net_dev, addr, len, firmware_data);
James Ketrenosee8e3652005-09-14 09:47:29 -05008585 firmware_data += len;
James Ketrenos2c86c272005-03-23 17:32:29 -06008586 firmware_data_left -= len;
8587 }
8588
8589 return 0;
8590}
8591
8592struct symbol_alive_response {
8593 u8 cmd_id;
8594 u8 seq_num;
8595 u8 ucode_rev;
8596 u8 eeprom_valid;
8597 u16 valid_flags;
8598 u8 IEEE_addr[6];
8599 u16 flags;
8600 u16 pcb_rev;
8601 u16 clock_settle_time; // 1us LSB
8602 u16 powerup_settle_time; // 1us LSB
8603 u16 hop_settle_time; // 1us LSB
8604 u8 date[3]; // month, day, year
8605 u8 time[2]; // hours, minutes
8606 u8 ucode_valid;
8607};
8608
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008609static int ipw2100_ucode_download(struct ipw2100_priv *priv,
8610 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008611{
8612 struct net_device *dev = priv->net_dev;
8613 const unsigned char *microcode_data = fw->uc.data;
8614 unsigned int microcode_data_left = fw->uc.size;
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008615 void __iomem *reg = (void __iomem *)dev->base_addr;
James Ketrenos2c86c272005-03-23 17:32:29 -06008616
8617 struct symbol_alive_response response;
8618 int i, j;
8619 u8 data;
8620
8621 /* Symbol control */
8622 write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008623 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008624 write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008625 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008626
8627 /* HW config */
8628 write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
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, 0x210014, 0x72); /* fifo width =16 */
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008631 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008632
8633 /* EN_CS_ACCESS bit to reset control store pointer */
8634 write_nic_byte(dev, 0x210000, 0x40);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008635 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008636 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008637 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008638 write_nic_byte(dev, 0x210000, 0x40);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008639 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008640
8641 /* copy microcode from buffer into Symbol */
8642
8643 while (microcode_data_left > 0) {
8644 write_nic_byte(dev, 0x210010, *microcode_data++);
8645 write_nic_byte(dev, 0x210010, *microcode_data++);
8646 microcode_data_left -= 2;
8647 }
8648
8649 /* EN_CS_ACCESS bit to reset the control store pointer */
8650 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008651 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008652
8653 /* Enable System (Reg 0)
8654 * first enable causes garbage in RX FIFO */
8655 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008656 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008657 write_nic_byte(dev, 0x210000, 0x80);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008658 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008659
8660 /* Reset External Baseband Reg */
8661 write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008662 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008663 write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008664 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008665
8666 /* HW Config (Reg 5) */
8667 write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008668 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008669 write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008670 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008671
8672 /* Enable System (Reg 0)
8673 * second enable should be OK */
8674 write_nic_byte(dev, 0x210000, 0x00); // clear enable system
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008675 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008676 write_nic_byte(dev, 0x210000, 0x80); // set enable system
8677
8678 /* check Symbol is enabled - upped this from 5 as it wasn't always
8679 * catching the update */
8680 for (i = 0; i < 10; i++) {
8681 udelay(10);
8682
8683 /* check Dino is enabled bit */
8684 read_nic_byte(dev, 0x210000, &data);
8685 if (data & 0x1)
8686 break;
8687 }
8688
8689 if (i == 10) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008690 printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06008691 dev->name);
8692 return -EIO;
8693 }
8694
8695 /* Get Symbol alive response */
8696 for (i = 0; i < 30; i++) {
8697 /* Read alive response structure */
8698 for (j = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05008699 j < (sizeof(struct symbol_alive_response) >> 1); j++)
8700 read_nic_word(dev, 0x210004, ((u16 *) & response) + j);
James Ketrenos2c86c272005-03-23 17:32:29 -06008701
James Ketrenosee8e3652005-09-14 09:47:29 -05008702 if ((response.cmd_id == 1) && (response.ucode_valid == 0x1))
James Ketrenos2c86c272005-03-23 17:32:29 -06008703 break;
8704 udelay(10);
8705 }
8706
8707 if (i == 30) {
James Ketrenosee8e3652005-09-14 09:47:29 -05008708 printk(KERN_ERR DRV_NAME
8709 ": %s: No response from Symbol - hw not alive\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06008710 dev->name);
James Ketrenosee8e3652005-09-14 09:47:29 -05008711 printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response));
James Ketrenos2c86c272005-03-23 17:32:29 -06008712 return -EIO;
8713 }
8714
8715 return 0;
8716}