blob: 3a6d810a7608bdfc88ec540f9c95dc3d96ee4a74 [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:
22 James P. Ketrenos <ipw2100-admin@linux.intel.com>
23 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
66of fragments, etc. The next TBD then referrs to the actual packet location.
67
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>
Mark Grossf011e2e2008-02-04 22:30:09 -0800164#include <linux/pm_qos_params.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
177/* Debugging stuff */
Brice Goglin0f52bf92005-12-01 01:41:46 -0800178#ifdef CONFIG_IPW2100_DEBUG
Robert P. J. Dayae800312007-01-31 02:39:40 -0500179#define IPW2100_RX_DEBUG /* Reception debugging */
James Ketrenos2c86c272005-03-23 17:32:29 -0600180#endif
181
182MODULE_DESCRIPTION(DRV_DESCRIPTION);
183MODULE_VERSION(DRV_VERSION);
184MODULE_AUTHOR(DRV_COPYRIGHT);
185MODULE_LICENSE("GPL");
186
187static int debug = 0;
188static int mode = 0;
189static int channel = 0;
Tim Gardner5c7f9b72008-10-14 10:38:03 -0600190static int associate = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -0600191static int disable = 0;
192#ifdef CONFIG_PM
193static struct ipw2100_fw ipw2100_firmware;
194#endif
195
196#include <linux/moduleparam.h>
197module_param(debug, int, 0444);
198module_param(mode, int, 0444);
199module_param(channel, int, 0444);
200module_param(associate, int, 0444);
201module_param(disable, int, 0444);
202
203MODULE_PARM_DESC(debug, "debug level");
204MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
205MODULE_PARM_DESC(channel, "channel");
Tim Gardner5c7f9b72008-10-14 10:38:03 -0600206MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
James Ketrenos2c86c272005-03-23 17:32:29 -0600207MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
208
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400209static u32 ipw2100_debug_level = IPW_DL_NONE;
210
Brice Goglin0f52bf92005-12-01 01:41:46 -0800211#ifdef CONFIG_IPW2100_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400212#define IPW_DEBUG(level, message...) \
213do { \
214 if (ipw2100_debug_level & (level)) { \
215 printk(KERN_DEBUG "ipw2100: %c %s ", \
Harvey Harrisonc94c93d2008-07-28 23:01:34 -0700216 in_interrupt() ? 'I' : 'U', __func__); \
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400217 printk(message); \
218 } \
219} while (0)
220#else
221#define IPW_DEBUG(level, message...) do {} while (0)
Brice Goglin0f52bf92005-12-01 01:41:46 -0800222#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -0600223
Brice Goglin0f52bf92005-12-01 01:41:46 -0800224#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -0600225static const char *command_types[] = {
226 "undefined",
James Ketrenosee8e3652005-09-14 09:47:29 -0500227 "unused", /* HOST_ATTENTION */
James Ketrenos2c86c272005-03-23 17:32:29 -0600228 "HOST_COMPLETE",
James Ketrenosee8e3652005-09-14 09:47:29 -0500229 "unused", /* SLEEP */
230 "unused", /* HOST_POWER_DOWN */
James Ketrenos2c86c272005-03-23 17:32:29 -0600231 "unused",
232 "SYSTEM_CONFIG",
James Ketrenosee8e3652005-09-14 09:47:29 -0500233 "unused", /* SET_IMR */
James Ketrenos2c86c272005-03-23 17:32:29 -0600234 "SSID",
235 "MANDATORY_BSSID",
236 "AUTHENTICATION_TYPE",
237 "ADAPTER_ADDRESS",
238 "PORT_TYPE",
239 "INTERNATIONAL_MODE",
240 "CHANNEL",
241 "RTS_THRESHOLD",
242 "FRAG_THRESHOLD",
243 "POWER_MODE",
244 "TX_RATES",
245 "BASIC_TX_RATES",
246 "WEP_KEY_INFO",
247 "unused",
248 "unused",
249 "unused",
250 "unused",
251 "WEP_KEY_INDEX",
252 "WEP_FLAGS",
253 "ADD_MULTICAST",
254 "CLEAR_ALL_MULTICAST",
255 "BEACON_INTERVAL",
256 "ATIM_WINDOW",
257 "CLEAR_STATISTICS",
258 "undefined",
259 "undefined",
260 "undefined",
261 "undefined",
262 "TX_POWER_INDEX",
263 "undefined",
264 "undefined",
265 "undefined",
266 "undefined",
267 "undefined",
268 "undefined",
269 "BROADCAST_SCAN",
270 "CARD_DISABLE",
271 "PREFERRED_BSSID",
272 "SET_SCAN_OPTIONS",
273 "SCAN_DWELL_TIME",
274 "SWEEP_TABLE",
275 "AP_OR_STATION_TABLE",
276 "GROUP_ORDINALS",
277 "SHORT_RETRY_LIMIT",
278 "LONG_RETRY_LIMIT",
James Ketrenosee8e3652005-09-14 09:47:29 -0500279 "unused", /* SAVE_CALIBRATION */
280 "unused", /* RESTORE_CALIBRATION */
James Ketrenos2c86c272005-03-23 17:32:29 -0600281 "undefined",
282 "undefined",
283 "undefined",
284 "HOST_PRE_POWER_DOWN",
James Ketrenosee8e3652005-09-14 09:47:29 -0500285 "unused", /* HOST_INTERRUPT_COALESCING */
James Ketrenos2c86c272005-03-23 17:32:29 -0600286 "undefined",
287 "CARD_DISABLE_PHY_OFF",
James Ketrenosee8e3652005-09-14 09:47:29 -0500288 "MSDU_TX_RATES" "undefined",
James Ketrenos2c86c272005-03-23 17:32:29 -0600289 "undefined",
290 "SET_STATION_STAT_BITS",
291 "CLEAR_STATIONS_STAT_BITS",
292 "LEAP_ROGUE_MODE",
293 "SET_SECURITY_INFORMATION",
294 "DISASSOCIATION_BSSID",
295 "SET_WPA_ASS_IE"
296};
297#endif
298
James Ketrenos2c86c272005-03-23 17:32:29 -0600299/* Pre-decl until we get the code solid and then we can clean it up */
Jiri Benc19f7f742005-08-25 20:02:10 -0400300static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
301static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
James Ketrenos2c86c272005-03-23 17:32:29 -0600302static int ipw2100_adapter_setup(struct ipw2100_priv *priv);
303
304static void ipw2100_queues_initialize(struct ipw2100_priv *priv);
305static void ipw2100_queues_free(struct ipw2100_priv *priv);
306static int ipw2100_queues_allocate(struct ipw2100_priv *priv);
307
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400308static int ipw2100_fw_download(struct ipw2100_priv *priv,
309 struct ipw2100_fw *fw);
310static int ipw2100_get_firmware(struct ipw2100_priv *priv,
311 struct ipw2100_fw *fw);
312static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
313 size_t max);
314static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
315 size_t max);
316static void ipw2100_release_firmware(struct ipw2100_priv *priv,
317 struct ipw2100_fw *fw);
318static int ipw2100_ucode_download(struct ipw2100_priv *priv,
319 struct ipw2100_fw *fw);
David Howellsc4028952006-11-22 14:57:56 +0000320static void ipw2100_wx_event_work(struct work_struct *work);
James Ketrenosee8e3652005-09-14 09:47:29 -0500321static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev);
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400322static struct iw_handler_def ipw2100_wx_handler_def;
323
James Ketrenosee8e3652005-09-14 09:47:29 -0500324static inline void read_register(struct net_device *dev, u32 reg, u32 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600325{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100326 *val = readl((void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600327 IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
328}
329
330static inline void write_register(struct net_device *dev, u32 reg, u32 val)
331{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100332 writel(val, (void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600333 IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
334}
335
James Ketrenosee8e3652005-09-14 09:47:29 -0500336static inline void read_register_word(struct net_device *dev, u32 reg,
337 u16 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600338{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100339 *val = readw((void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600340 IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
341}
342
James Ketrenosee8e3652005-09-14 09:47:29 -0500343static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600344{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100345 *val = readb((void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600346 IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
347}
348
349static inline void write_register_word(struct net_device *dev, u32 reg, u16 val)
350{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100351 writew(val, (void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600352 IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
353}
354
James Ketrenos2c86c272005-03-23 17:32:29 -0600355static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
356{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100357 writeb(val, (void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600358 IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
359}
360
James Ketrenosee8e3652005-09-14 09:47:29 -0500361static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600362{
363 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
364 addr & IPW_REG_INDIRECT_ADDR_MASK);
365 read_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
366}
367
368static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val)
369{
370 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
371 addr & IPW_REG_INDIRECT_ADDR_MASK);
372 write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
373}
374
James Ketrenosee8e3652005-09-14 09:47:29 -0500375static inline void read_nic_word(struct net_device *dev, u32 addr, u16 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600376{
377 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
378 addr & IPW_REG_INDIRECT_ADDR_MASK);
379 read_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
380}
381
382static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val)
383{
384 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
385 addr & IPW_REG_INDIRECT_ADDR_MASK);
386 write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
387}
388
James Ketrenosee8e3652005-09-14 09:47:29 -0500389static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600390{
391 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
392 addr & IPW_REG_INDIRECT_ADDR_MASK);
393 read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
394}
395
396static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val)
397{
398 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
399 addr & IPW_REG_INDIRECT_ADDR_MASK);
400 write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
401}
402
403static inline void write_nic_auto_inc_address(struct net_device *dev, u32 addr)
404{
405 write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
406 addr & IPW_REG_INDIRECT_ADDR_MASK);
407}
408
409static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val)
410{
411 write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val);
412}
413
Arjan van de Ven858119e2006-01-14 13:20:43 -0800414static void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
James Ketrenosee8e3652005-09-14 09:47:29 -0500415 const u8 * buf)
James Ketrenos2c86c272005-03-23 17:32:29 -0600416{
417 u32 aligned_addr;
418 u32 aligned_len;
419 u32 dif_len;
420 u32 i;
421
422 /* read first nibble byte by byte */
423 aligned_addr = addr & (~0x3);
424 dif_len = addr - aligned_addr;
425 if (dif_len) {
426 /* Start reading at aligned_addr + dif_len */
427 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
428 aligned_addr);
429 for (i = dif_len; i < 4; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500430 write_register_byte(dev,
431 IPW_REG_INDIRECT_ACCESS_DATA + i,
432 *buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600433
434 len -= dif_len;
435 aligned_addr += 4;
436 }
437
438 /* read DWs through autoincrement registers */
James Ketrenosee8e3652005-09-14 09:47:29 -0500439 write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600440 aligned_len = len & (~0x3);
441 for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
James Ketrenosee8e3652005-09-14 09:47:29 -0500442 write_register(dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *) buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600443
444 /* copy the last nibble */
445 dif_len = len - aligned_len;
446 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
447 for (i = 0; i < dif_len; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500448 write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
449 *buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600450}
451
Arjan van de Ven858119e2006-01-14 13:20:43 -0800452static void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
James Ketrenosee8e3652005-09-14 09:47:29 -0500453 u8 * buf)
James Ketrenos2c86c272005-03-23 17:32:29 -0600454{
455 u32 aligned_addr;
456 u32 aligned_len;
457 u32 dif_len;
458 u32 i;
459
460 /* read first nibble byte by byte */
461 aligned_addr = addr & (~0x3);
462 dif_len = addr - aligned_addr;
463 if (dif_len) {
464 /* Start reading at aligned_addr + dif_len */
465 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
466 aligned_addr);
467 for (i = dif_len; i < 4; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500468 read_register_byte(dev,
469 IPW_REG_INDIRECT_ACCESS_DATA + i,
470 buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600471
472 len -= dif_len;
473 aligned_addr += 4;
474 }
475
476 /* read DWs through autoincrement registers */
James Ketrenosee8e3652005-09-14 09:47:29 -0500477 write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600478 aligned_len = len & (~0x3);
479 for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
James Ketrenosee8e3652005-09-14 09:47:29 -0500480 read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600481
482 /* copy the last nibble */
483 dif_len = len - aligned_len;
James Ketrenosee8e3652005-09-14 09:47:29 -0500484 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600485 for (i = 0; i < dif_len; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500486 read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600487}
488
489static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev)
490{
491 return (dev->base_addr &&
James Ketrenosee8e3652005-09-14 09:47:29 -0500492 (readl
493 ((void __iomem *)(dev->base_addr +
494 IPW_REG_DOA_DEBUG_AREA_START))
James Ketrenos2c86c272005-03-23 17:32:29 -0600495 == IPW_DATA_DOA_DEBUG_VALUE));
496}
497
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400498static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
James Ketrenosee8e3652005-09-14 09:47:29 -0500499 void *val, u32 * len)
James Ketrenos2c86c272005-03-23 17:32:29 -0600500{
501 struct ipw2100_ordinals *ordinals = &priv->ordinals;
502 u32 addr;
503 u32 field_info;
504 u16 field_len;
505 u16 field_count;
506 u32 total_length;
507
508 if (ordinals->table1_addr == 0) {
Jiri Benc797b4f72005-08-25 20:03:27 -0400509 printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals "
James Ketrenos2c86c272005-03-23 17:32:29 -0600510 "before they have been loaded.\n");
511 return -EINVAL;
512 }
513
514 if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
515 if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) {
516 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
517
Jiri Benc797b4f72005-08-25 20:03:27 -0400518 printk(KERN_WARNING DRV_NAME
Jiri Bencaaa4d302005-06-07 14:58:41 +0200519 ": ordinal buffer length too small, need %zd\n",
James Ketrenos2c86c272005-03-23 17:32:29 -0600520 IPW_ORD_TAB_1_ENTRY_SIZE);
521
522 return -EINVAL;
523 }
524
James Ketrenosee8e3652005-09-14 09:47:29 -0500525 read_nic_dword(priv->net_dev,
526 ordinals->table1_addr + (ord << 2), &addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600527 read_nic_dword(priv->net_dev, addr, val);
528
529 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
530
531 return 0;
532 }
533
534 if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) {
535
536 ord -= IPW_START_ORD_TAB_2;
537
538 /* get the address of statistic */
James Ketrenosee8e3652005-09-14 09:47:29 -0500539 read_nic_dword(priv->net_dev,
540 ordinals->table2_addr + (ord << 3), &addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600541
542 /* get the second DW of statistics ;
543 * two 16-bit words - first is length, second is count */
544 read_nic_dword(priv->net_dev,
545 ordinals->table2_addr + (ord << 3) + sizeof(u32),
546 &field_info);
547
548 /* get each entry length */
James Ketrenosee8e3652005-09-14 09:47:29 -0500549 field_len = *((u16 *) & field_info);
James Ketrenos2c86c272005-03-23 17:32:29 -0600550
551 /* get number of entries */
James Ketrenosee8e3652005-09-14 09:47:29 -0500552 field_count = *(((u16 *) & field_info) + 1);
James Ketrenos2c86c272005-03-23 17:32:29 -0600553
554 /* abort if no enought memory */
555 total_length = field_len * field_count;
556 if (total_length > *len) {
557 *len = total_length;
558 return -EINVAL;
559 }
560
561 *len = total_length;
562 if (!total_length)
563 return 0;
564
565 /* read the ordinal data from the SRAM */
566 read_nic_memory(priv->net_dev, addr, total_length, val);
567
568 return 0;
569 }
570
Jiri Benc797b4f72005-08-25 20:03:27 -0400571 printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor "
James Ketrenos2c86c272005-03-23 17:32:29 -0600572 "in table 2\n", ord);
573
574 return -EINVAL;
575}
576
James Ketrenosee8e3652005-09-14 09:47:29 -0500577static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val,
578 u32 * len)
James Ketrenos2c86c272005-03-23 17:32:29 -0600579{
580 struct ipw2100_ordinals *ordinals = &priv->ordinals;
581 u32 addr;
582
583 if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
584 if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) {
585 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
586 IPW_DEBUG_INFO("wrong size\n");
587 return -EINVAL;
588 }
589
James Ketrenosee8e3652005-09-14 09:47:29 -0500590 read_nic_dword(priv->net_dev,
591 ordinals->table1_addr + (ord << 2), &addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600592
593 write_nic_dword(priv->net_dev, addr, *val);
594
595 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
596
597 return 0;
598 }
599
600 IPW_DEBUG_INFO("wrong table\n");
601 if (IS_ORDINAL_TABLE_TWO(ordinals, ord))
602 return -EINVAL;
603
604 return -EINVAL;
605}
606
607static char *snprint_line(char *buf, size_t count,
James Ketrenosee8e3652005-09-14 09:47:29 -0500608 const u8 * data, u32 len, u32 ofs)
James Ketrenos2c86c272005-03-23 17:32:29 -0600609{
610 int out, i, j, l;
611 char c;
612
613 out = snprintf(buf, count, "%08X", ofs);
614
615 for (l = 0, i = 0; i < 2; i++) {
616 out += snprintf(buf + out, count - out, " ");
617 for (j = 0; j < 8 && l < len; j++, l++)
618 out += snprintf(buf + out, count - out, "%02X ",
619 data[(i * 8 + j)]);
620 for (; j < 8; j++)
621 out += snprintf(buf + out, count - out, " ");
622 }
623
624 out += snprintf(buf + out, count - out, " ");
625 for (l = 0, i = 0; i < 2; i++) {
626 out += snprintf(buf + out, count - out, " ");
627 for (j = 0; j < 8 && l < len; j++, l++) {
628 c = data[(i * 8 + j)];
629 if (!isascii(c) || !isprint(c))
630 c = '.';
631
632 out += snprintf(buf + out, count - out, "%c", c);
633 }
634
635 for (; j < 8; j++)
636 out += snprintf(buf + out, count - out, " ");
637 }
638
639 return buf;
640}
641
James Ketrenosee8e3652005-09-14 09:47:29 -0500642static void printk_buf(int level, const u8 * data, u32 len)
James Ketrenos2c86c272005-03-23 17:32:29 -0600643{
644 char line[81];
645 u32 ofs = 0;
646 if (!(ipw2100_debug_level & level))
647 return;
648
649 while (len) {
650 printk(KERN_DEBUG "%s\n",
651 snprint_line(line, sizeof(line), &data[ofs],
652 min(len, 16U), ofs));
653 ofs += 16;
654 len -= min(len, 16U);
655 }
656}
657
James Ketrenos2c86c272005-03-23 17:32:29 -0600658#define MAX_RESET_BACKOFF 10
659
Arjan van de Ven858119e2006-01-14 13:20:43 -0800660static void schedule_reset(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -0600661{
662 unsigned long now = get_seconds();
663
664 /* If we haven't received a reset request within the backoff period,
665 * then we can reset the backoff interval so this reset occurs
666 * immediately */
667 if (priv->reset_backoff &&
668 (now - priv->last_reset > priv->reset_backoff))
669 priv->reset_backoff = 0;
670
671 priv->last_reset = get_seconds();
672
673 if (!(priv->status & STATUS_RESET_PENDING)) {
674 IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n",
675 priv->net_dev->name, priv->reset_backoff);
676 netif_carrier_off(priv->net_dev);
677 netif_stop_queue(priv->net_dev);
678 priv->status |= STATUS_RESET_PENDING;
679 if (priv->reset_backoff)
680 queue_delayed_work(priv->workqueue, &priv->reset_work,
681 priv->reset_backoff * HZ);
682 else
David Howellsc4028952006-11-22 14:57:56 +0000683 queue_delayed_work(priv->workqueue, &priv->reset_work,
684 0);
James Ketrenos2c86c272005-03-23 17:32:29 -0600685
686 if (priv->reset_backoff < MAX_RESET_BACKOFF)
687 priv->reset_backoff++;
688
689 wake_up_interruptible(&priv->wait_command_queue);
690 } else
691 IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n",
692 priv->net_dev->name);
693
694}
695
696#define HOST_COMPLETE_TIMEOUT (2 * HZ)
697static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
James Ketrenosee8e3652005-09-14 09:47:29 -0500698 struct host_command *cmd)
James Ketrenos2c86c272005-03-23 17:32:29 -0600699{
700 struct list_head *element;
701 struct ipw2100_tx_packet *packet;
702 unsigned long flags;
703 int err = 0;
704
705 IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
706 command_types[cmd->host_command], cmd->host_command,
707 cmd->host_command_length);
James Ketrenosee8e3652005-09-14 09:47:29 -0500708 printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters,
James Ketrenos2c86c272005-03-23 17:32:29 -0600709 cmd->host_command_length);
710
711 spin_lock_irqsave(&priv->low_lock, flags);
712
713 if (priv->fatal_error) {
James Ketrenosee8e3652005-09-14 09:47:29 -0500714 IPW_DEBUG_INFO
715 ("Attempt to send command while hardware in fatal error condition.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -0600716 err = -EIO;
717 goto fail_unlock;
718 }
719
720 if (!(priv->status & STATUS_RUNNING)) {
James Ketrenosee8e3652005-09-14 09:47:29 -0500721 IPW_DEBUG_INFO
722 ("Attempt to send command while hardware is not running.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -0600723 err = -EIO;
724 goto fail_unlock;
725 }
726
727 if (priv->status & STATUS_CMD_ACTIVE) {
James Ketrenosee8e3652005-09-14 09:47:29 -0500728 IPW_DEBUG_INFO
729 ("Attempt to send command while another command is pending.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -0600730 err = -EBUSY;
731 goto fail_unlock;
732 }
733
734 if (list_empty(&priv->msg_free_list)) {
735 IPW_DEBUG_INFO("no available msg buffers\n");
736 goto fail_unlock;
737 }
738
739 priv->status |= STATUS_CMD_ACTIVE;
740 priv->messages_sent++;
741
742 element = priv->msg_free_list.next;
743
744 packet = list_entry(element, struct ipw2100_tx_packet, list);
745 packet->jiffy_start = jiffies;
746
747 /* initialize the firmware command packet */
748 packet->info.c_struct.cmd->host_command_reg = cmd->host_command;
749 packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1;
James Ketrenosee8e3652005-09-14 09:47:29 -0500750 packet->info.c_struct.cmd->host_command_len_reg =
751 cmd->host_command_length;
James Ketrenos2c86c272005-03-23 17:32:29 -0600752 packet->info.c_struct.cmd->sequence = cmd->host_command_sequence;
753
754 memcpy(packet->info.c_struct.cmd->host_command_params_reg,
755 cmd->host_command_parameters,
756 sizeof(packet->info.c_struct.cmd->host_command_params_reg));
757
758 list_del(element);
759 DEC_STAT(&priv->msg_free_stat);
760
761 list_add_tail(element, &priv->msg_pend_list);
762 INC_STAT(&priv->msg_pend_stat);
763
Jiri Benc19f7f742005-08-25 20:02:10 -0400764 ipw2100_tx_send_commands(priv);
765 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -0600766
767 spin_unlock_irqrestore(&priv->low_lock, flags);
768
769 /*
770 * We must wait for this command to complete before another
771 * command can be sent... but if we wait more than 3 seconds
772 * then there is a problem.
773 */
774
James Ketrenosee8e3652005-09-14 09:47:29 -0500775 err =
776 wait_event_interruptible_timeout(priv->wait_command_queue,
777 !(priv->
778 status & STATUS_CMD_ACTIVE),
779 HOST_COMPLETE_TIMEOUT);
James Ketrenos2c86c272005-03-23 17:32:29 -0600780
781 if (err == 0) {
782 IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
James Ketrenos82328352005-08-24 22:33:31 -0500783 1000 * (HOST_COMPLETE_TIMEOUT / HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -0600784 priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT;
785 priv->status &= ~STATUS_CMD_ACTIVE;
786 schedule_reset(priv);
787 return -EIO;
788 }
789
790 if (priv->fatal_error) {
Jiri Benc797b4f72005-08-25 20:03:27 -0400791 printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n",
James Ketrenos2c86c272005-03-23 17:32:29 -0600792 priv->net_dev->name);
793 return -EIO;
794 }
795
796 /* !!!!! HACK TEST !!!!!
797 * When lots of debug trace statements are enabled, the driver
798 * doesn't seem to have as many firmware restart cycles...
799 *
800 * As a test, we're sticking in a 1/100s delay here */
Nishanth Aravamudan3173c892005-09-11 02:09:55 -0700801 schedule_timeout_uninterruptible(msecs_to_jiffies(10));
James Ketrenos2c86c272005-03-23 17:32:29 -0600802
803 return 0;
804
James Ketrenosee8e3652005-09-14 09:47:29 -0500805 fail_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -0600806 spin_unlock_irqrestore(&priv->low_lock, flags);
807
808 return err;
809}
810
James Ketrenos2c86c272005-03-23 17:32:29 -0600811/*
812 * Verify the values and data access of the hardware
813 * No locks needed or used. No functions called.
814 */
815static int ipw2100_verify(struct ipw2100_priv *priv)
816{
817 u32 data1, data2;
818 u32 address;
819
820 u32 val1 = 0x76543210;
821 u32 val2 = 0xFEDCBA98;
822
823 /* Domain 0 check - all values should be DOA_DEBUG */
824 for (address = IPW_REG_DOA_DEBUG_AREA_START;
James Ketrenosee8e3652005-09-14 09:47:29 -0500825 address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) {
James Ketrenos2c86c272005-03-23 17:32:29 -0600826 read_register(priv->net_dev, address, &data1);
827 if (data1 != IPW_DATA_DOA_DEBUG_VALUE)
828 return -EIO;
829 }
830
831 /* Domain 1 check - use arbitrary read/write compare */
832 for (address = 0; address < 5; address++) {
833 /* The memory area is not used now */
834 write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
835 val1);
836 write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
837 val2);
838 read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
839 &data1);
840 read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
841 &data2);
842 if (val1 == data1 && val2 == data2)
843 return 0;
844 }
845
846 return -EIO;
847}
848
849/*
850 *
851 * Loop until the CARD_DISABLED bit is the same value as the
852 * supplied parameter
853 *
854 * TODO: See if it would be more efficient to do a wait/wake
855 * cycle and have the completion event trigger the wakeup
856 *
857 */
858#define IPW_CARD_DISABLE_COMPLETE_WAIT 100 // 100 milli
859static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state)
860{
861 int i;
862 u32 card_state;
863 u32 len = sizeof(card_state);
864 int err;
865
866 for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) {
867 err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED,
868 &card_state, &len);
869 if (err) {
870 IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal "
871 "failed.\n");
872 return 0;
873 }
874
875 /* We'll break out if either the HW state says it is
876 * in the state we want, or if HOST_COMPLETE command
877 * finishes */
878 if ((card_state == state) ||
879 ((priv->status & STATUS_ENABLED) ?
880 IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) {
881 if (state == IPW_HW_STATE_ENABLED)
882 priv->status |= STATUS_ENABLED;
883 else
884 priv->status &= ~STATUS_ENABLED;
885
886 return 0;
887 }
888
889 udelay(50);
890 }
891
892 IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n",
893 state ? "DISABLED" : "ENABLED");
894 return -EIO;
895}
896
James Ketrenos2c86c272005-03-23 17:32:29 -0600897/*********************************************************************
898 Procedure : sw_reset_and_clock
899 Purpose : Asserts s/w reset, asserts clock initialization
900 and waits for clock stabilization
901 ********************************************************************/
902static int sw_reset_and_clock(struct ipw2100_priv *priv)
903{
904 int i;
905 u32 r;
906
907 // assert s/w reset
908 write_register(priv->net_dev, IPW_REG_RESET_REG,
909 IPW_AUX_HOST_RESET_REG_SW_RESET);
910
911 // wait for clock stabilization
912 for (i = 0; i < 1000; i++) {
913 udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY);
914
915 // check clock ready bit
916 read_register(priv->net_dev, IPW_REG_RESET_REG, &r);
917 if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET)
918 break;
919 }
920
921 if (i == 1000)
922 return -EIO; // TODO: better error value
923
924 /* set "initialization complete" bit to move adapter to
925 * D0 state */
926 write_register(priv->net_dev, IPW_REG_GP_CNTRL,
927 IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE);
928
929 /* wait for clock stabilization */
930 for (i = 0; i < 10000; i++) {
931 udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4);
932
933 /* check clock ready bit */
934 read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
935 if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY)
936 break;
937 }
938
939 if (i == 10000)
940 return -EIO; /* TODO: better error value */
941
James Ketrenos2c86c272005-03-23 17:32:29 -0600942 /* set D0 standby bit */
943 read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
944 write_register(priv->net_dev, IPW_REG_GP_CNTRL,
945 r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
James Ketrenos2c86c272005-03-23 17:32:29 -0600946
947 return 0;
948}
949
950/*********************************************************************
Pavel Machek8724a112005-06-20 14:28:43 -0700951 Procedure : ipw2100_download_firmware
James Ketrenos2c86c272005-03-23 17:32:29 -0600952 Purpose : Initiaze adapter after power on.
953 The sequence is:
954 1. assert s/w reset first!
955 2. awake clocks & wait for clock stabilization
956 3. hold ARC (don't ask me why...)
957 4. load Dino ucode and reset/clock init again
958 5. zero-out shared mem
959 6. download f/w
960 *******************************************************************/
961static int ipw2100_download_firmware(struct ipw2100_priv *priv)
962{
963 u32 address;
964 int err;
965
966#ifndef CONFIG_PM
967 /* Fetch the firmware and microcode */
968 struct ipw2100_fw ipw2100_firmware;
969#endif
970
971 if (priv->fatal_error) {
972 IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after "
James Ketrenosee8e3652005-09-14 09:47:29 -0500973 "fatal error %d. Interface must be brought down.\n",
974 priv->net_dev->name, priv->fatal_error);
James Ketrenos2c86c272005-03-23 17:32:29 -0600975 return -EINVAL;
976 }
James Ketrenos2c86c272005-03-23 17:32:29 -0600977#ifdef CONFIG_PM
978 if (!ipw2100_firmware.version) {
979 err = ipw2100_get_firmware(priv, &ipw2100_firmware);
980 if (err) {
981 IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -0500982 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -0600983 priv->fatal_error = IPW2100_ERR_FW_LOAD;
984 goto fail;
985 }
986 }
987#else
988 err = ipw2100_get_firmware(priv, &ipw2100_firmware);
989 if (err) {
990 IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -0500991 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -0600992 priv->fatal_error = IPW2100_ERR_FW_LOAD;
993 goto fail;
994 }
995#endif
996 priv->firmware_version = ipw2100_firmware.version;
997
998 /* s/w reset and clock stabilization */
999 err = sw_reset_and_clock(priv);
1000 if (err) {
1001 IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001002 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001003 goto fail;
1004 }
1005
1006 err = ipw2100_verify(priv);
1007 if (err) {
1008 IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001009 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001010 goto fail;
1011 }
1012
1013 /* Hold ARC */
1014 write_nic_dword(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05001015 IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000);
James Ketrenos2c86c272005-03-23 17:32:29 -06001016
1017 /* allow ARC to run */
1018 write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
1019
1020 /* load microcode */
1021 err = ipw2100_ucode_download(priv, &ipw2100_firmware);
1022 if (err) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001023 printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001024 priv->net_dev->name, err);
1025 goto fail;
1026 }
1027
1028 /* release ARC */
1029 write_nic_dword(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05001030 IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000);
James Ketrenos2c86c272005-03-23 17:32:29 -06001031
1032 /* s/w reset and clock stabilization (again!!!) */
1033 err = sw_reset_and_clock(priv);
1034 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001035 printk(KERN_ERR DRV_NAME
1036 ": %s: sw_reset_and_clock failed: %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001037 priv->net_dev->name, err);
1038 goto fail;
1039 }
1040
1041 /* load f/w */
1042 err = ipw2100_fw_download(priv, &ipw2100_firmware);
1043 if (err) {
1044 IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001045 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001046 goto fail;
1047 }
James Ketrenos2c86c272005-03-23 17:32:29 -06001048#ifndef CONFIG_PM
1049 /*
1050 * When the .resume method of the driver is called, the other
1051 * part of the system, i.e. the ide driver could still stay in
1052 * the suspend stage. This prevents us from loading the firmware
1053 * from the disk. --YZ
1054 */
1055
1056 /* free any storage allocated for firmware image */
1057 ipw2100_release_firmware(priv, &ipw2100_firmware);
1058#endif
1059
1060 /* zero out Domain 1 area indirectly (Si requirement) */
1061 for (address = IPW_HOST_FW_SHARED_AREA0;
1062 address < IPW_HOST_FW_SHARED_AREA0_END; address += 4)
1063 write_nic_dword(priv->net_dev, address, 0);
1064 for (address = IPW_HOST_FW_SHARED_AREA1;
1065 address < IPW_HOST_FW_SHARED_AREA1_END; address += 4)
1066 write_nic_dword(priv->net_dev, address, 0);
1067 for (address = IPW_HOST_FW_SHARED_AREA2;
1068 address < IPW_HOST_FW_SHARED_AREA2_END; address += 4)
1069 write_nic_dword(priv->net_dev, address, 0);
1070 for (address = IPW_HOST_FW_SHARED_AREA3;
1071 address < IPW_HOST_FW_SHARED_AREA3_END; address += 4)
1072 write_nic_dword(priv->net_dev, address, 0);
1073 for (address = IPW_HOST_FW_INTERRUPT_AREA;
1074 address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4)
1075 write_nic_dword(priv->net_dev, address, 0);
1076
1077 return 0;
1078
James Ketrenosee8e3652005-09-14 09:47:29 -05001079 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06001080 ipw2100_release_firmware(priv, &ipw2100_firmware);
1081 return err;
1082}
1083
1084static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv)
1085{
1086 if (priv->status & STATUS_INT_ENABLED)
1087 return;
1088 priv->status |= STATUS_INT_ENABLED;
1089 write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK);
1090}
1091
1092static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv)
1093{
1094 if (!(priv->status & STATUS_INT_ENABLED))
1095 return;
1096 priv->status &= ~STATUS_INT_ENABLED;
1097 write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0);
1098}
1099
James Ketrenos2c86c272005-03-23 17:32:29 -06001100static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv)
1101{
1102 struct ipw2100_ordinals *ord = &priv->ordinals;
1103
1104 IPW_DEBUG_INFO("enter\n");
1105
1106 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1,
1107 &ord->table1_addr);
1108
1109 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2,
1110 &ord->table2_addr);
1111
1112 read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size);
1113 read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size);
1114
1115 ord->table2_size &= 0x0000FFFF;
1116
1117 IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size);
1118 IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size);
1119 IPW_DEBUG_INFO("exit\n");
1120}
1121
1122static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv)
1123{
1124 u32 reg = 0;
1125 /*
1126 * Set GPIO 3 writable by FW; GPIO 1 writable
1127 * by driver and enable clock
1128 */
1129 reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE |
1130 IPW_BIT_GPIO_LED_OFF);
1131 write_register(priv->net_dev, IPW_REG_GPIO, reg);
1132}
1133
Arjan van de Ven858119e2006-01-14 13:20:43 -08001134static int rf_kill_active(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06001135{
1136#define MAX_RF_KILL_CHECKS 5
1137#define RF_KILL_CHECK_DELAY 40
James Ketrenos2c86c272005-03-23 17:32:29 -06001138
1139 unsigned short value = 0;
1140 u32 reg = 0;
1141 int i;
1142
1143 if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
1144 priv->status &= ~STATUS_RF_KILL_HW;
1145 return 0;
1146 }
1147
1148 for (i = 0; i < MAX_RF_KILL_CHECKS; i++) {
1149 udelay(RF_KILL_CHECK_DELAY);
1150 read_register(priv->net_dev, IPW_REG_GPIO, &reg);
1151 value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1);
1152 }
1153
1154 if (value == 0)
1155 priv->status |= STATUS_RF_KILL_HW;
1156 else
1157 priv->status &= ~STATUS_RF_KILL_HW;
1158
1159 return (value == 0);
1160}
1161
1162static int ipw2100_get_hw_features(struct ipw2100_priv *priv)
1163{
1164 u32 addr, len;
1165 u32 val;
1166
1167 /*
1168 * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1
1169 */
1170 len = sizeof(addr);
James Ketrenosee8e3652005-09-14 09:47:29 -05001171 if (ipw2100_get_ordinal
1172 (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06001173 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001174 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06001175 return -EIO;
1176 }
1177
1178 IPW_DEBUG_INFO("EEPROM address: %08X\n", addr);
1179
1180 /*
1181 * EEPROM version is the byte at offset 0xfd in firmware
1182 * We read 4 bytes, then shift out the byte we actually want */
1183 read_nic_dword(priv->net_dev, addr + 0xFC, &val);
1184 priv->eeprom_version = (val >> 24) & 0xFF;
1185 IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version);
1186
James Ketrenosee8e3652005-09-14 09:47:29 -05001187 /*
James Ketrenos2c86c272005-03-23 17:32:29 -06001188 * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware
1189 *
1190 * notice that the EEPROM bit is reverse polarity, i.e.
1191 * bit = 0 signifies HW RF kill switch is supported
1192 * bit = 1 signifies HW RF kill switch is NOT supported
1193 */
1194 read_nic_dword(priv->net_dev, addr + 0x20, &val);
1195 if (!((val >> 24) & 0x01))
1196 priv->hw_features |= HW_FEATURE_RFKILL;
1197
1198 IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001199 (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not ");
James Ketrenos2c86c272005-03-23 17:32:29 -06001200
1201 return 0;
1202}
1203
1204/*
1205 * Start firmware execution after power on and intialization
1206 * The sequence is:
1207 * 1. Release ARC
1208 * 2. Wait for f/w initialization completes;
1209 */
1210static int ipw2100_start_adapter(struct ipw2100_priv *priv)
1211{
James Ketrenos2c86c272005-03-23 17:32:29 -06001212 int i;
1213 u32 inta, inta_mask, gpio;
1214
1215 IPW_DEBUG_INFO("enter\n");
1216
1217 if (priv->status & STATUS_RUNNING)
1218 return 0;
1219
1220 /*
1221 * Initialize the hw - drive adapter to DO state by setting
1222 * init_done bit. Wait for clk_ready bit and Download
1223 * fw & dino ucode
1224 */
1225 if (ipw2100_download_firmware(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001226 printk(KERN_ERR DRV_NAME
1227 ": %s: Failed to power on the adapter.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001228 priv->net_dev->name);
1229 return -EIO;
1230 }
1231
1232 /* Clear the Tx, Rx and Msg queues and the r/w indexes
1233 * in the firmware RBD and TBD ring queue */
1234 ipw2100_queues_initialize(priv);
1235
1236 ipw2100_hw_set_gpio(priv);
1237
1238 /* TODO -- Look at disabling interrupts here to make sure none
1239 * get fired during FW initialization */
1240
1241 /* Release ARC - clear reset bit */
1242 write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
1243
1244 /* wait for f/w intialization complete */
1245 IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n");
1246 i = 5000;
1247 do {
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001248 schedule_timeout_uninterruptible(msecs_to_jiffies(40));
James Ketrenos2c86c272005-03-23 17:32:29 -06001249 /* Todo... wait for sync command ... */
1250
1251 read_register(priv->net_dev, IPW_REG_INTA, &inta);
1252
1253 /* check "init done" bit */
1254 if (inta & IPW2100_INTA_FW_INIT_DONE) {
1255 /* reset "init done" bit */
1256 write_register(priv->net_dev, IPW_REG_INTA,
1257 IPW2100_INTA_FW_INIT_DONE);
1258 break;
1259 }
1260
1261 /* check error conditions : we check these after the firmware
1262 * check so that if there is an error, the interrupt handler
1263 * will see it and the adapter will be reset */
1264 if (inta &
1265 (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) {
1266 /* clear error conditions */
1267 write_register(priv->net_dev, IPW_REG_INTA,
1268 IPW2100_INTA_FATAL_ERROR |
1269 IPW2100_INTA_PARITY_ERROR);
1270 }
Roel Kluina2a1c3e2007-11-05 23:55:02 +01001271 } while (--i);
James Ketrenos2c86c272005-03-23 17:32:29 -06001272
1273 /* Clear out any pending INTAs since we aren't supposed to have
1274 * interrupts enabled at this point... */
1275 read_register(priv->net_dev, IPW_REG_INTA, &inta);
1276 read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
1277 inta &= IPW_INTERRUPT_MASK;
1278 /* Clear out any pending interrupts */
1279 if (inta & inta_mask)
1280 write_register(priv->net_dev, IPW_REG_INTA, inta);
1281
1282 IPW_DEBUG_FW("f/w initialization complete: %s\n",
1283 i ? "SUCCESS" : "FAILED");
1284
1285 if (!i) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001286 printk(KERN_WARNING DRV_NAME
1287 ": %s: Firmware did not initialize.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001288 priv->net_dev->name);
1289 return -EIO;
1290 }
1291
1292 /* allow firmware to write to GPIO1 & GPIO3 */
1293 read_register(priv->net_dev, IPW_REG_GPIO, &gpio);
1294
1295 gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK);
1296
1297 write_register(priv->net_dev, IPW_REG_GPIO, gpio);
1298
1299 /* Ready to receive commands */
1300 priv->status |= STATUS_RUNNING;
1301
1302 /* The adapter has been reset; we are not associated */
1303 priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
1304
1305 IPW_DEBUG_INFO("exit\n");
1306
1307 return 0;
1308}
1309
1310static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv)
1311{
1312 if (!priv->fatal_error)
1313 return;
1314
1315 priv->fatal_errors[priv->fatal_index++] = priv->fatal_error;
1316 priv->fatal_index %= IPW2100_ERROR_QUEUE;
1317 priv->fatal_error = 0;
1318}
1319
James Ketrenos2c86c272005-03-23 17:32:29 -06001320/* NOTE: Our interrupt is disabled when this method is called */
1321static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
1322{
1323 u32 reg;
1324 int i;
1325
1326 IPW_DEBUG_INFO("Power cycling the hardware.\n");
1327
1328 ipw2100_hw_set_gpio(priv);
1329
1330 /* Step 1. Stop Master Assert */
1331 write_register(priv->net_dev, IPW_REG_RESET_REG,
1332 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
1333
1334 /* Step 2. Wait for stop Master Assert
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02001335 * (not more than 50us, otherwise ret error */
James Ketrenos2c86c272005-03-23 17:32:29 -06001336 i = 5;
1337 do {
1338 udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
1339 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
1340
1341 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
1342 break;
Roel Kluina2a1c3e2007-11-05 23:55:02 +01001343 } while (--i);
James Ketrenos2c86c272005-03-23 17:32:29 -06001344
1345 priv->status &= ~STATUS_RESET_PENDING;
1346
1347 if (!i) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001348 IPW_DEBUG_INFO
1349 ("exit - waited too long for master assert stop\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06001350 return -EIO;
1351 }
1352
1353 write_register(priv->net_dev, IPW_REG_RESET_REG,
1354 IPW_AUX_HOST_RESET_REG_SW_RESET);
1355
James Ketrenos2c86c272005-03-23 17:32:29 -06001356 /* Reset any fatal_error conditions */
1357 ipw2100_reset_fatalerror(priv);
1358
1359 /* At this point, the adapter is now stopped and disabled */
1360 priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING |
1361 STATUS_ASSOCIATED | STATUS_ENABLED);
1362
1363 return 0;
1364}
1365
1366/*
1367 * Send the CARD_DISABLE_PHY_OFF comamnd to the card to disable it
1368 *
1369 * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent.
1370 *
1371 * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of
1372 * if STATUS_ASSN_LOST is sent.
1373 */
1374static int ipw2100_hw_phy_off(struct ipw2100_priv *priv)
1375{
1376
1377#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000)
1378
1379 struct host_command cmd = {
1380 .host_command = CARD_DISABLE_PHY_OFF,
1381 .host_command_sequence = 0,
1382 .host_command_length = 0,
1383 };
1384 int err, i;
1385 u32 val1, val2;
1386
1387 IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n");
1388
1389 /* Turn off the radio */
1390 err = ipw2100_hw_send_command(priv, &cmd);
1391 if (err)
1392 return err;
1393
1394 for (i = 0; i < 2500; i++) {
1395 read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1);
1396 read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2);
1397
1398 if ((val1 & IPW2100_CONTROL_PHY_OFF) &&
1399 (val2 & IPW2100_COMMAND_PHY_OFF))
1400 return 0;
1401
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001402 schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY);
James Ketrenos2c86c272005-03-23 17:32:29 -06001403 }
1404
1405 return -EIO;
1406}
1407
James Ketrenos2c86c272005-03-23 17:32:29 -06001408static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
1409{
1410 struct host_command cmd = {
1411 .host_command = HOST_COMPLETE,
1412 .host_command_sequence = 0,
1413 .host_command_length = 0
1414 };
1415 int err = 0;
1416
1417 IPW_DEBUG_HC("HOST_COMPLETE\n");
1418
1419 if (priv->status & STATUS_ENABLED)
1420 return 0;
1421
Ingo Molnar752e3772006-02-28 07:20:54 +08001422 mutex_lock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001423
1424 if (rf_kill_active(priv)) {
1425 IPW_DEBUG_HC("Command aborted due to RF kill active.\n");
1426 goto fail_up;
1427 }
1428
1429 err = ipw2100_hw_send_command(priv, &cmd);
1430 if (err) {
1431 IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n");
1432 goto fail_up;
1433 }
1434
1435 err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED);
1436 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001437 IPW_DEBUG_INFO("%s: card not responding to init command.\n",
1438 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001439 goto fail_up;
1440 }
1441
1442 if (priv->stop_hang_check) {
1443 priv->stop_hang_check = 0;
1444 queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
1445 }
1446
James Ketrenosee8e3652005-09-14 09:47:29 -05001447 fail_up:
Ingo Molnar752e3772006-02-28 07:20:54 +08001448 mutex_unlock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001449 return err;
1450}
1451
1452static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
1453{
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001454#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100))
James Ketrenos2c86c272005-03-23 17:32:29 -06001455
1456 struct host_command cmd = {
1457 .host_command = HOST_PRE_POWER_DOWN,
1458 .host_command_sequence = 0,
1459 .host_command_length = 0,
1460 };
1461 int err, i;
1462 u32 reg;
1463
1464 if (!(priv->status & STATUS_RUNNING))
1465 return 0;
1466
1467 priv->status |= STATUS_STOPPING;
1468
1469 /* We can only shut down the card if the firmware is operational. So,
1470 * if we haven't reset since a fatal_error, then we can not send the
1471 * shutdown commands. */
1472 if (!priv->fatal_error) {
1473 /* First, make sure the adapter is enabled so that the PHY_OFF
1474 * command can shut it down */
1475 ipw2100_enable_adapter(priv);
1476
1477 err = ipw2100_hw_phy_off(priv);
1478 if (err)
James Ketrenosee8e3652005-09-14 09:47:29 -05001479 printk(KERN_WARNING DRV_NAME
1480 ": Error disabling radio %d\n", err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001481
1482 /*
1483 * If in D0-standby mode going directly to D3 may cause a
1484 * PCI bus violation. Therefore we must change out of the D0
1485 * state.
1486 *
1487 * Sending the PREPARE_FOR_POWER_DOWN will restrict the
1488 * hardware from going into standby mode and will transition
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001489 * out of D0-standby if it is already in that state.
James Ketrenos2c86c272005-03-23 17:32:29 -06001490 *
1491 * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the
1492 * driver upon completion. Once received, the driver can
1493 * proceed to the D3 state.
1494 *
1495 * Prepare for power down command to fw. This command would
1496 * take HW out of D0-standby and prepare it for D3 state.
1497 *
1498 * Currently FW does not support event notification for this
1499 * event. Therefore, skip waiting for it. Just wait a fixed
1500 * 100ms
1501 */
1502 IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n");
1503
1504 err = ipw2100_hw_send_command(priv, &cmd);
1505 if (err)
Jiri Benc797b4f72005-08-25 20:03:27 -04001506 printk(KERN_WARNING DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06001507 "%s: Power down command failed: Error %d\n",
1508 priv->net_dev->name, err);
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001509 else
1510 schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY);
James Ketrenos2c86c272005-03-23 17:32:29 -06001511 }
1512
1513 priv->status &= ~STATUS_ENABLED;
1514
1515 /*
1516 * Set GPIO 3 writable by FW; GPIO 1 writable
1517 * by driver and enable clock
1518 */
1519 ipw2100_hw_set_gpio(priv);
1520
1521 /*
1522 * Power down adapter. Sequence:
1523 * 1. Stop master assert (RESET_REG[9]=1)
1524 * 2. Wait for stop master (RESET_REG[8]==1)
1525 * 3. S/w reset assert (RESET_REG[7] = 1)
1526 */
1527
1528 /* Stop master assert */
1529 write_register(priv->net_dev, IPW_REG_RESET_REG,
1530 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
1531
1532 /* wait stop master not more than 50 usec.
1533 * Otherwise return error. */
1534 for (i = 5; i > 0; i--) {
1535 udelay(10);
1536
1537 /* Check master stop bit */
1538 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
1539
1540 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
1541 break;
1542 }
1543
1544 if (i == 0)
Jiri Benc797b4f72005-08-25 20:03:27 -04001545 printk(KERN_WARNING DRV_NAME
James Ketrenos2c86c272005-03-23 17:32:29 -06001546 ": %s: Could now power down adapter.\n",
1547 priv->net_dev->name);
1548
1549 /* assert s/w reset */
1550 write_register(priv->net_dev, IPW_REG_RESET_REG,
1551 IPW_AUX_HOST_RESET_REG_SW_RESET);
1552
1553 priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING);
1554
1555 return 0;
1556}
1557
James Ketrenos2c86c272005-03-23 17:32:29 -06001558static int ipw2100_disable_adapter(struct ipw2100_priv *priv)
1559{
1560 struct host_command cmd = {
1561 .host_command = CARD_DISABLE,
1562 .host_command_sequence = 0,
1563 .host_command_length = 0
1564 };
1565 int err = 0;
1566
1567 IPW_DEBUG_HC("CARD_DISABLE\n");
1568
1569 if (!(priv->status & STATUS_ENABLED))
1570 return 0;
1571
1572 /* Make sure we clear the associated state */
1573 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1574
1575 if (!priv->stop_hang_check) {
1576 priv->stop_hang_check = 1;
1577 cancel_delayed_work(&priv->hang_check);
1578 }
1579
Ingo Molnar752e3772006-02-28 07:20:54 +08001580 mutex_lock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001581
1582 err = ipw2100_hw_send_command(priv, &cmd);
1583 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001584 printk(KERN_WARNING DRV_NAME
1585 ": exit - failed to send CARD_DISABLE command\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06001586 goto fail_up;
1587 }
1588
1589 err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED);
1590 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001591 printk(KERN_WARNING DRV_NAME
1592 ": exit - card failed to change to DISABLED\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06001593 goto fail_up;
1594 }
1595
1596 IPW_DEBUG_INFO("TODO: implement scan state machine\n");
1597
James Ketrenosee8e3652005-09-14 09:47:29 -05001598 fail_up:
Ingo Molnar752e3772006-02-28 07:20:54 +08001599 mutex_unlock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001600 return err;
1601}
1602
Jiri Bencc4aee8c2005-08-25 20:04:43 -04001603static int ipw2100_set_scan_options(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06001604{
1605 struct host_command cmd = {
1606 .host_command = SET_SCAN_OPTIONS,
1607 .host_command_sequence = 0,
1608 .host_command_length = 8
1609 };
1610 int err;
1611
1612 IPW_DEBUG_INFO("enter\n");
1613
1614 IPW_DEBUG_SCAN("setting scan options\n");
1615
1616 cmd.host_command_parameters[0] = 0;
1617
1618 if (!(priv->config & CFG_ASSOCIATE))
1619 cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE;
25b645b2005-07-12 15:45:30 -05001620 if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled)
James Ketrenos2c86c272005-03-23 17:32:29 -06001621 cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL;
1622 if (priv->config & CFG_PASSIVE_SCAN)
1623 cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE;
1624
1625 cmd.host_command_parameters[1] = priv->channel_mask;
1626
1627 err = ipw2100_hw_send_command(priv, &cmd);
1628
1629 IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n",
1630 cmd.host_command_parameters[0]);
1631
1632 return err;
1633}
1634
Jiri Bencc4aee8c2005-08-25 20:04:43 -04001635static int ipw2100_start_scan(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06001636{
1637 struct host_command cmd = {
1638 .host_command = BROADCAST_SCAN,
1639 .host_command_sequence = 0,
1640 .host_command_length = 4
1641 };
1642 int err;
1643
1644 IPW_DEBUG_HC("START_SCAN\n");
1645
1646 cmd.host_command_parameters[0] = 0;
1647
1648 /* No scanning if in monitor mode */
1649 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
1650 return 1;
1651
1652 if (priv->status & STATUS_SCANNING) {
1653 IPW_DEBUG_SCAN("Scan requested while already in scan...\n");
1654 return 0;
1655 }
1656
1657 IPW_DEBUG_INFO("enter\n");
1658
1659 /* Not clearing here; doing so makes iwlist always return nothing...
1660 *
1661 * We should modify the table logic to use aging tables vs. clearing
1662 * the table on each scan start.
1663 */
1664 IPW_DEBUG_SCAN("starting scan\n");
1665
1666 priv->status |= STATUS_SCANNING;
1667 err = ipw2100_hw_send_command(priv, &cmd);
1668 if (err)
1669 priv->status &= ~STATUS_SCANNING;
1670
1671 IPW_DEBUG_INFO("exit\n");
1672
1673 return err;
1674}
1675
Zhu Yibe6b3b12006-01-24 13:49:08 +08001676static const struct ieee80211_geo ipw_geos[] = {
1677 { /* Restricted */
1678 "---",
1679 .bg_channels = 14,
1680 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
1681 {2427, 4}, {2432, 5}, {2437, 6},
1682 {2442, 7}, {2447, 8}, {2452, 9},
1683 {2457, 10}, {2462, 11}, {2467, 12},
1684 {2472, 13}, {2484, 14}},
1685 },
1686};
1687
James Ketrenos2c86c272005-03-23 17:32:29 -06001688static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
1689{
1690 unsigned long flags;
1691 int rc = 0;
1692 u32 lock;
1693 u32 ord_len = sizeof(lock);
1694
Dan Williamsc3d72b92009-02-11 13:26:06 -05001695 /* Age scan list entries found before suspend */
1696 if (priv->suspend_time) {
1697 ieee80211_networks_age(priv->ieee, priv->suspend_time);
1698 priv->suspend_time = 0;
1699 }
1700
1701 /* Quiet if manually disabled. */
James Ketrenos2c86c272005-03-23 17:32:29 -06001702 if (priv->status & STATUS_RF_KILL_SW) {
1703 IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "
1704 "switch\n", priv->net_dev->name);
1705 return 0;
1706 }
1707
Arjan van de Ven5c875792006-09-30 23:27:17 -07001708 /* the ipw2100 hardware really doesn't want power management delays
1709 * longer than 175usec
1710 */
Mark Grossf011e2e2008-02-04 22:30:09 -08001711 pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", 175);
Arjan van de Ven5c875792006-09-30 23:27:17 -07001712
James Ketrenos2c86c272005-03-23 17:32:29 -06001713 /* If the interrupt is enabled, turn it off... */
1714 spin_lock_irqsave(&priv->low_lock, flags);
1715 ipw2100_disable_interrupts(priv);
1716
1717 /* Reset any fatal_error conditions */
1718 ipw2100_reset_fatalerror(priv);
1719 spin_unlock_irqrestore(&priv->low_lock, flags);
1720
1721 if (priv->status & STATUS_POWERED ||
1722 (priv->status & STATUS_RESET_PENDING)) {
1723 /* Power cycle the card ... */
1724 if (ipw2100_power_cycle_adapter(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001725 printk(KERN_WARNING DRV_NAME
1726 ": %s: Could not cycle adapter.\n",
1727 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001728 rc = 1;
1729 goto exit;
1730 }
1731 } else
1732 priv->status |= STATUS_POWERED;
1733
Pavel Machek8724a112005-06-20 14:28:43 -07001734 /* Load the firmware, start the clocks, etc. */
James Ketrenos2c86c272005-03-23 17:32:29 -06001735 if (ipw2100_start_adapter(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001736 printk(KERN_ERR DRV_NAME
1737 ": %s: Failed to start the firmware.\n",
1738 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001739 rc = 1;
1740 goto exit;
1741 }
1742
1743 ipw2100_initialize_ordinals(priv);
1744
1745 /* Determine capabilities of this particular HW configuration */
1746 if (ipw2100_get_hw_features(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001747 printk(KERN_ERR DRV_NAME
1748 ": %s: Failed to determine HW features.\n",
1749 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001750 rc = 1;
1751 goto exit;
1752 }
1753
Zhu Yibe6b3b12006-01-24 13:49:08 +08001754 /* Initialize the geo */
1755 if (ieee80211_set_geo(priv->ieee, &ipw_geos[0])) {
1756 printk(KERN_WARNING DRV_NAME "Could not set geo\n");
1757 return 0;
1758 }
1759 priv->ieee->freq_band = IEEE80211_24GHZ_BAND;
1760
James Ketrenos2c86c272005-03-23 17:32:29 -06001761 lock = LOCK_NONE;
1762 if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001763 printk(KERN_ERR DRV_NAME
1764 ": %s: Failed to clear ordinal lock.\n",
1765 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001766 rc = 1;
1767 goto exit;
1768 }
1769
1770 priv->status &= ~STATUS_SCANNING;
1771
1772 if (rf_kill_active(priv)) {
1773 printk(KERN_INFO "%s: Radio is disabled by RF switch.\n",
1774 priv->net_dev->name);
1775
1776 if (priv->stop_rf_kill) {
1777 priv->stop_rf_kill = 0;
Stephen Hemmingera62056f2007-06-22 21:46:50 -07001778 queue_delayed_work(priv->workqueue, &priv->rf_kill,
Anton Blanchardbe84e3d2007-10-15 00:38:01 -05001779 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06001780 }
1781
1782 deferred = 1;
1783 }
1784
1785 /* Turn on the interrupt so that commands can be processed */
1786 ipw2100_enable_interrupts(priv);
1787
1788 /* Send all of the commands that must be sent prior to
1789 * HOST_COMPLETE */
1790 if (ipw2100_adapter_setup(priv)) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001791 printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001792 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001793 rc = 1;
1794 goto exit;
1795 }
1796
1797 if (!deferred) {
1798 /* Enable the adapter - sends HOST_COMPLETE */
1799 if (ipw2100_enable_adapter(priv)) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001800 printk(KERN_ERR DRV_NAME ": "
James Ketrenosee8e3652005-09-14 09:47:29 -05001801 "%s: failed in call to enable adapter.\n",
1802 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001803 ipw2100_hw_stop_adapter(priv);
1804 rc = 1;
1805 goto exit;
1806 }
1807
James Ketrenos2c86c272005-03-23 17:32:29 -06001808 /* Start a scan . . . */
1809 ipw2100_set_scan_options(priv);
1810 ipw2100_start_scan(priv);
1811 }
1812
James Ketrenosee8e3652005-09-14 09:47:29 -05001813 exit:
James Ketrenos2c86c272005-03-23 17:32:29 -06001814 return rc;
1815}
1816
1817/* Called by register_netdev() */
1818static int ipw2100_net_init(struct net_device *dev)
1819{
1820 struct ipw2100_priv *priv = ieee80211_priv(dev);
1821 return ipw2100_up(priv, 1);
1822}
1823
1824static void ipw2100_down(struct ipw2100_priv *priv)
1825{
1826 unsigned long flags;
1827 union iwreq_data wrqu = {
1828 .ap_addr = {
James Ketrenosee8e3652005-09-14 09:47:29 -05001829 .sa_family = ARPHRD_ETHER}
James Ketrenos2c86c272005-03-23 17:32:29 -06001830 };
1831 int associated = priv->status & STATUS_ASSOCIATED;
1832
1833 /* Kill the RF switch timer */
1834 if (!priv->stop_rf_kill) {
1835 priv->stop_rf_kill = 1;
1836 cancel_delayed_work(&priv->rf_kill);
1837 }
1838
Nick Andrew44072452009-01-03 18:52:40 +11001839 /* Kill the firmware hang check timer */
James Ketrenos2c86c272005-03-23 17:32:29 -06001840 if (!priv->stop_hang_check) {
1841 priv->stop_hang_check = 1;
1842 cancel_delayed_work(&priv->hang_check);
1843 }
1844
1845 /* Kill any pending resets */
1846 if (priv->status & STATUS_RESET_PENDING)
1847 cancel_delayed_work(&priv->reset_work);
1848
1849 /* Make sure the interrupt is on so that FW commands will be
1850 * processed correctly */
1851 spin_lock_irqsave(&priv->low_lock, flags);
1852 ipw2100_enable_interrupts(priv);
1853 spin_unlock_irqrestore(&priv->low_lock, flags);
1854
1855 if (ipw2100_hw_stop_adapter(priv))
Jiri Benc797b4f72005-08-25 20:03:27 -04001856 printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001857 priv->net_dev->name);
1858
1859 /* Do not disable the interrupt until _after_ we disable
1860 * the adaptor. Otherwise the CARD_DISABLE command will never
1861 * be ack'd by the firmware */
1862 spin_lock_irqsave(&priv->low_lock, flags);
1863 ipw2100_disable_interrupts(priv);
1864 spin_unlock_irqrestore(&priv->low_lock, flags);
1865
Mark Grossf011e2e2008-02-04 22:30:09 -08001866 pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100",
1867 PM_QOS_DEFAULT_VALUE);
Arjan van de Ven5c875792006-09-30 23:27:17 -07001868
James Ketrenos2c86c272005-03-23 17:32:29 -06001869 /* We have to signal any supplicant if we are disassociating */
1870 if (associated)
1871 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
1872
1873 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1874 netif_carrier_off(priv->net_dev);
1875 netif_stop_queue(priv->net_dev);
1876}
1877
David Howellsc4028952006-11-22 14:57:56 +00001878static void ipw2100_reset_adapter(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06001879{
David Howellsc4028952006-11-22 14:57:56 +00001880 struct ipw2100_priv *priv =
1881 container_of(work, struct ipw2100_priv, reset_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06001882 unsigned long flags;
1883 union iwreq_data wrqu = {
1884 .ap_addr = {
James Ketrenosee8e3652005-09-14 09:47:29 -05001885 .sa_family = ARPHRD_ETHER}
James Ketrenos2c86c272005-03-23 17:32:29 -06001886 };
1887 int associated = priv->status & STATUS_ASSOCIATED;
1888
1889 spin_lock_irqsave(&priv->low_lock, flags);
Zhu Yia1e695a2005-07-04 14:06:00 +08001890 IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001891 priv->resets++;
1892 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1893 priv->status |= STATUS_SECURITY_UPDATED;
1894
1895 /* Force a power cycle even if interface hasn't been opened
1896 * yet */
1897 cancel_delayed_work(&priv->reset_work);
1898 priv->status |= STATUS_RESET_PENDING;
1899 spin_unlock_irqrestore(&priv->low_lock, flags);
1900
Ingo Molnar752e3772006-02-28 07:20:54 +08001901 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001902 /* stop timed checks so that they don't interfere with reset */
1903 priv->stop_hang_check = 1;
1904 cancel_delayed_work(&priv->hang_check);
1905
1906 /* We have to signal any supplicant if we are disassociating */
1907 if (associated)
1908 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
1909
1910 ipw2100_up(priv, 0);
Ingo Molnar752e3772006-02-28 07:20:54 +08001911 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001912
1913}
1914
James Ketrenos2c86c272005-03-23 17:32:29 -06001915static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
1916{
1917
1918#define MAC_ASSOCIATION_READ_DELAY (HZ)
Hannes Ederb9da9e92009-02-14 11:50:26 +00001919 int ret;
1920 unsigned int len, essid_len;
James Ketrenos2c86c272005-03-23 17:32:29 -06001921 char essid[IW_ESSID_MAX_SIZE];
1922 u32 txrate;
1923 u32 chan;
1924 char *txratename;
James Ketrenosee8e3652005-09-14 09:47:29 -05001925 u8 bssid[ETH_ALEN];
John W. Linville9387b7c2008-09-30 20:59:05 -04001926 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06001927
1928 /*
1929 * TBD: BSSID is usually 00:00:00:00:00:00 here and not
1930 * an actual MAC of the AP. Seems like FW sets this
1931 * address too late. Read it later and expose through
1932 * /proc or schedule a later task to query and update
1933 */
1934
1935 essid_len = IW_ESSID_MAX_SIZE;
1936 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID,
1937 essid, &essid_len);
1938 if (ret) {
1939 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001940 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06001941 return;
1942 }
1943
1944 len = sizeof(u32);
James Ketrenosee8e3652005-09-14 09:47:29 -05001945 ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06001946 if (ret) {
1947 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001948 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06001949 return;
1950 }
1951
1952 len = sizeof(u32);
1953 ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len);
1954 if (ret) {
1955 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001956 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06001957 return;
1958 }
1959 len = ETH_ALEN;
James Ketrenosee8e3652005-09-14 09:47:29 -05001960 ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06001961 if (ret) {
1962 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001963 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06001964 return;
1965 }
1966 memcpy(priv->ieee->bssid, bssid, ETH_ALEN);
1967
James Ketrenos2c86c272005-03-23 17:32:29 -06001968 switch (txrate) {
1969 case TX_RATE_1_MBIT:
1970 txratename = "1Mbps";
1971 break;
1972 case TX_RATE_2_MBIT:
1973 txratename = "2Mbsp";
1974 break;
1975 case TX_RATE_5_5_MBIT:
1976 txratename = "5.5Mbps";
1977 break;
1978 case TX_RATE_11_MBIT:
1979 txratename = "11Mbps";
1980 break;
1981 default:
1982 IPW_DEBUG_INFO("Unknown rate: %d\n", txrate);
1983 txratename = "unknown rate";
1984 break;
1985 }
1986
Johannes Berge1749612008-10-27 15:59:26 -07001987 IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04001988 priv->net_dev->name, print_ssid(ssid, essid, essid_len),
Johannes Berge1749612008-10-27 15:59:26 -07001989 txratename, chan, bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06001990
1991 /* now we copy read ssid into dev */
1992 if (!(priv->config & CFG_STATIC_ESSID)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001993 priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE);
James Ketrenos2c86c272005-03-23 17:32:29 -06001994 memcpy(priv->essid, essid, priv->essid_len);
1995 }
1996 priv->channel = chan;
1997 memcpy(priv->bssid, bssid, ETH_ALEN);
1998
1999 priv->status |= STATUS_ASSOCIATING;
2000 priv->connect_start = get_seconds();
2001
2002 queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10);
2003}
2004
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002005static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
2006 int length, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06002007{
2008 int ssid_len = min(length, IW_ESSID_MAX_SIZE);
2009 struct host_command cmd = {
2010 .host_command = SSID,
2011 .host_command_sequence = 0,
2012 .host_command_length = ssid_len
2013 };
2014 int err;
John W. Linville9387b7c2008-09-30 20:59:05 -04002015 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002016
John W. Linville9387b7c2008-09-30 20:59:05 -04002017 IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len));
James Ketrenos2c86c272005-03-23 17:32:29 -06002018
2019 if (ssid_len)
James Ketrenos82328352005-08-24 22:33:31 -05002020 memcpy(cmd.host_command_parameters, essid, ssid_len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002021
2022 if (!batch_mode) {
2023 err = ipw2100_disable_adapter(priv);
2024 if (err)
2025 return err;
2026 }
2027
2028 /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to
2029 * disable auto association -- so we cheat by setting a bogus SSID */
2030 if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) {
2031 int i;
James Ketrenosee8e3652005-09-14 09:47:29 -05002032 u8 *bogus = (u8 *) cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06002033 for (i = 0; i < IW_ESSID_MAX_SIZE; i++)
2034 bogus[i] = 0x18 + i;
2035 cmd.host_command_length = IW_ESSID_MAX_SIZE;
2036 }
2037
2038 /* NOTE: We always send the SSID command even if the provided ESSID is
2039 * the same as what we currently think is set. */
2040
2041 err = ipw2100_hw_send_command(priv, &cmd);
2042 if (!err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002043 memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002044 memcpy(priv->essid, essid, ssid_len);
2045 priv->essid_len = ssid_len;
2046 }
2047
2048 if (!batch_mode) {
2049 if (ipw2100_enable_adapter(priv))
2050 err = -EIO;
2051 }
2052
2053 return err;
2054}
2055
2056static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
2057{
John W. Linville9387b7c2008-09-30 20:59:05 -04002058 DECLARE_SSID_BUF(ssid);
2059
James Ketrenos2c86c272005-03-23 17:32:29 -06002060 IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
Johannes Berge1749612008-10-27 15:59:26 -07002061 "disassociated: '%s' %pM \n",
John W. Linville9387b7c2008-09-30 20:59:05 -04002062 print_ssid(ssid, priv->essid, priv->essid_len),
Johannes Berge1749612008-10-27 15:59:26 -07002063 priv->bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002064
2065 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
2066
2067 if (priv->status & STATUS_STOPPING) {
2068 IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n");
2069 return;
2070 }
2071
2072 memset(priv->bssid, 0, ETH_ALEN);
2073 memset(priv->ieee->bssid, 0, ETH_ALEN);
2074
2075 netif_carrier_off(priv->net_dev);
2076 netif_stop_queue(priv->net_dev);
2077
2078 if (!(priv->status & STATUS_RUNNING))
2079 return;
2080
2081 if (priv->status & STATUS_SECURITY_UPDATED)
David Howellsc4028952006-11-22 14:57:56 +00002082 queue_delayed_work(priv->workqueue, &priv->security_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06002083
David Howellsc4028952006-11-22 14:57:56 +00002084 queue_delayed_work(priv->workqueue, &priv->wx_event_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06002085}
2086
2087static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
2088{
2089 IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002090 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002091
2092 /* RF_KILL is now enabled (else we wouldn't be here) */
2093 priv->status |= STATUS_RF_KILL_HW;
2094
James Ketrenos2c86c272005-03-23 17:32:29 -06002095 /* Make sure the RF Kill check timer is running */
2096 priv->stop_rf_kill = 0;
2097 cancel_delayed_work(&priv->rf_kill);
Anton Blanchardbe84e3d2007-10-15 00:38:01 -05002098 queue_delayed_work(priv->workqueue, &priv->rf_kill,
2099 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06002100}
2101
Dan Williamsd20c6782007-10-10 12:28:07 -04002102static void send_scan_event(void *data)
2103{
2104 struct ipw2100_priv *priv = data;
2105 union iwreq_data wrqu;
2106
2107 wrqu.data.length = 0;
2108 wrqu.data.flags = 0;
2109 wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
2110}
2111
2112static void ipw2100_scan_event_later(struct work_struct *work)
2113{
2114 send_scan_event(container_of(work, struct ipw2100_priv,
2115 scan_event_later.work));
2116}
2117
2118static void ipw2100_scan_event_now(struct work_struct *work)
2119{
2120 send_scan_event(container_of(work, struct ipw2100_priv,
2121 scan_event_now));
2122}
2123
James Ketrenos2c86c272005-03-23 17:32:29 -06002124static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
2125{
2126 IPW_DEBUG_SCAN("scan complete\n");
2127 /* Age the scan results... */
2128 priv->ieee->scans++;
2129 priv->status &= ~STATUS_SCANNING;
Dan Williamsd20c6782007-10-10 12:28:07 -04002130
2131 /* Only userspace-requested scan completion events go out immediately */
2132 if (!priv->user_requested_scan) {
2133 if (!delayed_work_pending(&priv->scan_event_later))
2134 queue_delayed_work(priv->workqueue,
2135 &priv->scan_event_later,
Anton Blanchardbe84e3d2007-10-15 00:38:01 -05002136 round_jiffies_relative(msecs_to_jiffies(4000)));
Dan Williamsd20c6782007-10-10 12:28:07 -04002137 } else {
2138 priv->user_requested_scan = 0;
2139 cancel_delayed_work(&priv->scan_event_later);
2140 queue_work(priv->workqueue, &priv->scan_event_now);
2141 }
James Ketrenos2c86c272005-03-23 17:32:29 -06002142}
2143
Brice Goglin0f52bf92005-12-01 01:41:46 -08002144#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002145#define IPW2100_HANDLER(v, f) { v, f, # v }
2146struct ipw2100_status_indicator {
2147 int status;
James Ketrenosee8e3652005-09-14 09:47:29 -05002148 void (*cb) (struct ipw2100_priv * priv, u32 status);
James Ketrenos2c86c272005-03-23 17:32:29 -06002149 char *name;
2150};
2151#else
2152#define IPW2100_HANDLER(v, f) { v, f }
2153struct ipw2100_status_indicator {
2154 int status;
James Ketrenosee8e3652005-09-14 09:47:29 -05002155 void (*cb) (struct ipw2100_priv * priv, u32 status);
James Ketrenos2c86c272005-03-23 17:32:29 -06002156};
Brice Goglin0f52bf92005-12-01 01:41:46 -08002157#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -06002158
2159static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
2160{
2161 IPW_DEBUG_SCAN("Scanning...\n");
2162 priv->status |= STATUS_SCANNING;
2163}
2164
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002165static const struct ipw2100_status_indicator status_handlers[] = {
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002166 IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL),
2167 IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002168 IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated),
2169 IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002170 IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002171 IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002172 IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL),
2173 IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002174 IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002175 IPW2100_HANDLER(IPW_STATE_DISABLED, NULL),
2176 IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002177 IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002178 IPW2100_HANDLER(-1, NULL)
James Ketrenos2c86c272005-03-23 17:32:29 -06002179};
2180
James Ketrenos2c86c272005-03-23 17:32:29 -06002181static void isr_status_change(struct ipw2100_priv *priv, int status)
2182{
2183 int i;
2184
2185 if (status == IPW_STATE_SCANNING &&
2186 priv->status & STATUS_ASSOCIATED &&
2187 !(priv->status & STATUS_SCANNING)) {
2188 IPW_DEBUG_INFO("Scan detected while associated, with "
2189 "no scan request. Restarting firmware.\n");
2190
2191 /* Wake up any sleeping jobs */
2192 schedule_reset(priv);
2193 }
2194
2195 for (i = 0; status_handlers[i].status != -1; i++) {
2196 if (status == status_handlers[i].status) {
2197 IPW_DEBUG_NOTIF("Status change: %s\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002198 status_handlers[i].name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002199 if (status_handlers[i].cb)
2200 status_handlers[i].cb(priv, status);
2201 priv->wstats.status = status;
2202 return;
2203 }
2204 }
2205
2206 IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);
2207}
2208
James Ketrenosee8e3652005-09-14 09:47:29 -05002209static void isr_rx_complete_command(struct ipw2100_priv *priv,
2210 struct ipw2100_cmd_header *cmd)
James Ketrenos2c86c272005-03-23 17:32:29 -06002211{
Brice Goglin0f52bf92005-12-01 01:41:46 -08002212#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002213 if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
2214 IPW_DEBUG_HC("Command completed '%s (%d)'\n",
2215 command_types[cmd->host_command_reg],
2216 cmd->host_command_reg);
2217 }
2218#endif
2219 if (cmd->host_command_reg == HOST_COMPLETE)
2220 priv->status |= STATUS_ENABLED;
2221
2222 if (cmd->host_command_reg == CARD_DISABLE)
2223 priv->status &= ~STATUS_ENABLED;
2224
2225 priv->status &= ~STATUS_CMD_ACTIVE;
2226
2227 wake_up_interruptible(&priv->wait_command_queue);
2228}
2229
Brice Goglin0f52bf92005-12-01 01:41:46 -08002230#ifdef CONFIG_IPW2100_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002231static const char *frame_types[] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06002232 "COMMAND_STATUS_VAL",
2233 "STATUS_CHANGE_VAL",
2234 "P80211_DATA_VAL",
2235 "P8023_DATA_VAL",
2236 "HOST_NOTIFICATION_VAL"
2237};
2238#endif
2239
Arjan van de Ven858119e2006-01-14 13:20:43 -08002240static int ipw2100_alloc_skb(struct ipw2100_priv *priv,
James Ketrenosee8e3652005-09-14 09:47:29 -05002241 struct ipw2100_rx_packet *packet)
James Ketrenos2c86c272005-03-23 17:32:29 -06002242{
2243 packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
2244 if (!packet->skb)
2245 return -ENOMEM;
2246
2247 packet->rxp = (struct ipw2100_rx *)packet->skb->data;
2248 packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data,
2249 sizeof(struct ipw2100_rx),
2250 PCI_DMA_FROMDEVICE);
2251 /* NOTE: pci_map_single does not return an error code, and 0 is a valid
2252 * dma_addr */
2253
2254 return 0;
2255}
2256
James Ketrenos2c86c272005-03-23 17:32:29 -06002257#define SEARCH_ERROR 0xffffffff
2258#define SEARCH_FAIL 0xfffffffe
2259#define SEARCH_SUCCESS 0xfffffff0
2260#define SEARCH_DISCARD 0
2261#define SEARCH_SNAPSHOT 1
2262
2263#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
Zhu Yi3c5eca52006-01-24 13:49:26 +08002264static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
2265{
2266 int i;
2267 if (!priv->snapshot[0])
2268 return;
2269 for (i = 0; i < 0x30; i++)
2270 kfree(priv->snapshot[i]);
2271 priv->snapshot[0] = NULL;
2272}
2273
Robert P. J. Dayae800312007-01-31 02:39:40 -05002274#ifdef IPW2100_DEBUG_C3
Arjan van de Ven858119e2006-01-14 13:20:43 -08002275static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002276{
2277 int i;
2278 if (priv->snapshot[0])
2279 return 1;
2280 for (i = 0; i < 0x30; i++) {
Robert P. J. Day5cbded52006-12-13 00:35:56 -08002281 priv->snapshot[i] = kmalloc(0x1000, GFP_ATOMIC);
James Ketrenos2c86c272005-03-23 17:32:29 -06002282 if (!priv->snapshot[i]) {
2283 IPW_DEBUG_INFO("%s: Error allocating snapshot "
James Ketrenosee8e3652005-09-14 09:47:29 -05002284 "buffer %d\n", priv->net_dev->name, i);
James Ketrenos2c86c272005-03-23 17:32:29 -06002285 while (i > 0)
2286 kfree(priv->snapshot[--i]);
2287 priv->snapshot[0] = NULL;
2288 return 0;
2289 }
2290 }
2291
2292 return 1;
2293}
2294
Arjan van de Ven858119e2006-01-14 13:20:43 -08002295static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
James Ketrenos2c86c272005-03-23 17:32:29 -06002296 size_t len, int mode)
2297{
2298 u32 i, j;
2299 u32 tmp;
2300 u8 *s, *d;
2301 u32 ret;
2302
2303 s = in_buf;
2304 if (mode == SEARCH_SNAPSHOT) {
2305 if (!ipw2100_snapshot_alloc(priv))
2306 mode = SEARCH_DISCARD;
2307 }
2308
2309 for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) {
2310 read_nic_dword(priv->net_dev, i, &tmp);
2311 if (mode == SEARCH_SNAPSHOT)
James Ketrenosee8e3652005-09-14 09:47:29 -05002312 *(u32 *) SNAPSHOT_ADDR(i) = tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06002313 if (ret == SEARCH_FAIL) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002314 d = (u8 *) & tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06002315 for (j = 0; j < 4; j++) {
2316 if (*s != *d) {
2317 s = in_buf;
2318 continue;
2319 }
2320
2321 s++;
2322 d++;
2323
2324 if ((s - in_buf) == len)
2325 ret = (i + j) - len + 1;
2326 }
2327 } else if (mode == SEARCH_DISCARD)
2328 return ret;
2329 }
2330
2331 return ret;
2332}
Zhu Yi3c5eca52006-01-24 13:49:26 +08002333#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06002334
2335/*
2336 *
2337 * 0) Disconnect the SKB from the firmware (just unmap)
2338 * 1) Pack the ETH header into the SKB
2339 * 2) Pass the SKB to the network stack
2340 *
2341 * When packet is provided by the firmware, it contains the following:
2342 *
2343 * . ieee80211_hdr
2344 * . ieee80211_snap_hdr
2345 *
2346 * The size of the constructed ethernet
2347 *
2348 */
Robert P. J. Dayae800312007-01-31 02:39:40 -05002349#ifdef IPW2100_RX_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002350static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
James Ketrenos2c86c272005-03-23 17:32:29 -06002351#endif
2352
Arjan van de Ven858119e2006-01-14 13:20:43 -08002353static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
James Ketrenos2c86c272005-03-23 17:32:29 -06002354{
Robert P. J. Dayae800312007-01-31 02:39:40 -05002355#ifdef IPW2100_DEBUG_C3
James Ketrenos2c86c272005-03-23 17:32:29 -06002356 struct ipw2100_status *status = &priv->status_queue.drv[i];
2357 u32 match, reg;
2358 int j;
2359#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06002360
Zhu Yia1e695a2005-07-04 14:06:00 +08002361 IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n",
2362 i * sizeof(struct ipw2100_status));
James Ketrenos2c86c272005-03-23 17:32:29 -06002363
Robert P. J. Dayae800312007-01-31 02:39:40 -05002364#ifdef IPW2100_DEBUG_C3
James Ketrenos2c86c272005-03-23 17:32:29 -06002365 /* Halt the fimrware so we can get a good image */
2366 write_register(priv->net_dev, IPW_REG_RESET_REG,
2367 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
2368 j = 5;
2369 do {
2370 udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
2371 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
2372
2373 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
2374 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05002375 } while (j--);
James Ketrenos2c86c272005-03-23 17:32:29 -06002376
James Ketrenosee8e3652005-09-14 09:47:29 -05002377 match = ipw2100_match_buf(priv, (u8 *) status,
James Ketrenos2c86c272005-03-23 17:32:29 -06002378 sizeof(struct ipw2100_status),
2379 SEARCH_SNAPSHOT);
2380 if (match < SEARCH_SUCCESS)
2381 IPW_DEBUG_INFO("%s: DMA status match in Firmware at "
2382 "offset 0x%06X, length %d:\n",
2383 priv->net_dev->name, match,
2384 sizeof(struct ipw2100_status));
2385 else
2386 IPW_DEBUG_INFO("%s: No DMA status match in "
2387 "Firmware.\n", priv->net_dev->name);
2388
James Ketrenosee8e3652005-09-14 09:47:29 -05002389 printk_buf((u8 *) priv->status_queue.drv,
James Ketrenos2c86c272005-03-23 17:32:29 -06002390 sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);
2391#endif
2392
2393 priv->fatal_error = IPW2100_ERR_C3_CORRUPTION;
2394 priv->ieee->stats.rx_errors++;
2395 schedule_reset(priv);
2396}
2397
Arjan van de Ven858119e2006-01-14 13:20:43 -08002398static void isr_rx(struct ipw2100_priv *priv, int i,
James Ketrenos2c86c272005-03-23 17:32:29 -06002399 struct ieee80211_rx_stats *stats)
2400{
2401 struct ipw2100_status *status = &priv->status_queue.drv[i];
2402 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
2403
2404 IPW_DEBUG_RX("Handler...\n");
2405
2406 if (unlikely(status->frame_size > skb_tailroom(packet->skb))) {
2407 IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
2408 " Dropping.\n",
2409 priv->net_dev->name,
2410 status->frame_size, skb_tailroom(packet->skb));
2411 priv->ieee->stats.rx_errors++;
2412 return;
2413 }
2414
2415 if (unlikely(!netif_running(priv->net_dev))) {
2416 priv->ieee->stats.rx_errors++;
2417 priv->wstats.discard.misc++;
2418 IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
2419 return;
2420 }
James Ketrenos2c86c272005-03-23 17:32:29 -06002421
2422 if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
James Ketrenosee8e3652005-09-14 09:47:29 -05002423 !(priv->status & STATUS_ASSOCIATED))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002424 IPW_DEBUG_DROP("Dropping packet while not associated.\n");
2425 priv->wstats.discard.misc++;
2426 return;
2427 }
2428
James Ketrenos2c86c272005-03-23 17:32:29 -06002429 pci_unmap_single(priv->pci_dev,
2430 packet->dma_addr,
James Ketrenosee8e3652005-09-14 09:47:29 -05002431 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002432
2433 skb_put(packet->skb, status->frame_size);
2434
Robert P. J. Dayae800312007-01-31 02:39:40 -05002435#ifdef IPW2100_RX_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002436 /* Make a copy of the frame so we can dump it to the logs if
2437 * ieee80211_rx fails */
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03002438 skb_copy_from_linear_data(packet->skb, packet_data,
2439 min_t(u32, status->frame_size,
2440 IPW_RX_NIC_BUFFER_LENGTH));
James Ketrenos2c86c272005-03-23 17:32:29 -06002441#endif
2442
2443 if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
Robert P. J. Dayae800312007-01-31 02:39:40 -05002444#ifdef IPW2100_RX_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002445 IPW_DEBUG_DROP("%s: Non consumed packet:\n",
2446 priv->net_dev->name);
2447 printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
2448#endif
2449 priv->ieee->stats.rx_errors++;
2450
2451 /* ieee80211_rx failed, so it didn't free the SKB */
2452 dev_kfree_skb_any(packet->skb);
2453 packet->skb = NULL;
2454 }
2455
2456 /* We need to allocate a new SKB and attach it to the RDB. */
2457 if (unlikely(ipw2100_alloc_skb(priv, packet))) {
Jiri Benc797b4f72005-08-25 20:03:27 -04002458 printk(KERN_WARNING DRV_NAME ": "
James Ketrenosee8e3652005-09-14 09:47:29 -05002459 "%s: Unable to allocate SKB onto RBD ring - disabling "
2460 "adapter.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002461 /* TODO: schedule adapter shutdown */
2462 IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
2463 }
2464
2465 /* Update the RDB entry */
2466 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
2467}
2468
Stefan Rompf15745a72006-02-21 18:36:17 +08002469#ifdef CONFIG_IPW2100_MONITOR
2470
2471static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
2472 struct ieee80211_rx_stats *stats)
2473{
2474 struct ipw2100_status *status = &priv->status_queue.drv[i];
2475 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
2476
Stefan Rompf15745a72006-02-21 18:36:17 +08002477 /* Magic struct that slots into the radiotap header -- no reason
2478 * to build this manually element by element, we can write it much
2479 * more efficiently than we can parse it. ORDER MATTERS HERE */
2480 struct ipw_rt_hdr {
2481 struct ieee80211_radiotap_header rt_hdr;
2482 s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
2483 } *ipw_rt;
2484
Zhu Yicae16292006-02-21 18:41:14 +08002485 IPW_DEBUG_RX("Handler...\n");
2486
2487 if (unlikely(status->frame_size > skb_tailroom(packet->skb) -
2488 sizeof(struct ipw_rt_hdr))) {
Stefan Rompf15745a72006-02-21 18:36:17 +08002489 IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
2490 " Dropping.\n",
2491 priv->net_dev->name,
Zhu Yicae16292006-02-21 18:41:14 +08002492 status->frame_size,
2493 skb_tailroom(packet->skb));
Stefan Rompf15745a72006-02-21 18:36:17 +08002494 priv->ieee->stats.rx_errors++;
2495 return;
2496 }
2497
2498 if (unlikely(!netif_running(priv->net_dev))) {
2499 priv->ieee->stats.rx_errors++;
2500 priv->wstats.discard.misc++;
2501 IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
2502 return;
2503 }
2504
2505 if (unlikely(priv->config & CFG_CRC_CHECK &&
2506 status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
2507 IPW_DEBUG_RX("CRC error in packet. Dropping.\n");
2508 priv->ieee->stats.rx_errors++;
2509 return;
2510 }
2511
Zhu Yicae16292006-02-21 18:41:14 +08002512 pci_unmap_single(priv->pci_dev, packet->dma_addr,
Stefan Rompf15745a72006-02-21 18:36:17 +08002513 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
2514 memmove(packet->skb->data + sizeof(struct ipw_rt_hdr),
2515 packet->skb->data, status->frame_size);
2516
2517 ipw_rt = (struct ipw_rt_hdr *) packet->skb->data;
2518
2519 ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
2520 ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
Al Viro1edd3a52007-12-21 00:15:18 -05002521 ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total hdr+data */
Stefan Rompf15745a72006-02-21 18:36:17 +08002522
Al Viro1edd3a52007-12-21 00:15:18 -05002523 ipw_rt->rt_hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
Stefan Rompf15745a72006-02-21 18:36:17 +08002524
2525 ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM;
2526
2527 skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr));
2528
2529 if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
2530 priv->ieee->stats.rx_errors++;
2531
2532 /* ieee80211_rx failed, so it didn't free the SKB */
2533 dev_kfree_skb_any(packet->skb);
2534 packet->skb = NULL;
2535 }
2536
2537 /* We need to allocate a new SKB and attach it to the RDB. */
2538 if (unlikely(ipw2100_alloc_skb(priv, packet))) {
2539 IPW_DEBUG_WARNING(
2540 "%s: Unable to allocate SKB onto RBD ring - disabling "
2541 "adapter.\n", priv->net_dev->name);
2542 /* TODO: schedule adapter shutdown */
2543 IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
2544 }
2545
2546 /* Update the RDB entry */
2547 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
2548}
2549
2550#endif
2551
Arjan van de Ven858119e2006-01-14 13:20:43 -08002552static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
James Ketrenos2c86c272005-03-23 17:32:29 -06002553{
2554 struct ipw2100_status *status = &priv->status_queue.drv[i];
2555 struct ipw2100_rx *u = priv->rx_buffers[i].rxp;
2556 u16 frame_type = status->status_fields & STATUS_TYPE_MASK;
2557
2558 switch (frame_type) {
2559 case COMMAND_STATUS_VAL:
2560 return (status->frame_size != sizeof(u->rx_data.command));
2561 case STATUS_CHANGE_VAL:
2562 return (status->frame_size != sizeof(u->rx_data.status));
2563 case HOST_NOTIFICATION_VAL:
2564 return (status->frame_size < sizeof(u->rx_data.notification));
2565 case P80211_DATA_VAL:
2566 case P8023_DATA_VAL:
2567#ifdef CONFIG_IPW2100_MONITOR
2568 return 0;
2569#else
Al Viro1edd3a52007-12-21 00:15:18 -05002570 switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002571 case IEEE80211_FTYPE_MGMT:
2572 case IEEE80211_FTYPE_CTL:
2573 return 0;
2574 case IEEE80211_FTYPE_DATA:
2575 return (status->frame_size >
2576 IPW_MAX_802_11_PAYLOAD_LENGTH);
2577 }
2578#endif
2579 }
2580
2581 return 1;
2582}
2583
2584/*
2585 * ipw2100 interrupts are disabled at this point, and the ISR
2586 * is the only code that calls this method. So, we do not need
2587 * to play with any locks.
2588 *
2589 * RX Queue works as follows:
2590 *
2591 * Read index - firmware places packet in entry identified by the
2592 * Read index and advances Read index. In this manner,
2593 * Read index will always point to the next packet to
2594 * be filled--but not yet valid.
2595 *
2596 * Write index - driver fills this entry with an unused RBD entry.
2597 * This entry has not filled by the firmware yet.
2598 *
2599 * In between the W and R indexes are the RBDs that have been received
2600 * but not yet processed.
2601 *
2602 * The process of handling packets will start at WRITE + 1 and advance
2603 * until it reaches the READ index.
2604 *
2605 * The WRITE index is cached in the variable 'priv->rx_queue.next'.
2606 *
2607 */
Arjan van de Ven858119e2006-01-14 13:20:43 -08002608static void __ipw2100_rx_process(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002609{
2610 struct ipw2100_bd_queue *rxq = &priv->rx_queue;
2611 struct ipw2100_status_queue *sq = &priv->status_queue;
2612 struct ipw2100_rx_packet *packet;
2613 u16 frame_type;
2614 u32 r, w, i, s;
2615 struct ipw2100_rx *u;
2616 struct ieee80211_rx_stats stats = {
2617 .mac_time = jiffies,
2618 };
2619
2620 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r);
2621 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w);
2622
2623 if (r >= rxq->entries) {
2624 IPW_DEBUG_RX("exit - bad read index\n");
2625 return;
2626 }
2627
2628 i = (rxq->next + 1) % rxq->entries;
2629 s = i;
2630 while (i != r) {
2631 /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n",
2632 r, rxq->next, i); */
2633
2634 packet = &priv->rx_buffers[i];
2635
2636 /* Sync the DMA for the STATUS buffer so CPU is sure to get
2637 * the correct values */
James Ketrenosee8e3652005-09-14 09:47:29 -05002638 pci_dma_sync_single_for_cpu(priv->pci_dev,
2639 sq->nic +
2640 sizeof(struct ipw2100_status) * i,
2641 sizeof(struct ipw2100_status),
2642 PCI_DMA_FROMDEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002643
2644 /* Sync the DMA for the RX buffer so CPU is sure to get
2645 * the correct values */
2646 pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr,
2647 sizeof(struct ipw2100_rx),
2648 PCI_DMA_FROMDEVICE);
2649
2650 if (unlikely(ipw2100_corruption_check(priv, i))) {
2651 ipw2100_corruption_detected(priv, i);
2652 goto increment;
2653 }
2654
2655 u = packet->rxp;
James Ketrenosee8e3652005-09-14 09:47:29 -05002656 frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK;
James Ketrenos2c86c272005-03-23 17:32:29 -06002657 stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM;
2658 stats.len = sq->drv[i].frame_size;
2659
2660 stats.mask = 0;
2661 if (stats.rssi != 0)
2662 stats.mask |= IEEE80211_STATMASK_RSSI;
2663 stats.freq = IEEE80211_24GHZ_BAND;
2664
James Ketrenosee8e3652005-09-14 09:47:29 -05002665 IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n",
2666 priv->net_dev->name, frame_types[frame_type],
2667 stats.len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002668
2669 switch (frame_type) {
2670 case COMMAND_STATUS_VAL:
2671 /* Reset Rx watchdog */
James Ketrenosee8e3652005-09-14 09:47:29 -05002672 isr_rx_complete_command(priv, &u->rx_data.command);
James Ketrenos2c86c272005-03-23 17:32:29 -06002673 break;
2674
2675 case STATUS_CHANGE_VAL:
2676 isr_status_change(priv, u->rx_data.status);
2677 break;
2678
2679 case P80211_DATA_VAL:
2680 case P8023_DATA_VAL:
2681#ifdef CONFIG_IPW2100_MONITOR
2682 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
Stefan Rompf15745a72006-02-21 18:36:17 +08002683 isr_rx_monitor(priv, i, &stats);
James Ketrenos2c86c272005-03-23 17:32:29 -06002684 break;
2685 }
2686#endif
Zhu Yife5f8e22006-12-20 16:11:58 +08002687 if (stats.len < sizeof(struct ieee80211_hdr_3addr))
James Ketrenos2c86c272005-03-23 17:32:29 -06002688 break;
Al Viro1edd3a52007-12-21 00:15:18 -05002689 switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002690 case IEEE80211_FTYPE_MGMT:
2691 ieee80211_rx_mgt(priv->ieee,
James Ketrenosee8e3652005-09-14 09:47:29 -05002692 &u->rx_data.header, &stats);
James Ketrenos2c86c272005-03-23 17:32:29 -06002693 break;
2694
2695 case IEEE80211_FTYPE_CTL:
2696 break;
2697
2698 case IEEE80211_FTYPE_DATA:
2699 isr_rx(priv, i, &stats);
2700 break;
2701
2702 }
2703 break;
2704 }
2705
James Ketrenosee8e3652005-09-14 09:47:29 -05002706 increment:
James Ketrenos2c86c272005-03-23 17:32:29 -06002707 /* clear status field associated with this RBD */
2708 rxq->drv[i].status.info.field = 0;
2709
2710 i = (i + 1) % rxq->entries;
2711 }
2712
2713 if (i != s) {
2714 /* backtrack one entry, wrapping to end if at 0 */
2715 rxq->next = (i ? i : rxq->entries) - 1;
2716
2717 write_register(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05002718 IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next);
James Ketrenos2c86c272005-03-23 17:32:29 -06002719 }
2720}
2721
James Ketrenos2c86c272005-03-23 17:32:29 -06002722/*
2723 * __ipw2100_tx_process
2724 *
2725 * This routine will determine whether the next packet on
2726 * the fw_pend_list has been processed by the firmware yet.
2727 *
2728 * If not, then it does nothing and returns.
2729 *
2730 * If so, then it removes the item from the fw_pend_list, frees
2731 * any associated storage, and places the item back on the
2732 * free list of its source (either msg_free_list or tx_free_list)
2733 *
2734 * TX Queue works as follows:
2735 *
2736 * Read index - points to the next TBD that the firmware will
2737 * process. The firmware will read the data, and once
2738 * done processing, it will advance the Read index.
2739 *
2740 * Write index - driver fills this entry with an constructed TBD
2741 * entry. The Write index is not advanced until the
2742 * packet has been configured.
2743 *
2744 * In between the W and R indexes are the TBDs that have NOT been
2745 * processed. Lagging behind the R index are packets that have
2746 * been processed but have not been freed by the driver.
2747 *
2748 * In order to free old storage, an internal index will be maintained
2749 * that points to the next packet to be freed. When all used
2750 * packets have been freed, the oldest index will be the same as the
2751 * firmware's read index.
2752 *
2753 * The OLDEST index is cached in the variable 'priv->tx_queue.oldest'
2754 *
2755 * Because the TBD structure can not contain arbitrary data, the
2756 * driver must keep an internal queue of cached allocations such that
2757 * it can put that data back into the tx_free_list and msg_free_list
2758 * for use by future command and data packets.
2759 *
2760 */
Arjan van de Ven858119e2006-01-14 13:20:43 -08002761static int __ipw2100_tx_process(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002762{
2763 struct ipw2100_bd_queue *txq = &priv->tx_queue;
James Ketrenosee8e3652005-09-14 09:47:29 -05002764 struct ipw2100_bd *tbd;
James Ketrenos2c86c272005-03-23 17:32:29 -06002765 struct list_head *element;
2766 struct ipw2100_tx_packet *packet;
2767 int descriptors_used;
2768 int e, i;
2769 u32 r, w, frag_num = 0;
2770
2771 if (list_empty(&priv->fw_pend_list))
2772 return 0;
2773
2774 element = priv->fw_pend_list.next;
2775
2776 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenosee8e3652005-09-14 09:47:29 -05002777 tbd = &txq->drv[packet->index];
James Ketrenos2c86c272005-03-23 17:32:29 -06002778
2779 /* Determine how many TBD entries must be finished... */
2780 switch (packet->type) {
2781 case COMMAND:
2782 /* COMMAND uses only one slot; don't advance */
2783 descriptors_used = 1;
2784 e = txq->oldest;
2785 break;
2786
2787 case DATA:
2788 /* DATA uses two slots; advance and loop position. */
2789 descriptors_used = tbd->num_fragments;
James Ketrenosee8e3652005-09-14 09:47:29 -05002790 frag_num = tbd->num_fragments - 1;
James Ketrenos2c86c272005-03-23 17:32:29 -06002791 e = txq->oldest + frag_num;
2792 e %= txq->entries;
2793 break;
2794
2795 default:
Jiri Benc797b4f72005-08-25 20:03:27 -04002796 printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002797 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002798 return 0;
2799 }
2800
2801 /* if the last TBD is not done by NIC yet, then packet is
2802 * not ready to be released.
2803 *
2804 */
2805 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
2806 &r);
2807 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
2808 &w);
2809 if (w != txq->next)
Jiri Benc797b4f72005-08-25 20:03:27 -04002810 printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06002811 priv->net_dev->name);
2812
James Ketrenosee8e3652005-09-14 09:47:29 -05002813 /*
James Ketrenos2c86c272005-03-23 17:32:29 -06002814 * txq->next is the index of the last packet written txq->oldest is
2815 * the index of the r is the index of the next packet to be read by
2816 * firmware
2817 */
2818
James Ketrenos2c86c272005-03-23 17:32:29 -06002819 /*
2820 * Quick graphic to help you visualize the following
2821 * if / else statement
2822 *
2823 * ===>| s---->|===============
2824 * e>|
2825 * | a | b | c | d | e | f | g | h | i | j | k | l
2826 * r---->|
2827 * w
2828 *
2829 * w - updated by driver
2830 * r - updated by firmware
2831 * s - start of oldest BD entry (txq->oldest)
2832 * e - end of oldest BD entry
2833 *
2834 */
2835 if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) {
2836 IPW_DEBUG_TX("exit - no processed packets ready to release.\n");
2837 return 0;
2838 }
2839
2840 list_del(element);
2841 DEC_STAT(&priv->fw_pend_stat);
2842
Brice Goglin0f52bf92005-12-01 01:41:46 -08002843#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002844 {
2845 int i = txq->oldest;
James Ketrenosee8e3652005-09-14 09:47:29 -05002846 IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
2847 &txq->drv[i],
2848 (u32) (txq->nic + i * sizeof(struct ipw2100_bd)),
2849 txq->drv[i].host_addr, txq->drv[i].buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002850
2851 if (packet->type == DATA) {
2852 i = (i + 1) % txq->entries;
2853
James Ketrenosee8e3652005-09-14 09:47:29 -05002854 IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
2855 &txq->drv[i],
2856 (u32) (txq->nic + i *
2857 sizeof(struct ipw2100_bd)),
2858 (u32) txq->drv[i].host_addr,
2859 txq->drv[i].buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002860 }
2861 }
2862#endif
2863
2864 switch (packet->type) {
2865 case DATA:
2866 if (txq->drv[txq->oldest].status.info.fields.txType != 0)
Jiri Benc797b4f72005-08-25 20:03:27 -04002867 printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
James Ketrenos2c86c272005-03-23 17:32:29 -06002868 "Expecting DATA TBD but pulled "
2869 "something else: ids %d=%d.\n",
2870 priv->net_dev->name, txq->oldest, packet->index);
2871
2872 /* DATA packet; we have to unmap and free the SKB */
James Ketrenos2c86c272005-03-23 17:32:29 -06002873 for (i = 0; i < frag_num; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002874 tbd = &txq->drv[(packet->index + 1 + i) % txq->entries];
James Ketrenos2c86c272005-03-23 17:32:29 -06002875
James Ketrenosee8e3652005-09-14 09:47:29 -05002876 IPW_DEBUG_TX("TX%d P=%08x L=%d\n",
2877 (packet->index + 1 + i) % txq->entries,
2878 tbd->host_addr, tbd->buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002879
2880 pci_unmap_single(priv->pci_dev,
2881 tbd->host_addr,
James Ketrenosee8e3652005-09-14 09:47:29 -05002882 tbd->buf_length, PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002883 }
2884
James Ketrenos2c86c272005-03-23 17:32:29 -06002885 ieee80211_txb_free(packet->info.d_struct.txb);
2886 packet->info.d_struct.txb = NULL;
2887
2888 list_add_tail(element, &priv->tx_free_list);
2889 INC_STAT(&priv->tx_free_stat);
2890
2891 /* We have a free slot in the Tx queue, so wake up the
2892 * transmit layer if it is stopped. */
James Ketrenos82328352005-08-24 22:33:31 -05002893 if (priv->status & STATUS_ASSOCIATED)
James Ketrenos2c86c272005-03-23 17:32:29 -06002894 netif_wake_queue(priv->net_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06002895
2896 /* A packet was processed by the hardware, so update the
2897 * watchdog */
2898 priv->net_dev->trans_start = jiffies;
2899
2900 break;
2901
2902 case COMMAND:
2903 if (txq->drv[txq->oldest].status.info.fields.txType != 1)
Jiri Benc797b4f72005-08-25 20:03:27 -04002904 printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
James Ketrenos2c86c272005-03-23 17:32:29 -06002905 "Expecting COMMAND TBD but pulled "
2906 "something else: ids %d=%d.\n",
2907 priv->net_dev->name, txq->oldest, packet->index);
2908
Brice Goglin0f52bf92005-12-01 01:41:46 -08002909#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002910 if (packet->info.c_struct.cmd->host_command_reg <
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02002911 ARRAY_SIZE(command_types))
James Ketrenosee8e3652005-09-14 09:47:29 -05002912 IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n",
2913 command_types[packet->info.c_struct.cmd->
2914 host_command_reg],
2915 packet->info.c_struct.cmd->
2916 host_command_reg,
2917 packet->info.c_struct.cmd->cmd_status_reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06002918#endif
2919
2920 list_add_tail(element, &priv->msg_free_list);
2921 INC_STAT(&priv->msg_free_stat);
2922 break;
2923 }
2924
2925 /* advance oldest used TBD pointer to start of next entry */
2926 txq->oldest = (e + 1) % txq->entries;
2927 /* increase available TBDs number */
2928 txq->available += descriptors_used;
2929 SET_STAT(&priv->txq_stat, txq->available);
2930
2931 IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002932 jiffies - packet->jiffy_start);
James Ketrenos2c86c272005-03-23 17:32:29 -06002933
2934 return (!list_empty(&priv->fw_pend_list));
2935}
2936
James Ketrenos2c86c272005-03-23 17:32:29 -06002937static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
2938{
2939 int i = 0;
2940
James Ketrenosee8e3652005-09-14 09:47:29 -05002941 while (__ipw2100_tx_process(priv) && i < 200)
2942 i++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002943
2944 if (i == 200) {
Jiri Benc19f7f742005-08-25 20:02:10 -04002945 printk(KERN_WARNING DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06002946 "%s: Driver is running slow (%d iters).\n",
2947 priv->net_dev->name, i);
2948 }
2949}
2950
Jiri Benc19f7f742005-08-25 20:02:10 -04002951static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002952{
2953 struct list_head *element;
2954 struct ipw2100_tx_packet *packet;
2955 struct ipw2100_bd_queue *txq = &priv->tx_queue;
2956 struct ipw2100_bd *tbd;
2957 int next = txq->next;
2958
2959 while (!list_empty(&priv->msg_pend_list)) {
2960 /* if there isn't enough space in TBD queue, then
2961 * don't stuff a new one in.
2962 * NOTE: 3 are needed as a command will take one,
2963 * and there is a minimum of 2 that must be
2964 * maintained between the r and w indexes
2965 */
2966 if (txq->available <= 3) {
2967 IPW_DEBUG_TX("no room in tx_queue\n");
2968 break;
2969 }
2970
2971 element = priv->msg_pend_list.next;
2972 list_del(element);
2973 DEC_STAT(&priv->msg_pend_stat);
2974
James Ketrenosee8e3652005-09-14 09:47:29 -05002975 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06002976
2977 IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002978 &txq->drv[txq->next],
2979 (void *)(txq->nic + txq->next *
2980 sizeof(struct ipw2100_bd)));
James Ketrenos2c86c272005-03-23 17:32:29 -06002981
2982 packet->index = txq->next;
2983
2984 tbd = &txq->drv[txq->next];
2985
2986 /* initialize TBD */
2987 tbd->host_addr = packet->info.c_struct.cmd_phys;
2988 tbd->buf_length = sizeof(struct ipw2100_cmd_header);
2989 /* not marking number of fragments causes problems
2990 * with f/w debug version */
2991 tbd->num_fragments = 1;
2992 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05002993 IPW_BD_STATUS_TX_FRAME_COMMAND |
2994 IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06002995
2996 /* update TBD queue counters */
2997 txq->next++;
2998 txq->next %= txq->entries;
2999 txq->available--;
3000 DEC_STAT(&priv->txq_stat);
3001
3002 list_add_tail(element, &priv->fw_pend_list);
3003 INC_STAT(&priv->fw_pend_stat);
3004 }
3005
3006 if (txq->next != next) {
3007 /* kick off the DMA by notifying firmware the
3008 * write index has moved; make sure TBD stores are sync'd */
3009 wmb();
3010 write_register(priv->net_dev,
3011 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
3012 txq->next);
3013 }
3014}
3015
James Ketrenos2c86c272005-03-23 17:32:29 -06003016/*
Jiri Benc19f7f742005-08-25 20:02:10 -04003017 * ipw2100_tx_send_data
James Ketrenos2c86c272005-03-23 17:32:29 -06003018 *
3019 */
Jiri Benc19f7f742005-08-25 20:02:10 -04003020static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06003021{
3022 struct list_head *element;
3023 struct ipw2100_tx_packet *packet;
3024 struct ipw2100_bd_queue *txq = &priv->tx_queue;
3025 struct ipw2100_bd *tbd;
3026 int next = txq->next;
James Ketrenosee8e3652005-09-14 09:47:29 -05003027 int i = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06003028 struct ipw2100_data_header *ipw_hdr;
James Ketrenos99a4b232005-09-21 12:23:25 -05003029 struct ieee80211_hdr_3addr *hdr;
James Ketrenos2c86c272005-03-23 17:32:29 -06003030
3031 while (!list_empty(&priv->tx_pend_list)) {
3032 /* if there isn't enough space in TBD queue, then
3033 * don't stuff a new one in.
3034 * NOTE: 4 are needed as a data will take two,
3035 * and there is a minimum of 2 that must be
3036 * maintained between the r and w indexes
3037 */
3038 element = priv->tx_pend_list.next;
James Ketrenosee8e3652005-09-14 09:47:29 -05003039 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06003040
3041 if (unlikely(1 + packet->info.d_struct.txb->nr_frags >
3042 IPW_MAX_BDS)) {
3043 /* TODO: Support merging buffers if more than
3044 * IPW_MAX_BDS are used */
James Ketrenosee8e3652005-09-14 09:47:29 -05003045 IPW_DEBUG_INFO("%s: Maximum BD theshold exceeded. "
3046 "Increase fragmentation level.\n",
3047 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003048 }
3049
James Ketrenosee8e3652005-09-14 09:47:29 -05003050 if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003051 IPW_DEBUG_TX("no room in tx_queue\n");
3052 break;
3053 }
3054
3055 list_del(element);
3056 DEC_STAT(&priv->tx_pend_stat);
3057
3058 tbd = &txq->drv[txq->next];
3059
3060 packet->index = txq->next;
3061
3062 ipw_hdr = packet->info.d_struct.data;
James Ketrenos99a4b232005-09-21 12:23:25 -05003063 hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb->
James Ketrenosee8e3652005-09-14 09:47:29 -05003064 fragments[0]->data;
James Ketrenos2c86c272005-03-23 17:32:29 -06003065
3066 if (priv->ieee->iw_mode == IW_MODE_INFRA) {
3067 /* To DS: Addr1 = BSSID, Addr2 = SA,
3068 Addr3 = DA */
3069 memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
3070 memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN);
3071 } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
3072 /* not From/To DS: Addr1 = DA, Addr2 = SA,
3073 Addr3 = BSSID */
3074 memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
3075 memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN);
3076 }
3077
3078 ipw_hdr->host_command_reg = SEND;
3079 ipw_hdr->host_command_reg1 = 0;
3080
3081 /* For now we only support host based encryption */
3082 ipw_hdr->needs_encryption = 0;
3083 ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted;
3084 if (packet->info.d_struct.txb->nr_frags > 1)
3085 ipw_hdr->fragment_size =
James Ketrenosee8e3652005-09-14 09:47:29 -05003086 packet->info.d_struct.txb->frag_size -
3087 IEEE80211_3ADDR_LEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06003088 else
3089 ipw_hdr->fragment_size = 0;
3090
3091 tbd->host_addr = packet->info.d_struct.data_phys;
3092 tbd->buf_length = sizeof(struct ipw2100_data_header);
3093 tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags;
3094 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003095 IPW_BD_STATUS_TX_FRAME_802_3 |
3096 IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
James Ketrenos2c86c272005-03-23 17:32:29 -06003097 txq->next++;
3098 txq->next %= txq->entries;
3099
James Ketrenosee8e3652005-09-14 09:47:29 -05003100 IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n",
3101 packet->index, tbd->host_addr, tbd->buf_length);
Brice Goglin0f52bf92005-12-01 01:41:46 -08003102#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06003103 if (packet->info.d_struct.txb->nr_frags > 1)
3104 IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
3105 packet->info.d_struct.txb->nr_frags);
3106#endif
3107
James Ketrenosee8e3652005-09-14 09:47:29 -05003108 for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
3109 tbd = &txq->drv[txq->next];
James Ketrenos2c86c272005-03-23 17:32:29 -06003110 if (i == packet->info.d_struct.txb->nr_frags - 1)
3111 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003112 IPW_BD_STATUS_TX_FRAME_802_3 |
3113 IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06003114 else
3115 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003116 IPW_BD_STATUS_TX_FRAME_802_3 |
3117 IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
James Ketrenos2c86c272005-03-23 17:32:29 -06003118
3119 tbd->buf_length = packet->info.d_struct.txb->
James Ketrenosee8e3652005-09-14 09:47:29 -05003120 fragments[i]->len - IEEE80211_3ADDR_LEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06003121
James Ketrenosee8e3652005-09-14 09:47:29 -05003122 tbd->host_addr = pci_map_single(priv->pci_dev,
3123 packet->info.d_struct.
3124 txb->fragments[i]->
3125 data +
3126 IEEE80211_3ADDR_LEN,
3127 tbd->buf_length,
3128 PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003129
James Ketrenosee8e3652005-09-14 09:47:29 -05003130 IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n",
3131 txq->next, tbd->host_addr,
3132 tbd->buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06003133
James Ketrenosee8e3652005-09-14 09:47:29 -05003134 pci_dma_sync_single_for_device(priv->pci_dev,
3135 tbd->host_addr,
3136 tbd->buf_length,
3137 PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003138
3139 txq->next++;
3140 txq->next %= txq->entries;
James Ketrenosee8e3652005-09-14 09:47:29 -05003141 }
James Ketrenos2c86c272005-03-23 17:32:29 -06003142
3143 txq->available -= 1 + packet->info.d_struct.txb->nr_frags;
3144 SET_STAT(&priv->txq_stat, txq->available);
3145
3146 list_add_tail(element, &priv->fw_pend_list);
3147 INC_STAT(&priv->fw_pend_stat);
3148 }
3149
3150 if (txq->next != next) {
3151 /* kick off the DMA by notifying firmware the
3152 * write index has moved; make sure TBD stores are sync'd */
3153 write_register(priv->net_dev,
3154 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
3155 txq->next);
3156 }
James Ketrenosee8e3652005-09-14 09:47:29 -05003157 return;
James Ketrenos2c86c272005-03-23 17:32:29 -06003158}
3159
3160static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
3161{
3162 struct net_device *dev = priv->net_dev;
3163 unsigned long flags;
3164 u32 inta, tmp;
3165
3166 spin_lock_irqsave(&priv->low_lock, flags);
3167 ipw2100_disable_interrupts(priv);
3168
3169 read_register(dev, IPW_REG_INTA, &inta);
3170
3171 IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n",
3172 (unsigned long)inta & IPW_INTERRUPT_MASK);
3173
3174 priv->in_isr++;
3175 priv->interrupts++;
3176
3177 /* We do not loop and keep polling for more interrupts as this
3178 * is frowned upon and doesn't play nicely with other potentially
3179 * chained IRQs */
3180 IPW_DEBUG_ISR("INTA: 0x%08lX\n",
3181 (unsigned long)inta & IPW_INTERRUPT_MASK);
3182
3183 if (inta & IPW2100_INTA_FATAL_ERROR) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003184 printk(KERN_WARNING DRV_NAME
James Ketrenosee8e3652005-09-14 09:47:29 -05003185 ": Fatal interrupt. Scheduling firmware restart.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003186 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003187 write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003188
3189 read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error);
3190 IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n",
3191 priv->net_dev->name, priv->fatal_error);
3192
3193 read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp);
3194 IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n",
3195 priv->net_dev->name, tmp);
3196
3197 /* Wake up any sleeping jobs */
3198 schedule_reset(priv);
3199 }
3200
3201 if (inta & IPW2100_INTA_PARITY_ERROR) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003202 printk(KERN_ERR DRV_NAME
3203 ": ***** PARITY ERROR INTERRUPT !!!! \n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003204 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003205 write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003206 }
3207
3208 if (inta & IPW2100_INTA_RX_TRANSFER) {
3209 IPW_DEBUG_ISR("RX interrupt\n");
3210
3211 priv->rx_interrupts++;
3212
James Ketrenosee8e3652005-09-14 09:47:29 -05003213 write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER);
James Ketrenos2c86c272005-03-23 17:32:29 -06003214
3215 __ipw2100_rx_process(priv);
3216 __ipw2100_tx_complete(priv);
3217 }
3218
3219 if (inta & IPW2100_INTA_TX_TRANSFER) {
3220 IPW_DEBUG_ISR("TX interrupt\n");
3221
3222 priv->tx_interrupts++;
3223
James Ketrenosee8e3652005-09-14 09:47:29 -05003224 write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER);
James Ketrenos2c86c272005-03-23 17:32:29 -06003225
3226 __ipw2100_tx_complete(priv);
Jiri Benc19f7f742005-08-25 20:02:10 -04003227 ipw2100_tx_send_commands(priv);
3228 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06003229 }
3230
3231 if (inta & IPW2100_INTA_TX_COMPLETE) {
3232 IPW_DEBUG_ISR("TX complete\n");
3233 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003234 write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003235
3236 __ipw2100_tx_complete(priv);
3237 }
3238
3239 if (inta & IPW2100_INTA_EVENT_INTERRUPT) {
3240 /* ipw2100_handle_event(dev); */
3241 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003242 write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT);
James Ketrenos2c86c272005-03-23 17:32:29 -06003243 }
3244
3245 if (inta & IPW2100_INTA_FW_INIT_DONE) {
3246 IPW_DEBUG_ISR("FW init done interrupt\n");
3247 priv->inta_other++;
3248
3249 read_register(dev, IPW_REG_INTA, &tmp);
3250 if (tmp & (IPW2100_INTA_FATAL_ERROR |
3251 IPW2100_INTA_PARITY_ERROR)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003252 write_register(dev, IPW_REG_INTA,
3253 IPW2100_INTA_FATAL_ERROR |
3254 IPW2100_INTA_PARITY_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003255 }
3256
James Ketrenosee8e3652005-09-14 09:47:29 -05003257 write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003258 }
3259
3260 if (inta & IPW2100_INTA_STATUS_CHANGE) {
3261 IPW_DEBUG_ISR("Status change interrupt\n");
3262 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003263 write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003264 }
3265
3266 if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) {
3267 IPW_DEBUG_ISR("slave host mode interrupt\n");
3268 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003269 write_register(dev, IPW_REG_INTA,
3270 IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003271 }
3272
3273 priv->in_isr--;
3274 ipw2100_enable_interrupts(priv);
3275
3276 spin_unlock_irqrestore(&priv->low_lock, flags);
3277
3278 IPW_DEBUG_ISR("exit\n");
3279}
3280
David Howells7d12e782006-10-05 14:55:46 +01003281static irqreturn_t ipw2100_interrupt(int irq, void *data)
James Ketrenos2c86c272005-03-23 17:32:29 -06003282{
3283 struct ipw2100_priv *priv = data;
3284 u32 inta, inta_mask;
3285
3286 if (!data)
3287 return IRQ_NONE;
3288
James Ketrenosee8e3652005-09-14 09:47:29 -05003289 spin_lock(&priv->low_lock);
James Ketrenos2c86c272005-03-23 17:32:29 -06003290
3291 /* We check to see if we should be ignoring interrupts before
3292 * we touch the hardware. During ucode load if we try and handle
3293 * an interrupt we can cause keyboard problems as well as cause
3294 * the ucode to fail to initialize */
3295 if (!(priv->status & STATUS_INT_ENABLED)) {
3296 /* Shared IRQ */
3297 goto none;
3298 }
3299
3300 read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
3301 read_register(priv->net_dev, IPW_REG_INTA, &inta);
3302
3303 if (inta == 0xFFFFFFFF) {
3304 /* Hardware disappeared */
Jiri Benc797b4f72005-08-25 20:03:27 -04003305 printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003306 goto none;
3307 }
3308
3309 inta &= IPW_INTERRUPT_MASK;
3310
3311 if (!(inta & inta_mask)) {
3312 /* Shared interrupt */
3313 goto none;
3314 }
3315
3316 /* We disable the hardware interrupt here just to prevent unneeded
3317 * calls to be made. We disable this again within the actual
3318 * work tasklet, so if another part of the code re-enables the
3319 * interrupt, that is fine */
3320 ipw2100_disable_interrupts(priv);
3321
3322 tasklet_schedule(&priv->irq_tasklet);
James Ketrenosee8e3652005-09-14 09:47:29 -05003323 spin_unlock(&priv->low_lock);
James Ketrenos2c86c272005-03-23 17:32:29 -06003324
3325 return IRQ_HANDLED;
James Ketrenosee8e3652005-09-14 09:47:29 -05003326 none:
James Ketrenos2c86c272005-03-23 17:32:29 -06003327 spin_unlock(&priv->low_lock);
3328 return IRQ_NONE;
3329}
3330
James Ketrenos3a5becf2005-09-21 12:23:37 -05003331static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev,
3332 int pri)
James Ketrenos2c86c272005-03-23 17:32:29 -06003333{
3334 struct ipw2100_priv *priv = ieee80211_priv(dev);
3335 struct list_head *element;
3336 struct ipw2100_tx_packet *packet;
3337 unsigned long flags;
3338
3339 spin_lock_irqsave(&priv->low_lock, flags);
3340
3341 if (!(priv->status & STATUS_ASSOCIATED)) {
3342 IPW_DEBUG_INFO("Can not transmit when not connected.\n");
3343 priv->ieee->stats.tx_carrier_errors++;
3344 netif_stop_queue(dev);
3345 goto fail_unlock;
3346 }
3347
3348 if (list_empty(&priv->tx_free_list))
3349 goto fail_unlock;
3350
3351 element = priv->tx_free_list.next;
3352 packet = list_entry(element, struct ipw2100_tx_packet, list);
3353
3354 packet->info.d_struct.txb = txb;
3355
James Ketrenosee8e3652005-09-14 09:47:29 -05003356 IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len);
3357 printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len);
James Ketrenos2c86c272005-03-23 17:32:29 -06003358
3359 packet->jiffy_start = jiffies;
3360
3361 list_del(element);
3362 DEC_STAT(&priv->tx_free_stat);
3363
3364 list_add_tail(element, &priv->tx_pend_list);
3365 INC_STAT(&priv->tx_pend_stat);
3366
Jiri Benc19f7f742005-08-25 20:02:10 -04003367 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06003368
3369 spin_unlock_irqrestore(&priv->low_lock, flags);
3370 return 0;
3371
James Ketrenosee8e3652005-09-14 09:47:29 -05003372 fail_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -06003373 netif_stop_queue(dev);
3374 spin_unlock_irqrestore(&priv->low_lock, flags);
3375 return 1;
3376}
3377
James Ketrenos2c86c272005-03-23 17:32:29 -06003378static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
3379{
3380 int i, j, err = -EINVAL;
3381 void *v;
3382 dma_addr_t p;
3383
James Ketrenosee8e3652005-09-14 09:47:29 -05003384 priv->msg_buffers =
3385 (struct ipw2100_tx_packet *)kmalloc(IPW_COMMAND_POOL_SIZE *
3386 sizeof(struct
3387 ipw2100_tx_packet),
3388 GFP_KERNEL);
James Ketrenos2c86c272005-03-23 17:32:29 -06003389 if (!priv->msg_buffers) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003390 printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg "
James Ketrenos2c86c272005-03-23 17:32:29 -06003391 "buffers.\n", priv->net_dev->name);
3392 return -ENOMEM;
3393 }
3394
3395 for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003396 v = pci_alloc_consistent(priv->pci_dev,
3397 sizeof(struct ipw2100_cmd_header), &p);
James Ketrenos2c86c272005-03-23 17:32:29 -06003398 if (!v) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003399 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06003400 "%s: PCI alloc failed for msg "
James Ketrenosee8e3652005-09-14 09:47:29 -05003401 "buffers.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003402 err = -ENOMEM;
3403 break;
3404 }
3405
3406 memset(v, 0, sizeof(struct ipw2100_cmd_header));
3407
3408 priv->msg_buffers[i].type = COMMAND;
3409 priv->msg_buffers[i].info.c_struct.cmd =
James Ketrenosee8e3652005-09-14 09:47:29 -05003410 (struct ipw2100_cmd_header *)v;
James Ketrenos2c86c272005-03-23 17:32:29 -06003411 priv->msg_buffers[i].info.c_struct.cmd_phys = p;
3412 }
3413
3414 if (i == IPW_COMMAND_POOL_SIZE)
3415 return 0;
3416
3417 for (j = 0; j < i; j++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003418 pci_free_consistent(priv->pci_dev,
3419 sizeof(struct ipw2100_cmd_header),
3420 priv->msg_buffers[j].info.c_struct.cmd,
3421 priv->msg_buffers[j].info.c_struct.
3422 cmd_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06003423 }
3424
3425 kfree(priv->msg_buffers);
3426 priv->msg_buffers = NULL;
3427
3428 return err;
3429}
3430
3431static int ipw2100_msg_initialize(struct ipw2100_priv *priv)
3432{
3433 int i;
3434
3435 INIT_LIST_HEAD(&priv->msg_free_list);
3436 INIT_LIST_HEAD(&priv->msg_pend_list);
3437
3438 for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++)
3439 list_add_tail(&priv->msg_buffers[i].list, &priv->msg_free_list);
3440 SET_STAT(&priv->msg_free_stat, i);
3441
3442 return 0;
3443}
3444
3445static void ipw2100_msg_free(struct ipw2100_priv *priv)
3446{
3447 int i;
3448
3449 if (!priv->msg_buffers)
3450 return;
3451
3452 for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
3453 pci_free_consistent(priv->pci_dev,
3454 sizeof(struct ipw2100_cmd_header),
3455 priv->msg_buffers[i].info.c_struct.cmd,
James Ketrenosee8e3652005-09-14 09:47:29 -05003456 priv->msg_buffers[i].info.c_struct.
3457 cmd_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06003458 }
3459
3460 kfree(priv->msg_buffers);
3461 priv->msg_buffers = NULL;
3462}
3463
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003464static ssize_t show_pci(struct device *d, struct device_attribute *attr,
3465 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003466{
3467 struct pci_dev *pci_dev = container_of(d, struct pci_dev, dev);
3468 char *out = buf;
3469 int i, j;
3470 u32 val;
3471
3472 for (i = 0; i < 16; i++) {
3473 out += sprintf(out, "[%08X] ", i * 16);
3474 for (j = 0; j < 16; j += 4) {
3475 pci_read_config_dword(pci_dev, i * 16 + j, &val);
3476 out += sprintf(out, "%08X ", val);
3477 }
3478 out += sprintf(out, "\n");
3479 }
3480
3481 return out - buf;
3482}
James Ketrenosee8e3652005-09-14 09:47:29 -05003483
James Ketrenos2c86c272005-03-23 17:32:29 -06003484static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL);
3485
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003486static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
3487 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003488{
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003489 struct ipw2100_priv *p = d->driver_data;
James Ketrenos2c86c272005-03-23 17:32:29 -06003490 return sprintf(buf, "0x%08x\n", (int)p->config);
3491}
James Ketrenosee8e3652005-09-14 09:47:29 -05003492
James Ketrenos2c86c272005-03-23 17:32:29 -06003493static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
3494
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003495static ssize_t show_status(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003496 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003497{
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003498 struct ipw2100_priv *p = d->driver_data;
James Ketrenos2c86c272005-03-23 17:32:29 -06003499 return sprintf(buf, "0x%08x\n", (int)p->status);
3500}
James Ketrenosee8e3652005-09-14 09:47:29 -05003501
James Ketrenos2c86c272005-03-23 17:32:29 -06003502static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
3503
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003504static ssize_t show_capability(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003505 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003506{
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003507 struct ipw2100_priv *p = d->driver_data;
James Ketrenos2c86c272005-03-23 17:32:29 -06003508 return sprintf(buf, "0x%08x\n", (int)p->capability);
3509}
James Ketrenos2c86c272005-03-23 17:32:29 -06003510
James Ketrenosee8e3652005-09-14 09:47:29 -05003511static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL);
James Ketrenos2c86c272005-03-23 17:32:29 -06003512
3513#define IPW2100_REG(x) { IPW_ ##x, #x }
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003514static const struct {
James Ketrenos2c86c272005-03-23 17:32:29 -06003515 u32 addr;
3516 const char *name;
3517} hw_data[] = {
James Ketrenosee8e3652005-09-14 09:47:29 -05003518IPW2100_REG(REG_GP_CNTRL),
3519 IPW2100_REG(REG_GPIO),
3520 IPW2100_REG(REG_INTA),
3521 IPW2100_REG(REG_INTA_MASK), IPW2100_REG(REG_RESET_REG),};
James Ketrenos2c86c272005-03-23 17:32:29 -06003522#define IPW2100_NIC(x, s) { x, #x, s }
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003523static const struct {
James Ketrenos2c86c272005-03-23 17:32:29 -06003524 u32 addr;
3525 const char *name;
3526 size_t size;
3527} nic_data[] = {
James Ketrenosee8e3652005-09-14 09:47:29 -05003528IPW2100_NIC(IPW2100_CONTROL_REG, 2),
3529 IPW2100_NIC(0x210014, 1), IPW2100_NIC(0x210000, 1),};
James Ketrenos2c86c272005-03-23 17:32:29 -06003530#define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d }
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003531static const struct {
James Ketrenos2c86c272005-03-23 17:32:29 -06003532 u8 index;
3533 const char *name;
3534 const char *desc;
3535} ord_data[] = {
James Ketrenosee8e3652005-09-14 09:47:29 -05003536IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
3537 IPW2100_ORD(STAT_TX_HOST_COMPLETE,
3538 "successful Host Tx's (MSDU)"),
3539 IPW2100_ORD(STAT_TX_DIR_DATA,
3540 "successful Directed Tx's (MSDU)"),
3541 IPW2100_ORD(STAT_TX_DIR_DATA1,
3542 "successful Directed Tx's (MSDU) @ 1MB"),
3543 IPW2100_ORD(STAT_TX_DIR_DATA2,
3544 "successful Directed Tx's (MSDU) @ 2MB"),
3545 IPW2100_ORD(STAT_TX_DIR_DATA5_5,
3546 "successful Directed Tx's (MSDU) @ 5_5MB"),
3547 IPW2100_ORD(STAT_TX_DIR_DATA11,
3548 "successful Directed Tx's (MSDU) @ 11MB"),
3549 IPW2100_ORD(STAT_TX_NODIR_DATA1,
3550 "successful Non_Directed Tx's (MSDU) @ 1MB"),
3551 IPW2100_ORD(STAT_TX_NODIR_DATA2,
3552 "successful Non_Directed Tx's (MSDU) @ 2MB"),
3553 IPW2100_ORD(STAT_TX_NODIR_DATA5_5,
3554 "successful Non_Directed Tx's (MSDU) @ 5.5MB"),
3555 IPW2100_ORD(STAT_TX_NODIR_DATA11,
3556 "successful Non_Directed Tx's (MSDU) @ 11MB"),
3557 IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"),
3558 IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"),
3559 IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"),
3560 IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"),
3561 IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"),
3562 IPW2100_ORD(STAT_TX_ASSN_RESP,
3563 "successful Association response Tx's"),
3564 IPW2100_ORD(STAT_TX_REASSN,
3565 "successful Reassociation Tx's"),
3566 IPW2100_ORD(STAT_TX_REASSN_RESP,
3567 "successful Reassociation response Tx's"),
3568 IPW2100_ORD(STAT_TX_PROBE,
3569 "probes successfully transmitted"),
3570 IPW2100_ORD(STAT_TX_PROBE_RESP,
3571 "probe responses successfully transmitted"),
3572 IPW2100_ORD(STAT_TX_BEACON, "tx beacon"),
3573 IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"),
3574 IPW2100_ORD(STAT_TX_DISASSN,
3575 "successful Disassociation TX"),
3576 IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"),
3577 IPW2100_ORD(STAT_TX_DEAUTH,
3578 "successful Deauthentication TX"),
3579 IPW2100_ORD(STAT_TX_TOTAL_BYTES,
3580 "Total successful Tx data bytes"),
3581 IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"),
3582 IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"),
3583 IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"),
3584 IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"),
3585 IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"),
3586 IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"),
3587 IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,
3588 "times max tries in a hop failed"),
3589 IPW2100_ORD(STAT_TX_DISASSN_FAIL,
3590 "times disassociation failed"),
3591 IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"),
3592 IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"),
3593 IPW2100_ORD(STAT_RX_HOST, "packets passed to host"),
3594 IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"),
3595 IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"),
3596 IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"),
3597 IPW2100_ORD(STAT_RX_DIR_DATA5_5,
3598 "directed packets at 5.5MB"),
3599 IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"),
3600 IPW2100_ORD(STAT_RX_NODIR_DATA, "nondirected packets"),
3601 IPW2100_ORD(STAT_RX_NODIR_DATA1,
3602 "nondirected packets at 1MB"),
3603 IPW2100_ORD(STAT_RX_NODIR_DATA2,
3604 "nondirected packets at 2MB"),
3605 IPW2100_ORD(STAT_RX_NODIR_DATA5_5,
3606 "nondirected packets at 5.5MB"),
3607 IPW2100_ORD(STAT_RX_NODIR_DATA11,
3608 "nondirected packets at 11MB"),
3609 IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"),
3610 IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), IPW2100_ORD(STAT_RX_CTS,
3611 "Rx CTS"),
3612 IPW2100_ORD(STAT_RX_ACK, "Rx ACK"),
3613 IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"),
3614 IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"),
3615 IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"),
3616 IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"),
3617 IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"),
3618 IPW2100_ORD(STAT_RX_REASSN_RESP,
3619 "Reassociation response Rx's"),
3620 IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"),
3621 IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"),
3622 IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"),
3623 IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"),
3624 IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"),
3625 IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"),
3626 IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"),
3627 IPW2100_ORD(STAT_RX_TOTAL_BYTES,
3628 "Total rx data bytes received"),
3629 IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"),
3630 IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"),
3631 IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"),
3632 IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"),
3633 IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"),
3634 IPW2100_ORD(STAT_RX_DUPLICATE1,
3635 "duplicate rx packets at 1MB"),
3636 IPW2100_ORD(STAT_RX_DUPLICATE2,
3637 "duplicate rx packets at 2MB"),
3638 IPW2100_ORD(STAT_RX_DUPLICATE5_5,
3639 "duplicate rx packets at 5.5MB"),
3640 IPW2100_ORD(STAT_RX_DUPLICATE11,
3641 "duplicate rx packets at 11MB"),
3642 IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
3643 IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"),
3644 IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"),
3645 IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"),
3646 IPW2100_ORD(STAT_RX_INVALID_PROTOCOL,
3647 "rx frames with invalid protocol"),
3648 IPW2100_ORD(SYS_BOOT_TIME, "Boot time"),
3649 IPW2100_ORD(STAT_RX_NO_BUFFER,
3650 "rx frames rejected due to no buffer"),
3651 IPW2100_ORD(STAT_RX_MISSING_FRAG,
3652 "rx frames dropped due to missing fragment"),
3653 IPW2100_ORD(STAT_RX_ORPHAN_FRAG,
3654 "rx frames dropped due to non-sequential fragment"),
3655 IPW2100_ORD(STAT_RX_ORPHAN_FRAME,
3656 "rx frames dropped due to unmatched 1st frame"),
3657 IPW2100_ORD(STAT_RX_FRAG_AGEOUT,
3658 "rx frames dropped due to uncompleted frame"),
3659 IPW2100_ORD(STAT_RX_ICV_ERRORS,
3660 "ICV errors during decryption"),
3661 IPW2100_ORD(STAT_PSP_SUSPENSION, "times adapter suspended"),
3662 IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"),
3663 IPW2100_ORD(STAT_PSP_POLL_TIMEOUT,
3664 "poll response timeouts"),
3665 IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT,
3666 "timeouts waiting for last {broad,multi}cast pkt"),
3667 IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"),
3668 IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"),
3669 IPW2100_ORD(STAT_PSP_STATION_ID, "PSP Station ID"),
3670 IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"),
3671 IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,
3672 "current calculation of % missed beacons"),
3673 IPW2100_ORD(STAT_PERCENT_RETRIES,
3674 "current calculation of % missed tx retries"),
3675 IPW2100_ORD(ASSOCIATED_AP_PTR,
3676 "0 if not associated, else pointer to AP table entry"),
3677 IPW2100_ORD(AVAILABLE_AP_CNT,
3678 "AP's decsribed in the AP table"),
3679 IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"),
3680 IPW2100_ORD(STAT_AP_ASSNS, "associations"),
3681 IPW2100_ORD(STAT_ASSN_FAIL, "association failures"),
3682 IPW2100_ORD(STAT_ASSN_RESP_FAIL,
3683 "failures due to response fail"),
3684 IPW2100_ORD(STAT_FULL_SCANS, "full scans"),
3685 IPW2100_ORD(CARD_DISABLED, "Card Disabled"),
3686 IPW2100_ORD(STAT_ROAM_INHIBIT,
3687 "times roaming was inhibited due to activity"),
3688 IPW2100_ORD(RSSI_AT_ASSN,
3689 "RSSI of associated AP at time of association"),
3690 IPW2100_ORD(STAT_ASSN_CAUSE1,
3691 "reassociation: no probe response or TX on hop"),
3692 IPW2100_ORD(STAT_ASSN_CAUSE2,
3693 "reassociation: poor tx/rx quality"),
3694 IPW2100_ORD(STAT_ASSN_CAUSE3,
3695 "reassociation: tx/rx quality (excessive AP load"),
3696 IPW2100_ORD(STAT_ASSN_CAUSE4,
3697 "reassociation: AP RSSI level"),
3698 IPW2100_ORD(STAT_ASSN_CAUSE5,
3699 "reassociations due to load leveling"),
3700 IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"),
3701 IPW2100_ORD(STAT_AUTH_RESP_FAIL,
3702 "times authentication response failed"),
3703 IPW2100_ORD(STATION_TABLE_CNT,
3704 "entries in association table"),
3705 IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"),
3706 IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"),
3707 IPW2100_ORD(COUNTRY_CODE,
3708 "IEEE country code as recv'd from beacon"),
3709 IPW2100_ORD(COUNTRY_CHANNELS,
3710 "channels suported by country"),
3711 IPW2100_ORD(RESET_CNT, "adapter resets (warm)"),
3712 IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"),
3713 IPW2100_ORD(ANTENNA_DIVERSITY,
3714 "TRUE if antenna diversity is disabled"),
3715 IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"),
3716 IPW2100_ORD(OUR_FREQ,
3717 "current radio freq lower digits - channel ID"),
3718 IPW2100_ORD(RTC_TIME, "current RTC time"),
3719 IPW2100_ORD(PORT_TYPE, "operating mode"),
3720 IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"),
3721 IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"),
3722 IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"),
3723 IPW2100_ORD(BASIC_RATES, "basic tx rates"),
3724 IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"),
3725 IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"),
3726 IPW2100_ORD(CAPABILITIES,
3727 "Management frame capability field"),
3728 IPW2100_ORD(AUTH_TYPE, "Type of authentication"),
3729 IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"),
3730 IPW2100_ORD(RTS_THRESHOLD,
3731 "Min packet length for RTS handshaking"),
3732 IPW2100_ORD(INT_MODE, "International mode"),
3733 IPW2100_ORD(FRAGMENTATION_THRESHOLD,
3734 "protocol frag threshold"),
3735 IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
3736 "EEPROM offset in SRAM"),
3737 IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE,
3738 "EEPROM size in SRAM"),
3739 IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"),
3740 IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS,
3741 "EEPROM IBSS 11b channel set"),
3742 IPW2100_ORD(MAC_VERSION, "MAC Version"),
3743 IPW2100_ORD(MAC_REVISION, "MAC Revision"),
3744 IPW2100_ORD(RADIO_VERSION, "Radio Version"),
3745 IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"),
3746 IPW2100_ORD(UCODE_VERSION, "Ucode Version"),};
James Ketrenos2c86c272005-03-23 17:32:29 -06003747
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003748static ssize_t show_registers(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003749 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003750{
3751 int i;
3752 struct ipw2100_priv *priv = dev_get_drvdata(d);
3753 struct net_device *dev = priv->net_dev;
James Ketrenosee8e3652005-09-14 09:47:29 -05003754 char *out = buf;
James Ketrenos2c86c272005-03-23 17:32:29 -06003755 u32 val = 0;
3756
3757 out += sprintf(out, "%30s [Address ] : Hex\n", "Register");
3758
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003759 for (i = 0; i < ARRAY_SIZE(hw_data); i++) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003760 read_register(dev, hw_data[i].addr, &val);
3761 out += sprintf(out, "%30s [%08X] : %08X\n",
3762 hw_data[i].name, hw_data[i].addr, val);
3763 }
3764
3765 return out - buf;
3766}
James Ketrenosee8e3652005-09-14 09:47:29 -05003767
James Ketrenos2c86c272005-03-23 17:32:29 -06003768static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
3769
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003770static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003771 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003772{
3773 struct ipw2100_priv *priv = dev_get_drvdata(d);
3774 struct net_device *dev = priv->net_dev;
James Ketrenosee8e3652005-09-14 09:47:29 -05003775 char *out = buf;
James Ketrenos2c86c272005-03-23 17:32:29 -06003776 int i;
3777
3778 out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry");
3779
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003780 for (i = 0; i < ARRAY_SIZE(nic_data); i++) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003781 u8 tmp8;
3782 u16 tmp16;
3783 u32 tmp32;
3784
3785 switch (nic_data[i].size) {
3786 case 1:
3787 read_nic_byte(dev, nic_data[i].addr, &tmp8);
3788 out += sprintf(out, "%30s [%08X] : %02X\n",
3789 nic_data[i].name, nic_data[i].addr,
3790 tmp8);
3791 break;
3792 case 2:
3793 read_nic_word(dev, nic_data[i].addr, &tmp16);
3794 out += sprintf(out, "%30s [%08X] : %04X\n",
3795 nic_data[i].name, nic_data[i].addr,
3796 tmp16);
3797 break;
3798 case 4:
3799 read_nic_dword(dev, nic_data[i].addr, &tmp32);
3800 out += sprintf(out, "%30s [%08X] : %08X\n",
3801 nic_data[i].name, nic_data[i].addr,
3802 tmp32);
3803 break;
3804 }
3805 }
3806 return out - buf;
3807}
James Ketrenosee8e3652005-09-14 09:47:29 -05003808
James Ketrenos2c86c272005-03-23 17:32:29 -06003809static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
3810
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003811static ssize_t show_memory(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003812 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003813{
3814 struct ipw2100_priv *priv = dev_get_drvdata(d);
3815 struct net_device *dev = priv->net_dev;
3816 static unsigned long loop = 0;
3817 int len = 0;
3818 u32 buffer[4];
3819 int i;
3820 char line[81];
3821
3822 if (loop >= 0x30000)
3823 loop = 0;
3824
3825 /* sysfs provides us PAGE_SIZE buffer */
3826 while (len < PAGE_SIZE - 128 && loop < 0x30000) {
3827
James Ketrenosee8e3652005-09-14 09:47:29 -05003828 if (priv->snapshot[0])
3829 for (i = 0; i < 4; i++)
3830 buffer[i] =
3831 *(u32 *) SNAPSHOT_ADDR(loop + i * 4);
3832 else
3833 for (i = 0; i < 4; i++)
3834 read_nic_dword(dev, loop + i * 4, &buffer[i]);
James Ketrenos2c86c272005-03-23 17:32:29 -06003835
3836 if (priv->dump_raw)
3837 len += sprintf(buf + len,
3838 "%c%c%c%c"
3839 "%c%c%c%c"
3840 "%c%c%c%c"
3841 "%c%c%c%c",
James Ketrenosee8e3652005-09-14 09:47:29 -05003842 ((u8 *) buffer)[0x0],
3843 ((u8 *) buffer)[0x1],
3844 ((u8 *) buffer)[0x2],
3845 ((u8 *) buffer)[0x3],
3846 ((u8 *) buffer)[0x4],
3847 ((u8 *) buffer)[0x5],
3848 ((u8 *) buffer)[0x6],
3849 ((u8 *) buffer)[0x7],
3850 ((u8 *) buffer)[0x8],
3851 ((u8 *) buffer)[0x9],
3852 ((u8 *) buffer)[0xa],
3853 ((u8 *) buffer)[0xb],
3854 ((u8 *) buffer)[0xc],
3855 ((u8 *) buffer)[0xd],
3856 ((u8 *) buffer)[0xe],
3857 ((u8 *) buffer)[0xf]);
James Ketrenos2c86c272005-03-23 17:32:29 -06003858 else
3859 len += sprintf(buf + len, "%s\n",
3860 snprint_line(line, sizeof(line),
James Ketrenosee8e3652005-09-14 09:47:29 -05003861 (u8 *) buffer, 16, loop));
James Ketrenos2c86c272005-03-23 17:32:29 -06003862 loop += 16;
3863 }
3864
3865 return len;
3866}
3867
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003868static ssize_t store_memory(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003869 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06003870{
3871 struct ipw2100_priv *priv = dev_get_drvdata(d);
3872 struct net_device *dev = priv->net_dev;
3873 const char *p = buf;
3874
Zhu Yi8ed55a42006-01-24 13:49:20 +08003875 (void)dev; /* kill unused-var warning for debug-only code */
Jeff Garzikc2a8fad2005-11-09 00:49:38 -05003876
James Ketrenos2c86c272005-03-23 17:32:29 -06003877 if (count < 1)
3878 return count;
3879
3880 if (p[0] == '1' ||
3881 (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) {
3882 IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003883 dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003884 priv->dump_raw = 1;
3885
3886 } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' &&
James Ketrenosee8e3652005-09-14 09:47:29 -05003887 tolower(p[1]) == 'f')) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003888 IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003889 dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003890 priv->dump_raw = 0;
3891
3892 } else if (tolower(p[0]) == 'r') {
James Ketrenosee8e3652005-09-14 09:47:29 -05003893 IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003894 ipw2100_snapshot_free(priv);
3895
3896 } else
3897 IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, "
James Ketrenosee8e3652005-09-14 09:47:29 -05003898 "reset = clear memory snapshot\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003899
3900 return count;
3901}
James Ketrenos2c86c272005-03-23 17:32:29 -06003902
James Ketrenosee8e3652005-09-14 09:47:29 -05003903static DEVICE_ATTR(memory, S_IWUSR | S_IRUGO, show_memory, store_memory);
James Ketrenos2c86c272005-03-23 17:32:29 -06003904
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003905static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003906 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003907{
3908 struct ipw2100_priv *priv = dev_get_drvdata(d);
3909 u32 val = 0;
3910 int len = 0;
3911 u32 val_len;
3912 static int loop = 0;
3913
James Ketrenos82328352005-08-24 22:33:31 -05003914 if (priv->status & STATUS_RF_KILL_MASK)
3915 return 0;
3916
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003917 if (loop >= ARRAY_SIZE(ord_data))
James Ketrenos2c86c272005-03-23 17:32:29 -06003918 loop = 0;
3919
3920 /* sysfs provides us PAGE_SIZE buffer */
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003921 while (len < PAGE_SIZE - 128 && loop < ARRAY_SIZE(ord_data)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003922 val_len = sizeof(u32);
3923
3924 if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val,
3925 &val_len))
3926 len += sprintf(buf + len, "[0x%02X] = ERROR %s\n",
3927 ord_data[loop].index,
3928 ord_data[loop].desc);
3929 else
3930 len += sprintf(buf + len, "[0x%02X] = 0x%08X %s\n",
3931 ord_data[loop].index, val,
3932 ord_data[loop].desc);
3933 loop++;
3934 }
3935
3936 return len;
3937}
James Ketrenosee8e3652005-09-14 09:47:29 -05003938
James Ketrenos2c86c272005-03-23 17:32:29 -06003939static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL);
3940
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003941static ssize_t show_stats(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003942 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003943{
3944 struct ipw2100_priv *priv = dev_get_drvdata(d);
James Ketrenosee8e3652005-09-14 09:47:29 -05003945 char *out = buf;
James Ketrenos2c86c272005-03-23 17:32:29 -06003946
3947 out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n",
3948 priv->interrupts, priv->tx_interrupts,
3949 priv->rx_interrupts, priv->inta_other);
3950 out += sprintf(out, "firmware resets: %d\n", priv->resets);
3951 out += sprintf(out, "firmware hangs: %d\n", priv->hangs);
Brice Goglin0f52bf92005-12-01 01:41:46 -08003952#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06003953 out += sprintf(out, "packet mismatch image: %s\n",
3954 priv->snapshot[0] ? "YES" : "NO");
3955#endif
3956
3957 return out - buf;
3958}
James Ketrenos2c86c272005-03-23 17:32:29 -06003959
James Ketrenosee8e3652005-09-14 09:47:29 -05003960static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL);
James Ketrenos2c86c272005-03-23 17:32:29 -06003961
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003962static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06003963{
3964 int err;
3965
3966 if (mode == priv->ieee->iw_mode)
3967 return 0;
3968
3969 err = ipw2100_disable_adapter(priv);
3970 if (err) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003971 printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06003972 priv->net_dev->name, err);
3973 return err;
3974 }
3975
3976 switch (mode) {
3977 case IW_MODE_INFRA:
3978 priv->net_dev->type = ARPHRD_ETHER;
3979 break;
3980 case IW_MODE_ADHOC:
3981 priv->net_dev->type = ARPHRD_ETHER;
3982 break;
3983#ifdef CONFIG_IPW2100_MONITOR
3984 case IW_MODE_MONITOR:
3985 priv->last_mode = priv->ieee->iw_mode;
Stefan Rompf15745a72006-02-21 18:36:17 +08003986 priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
James Ketrenos2c86c272005-03-23 17:32:29 -06003987 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05003988#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06003989 }
3990
3991 priv->ieee->iw_mode = mode;
3992
3993#ifdef CONFIG_PM
James Ketrenosee8e3652005-09-14 09:47:29 -05003994 /* Indicate ipw2100_download_firmware download firmware
James Ketrenos2c86c272005-03-23 17:32:29 -06003995 * from disk instead of memory. */
3996 ipw2100_firmware.version = 0;
3997#endif
3998
James Ketrenosee8e3652005-09-14 09:47:29 -05003999 printk(KERN_INFO "%s: Reseting on mode change.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004000 priv->reset_backoff = 0;
4001 schedule_reset(priv);
4002
4003 return 0;
4004}
4005
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004006static ssize_t show_internals(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004007 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004008{
4009 struct ipw2100_priv *priv = dev_get_drvdata(d);
4010 int len = 0;
4011
James Ketrenosee8e3652005-09-14 09:47:29 -05004012#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x)
James Ketrenos2c86c272005-03-23 17:32:29 -06004013
4014 if (priv->status & STATUS_ASSOCIATED)
4015 len += sprintf(buf + len, "connected: %lu\n",
4016 get_seconds() - priv->connect_start);
4017 else
4018 len += sprintf(buf + len, "not connected\n");
4019
John W. Linville274bfb82008-10-29 11:35:05 -04004020 DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p");
James Ketrenosee8e3652005-09-14 09:47:29 -05004021 DUMP_VAR(status, "08lx");
4022 DUMP_VAR(config, "08lx");
4023 DUMP_VAR(capability, "08lx");
James Ketrenos2c86c272005-03-23 17:32:29 -06004024
James Ketrenosee8e3652005-09-14 09:47:29 -05004025 len +=
4026 sprintf(buf + len, "last_rtc: %lu\n",
4027 (unsigned long)priv->last_rtc);
James Ketrenos2c86c272005-03-23 17:32:29 -06004028
James Ketrenosee8e3652005-09-14 09:47:29 -05004029 DUMP_VAR(fatal_error, "d");
4030 DUMP_VAR(stop_hang_check, "d");
4031 DUMP_VAR(stop_rf_kill, "d");
4032 DUMP_VAR(messages_sent, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004033
James Ketrenosee8e3652005-09-14 09:47:29 -05004034 DUMP_VAR(tx_pend_stat.value, "d");
4035 DUMP_VAR(tx_pend_stat.hi, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004036
James Ketrenosee8e3652005-09-14 09:47:29 -05004037 DUMP_VAR(tx_free_stat.value, "d");
4038 DUMP_VAR(tx_free_stat.lo, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004039
James Ketrenosee8e3652005-09-14 09:47:29 -05004040 DUMP_VAR(msg_free_stat.value, "d");
4041 DUMP_VAR(msg_free_stat.lo, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004042
James Ketrenosee8e3652005-09-14 09:47:29 -05004043 DUMP_VAR(msg_pend_stat.value, "d");
4044 DUMP_VAR(msg_pend_stat.hi, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004045
James Ketrenosee8e3652005-09-14 09:47:29 -05004046 DUMP_VAR(fw_pend_stat.value, "d");
4047 DUMP_VAR(fw_pend_stat.hi, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004048
James Ketrenosee8e3652005-09-14 09:47:29 -05004049 DUMP_VAR(txq_stat.value, "d");
4050 DUMP_VAR(txq_stat.lo, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004051
James Ketrenosee8e3652005-09-14 09:47:29 -05004052 DUMP_VAR(ieee->scans, "d");
4053 DUMP_VAR(reset_backoff, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004054
4055 return len;
4056}
James Ketrenosee8e3652005-09-14 09:47:29 -05004057
James Ketrenos2c86c272005-03-23 17:32:29 -06004058static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL);
4059
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004060static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004061 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004062{
4063 struct ipw2100_priv *priv = dev_get_drvdata(d);
4064 char essid[IW_ESSID_MAX_SIZE + 1];
4065 u8 bssid[ETH_ALEN];
4066 u32 chan = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05004067 char *out = buf;
Hannes Ederb9da9e92009-02-14 11:50:26 +00004068 unsigned int length;
James Ketrenos2c86c272005-03-23 17:32:29 -06004069 int ret;
4070
James Ketrenos82328352005-08-24 22:33:31 -05004071 if (priv->status & STATUS_RF_KILL_MASK)
4072 return 0;
4073
James Ketrenos2c86c272005-03-23 17:32:29 -06004074 memset(essid, 0, sizeof(essid));
4075 memset(bssid, 0, sizeof(bssid));
4076
4077 length = IW_ESSID_MAX_SIZE;
4078 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &length);
4079 if (ret)
4080 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
4081 __LINE__);
4082
4083 length = sizeof(bssid);
4084 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
4085 bssid, &length);
4086 if (ret)
4087 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
4088 __LINE__);
4089
4090 length = sizeof(u32);
4091 ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &length);
4092 if (ret)
4093 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
4094 __LINE__);
4095
4096 out += sprintf(out, "ESSID: %s\n", essid);
Johannes Berge1749612008-10-27 15:59:26 -07004097 out += sprintf(out, "BSSID: %pM\n", bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06004098 out += sprintf(out, "Channel: %d\n", chan);
4099
4100 return out - buf;
4101}
James Ketrenos2c86c272005-03-23 17:32:29 -06004102
James Ketrenosee8e3652005-09-14 09:47:29 -05004103static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
James Ketrenos2c86c272005-03-23 17:32:29 -06004104
Brice Goglin0f52bf92005-12-01 01:41:46 -08004105#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06004106static ssize_t show_debug_level(struct device_driver *d, char *buf)
4107{
4108 return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
4109}
4110
James Ketrenos82328352005-08-24 22:33:31 -05004111static ssize_t store_debug_level(struct device_driver *d,
4112 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004113{
4114 char *p = (char *)buf;
4115 u32 val;
4116
4117 if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
4118 p++;
4119 if (p[0] == 'x' || p[0] == 'X')
4120 p++;
4121 val = simple_strtoul(p, &p, 16);
4122 } else
4123 val = simple_strtoul(p, &p, 10);
4124 if (p == buf)
Zhu Yia1e695a2005-07-04 14:06:00 +08004125 IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf);
James Ketrenos2c86c272005-03-23 17:32:29 -06004126 else
4127 ipw2100_debug_level = val;
4128
4129 return strnlen(buf, count);
4130}
James Ketrenosee8e3652005-09-14 09:47:29 -05004131
James Ketrenos2c86c272005-03-23 17:32:29 -06004132static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level,
4133 store_debug_level);
Brice Goglin0f52bf92005-12-01 01:41:46 -08004134#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -06004135
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004136static ssize_t show_fatal_error(struct device *d,
James Ketrenosee8e3652005-09-14 09:47:29 -05004137 struct device_attribute *attr, char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004138{
4139 struct ipw2100_priv *priv = dev_get_drvdata(d);
4140 char *out = buf;
4141 int i;
4142
4143 if (priv->fatal_error)
James Ketrenosee8e3652005-09-14 09:47:29 -05004144 out += sprintf(out, "0x%08X\n", priv->fatal_error);
James Ketrenos2c86c272005-03-23 17:32:29 -06004145 else
4146 out += sprintf(out, "0\n");
4147
4148 for (i = 1; i <= IPW2100_ERROR_QUEUE; i++) {
4149 if (!priv->fatal_errors[(priv->fatal_index - i) %
4150 IPW2100_ERROR_QUEUE])
4151 continue;
4152
4153 out += sprintf(out, "%d. 0x%08X\n", i,
4154 priv->fatal_errors[(priv->fatal_index - i) %
4155 IPW2100_ERROR_QUEUE]);
4156 }
4157
4158 return out - buf;
4159}
4160
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004161static ssize_t store_fatal_error(struct device *d,
James Ketrenosee8e3652005-09-14 09:47:29 -05004162 struct device_attribute *attr, const char *buf,
4163 size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004164{
4165 struct ipw2100_priv *priv = dev_get_drvdata(d);
4166 schedule_reset(priv);
4167 return count;
4168}
James Ketrenos2c86c272005-03-23 17:32:29 -06004169
James Ketrenosee8e3652005-09-14 09:47:29 -05004170static DEVICE_ATTR(fatal_error, S_IWUSR | S_IRUGO, show_fatal_error,
4171 store_fatal_error);
James Ketrenos2c86c272005-03-23 17:32:29 -06004172
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004173static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004174 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004175{
4176 struct ipw2100_priv *priv = dev_get_drvdata(d);
4177 return sprintf(buf, "%d\n", priv->ieee->scan_age);
4178}
4179
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004180static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004181 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004182{
4183 struct ipw2100_priv *priv = dev_get_drvdata(d);
4184 struct net_device *dev = priv->net_dev;
4185 char buffer[] = "00000000";
4186 unsigned long len =
4187 (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
4188 unsigned long val;
4189 char *p = buffer;
4190
Zhu Yi8ed55a42006-01-24 13:49:20 +08004191 (void)dev; /* kill unused-var warning for debug-only code */
Jeff Garzikc2a8fad2005-11-09 00:49:38 -05004192
James Ketrenos2c86c272005-03-23 17:32:29 -06004193 IPW_DEBUG_INFO("enter\n");
4194
4195 strncpy(buffer, buf, len);
4196 buffer[len] = 0;
4197
4198 if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
4199 p++;
4200 if (p[0] == 'x' || p[0] == 'X')
4201 p++;
4202 val = simple_strtoul(p, &p, 16);
4203 } else
4204 val = simple_strtoul(p, &p, 10);
4205 if (p == buffer) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004206 IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004207 } else {
4208 priv->ieee->scan_age = val;
4209 IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
4210 }
4211
4212 IPW_DEBUG_INFO("exit\n");
4213 return len;
4214}
James Ketrenosee8e3652005-09-14 09:47:29 -05004215
James Ketrenos2c86c272005-03-23 17:32:29 -06004216static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
4217
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004218static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004219 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004220{
4221 /* 0 - RF kill not enabled
4222 1 - SW based RF kill active (sysfs)
4223 2 - HW based RF kill active
4224 3 - Both HW and SW baed RF kill active */
4225 struct ipw2100_priv *priv = (struct ipw2100_priv *)d->driver_data;
4226 int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
James Ketrenosee8e3652005-09-14 09:47:29 -05004227 (rf_kill_active(priv) ? 0x2 : 0x0);
James Ketrenos2c86c272005-03-23 17:32:29 -06004228 return sprintf(buf, "%i\n", val);
4229}
4230
4231static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
4232{
4233 if ((disable_radio ? 1 : 0) ==
4234 (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
James Ketrenosee8e3652005-09-14 09:47:29 -05004235 return 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06004236
4237 IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
4238 disable_radio ? "OFF" : "ON");
4239
Ingo Molnar752e3772006-02-28 07:20:54 +08004240 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06004241
4242 if (disable_radio) {
4243 priv->status |= STATUS_RF_KILL_SW;
4244 ipw2100_down(priv);
4245 } else {
4246 priv->status &= ~STATUS_RF_KILL_SW;
4247 if (rf_kill_active(priv)) {
4248 IPW_DEBUG_RF_KILL("Can not turn radio back on - "
4249 "disabled by HW switch\n");
4250 /* Make sure the RF_KILL check timer is running */
4251 priv->stop_rf_kill = 0;
4252 cancel_delayed_work(&priv->rf_kill);
Stephen Hemmingera62056f2007-06-22 21:46:50 -07004253 queue_delayed_work(priv->workqueue, &priv->rf_kill,
Anton Blanchardbe84e3d2007-10-15 00:38:01 -05004254 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06004255 } else
4256 schedule_reset(priv);
4257 }
4258
Ingo Molnar752e3772006-02-28 07:20:54 +08004259 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06004260 return 1;
4261}
4262
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004263static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004264 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004265{
4266 struct ipw2100_priv *priv = dev_get_drvdata(d);
4267 ipw_radio_kill_sw(priv, buf[0] == '1');
4268 return count;
4269}
James Ketrenos2c86c272005-03-23 17:32:29 -06004270
James Ketrenosee8e3652005-09-14 09:47:29 -05004271static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
James Ketrenos2c86c272005-03-23 17:32:29 -06004272
4273static struct attribute *ipw2100_sysfs_entries[] = {
4274 &dev_attr_hardware.attr,
4275 &dev_attr_registers.attr,
4276 &dev_attr_ordinals.attr,
4277 &dev_attr_pci.attr,
4278 &dev_attr_stats.attr,
4279 &dev_attr_internals.attr,
4280 &dev_attr_bssinfo.attr,
4281 &dev_attr_memory.attr,
4282 &dev_attr_scan_age.attr,
4283 &dev_attr_fatal_error.attr,
4284 &dev_attr_rf_kill.attr,
4285 &dev_attr_cfg.attr,
4286 &dev_attr_status.attr,
4287 &dev_attr_capability.attr,
4288 NULL,
4289};
4290
4291static struct attribute_group ipw2100_attribute_group = {
4292 .attrs = ipw2100_sysfs_entries,
4293};
4294
James Ketrenos2c86c272005-03-23 17:32:29 -06004295static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
4296{
4297 struct ipw2100_status_queue *q = &priv->status_queue;
4298
4299 IPW_DEBUG_INFO("enter\n");
4300
4301 q->size = entries * sizeof(struct ipw2100_status);
James Ketrenosee8e3652005-09-14 09:47:29 -05004302 q->drv =
4303 (struct ipw2100_status *)pci_alloc_consistent(priv->pci_dev,
4304 q->size, &q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004305 if (!q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004306 IPW_DEBUG_WARNING("Can not allocate status queue.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06004307 return -ENOMEM;
4308 }
4309
4310 memset(q->drv, 0, q->size);
4311
4312 IPW_DEBUG_INFO("exit\n");
4313
4314 return 0;
4315}
4316
4317static void status_queue_free(struct ipw2100_priv *priv)
4318{
4319 IPW_DEBUG_INFO("enter\n");
4320
4321 if (priv->status_queue.drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004322 pci_free_consistent(priv->pci_dev, priv->status_queue.size,
4323 priv->status_queue.drv,
4324 priv->status_queue.nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004325 priv->status_queue.drv = NULL;
4326 }
4327
4328 IPW_DEBUG_INFO("exit\n");
4329}
4330
4331static int bd_queue_allocate(struct ipw2100_priv *priv,
4332 struct ipw2100_bd_queue *q, int entries)
4333{
4334 IPW_DEBUG_INFO("enter\n");
4335
4336 memset(q, 0, sizeof(struct ipw2100_bd_queue));
4337
4338 q->entries = entries;
4339 q->size = entries * sizeof(struct ipw2100_bd);
4340 q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic);
4341 if (!q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004342 IPW_DEBUG_INFO
4343 ("can't allocate shared memory for buffer descriptors\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06004344 return -ENOMEM;
4345 }
4346 memset(q->drv, 0, q->size);
4347
4348 IPW_DEBUG_INFO("exit\n");
4349
4350 return 0;
4351}
4352
James Ketrenosee8e3652005-09-14 09:47:29 -05004353static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q)
James Ketrenos2c86c272005-03-23 17:32:29 -06004354{
4355 IPW_DEBUG_INFO("enter\n");
4356
4357 if (!q)
4358 return;
4359
4360 if (q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004361 pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004362 q->drv = NULL;
4363 }
4364
4365 IPW_DEBUG_INFO("exit\n");
4366}
4367
James Ketrenosee8e3652005-09-14 09:47:29 -05004368static void bd_queue_initialize(struct ipw2100_priv *priv,
4369 struct ipw2100_bd_queue *q, u32 base, u32 size,
4370 u32 r, u32 w)
James Ketrenos2c86c272005-03-23 17:32:29 -06004371{
4372 IPW_DEBUG_INFO("enter\n");
4373
James Ketrenosee8e3652005-09-14 09:47:29 -05004374 IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv,
4375 (u32) q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004376
4377 write_register(priv->net_dev, base, q->nic);
4378 write_register(priv->net_dev, size, q->entries);
4379 write_register(priv->net_dev, r, q->oldest);
4380 write_register(priv->net_dev, w, q->next);
4381
4382 IPW_DEBUG_INFO("exit\n");
4383}
4384
4385static void ipw2100_kill_workqueue(struct ipw2100_priv *priv)
4386{
4387 if (priv->workqueue) {
4388 priv->stop_rf_kill = 1;
4389 priv->stop_hang_check = 1;
4390 cancel_delayed_work(&priv->reset_work);
4391 cancel_delayed_work(&priv->security_work);
4392 cancel_delayed_work(&priv->wx_event_work);
4393 cancel_delayed_work(&priv->hang_check);
4394 cancel_delayed_work(&priv->rf_kill);
Dan Williamsd20c6782007-10-10 12:28:07 -04004395 cancel_delayed_work(&priv->scan_event_later);
James Ketrenos2c86c272005-03-23 17:32:29 -06004396 destroy_workqueue(priv->workqueue);
4397 priv->workqueue = NULL;
4398 }
4399}
4400
4401static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
4402{
4403 int i, j, err = -EINVAL;
4404 void *v;
4405 dma_addr_t p;
4406
4407 IPW_DEBUG_INFO("enter\n");
4408
4409 err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH);
4410 if (err) {
4411 IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05004412 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004413 return err;
4414 }
4415
James Ketrenosee8e3652005-09-14 09:47:29 -05004416 priv->tx_buffers =
4417 (struct ipw2100_tx_packet *)kmalloc(TX_PENDED_QUEUE_LENGTH *
4418 sizeof(struct
4419 ipw2100_tx_packet),
4420 GFP_ATOMIC);
James Ketrenos2c86c272005-03-23 17:32:29 -06004421 if (!priv->tx_buffers) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004422 printk(KERN_ERR DRV_NAME
4423 ": %s: alloc failed form tx buffers.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06004424 priv->net_dev->name);
4425 bd_queue_free(priv, &priv->tx_queue);
4426 return -ENOMEM;
4427 }
4428
4429 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004430 v = pci_alloc_consistent(priv->pci_dev,
4431 sizeof(struct ipw2100_data_header),
4432 &p);
James Ketrenos2c86c272005-03-23 17:32:29 -06004433 if (!v) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004434 printk(KERN_ERR DRV_NAME
4435 ": %s: PCI alloc failed for tx " "buffers.\n",
4436 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004437 err = -ENOMEM;
4438 break;
4439 }
4440
4441 priv->tx_buffers[i].type = DATA;
James Ketrenosee8e3652005-09-14 09:47:29 -05004442 priv->tx_buffers[i].info.d_struct.data =
4443 (struct ipw2100_data_header *)v;
James Ketrenos2c86c272005-03-23 17:32:29 -06004444 priv->tx_buffers[i].info.d_struct.data_phys = p;
4445 priv->tx_buffers[i].info.d_struct.txb = NULL;
4446 }
4447
4448 if (i == TX_PENDED_QUEUE_LENGTH)
4449 return 0;
4450
4451 for (j = 0; j < i; j++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004452 pci_free_consistent(priv->pci_dev,
4453 sizeof(struct ipw2100_data_header),
4454 priv->tx_buffers[j].info.d_struct.data,
4455 priv->tx_buffers[j].info.d_struct.
4456 data_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06004457 }
4458
4459 kfree(priv->tx_buffers);
4460 priv->tx_buffers = NULL;
4461
4462 return err;
4463}
4464
4465static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
4466{
4467 int i;
4468
4469 IPW_DEBUG_INFO("enter\n");
4470
4471 /*
4472 * reinitialize packet info lists
4473 */
4474 INIT_LIST_HEAD(&priv->fw_pend_list);
4475 INIT_STAT(&priv->fw_pend_stat);
4476
4477 /*
4478 * reinitialize lists
4479 */
4480 INIT_LIST_HEAD(&priv->tx_pend_list);
4481 INIT_LIST_HEAD(&priv->tx_free_list);
4482 INIT_STAT(&priv->tx_pend_stat);
4483 INIT_STAT(&priv->tx_free_stat);
4484
4485 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
4486 /* We simply drop any SKBs that have been queued for
4487 * transmit */
4488 if (priv->tx_buffers[i].info.d_struct.txb) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004489 ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.
4490 txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06004491 priv->tx_buffers[i].info.d_struct.txb = NULL;
4492 }
4493
4494 list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list);
4495 }
4496
4497 SET_STAT(&priv->tx_free_stat, i);
4498
4499 priv->tx_queue.oldest = 0;
4500 priv->tx_queue.available = priv->tx_queue.entries;
4501 priv->tx_queue.next = 0;
4502 INIT_STAT(&priv->txq_stat);
4503 SET_STAT(&priv->txq_stat, priv->tx_queue.available);
4504
4505 bd_queue_initialize(priv, &priv->tx_queue,
4506 IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE,
4507 IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE,
4508 IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
4509 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX);
4510
4511 IPW_DEBUG_INFO("exit\n");
4512
4513}
4514
4515static void ipw2100_tx_free(struct ipw2100_priv *priv)
4516{
4517 int i;
4518
4519 IPW_DEBUG_INFO("enter\n");
4520
4521 bd_queue_free(priv, &priv->tx_queue);
4522
4523 if (!priv->tx_buffers)
4524 return;
4525
4526 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
4527 if (priv->tx_buffers[i].info.d_struct.txb) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004528 ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.
4529 txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06004530 priv->tx_buffers[i].info.d_struct.txb = NULL;
4531 }
4532 if (priv->tx_buffers[i].info.d_struct.data)
James Ketrenosee8e3652005-09-14 09:47:29 -05004533 pci_free_consistent(priv->pci_dev,
4534 sizeof(struct ipw2100_data_header),
4535 priv->tx_buffers[i].info.d_struct.
4536 data,
4537 priv->tx_buffers[i].info.d_struct.
4538 data_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06004539 }
4540
4541 kfree(priv->tx_buffers);
4542 priv->tx_buffers = NULL;
4543
4544 IPW_DEBUG_INFO("exit\n");
4545}
4546
James Ketrenos2c86c272005-03-23 17:32:29 -06004547static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
4548{
4549 int i, j, err = -EINVAL;
4550
4551 IPW_DEBUG_INFO("enter\n");
4552
4553 err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH);
4554 if (err) {
4555 IPW_DEBUG_INFO("failed bd_queue_allocate\n");
4556 return err;
4557 }
4558
4559 err = status_queue_allocate(priv, RX_QUEUE_LENGTH);
4560 if (err) {
4561 IPW_DEBUG_INFO("failed status_queue_allocate\n");
4562 bd_queue_free(priv, &priv->rx_queue);
4563 return err;
4564 }
4565
4566 /*
4567 * allocate packets
4568 */
4569 priv->rx_buffers = (struct ipw2100_rx_packet *)
4570 kmalloc(RX_QUEUE_LENGTH * sizeof(struct ipw2100_rx_packet),
4571 GFP_KERNEL);
4572 if (!priv->rx_buffers) {
4573 IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
4574
4575 bd_queue_free(priv, &priv->rx_queue);
4576
4577 status_queue_free(priv);
4578
4579 return -ENOMEM;
4580 }
4581
4582 for (i = 0; i < RX_QUEUE_LENGTH; i++) {
4583 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
4584
4585 err = ipw2100_alloc_skb(priv, packet);
4586 if (unlikely(err)) {
4587 err = -ENOMEM;
4588 break;
4589 }
4590
4591 /* The BD holds the cache aligned address */
4592 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
4593 priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH;
4594 priv->status_queue.drv[i].status_fields = 0;
4595 }
4596
4597 if (i == RX_QUEUE_LENGTH)
4598 return 0;
4599
4600 for (j = 0; j < i; j++) {
4601 pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr,
4602 sizeof(struct ipw2100_rx_packet),
4603 PCI_DMA_FROMDEVICE);
4604 dev_kfree_skb(priv->rx_buffers[j].skb);
4605 }
4606
4607 kfree(priv->rx_buffers);
4608 priv->rx_buffers = NULL;
4609
4610 bd_queue_free(priv, &priv->rx_queue);
4611
4612 status_queue_free(priv);
4613
4614 return err;
4615}
4616
4617static void ipw2100_rx_initialize(struct ipw2100_priv *priv)
4618{
4619 IPW_DEBUG_INFO("enter\n");
4620
4621 priv->rx_queue.oldest = 0;
4622 priv->rx_queue.available = priv->rx_queue.entries - 1;
4623 priv->rx_queue.next = priv->rx_queue.entries - 1;
4624
4625 INIT_STAT(&priv->rxq_stat);
4626 SET_STAT(&priv->rxq_stat, priv->rx_queue.available);
4627
4628 bd_queue_initialize(priv, &priv->rx_queue,
4629 IPW_MEM_HOST_SHARED_RX_BD_BASE,
4630 IPW_MEM_HOST_SHARED_RX_BD_SIZE,
4631 IPW_MEM_HOST_SHARED_RX_READ_INDEX,
4632 IPW_MEM_HOST_SHARED_RX_WRITE_INDEX);
4633
4634 /* set up the status queue */
4635 write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE,
4636 priv->status_queue.nic);
4637
4638 IPW_DEBUG_INFO("exit\n");
4639}
4640
4641static void ipw2100_rx_free(struct ipw2100_priv *priv)
4642{
4643 int i;
4644
4645 IPW_DEBUG_INFO("enter\n");
4646
4647 bd_queue_free(priv, &priv->rx_queue);
4648 status_queue_free(priv);
4649
4650 if (!priv->rx_buffers)
4651 return;
4652
4653 for (i = 0; i < RX_QUEUE_LENGTH; i++) {
4654 if (priv->rx_buffers[i].rxp) {
4655 pci_unmap_single(priv->pci_dev,
4656 priv->rx_buffers[i].dma_addr,
4657 sizeof(struct ipw2100_rx),
4658 PCI_DMA_FROMDEVICE);
4659 dev_kfree_skb(priv->rx_buffers[i].skb);
4660 }
4661 }
4662
4663 kfree(priv->rx_buffers);
4664 priv->rx_buffers = NULL;
4665
4666 IPW_DEBUG_INFO("exit\n");
4667}
4668
4669static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
4670{
4671 u32 length = ETH_ALEN;
Joe Perches0795af52007-10-03 17:59:30 -07004672 u8 addr[ETH_ALEN];
James Ketrenos2c86c272005-03-23 17:32:29 -06004673
4674 int err;
4675
Joe Perches0795af52007-10-03 17:59:30 -07004676 err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
James Ketrenos2c86c272005-03-23 17:32:29 -06004677 if (err) {
4678 IPW_DEBUG_INFO("MAC address read failed\n");
4679 return -EIO;
4680 }
James Ketrenos2c86c272005-03-23 17:32:29 -06004681
Joe Perches0795af52007-10-03 17:59:30 -07004682 memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN);
Johannes Berge1749612008-10-27 15:59:26 -07004683 IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06004684
4685 return 0;
4686}
4687
4688/********************************************************************
4689 *
4690 * Firmware Commands
4691 *
4692 ********************************************************************/
4693
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004694static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004695{
4696 struct host_command cmd = {
4697 .host_command = ADAPTER_ADDRESS,
4698 .host_command_sequence = 0,
4699 .host_command_length = ETH_ALEN
4700 };
4701 int err;
4702
4703 IPW_DEBUG_HC("SET_MAC_ADDRESS\n");
4704
4705 IPW_DEBUG_INFO("enter\n");
4706
4707 if (priv->config & CFG_CUSTOM_MAC) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004708 memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06004709 memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
4710 } else
4711 memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr,
4712 ETH_ALEN);
4713
4714 err = ipw2100_hw_send_command(priv, &cmd);
4715
4716 IPW_DEBUG_INFO("exit\n");
4717 return err;
4718}
4719
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004720static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type,
James Ketrenos2c86c272005-03-23 17:32:29 -06004721 int batch_mode)
4722{
4723 struct host_command cmd = {
4724 .host_command = PORT_TYPE,
4725 .host_command_sequence = 0,
4726 .host_command_length = sizeof(u32)
4727 };
4728 int err;
4729
4730 switch (port_type) {
4731 case IW_MODE_INFRA:
4732 cmd.host_command_parameters[0] = IPW_BSS;
4733 break;
4734 case IW_MODE_ADHOC:
4735 cmd.host_command_parameters[0] = IPW_IBSS;
4736 break;
4737 }
4738
4739 IPW_DEBUG_HC("PORT_TYPE: %s\n",
4740 port_type == IPW_IBSS ? "Ad-Hoc" : "Managed");
4741
4742 if (!batch_mode) {
4743 err = ipw2100_disable_adapter(priv);
4744 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004745 printk(KERN_ERR DRV_NAME
4746 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06004747 priv->net_dev->name, err);
4748 return err;
4749 }
4750 }
4751
4752 /* send cmd to firmware */
4753 err = ipw2100_hw_send_command(priv, &cmd);
4754
4755 if (!batch_mode)
4756 ipw2100_enable_adapter(priv);
4757
4758 return err;
4759}
4760
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004761static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
4762 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004763{
4764 struct host_command cmd = {
4765 .host_command = CHANNEL,
4766 .host_command_sequence = 0,
4767 .host_command_length = sizeof(u32)
4768 };
4769 int err;
4770
4771 cmd.host_command_parameters[0] = channel;
4772
4773 IPW_DEBUG_HC("CHANNEL: %d\n", channel);
4774
4775 /* If BSS then we don't support channel selection */
4776 if (priv->ieee->iw_mode == IW_MODE_INFRA)
4777 return 0;
4778
4779 if ((channel != 0) &&
4780 ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL)))
4781 return -EINVAL;
4782
4783 if (!batch_mode) {
4784 err = ipw2100_disable_adapter(priv);
4785 if (err)
4786 return err;
4787 }
4788
4789 err = ipw2100_hw_send_command(priv, &cmd);
4790 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004791 IPW_DEBUG_INFO("Failed to set channel to %d", channel);
James Ketrenos2c86c272005-03-23 17:32:29 -06004792 return err;
4793 }
4794
4795 if (channel)
4796 priv->config |= CFG_STATIC_CHANNEL;
4797 else
4798 priv->config &= ~CFG_STATIC_CHANNEL;
4799
4800 priv->channel = channel;
4801
4802 if (!batch_mode) {
4803 err = ipw2100_enable_adapter(priv);
4804 if (err)
4805 return err;
4806 }
4807
4808 return 0;
4809}
4810
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004811static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004812{
4813 struct host_command cmd = {
4814 .host_command = SYSTEM_CONFIG,
4815 .host_command_sequence = 0,
4816 .host_command_length = 12,
4817 };
4818 u32 ibss_mask, len = sizeof(u32);
4819 int err;
4820
4821 /* Set system configuration */
4822
4823 if (!batch_mode) {
4824 err = ipw2100_disable_adapter(priv);
4825 if (err)
4826 return err;
4827 }
4828
4829 if (priv->ieee->iw_mode == IW_MODE_ADHOC)
4830 cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START;
4831
4832 cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK |
James Ketrenosee8e3652005-09-14 09:47:29 -05004833 IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06004834
4835 if (!(priv->config & CFG_LONG_PREAMBLE))
4836 cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO;
4837
4838 err = ipw2100_get_ordinal(priv,
4839 IPW_ORD_EEPROM_IBSS_11B_CHANNELS,
James Ketrenosee8e3652005-09-14 09:47:29 -05004840 &ibss_mask, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06004841 if (err)
4842 ibss_mask = IPW_IBSS_11B_DEFAULT_MASK;
4843
4844 cmd.host_command_parameters[1] = REG_CHANNEL_MASK;
4845 cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask;
4846
4847 /* 11b only */
James Ketrenosee8e3652005-09-14 09:47:29 -05004848 /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */
James Ketrenos2c86c272005-03-23 17:32:29 -06004849
4850 err = ipw2100_hw_send_command(priv, &cmd);
4851 if (err)
4852 return err;
4853
4854/* If IPv6 is configured in the kernel then we don't want to filter out all
4855 * of the multicast packets as IPv6 needs some. */
4856#if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE)
4857 cmd.host_command = ADD_MULTICAST;
4858 cmd.host_command_sequence = 0;
4859 cmd.host_command_length = 0;
4860
4861 ipw2100_hw_send_command(priv, &cmd);
4862#endif
4863 if (!batch_mode) {
4864 err = ipw2100_enable_adapter(priv);
4865 if (err)
4866 return err;
4867 }
4868
4869 return 0;
4870}
4871
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004872static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate,
4873 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004874{
4875 struct host_command cmd = {
4876 .host_command = BASIC_TX_RATES,
4877 .host_command_sequence = 0,
4878 .host_command_length = 4
4879 };
4880 int err;
4881
4882 cmd.host_command_parameters[0] = rate & TX_RATE_MASK;
4883
4884 if (!batch_mode) {
4885 err = ipw2100_disable_adapter(priv);
4886 if (err)
4887 return err;
4888 }
4889
4890 /* Set BASIC TX Rate first */
4891 ipw2100_hw_send_command(priv, &cmd);
4892
4893 /* Set TX Rate */
4894 cmd.host_command = TX_RATES;
4895 ipw2100_hw_send_command(priv, &cmd);
4896
4897 /* Set MSDU TX Rate */
4898 cmd.host_command = MSDU_TX_RATES;
4899 ipw2100_hw_send_command(priv, &cmd);
4900
4901 if (!batch_mode) {
4902 err = ipw2100_enable_adapter(priv);
4903 if (err)
4904 return err;
4905 }
4906
4907 priv->tx_rates = rate;
4908
4909 return 0;
4910}
4911
James Ketrenosee8e3652005-09-14 09:47:29 -05004912static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
James Ketrenos2c86c272005-03-23 17:32:29 -06004913{
4914 struct host_command cmd = {
4915 .host_command = POWER_MODE,
4916 .host_command_sequence = 0,
4917 .host_command_length = 4
4918 };
4919 int err;
4920
4921 cmd.host_command_parameters[0] = power_level;
4922
4923 err = ipw2100_hw_send_command(priv, &cmd);
4924 if (err)
4925 return err;
4926
4927 if (power_level == IPW_POWER_MODE_CAM)
4928 priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
4929 else
4930 priv->power_mode = IPW_POWER_ENABLED | power_level;
4931
Robert P. J. Dayae800312007-01-31 02:39:40 -05004932#ifdef IPW2100_TX_POWER
James Ketrenosee8e3652005-09-14 09:47:29 -05004933 if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
James Ketrenos2c86c272005-03-23 17:32:29 -06004934 /* Set beacon interval */
4935 cmd.host_command = TX_POWER_INDEX;
James Ketrenosee8e3652005-09-14 09:47:29 -05004936 cmd.host_command_parameters[0] = (u32) priv->adhoc_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06004937
4938 err = ipw2100_hw_send_command(priv, &cmd);
4939 if (err)
4940 return err;
4941 }
4942#endif
4943
4944 return 0;
4945}
4946
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004947static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold)
James Ketrenos2c86c272005-03-23 17:32:29 -06004948{
4949 struct host_command cmd = {
4950 .host_command = RTS_THRESHOLD,
4951 .host_command_sequence = 0,
4952 .host_command_length = 4
4953 };
4954 int err;
4955
4956 if (threshold & RTS_DISABLED)
4957 cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD;
4958 else
4959 cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED;
4960
4961 err = ipw2100_hw_send_command(priv, &cmd);
4962 if (err)
4963 return err;
4964
4965 priv->rts_threshold = threshold;
4966
4967 return 0;
4968}
4969
4970#if 0
4971int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv,
4972 u32 threshold, int batch_mode)
4973{
4974 struct host_command cmd = {
4975 .host_command = FRAG_THRESHOLD,
4976 .host_command_sequence = 0,
4977 .host_command_length = 4,
4978 .host_command_parameters[0] = 0,
4979 };
4980 int err;
4981
4982 if (!batch_mode) {
4983 err = ipw2100_disable_adapter(priv);
4984 if (err)
4985 return err;
4986 }
4987
4988 if (threshold == 0)
4989 threshold = DEFAULT_FRAG_THRESHOLD;
4990 else {
4991 threshold = max(threshold, MIN_FRAG_THRESHOLD);
4992 threshold = min(threshold, MAX_FRAG_THRESHOLD);
4993 }
4994
4995 cmd.host_command_parameters[0] = threshold;
4996
4997 IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold);
4998
4999 err = ipw2100_hw_send_command(priv, &cmd);
5000
5001 if (!batch_mode)
5002 ipw2100_enable_adapter(priv);
5003
5004 if (!err)
5005 priv->frag_threshold = threshold;
5006
5007 return err;
5008}
5009#endif
5010
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005011static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry)
James Ketrenos2c86c272005-03-23 17:32:29 -06005012{
5013 struct host_command cmd = {
5014 .host_command = SHORT_RETRY_LIMIT,
5015 .host_command_sequence = 0,
5016 .host_command_length = 4
5017 };
5018 int err;
5019
5020 cmd.host_command_parameters[0] = retry;
5021
5022 err = ipw2100_hw_send_command(priv, &cmd);
5023 if (err)
5024 return err;
5025
5026 priv->short_retry_limit = retry;
5027
5028 return 0;
5029}
5030
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005031static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry)
James Ketrenos2c86c272005-03-23 17:32:29 -06005032{
5033 struct host_command cmd = {
5034 .host_command = LONG_RETRY_LIMIT,
5035 .host_command_sequence = 0,
5036 .host_command_length = 4
5037 };
5038 int err;
5039
5040 cmd.host_command_parameters[0] = retry;
5041
5042 err = ipw2100_hw_send_command(priv, &cmd);
5043 if (err)
5044 return err;
5045
5046 priv->long_retry_limit = retry;
5047
5048 return 0;
5049}
5050
James Ketrenosee8e3652005-09-14 09:47:29 -05005051static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005052 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005053{
5054 struct host_command cmd = {
5055 .host_command = MANDATORY_BSSID,
5056 .host_command_sequence = 0,
5057 .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN
5058 };
5059 int err;
5060
Brice Goglin0f52bf92005-12-01 01:41:46 -08005061#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06005062 if (bssid != NULL)
Johannes Berge1749612008-10-27 15:59:26 -07005063 IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06005064 else
5065 IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
5066#endif
5067 /* if BSSID is empty then we disable mandatory bssid mode */
5068 if (bssid != NULL)
James Ketrenos82328352005-08-24 22:33:31 -05005069 memcpy(cmd.host_command_parameters, bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06005070
5071 if (!batch_mode) {
5072 err = ipw2100_disable_adapter(priv);
5073 if (err)
5074 return err;
5075 }
5076
5077 err = ipw2100_hw_send_command(priv, &cmd);
5078
5079 if (!batch_mode)
5080 ipw2100_enable_adapter(priv);
5081
5082 return err;
5083}
5084
James Ketrenos2c86c272005-03-23 17:32:29 -06005085static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
5086{
5087 struct host_command cmd = {
5088 .host_command = DISASSOCIATION_BSSID,
5089 .host_command_sequence = 0,
5090 .host_command_length = ETH_ALEN
5091 };
5092 int err;
5093 int len;
5094
5095 IPW_DEBUG_HC("DISASSOCIATION_BSSID\n");
5096
5097 len = ETH_ALEN;
5098 /* The Firmware currently ignores the BSSID and just disassociates from
5099 * the currently associated AP -- but in the off chance that a future
5100 * firmware does use the BSSID provided here, we go ahead and try and
5101 * set it to the currently associated AP's BSSID */
5102 memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN);
5103
5104 err = ipw2100_hw_send_command(priv, &cmd);
5105
5106 return err;
5107}
James Ketrenos2c86c272005-03-23 17:32:29 -06005108
5109static int ipw2100_set_wpa_ie(struct ipw2100_priv *,
5110 struct ipw2100_wpa_assoc_frame *, int)
James Ketrenosee8e3652005-09-14 09:47:29 -05005111 __attribute__ ((unused));
James Ketrenos2c86c272005-03-23 17:32:29 -06005112
5113static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv,
5114 struct ipw2100_wpa_assoc_frame *wpa_frame,
5115 int batch_mode)
5116{
5117 struct host_command cmd = {
5118 .host_command = SET_WPA_IE,
5119 .host_command_sequence = 0,
5120 .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame),
5121 };
5122 int err;
5123
5124 IPW_DEBUG_HC("SET_WPA_IE\n");
5125
5126 if (!batch_mode) {
5127 err = ipw2100_disable_adapter(priv);
5128 if (err)
5129 return err;
5130 }
5131
5132 memcpy(cmd.host_command_parameters, wpa_frame,
5133 sizeof(struct ipw2100_wpa_assoc_frame));
5134
5135 err = ipw2100_hw_send_command(priv, &cmd);
5136
5137 if (!batch_mode) {
5138 if (ipw2100_enable_adapter(priv))
5139 err = -EIO;
5140 }
5141
5142 return err;
5143}
5144
5145struct security_info_params {
5146 u32 allowed_ciphers;
5147 u16 version;
5148 u8 auth_mode;
5149 u8 replay_counters_number;
5150 u8 unicast_using_group;
5151} __attribute__ ((packed));
5152
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005153static int ipw2100_set_security_information(struct ipw2100_priv *priv,
5154 int auth_mode,
5155 int security_level,
5156 int unicast_using_group,
5157 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005158{
5159 struct host_command cmd = {
5160 .host_command = SET_SECURITY_INFORMATION,
5161 .host_command_sequence = 0,
5162 .host_command_length = sizeof(struct security_info_params)
5163 };
5164 struct security_info_params *security =
James Ketrenosee8e3652005-09-14 09:47:29 -05005165 (struct security_info_params *)&cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06005166 int err;
5167 memset(security, 0, sizeof(*security));
5168
5169 /* If shared key AP authentication is turned on, then we need to
5170 * configure the firmware to try and use it.
5171 *
5172 * Actual data encryption/decryption is handled by the host. */
5173 security->auth_mode = auth_mode;
5174 security->unicast_using_group = unicast_using_group;
5175
5176 switch (security_level) {
5177 default:
5178 case SEC_LEVEL_0:
5179 security->allowed_ciphers = IPW_NONE_CIPHER;
5180 break;
5181 case SEC_LEVEL_1:
5182 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005183 IPW_WEP104_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005184 break;
5185 case SEC_LEVEL_2:
5186 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005187 IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005188 break;
5189 case SEC_LEVEL_2_CKIP:
5190 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005191 IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005192 break;
5193 case SEC_LEVEL_3:
5194 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005195 IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005196 break;
5197 }
5198
James Ketrenosee8e3652005-09-14 09:47:29 -05005199 IPW_DEBUG_HC
5200 ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
5201 security->auth_mode, security->allowed_ciphers, security_level);
James Ketrenos2c86c272005-03-23 17:32:29 -06005202
5203 security->replay_counters_number = 0;
5204
5205 if (!batch_mode) {
5206 err = ipw2100_disable_adapter(priv);
5207 if (err)
5208 return err;
5209 }
5210
5211 err = ipw2100_hw_send_command(priv, &cmd);
5212
5213 if (!batch_mode)
5214 ipw2100_enable_adapter(priv);
5215
5216 return err;
5217}
5218
James Ketrenosee8e3652005-09-14 09:47:29 -05005219static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power)
James Ketrenos2c86c272005-03-23 17:32:29 -06005220{
5221 struct host_command cmd = {
5222 .host_command = TX_POWER_INDEX,
5223 .host_command_sequence = 0,
5224 .host_command_length = 4
5225 };
5226 int err = 0;
Zhu Yi3173ca02006-01-24 13:49:01 +08005227 u32 tmp = tx_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06005228
Liu Hongf75459e2005-07-13 12:29:21 -05005229 if (tx_power != IPW_TX_POWER_DEFAULT)
Zhu Yi3173ca02006-01-24 13:49:01 +08005230 tmp = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 /
5231 (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
Liu Hongf75459e2005-07-13 12:29:21 -05005232
Zhu Yi3173ca02006-01-24 13:49:01 +08005233 cmd.host_command_parameters[0] = tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06005234
5235 if (priv->ieee->iw_mode == IW_MODE_ADHOC)
5236 err = ipw2100_hw_send_command(priv, &cmd);
5237 if (!err)
5238 priv->tx_power = tx_power;
5239
5240 return 0;
5241}
5242
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005243static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv,
5244 u32 interval, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005245{
5246 struct host_command cmd = {
5247 .host_command = BEACON_INTERVAL,
5248 .host_command_sequence = 0,
5249 .host_command_length = 4
5250 };
5251 int err;
5252
5253 cmd.host_command_parameters[0] = interval;
5254
5255 IPW_DEBUG_INFO("enter\n");
5256
5257 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
5258 if (!batch_mode) {
5259 err = ipw2100_disable_adapter(priv);
5260 if (err)
5261 return err;
5262 }
5263
5264 ipw2100_hw_send_command(priv, &cmd);
5265
5266 if (!batch_mode) {
5267 err = ipw2100_enable_adapter(priv);
5268 if (err)
5269 return err;
5270 }
5271 }
5272
5273 IPW_DEBUG_INFO("exit\n");
5274
5275 return 0;
5276}
5277
Hannes Edera3d1fd22008-12-26 00:14:41 -08005278static void ipw2100_queues_initialize(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005279{
5280 ipw2100_tx_initialize(priv);
5281 ipw2100_rx_initialize(priv);
5282 ipw2100_msg_initialize(priv);
5283}
5284
Hannes Edera3d1fd22008-12-26 00:14:41 -08005285static void ipw2100_queues_free(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005286{
5287 ipw2100_tx_free(priv);
5288 ipw2100_rx_free(priv);
5289 ipw2100_msg_free(priv);
5290}
5291
Hannes Edera3d1fd22008-12-26 00:14:41 -08005292static int ipw2100_queues_allocate(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005293{
5294 if (ipw2100_tx_allocate(priv) ||
James Ketrenosee8e3652005-09-14 09:47:29 -05005295 ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv))
James Ketrenos2c86c272005-03-23 17:32:29 -06005296 goto fail;
5297
5298 return 0;
5299
James Ketrenosee8e3652005-09-14 09:47:29 -05005300 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06005301 ipw2100_tx_free(priv);
5302 ipw2100_rx_free(priv);
5303 ipw2100_msg_free(priv);
5304 return -ENOMEM;
5305}
5306
5307#define IPW_PRIVACY_CAPABLE 0x0008
5308
5309static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags,
5310 int batch_mode)
5311{
5312 struct host_command cmd = {
5313 .host_command = WEP_FLAGS,
5314 .host_command_sequence = 0,
5315 .host_command_length = 4
5316 };
5317 int err;
5318
5319 cmd.host_command_parameters[0] = flags;
5320
5321 IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags);
5322
5323 if (!batch_mode) {
5324 err = ipw2100_disable_adapter(priv);
5325 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005326 printk(KERN_ERR DRV_NAME
5327 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005328 priv->net_dev->name, err);
5329 return err;
5330 }
5331 }
5332
5333 /* send cmd to firmware */
5334 err = ipw2100_hw_send_command(priv, &cmd);
5335
5336 if (!batch_mode)
5337 ipw2100_enable_adapter(priv);
5338
5339 return err;
5340}
5341
5342struct ipw2100_wep_key {
5343 u8 idx;
5344 u8 len;
5345 u8 key[13];
5346};
5347
5348/* Macros to ease up priting WEP keys */
5349#define WEP_FMT_64 "%02X%02X%02X%02X-%02X"
5350#define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X"
5351#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4]
5352#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]
5353
James Ketrenos2c86c272005-03-23 17:32:29 -06005354/**
5355 * Set a the wep key
5356 *
5357 * @priv: struct to work on
5358 * @idx: index of the key we want to set
5359 * @key: ptr to the key data to set
5360 * @len: length of the buffer at @key
5361 * @batch_mode: FIXME perform the operation in batch mode, not
5362 * disabling the device.
5363 *
5364 * @returns 0 if OK, < 0 errno code on error.
5365 *
5366 * Fill out a command structure with the new wep key, length an
5367 * index and send it down the wire.
5368 */
5369static int ipw2100_set_key(struct ipw2100_priv *priv,
5370 int idx, char *key, int len, int batch_mode)
5371{
5372 int keylen = len ? (len <= 5 ? 5 : 13) : 0;
5373 struct host_command cmd = {
5374 .host_command = WEP_KEY_INFO,
5375 .host_command_sequence = 0,
5376 .host_command_length = sizeof(struct ipw2100_wep_key),
5377 };
James Ketrenosee8e3652005-09-14 09:47:29 -05005378 struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06005379 int err;
5380
5381 IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005382 idx, keylen, len);
James Ketrenos2c86c272005-03-23 17:32:29 -06005383
5384 /* NOTE: We don't check cached values in case the firmware was reset
Adrian Bunk80f72282006-06-30 18:27:16 +02005385 * or some other problem is occurring. If the user is setting the key,
James Ketrenos2c86c272005-03-23 17:32:29 -06005386 * then we push the change */
5387
5388 wep_key->idx = idx;
5389 wep_key->len = keylen;
5390
5391 if (keylen) {
5392 memcpy(wep_key->key, key, len);
5393 memset(wep_key->key + len, 0, keylen - len);
5394 }
5395
5396 /* Will be optimized out on debug not being configured in */
5397 if (keylen == 0)
5398 IPW_DEBUG_WEP("%s: Clearing key %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005399 priv->net_dev->name, wep_key->idx);
James Ketrenos2c86c272005-03-23 17:32:29 -06005400 else if (keylen == 5)
5401 IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005402 priv->net_dev->name, wep_key->idx, wep_key->len,
5403 WEP_STR_64(wep_key->key));
James Ketrenos2c86c272005-03-23 17:32:29 -06005404 else
5405 IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128
James Ketrenosee8e3652005-09-14 09:47:29 -05005406 "\n",
5407 priv->net_dev->name, wep_key->idx, wep_key->len,
5408 WEP_STR_128(wep_key->key));
James Ketrenos2c86c272005-03-23 17:32:29 -06005409
5410 if (!batch_mode) {
5411 err = ipw2100_disable_adapter(priv);
5412 /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */
5413 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005414 printk(KERN_ERR DRV_NAME
5415 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005416 priv->net_dev->name, err);
5417 return err;
5418 }
5419 }
5420
5421 /* send cmd to firmware */
5422 err = ipw2100_hw_send_command(priv, &cmd);
5423
5424 if (!batch_mode) {
5425 int err2 = ipw2100_enable_adapter(priv);
5426 if (err == 0)
5427 err = err2;
5428 }
5429 return err;
5430}
5431
5432static int ipw2100_set_key_index(struct ipw2100_priv *priv,
5433 int idx, int batch_mode)
5434{
5435 struct host_command cmd = {
5436 .host_command = WEP_KEY_INDEX,
5437 .host_command_sequence = 0,
5438 .host_command_length = 4,
James Ketrenosee8e3652005-09-14 09:47:29 -05005439 .host_command_parameters = {idx},
James Ketrenos2c86c272005-03-23 17:32:29 -06005440 };
5441 int err;
5442
5443 IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx);
5444
5445 if (idx < 0 || idx > 3)
5446 return -EINVAL;
5447
5448 if (!batch_mode) {
5449 err = ipw2100_disable_adapter(priv);
5450 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005451 printk(KERN_ERR DRV_NAME
5452 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005453 priv->net_dev->name, err);
5454 return err;
5455 }
5456 }
5457
5458 /* send cmd to firmware */
5459 err = ipw2100_hw_send_command(priv, &cmd);
5460
5461 if (!batch_mode)
5462 ipw2100_enable_adapter(priv);
5463
5464 return err;
5465}
5466
James Ketrenosee8e3652005-09-14 09:47:29 -05005467static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005468{
5469 int i, err, auth_mode, sec_level, use_group;
5470
5471 if (!(priv->status & STATUS_RUNNING))
5472 return 0;
5473
5474 if (!batch_mode) {
5475 err = ipw2100_disable_adapter(priv);
5476 if (err)
5477 return err;
5478 }
5479
25b645b2005-07-12 15:45:30 -05005480 if (!priv->ieee->sec.enabled) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005481 err =
5482 ipw2100_set_security_information(priv, IPW_AUTH_OPEN,
5483 SEC_LEVEL_0, 0, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005484 } else {
5485 auth_mode = IPW_AUTH_OPEN;
Zhu Yicbbdd032006-01-24 13:48:53 +08005486 if (priv->ieee->sec.flags & SEC_AUTH_MODE) {
5487 if (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)
5488 auth_mode = IPW_AUTH_SHARED;
5489 else if (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)
5490 auth_mode = IPW_AUTH_LEAP_CISCO_ID;
5491 }
James Ketrenos2c86c272005-03-23 17:32:29 -06005492
5493 sec_level = SEC_LEVEL_0;
25b645b2005-07-12 15:45:30 -05005494 if (priv->ieee->sec.flags & SEC_LEVEL)
5495 sec_level = priv->ieee->sec.level;
James Ketrenos2c86c272005-03-23 17:32:29 -06005496
5497 use_group = 0;
25b645b2005-07-12 15:45:30 -05005498 if (priv->ieee->sec.flags & SEC_UNICAST_GROUP)
5499 use_group = priv->ieee->sec.unicast_uses_group;
James Ketrenos2c86c272005-03-23 17:32:29 -06005500
James Ketrenosee8e3652005-09-14 09:47:29 -05005501 err =
5502 ipw2100_set_security_information(priv, auth_mode, sec_level,
5503 use_group, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005504 }
5505
5506 if (err)
5507 goto exit;
5508
25b645b2005-07-12 15:45:30 -05005509 if (priv->ieee->sec.enabled) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005510 for (i = 0; i < 4; i++) {
25b645b2005-07-12 15:45:30 -05005511 if (!(priv->ieee->sec.flags & (1 << i))) {
5512 memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN);
5513 priv->ieee->sec.key_sizes[i] = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005514 } else {
5515 err = ipw2100_set_key(priv, i,
25b645b2005-07-12 15:45:30 -05005516 priv->ieee->sec.keys[i],
5517 priv->ieee->sec.
5518 key_sizes[i], 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005519 if (err)
5520 goto exit;
5521 }
5522 }
5523
John W. Linville274bfb82008-10-29 11:35:05 -04005524 ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005525 }
5526
5527 /* Always enable privacy so the Host can filter WEP packets if
5528 * encrypted data is sent up */
James Ketrenosee8e3652005-09-14 09:47:29 -05005529 err =
5530 ipw2100_set_wep_flags(priv,
25b645b2005-07-12 15:45:30 -05005531 priv->ieee->sec.
5532 enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005533 if (err)
5534 goto exit;
5535
5536 priv->status &= ~STATUS_SECURITY_UPDATED;
5537
James Ketrenosee8e3652005-09-14 09:47:29 -05005538 exit:
James Ketrenos2c86c272005-03-23 17:32:29 -06005539 if (!batch_mode)
5540 ipw2100_enable_adapter(priv);
5541
5542 return err;
5543}
5544
David Howellsc4028952006-11-22 14:57:56 +00005545static void ipw2100_security_work(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06005546{
David Howellsc4028952006-11-22 14:57:56 +00005547 struct ipw2100_priv *priv =
5548 container_of(work, struct ipw2100_priv, security_work.work);
5549
James Ketrenos2c86c272005-03-23 17:32:29 -06005550 /* If we happen to have reconnected before we get a chance to
5551 * process this, then update the security settings--which causes
5552 * a disassociation to occur */
5553 if (!(priv->status & STATUS_ASSOCIATED) &&
5554 priv->status & STATUS_SECURITY_UPDATED)
5555 ipw2100_configure_security(priv, 0);
5556}
5557
5558static void shim__set_security(struct net_device *dev,
5559 struct ieee80211_security *sec)
5560{
5561 struct ipw2100_priv *priv = ieee80211_priv(dev);
5562 int i, force_update = 0;
5563
Ingo Molnar752e3772006-02-28 07:20:54 +08005564 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005565 if (!(priv->status & STATUS_INITIALIZED))
5566 goto done;
5567
5568 for (i = 0; i < 4; i++) {
5569 if (sec->flags & (1 << i)) {
25b645b2005-07-12 15:45:30 -05005570 priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
James Ketrenos2c86c272005-03-23 17:32:29 -06005571 if (sec->key_sizes[i] == 0)
25b645b2005-07-12 15:45:30 -05005572 priv->ieee->sec.flags &= ~(1 << i);
James Ketrenos2c86c272005-03-23 17:32:29 -06005573 else
25b645b2005-07-12 15:45:30 -05005574 memcpy(priv->ieee->sec.keys[i], sec->keys[i],
James Ketrenos2c86c272005-03-23 17:32:29 -06005575 sec->key_sizes[i]);
Hong Liu054b08d2005-08-25 17:45:49 +08005576 if (sec->level == SEC_LEVEL_1) {
5577 priv->ieee->sec.flags |= (1 << i);
5578 priv->status |= STATUS_SECURITY_UPDATED;
5579 } else
5580 priv->ieee->sec.flags &= ~(1 << i);
James Ketrenos2c86c272005-03-23 17:32:29 -06005581 }
5582 }
5583
5584 if ((sec->flags & SEC_ACTIVE_KEY) &&
25b645b2005-07-12 15:45:30 -05005585 priv->ieee->sec.active_key != sec->active_key) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005586 if (sec->active_key <= 3) {
25b645b2005-07-12 15:45:30 -05005587 priv->ieee->sec.active_key = sec->active_key;
5588 priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
James Ketrenos2c86c272005-03-23 17:32:29 -06005589 } else
25b645b2005-07-12 15:45:30 -05005590 priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
James Ketrenos2c86c272005-03-23 17:32:29 -06005591
5592 priv->status |= STATUS_SECURITY_UPDATED;
5593 }
5594
5595 if ((sec->flags & SEC_AUTH_MODE) &&
25b645b2005-07-12 15:45:30 -05005596 (priv->ieee->sec.auth_mode != sec->auth_mode)) {
5597 priv->ieee->sec.auth_mode = sec->auth_mode;
5598 priv->ieee->sec.flags |= SEC_AUTH_MODE;
James Ketrenos2c86c272005-03-23 17:32:29 -06005599 priv->status |= STATUS_SECURITY_UPDATED;
5600 }
5601
25b645b2005-07-12 15:45:30 -05005602 if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
5603 priv->ieee->sec.flags |= SEC_ENABLED;
5604 priv->ieee->sec.enabled = sec->enabled;
James Ketrenos2c86c272005-03-23 17:32:29 -06005605 priv->status |= STATUS_SECURITY_UPDATED;
5606 force_update = 1;
5607 }
5608
25b645b2005-07-12 15:45:30 -05005609 if (sec->flags & SEC_ENCRYPT)
5610 priv->ieee->sec.encrypt = sec->encrypt;
5611
5612 if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
5613 priv->ieee->sec.level = sec->level;
5614 priv->ieee->sec.flags |= SEC_LEVEL;
James Ketrenos2c86c272005-03-23 17:32:29 -06005615 priv->status |= STATUS_SECURITY_UPDATED;
5616 }
5617
5618 IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n",
25b645b2005-07-12 15:45:30 -05005619 priv->ieee->sec.flags & (1 << 8) ? '1' : '0',
5620 priv->ieee->sec.flags & (1 << 7) ? '1' : '0',
5621 priv->ieee->sec.flags & (1 << 6) ? '1' : '0',
5622 priv->ieee->sec.flags & (1 << 5) ? '1' : '0',
5623 priv->ieee->sec.flags & (1 << 4) ? '1' : '0',
5624 priv->ieee->sec.flags & (1 << 3) ? '1' : '0',
5625 priv->ieee->sec.flags & (1 << 2) ? '1' : '0',
5626 priv->ieee->sec.flags & (1 << 1) ? '1' : '0',
5627 priv->ieee->sec.flags & (1 << 0) ? '1' : '0');
James Ketrenos2c86c272005-03-23 17:32:29 -06005628
5629/* As a temporary work around to enable WPA until we figure out why
5630 * wpa_supplicant toggles the security capability of the driver, which
5631 * forces a disassocation with force_update...
5632 *
5633 * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/
5634 if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
5635 ipw2100_configure_security(priv, 0);
James Ketrenosee8e3652005-09-14 09:47:29 -05005636 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08005637 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005638}
5639
5640static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
5641{
5642 int err;
5643 int batch_mode = 1;
5644 u8 *bssid;
5645
5646 IPW_DEBUG_INFO("enter\n");
5647
5648 err = ipw2100_disable_adapter(priv);
5649 if (err)
5650 return err;
5651#ifdef CONFIG_IPW2100_MONITOR
5652 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
5653 err = ipw2100_set_channel(priv, priv->channel, batch_mode);
5654 if (err)
5655 return err;
5656
5657 IPW_DEBUG_INFO("exit\n");
5658
5659 return 0;
5660 }
James Ketrenosee8e3652005-09-14 09:47:29 -05005661#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06005662
5663 err = ipw2100_read_mac_address(priv);
5664 if (err)
5665 return -EIO;
5666
5667 err = ipw2100_set_mac_address(priv, batch_mode);
5668 if (err)
5669 return err;
5670
5671 err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode);
5672 if (err)
5673 return err;
5674
5675 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
5676 err = ipw2100_set_channel(priv, priv->channel, batch_mode);
5677 if (err)
5678 return err;
5679 }
5680
James Ketrenosee8e3652005-09-14 09:47:29 -05005681 err = ipw2100_system_config(priv, batch_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06005682 if (err)
5683 return err;
5684
5685 err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode);
5686 if (err)
5687 return err;
5688
5689 /* Default to power mode OFF */
5690 err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
5691 if (err)
5692 return err;
5693
5694 err = ipw2100_set_rts_threshold(priv, priv->rts_threshold);
5695 if (err)
5696 return err;
5697
5698 if (priv->config & CFG_STATIC_BSSID)
5699 bssid = priv->bssid;
5700 else
5701 bssid = NULL;
5702 err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode);
5703 if (err)
5704 return err;
5705
5706 if (priv->config & CFG_STATIC_ESSID)
5707 err = ipw2100_set_essid(priv, priv->essid, priv->essid_len,
5708 batch_mode);
5709 else
5710 err = ipw2100_set_essid(priv, NULL, 0, batch_mode);
5711 if (err)
5712 return err;
5713
5714 err = ipw2100_configure_security(priv, batch_mode);
5715 if (err)
5716 return err;
5717
5718 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005719 err =
5720 ipw2100_set_ibss_beacon_interval(priv,
5721 priv->beacon_interval,
5722 batch_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06005723 if (err)
5724 return err;
5725
5726 err = ipw2100_set_tx_power(priv, priv->tx_power);
5727 if (err)
5728 return err;
5729 }
5730
5731 /*
James Ketrenosee8e3652005-09-14 09:47:29 -05005732 err = ipw2100_set_fragmentation_threshold(
5733 priv, priv->frag_threshold, batch_mode);
5734 if (err)
5735 return err;
5736 */
James Ketrenos2c86c272005-03-23 17:32:29 -06005737
5738 IPW_DEBUG_INFO("exit\n");
5739
5740 return 0;
5741}
5742
James Ketrenos2c86c272005-03-23 17:32:29 -06005743/*************************************************************************
5744 *
5745 * EXTERNALLY CALLED METHODS
5746 *
5747 *************************************************************************/
5748
5749/* This method is called by the network layer -- not to be confused with
5750 * ipw2100_set_mac_address() declared above called by this driver (and this
5751 * method as well) to talk to the firmware */
5752static int ipw2100_set_address(struct net_device *dev, void *p)
5753{
5754 struct ipw2100_priv *priv = ieee80211_priv(dev);
5755 struct sockaddr *addr = p;
5756 int err = 0;
5757
5758 if (!is_valid_ether_addr(addr->sa_data))
5759 return -EADDRNOTAVAIL;
5760
Ingo Molnar752e3772006-02-28 07:20:54 +08005761 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005762
5763 priv->config |= CFG_CUSTOM_MAC;
5764 memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
5765
5766 err = ipw2100_set_mac_address(priv, 0);
5767 if (err)
5768 goto done;
5769
5770 priv->reset_backoff = 0;
Ingo Molnar752e3772006-02-28 07:20:54 +08005771 mutex_unlock(&priv->action_mutex);
David Howellsc4028952006-11-22 14:57:56 +00005772 ipw2100_reset_adapter(&priv->reset_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06005773 return 0;
5774
James Ketrenosee8e3652005-09-14 09:47:29 -05005775 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08005776 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005777 return err;
5778}
5779
5780static int ipw2100_open(struct net_device *dev)
5781{
5782 struct ipw2100_priv *priv = ieee80211_priv(dev);
5783 unsigned long flags;
5784 IPW_DEBUG_INFO("dev->open\n");
5785
5786 spin_lock_irqsave(&priv->low_lock, flags);
Jiri Benc3ce329c2005-08-25 20:07:01 -04005787 if (priv->status & STATUS_ASSOCIATED) {
5788 netif_carrier_on(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005789 netif_start_queue(dev);
Jiri Benc3ce329c2005-08-25 20:07:01 -04005790 }
James Ketrenos2c86c272005-03-23 17:32:29 -06005791 spin_unlock_irqrestore(&priv->low_lock, flags);
5792
5793 return 0;
5794}
5795
5796static int ipw2100_close(struct net_device *dev)
5797{
5798 struct ipw2100_priv *priv = ieee80211_priv(dev);
5799 unsigned long flags;
5800 struct list_head *element;
5801 struct ipw2100_tx_packet *packet;
5802
5803 IPW_DEBUG_INFO("enter\n");
5804
5805 spin_lock_irqsave(&priv->low_lock, flags);
5806
5807 if (priv->status & STATUS_ASSOCIATED)
5808 netif_carrier_off(dev);
5809 netif_stop_queue(dev);
5810
5811 /* Flush the TX queue ... */
5812 while (!list_empty(&priv->tx_pend_list)) {
5813 element = priv->tx_pend_list.next;
James Ketrenosee8e3652005-09-14 09:47:29 -05005814 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06005815
5816 list_del(element);
5817 DEC_STAT(&priv->tx_pend_stat);
5818
5819 ieee80211_txb_free(packet->info.d_struct.txb);
5820 packet->info.d_struct.txb = NULL;
5821
5822 list_add_tail(element, &priv->tx_free_list);
5823 INC_STAT(&priv->tx_free_stat);
5824 }
5825 spin_unlock_irqrestore(&priv->low_lock, flags);
5826
5827 IPW_DEBUG_INFO("exit\n");
5828
5829 return 0;
5830}
5831
James Ketrenos2c86c272005-03-23 17:32:29 -06005832/*
5833 * TODO: Fix this function... its just wrong
5834 */
5835static void ipw2100_tx_timeout(struct net_device *dev)
5836{
5837 struct ipw2100_priv *priv = ieee80211_priv(dev);
5838
5839 priv->ieee->stats.tx_errors++;
5840
5841#ifdef CONFIG_IPW2100_MONITOR
5842 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
5843 return;
5844#endif
5845
5846 IPW_DEBUG_INFO("%s: TX timed out. Scheduling firmware restart.\n",
5847 dev->name);
5848 schedule_reset(priv);
5849}
5850
James Ketrenosee8e3652005-09-14 09:47:29 -05005851static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value)
5852{
James Ketrenos82328352005-08-24 22:33:31 -05005853 /* This is called when wpa_supplicant loads and closes the driver
5854 * interface. */
5855 priv->ieee->wpa_enabled = value;
5856 return 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005857}
5858
James Ketrenosee8e3652005-09-14 09:47:29 -05005859static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value)
5860{
James Ketrenos2c86c272005-03-23 17:32:29 -06005861
5862 struct ieee80211_device *ieee = priv->ieee;
5863 struct ieee80211_security sec = {
5864 .flags = SEC_AUTH_MODE,
5865 };
5866 int ret = 0;
5867
James Ketrenos82328352005-08-24 22:33:31 -05005868 if (value & IW_AUTH_ALG_SHARED_KEY) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005869 sec.auth_mode = WLAN_AUTH_SHARED_KEY;
5870 ieee->open_wep = 0;
James Ketrenos82328352005-08-24 22:33:31 -05005871 } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005872 sec.auth_mode = WLAN_AUTH_OPEN;
5873 ieee->open_wep = 1;
Zhu Yicbbdd032006-01-24 13:48:53 +08005874 } else if (value & IW_AUTH_ALG_LEAP) {
5875 sec.auth_mode = WLAN_AUTH_LEAP;
5876 ieee->open_wep = 1;
James Ketrenos82328352005-08-24 22:33:31 -05005877 } else
5878 return -EINVAL;
James Ketrenos2c86c272005-03-23 17:32:29 -06005879
5880 if (ieee->set_security)
5881 ieee->set_security(ieee->dev, &sec);
5882 else
5883 ret = -EOPNOTSUPP;
5884
5885 return ret;
5886}
5887
Adrian Bunk3c398b82006-01-21 01:36:36 +01005888static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
5889 char *wpa_ie, int wpa_ie_len)
James Ketrenosee8e3652005-09-14 09:47:29 -05005890{
James Ketrenos2c86c272005-03-23 17:32:29 -06005891
5892 struct ipw2100_wpa_assoc_frame frame;
5893
5894 frame.fixed_ie_mask = 0;
5895
5896 /* copy WPA IE */
5897 memcpy(frame.var_ie, wpa_ie, wpa_ie_len);
5898 frame.var_ie_len = wpa_ie_len;
5899
5900 /* make sure WPA is enabled */
5901 ipw2100_wpa_enable(priv, 1);
5902 ipw2100_set_wpa_ie(priv, &frame, 0);
5903}
5904
James Ketrenos2c86c272005-03-23 17:32:29 -06005905static void ipw_ethtool_get_drvinfo(struct net_device *dev,
5906 struct ethtool_drvinfo *info)
5907{
5908 struct ipw2100_priv *priv = ieee80211_priv(dev);
5909 char fw_ver[64], ucode_ver[64];
5910
5911 strcpy(info->driver, DRV_NAME);
5912 strcpy(info->version, DRV_VERSION);
5913
5914 ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver));
5915 ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver));
5916
5917 snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s",
5918 fw_ver, priv->eeprom_version, ucode_ver);
5919
5920 strcpy(info->bus_info, pci_name(priv->pci_dev));
5921}
5922
5923static u32 ipw2100_ethtool_get_link(struct net_device *dev)
5924{
James Ketrenosee8e3652005-09-14 09:47:29 -05005925 struct ipw2100_priv *priv = ieee80211_priv(dev);
5926 return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005927}
5928
Jeff Garzik7282d492006-09-13 14:30:00 -04005929static const struct ethtool_ops ipw2100_ethtool_ops = {
James Ketrenosee8e3652005-09-14 09:47:29 -05005930 .get_link = ipw2100_ethtool_get_link,
5931 .get_drvinfo = ipw_ethtool_get_drvinfo,
James Ketrenos2c86c272005-03-23 17:32:29 -06005932};
5933
David Howellsc4028952006-11-22 14:57:56 +00005934static void ipw2100_hang_check(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06005935{
David Howellsc4028952006-11-22 14:57:56 +00005936 struct ipw2100_priv *priv =
5937 container_of(work, struct ipw2100_priv, hang_check.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06005938 unsigned long flags;
5939 u32 rtc = 0xa5a5a5a5;
5940 u32 len = sizeof(rtc);
5941 int restart = 0;
5942
5943 spin_lock_irqsave(&priv->low_lock, flags);
5944
5945 if (priv->fatal_error != 0) {
5946 /* If fatal_error is set then we need to restart */
5947 IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n",
5948 priv->net_dev->name);
5949
5950 restart = 1;
5951 } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) ||
5952 (rtc == priv->last_rtc)) {
5953 /* Check if firmware is hung */
5954 IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n",
5955 priv->net_dev->name);
5956
5957 restart = 1;
5958 }
5959
5960 if (restart) {
5961 /* Kill timer */
5962 priv->stop_hang_check = 1;
5963 priv->hangs++;
5964
5965 /* Restart the NIC */
5966 schedule_reset(priv);
5967 }
5968
5969 priv->last_rtc = rtc;
5970
5971 if (!priv->stop_hang_check)
5972 queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
5973
5974 spin_unlock_irqrestore(&priv->low_lock, flags);
5975}
5976
David Howellsc4028952006-11-22 14:57:56 +00005977static void ipw2100_rf_kill(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06005978{
David Howellsc4028952006-11-22 14:57:56 +00005979 struct ipw2100_priv *priv =
5980 container_of(work, struct ipw2100_priv, rf_kill.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06005981 unsigned long flags;
5982
5983 spin_lock_irqsave(&priv->low_lock, flags);
5984
5985 if (rf_kill_active(priv)) {
5986 IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
5987 if (!priv->stop_rf_kill)
Stephen Hemmingera62056f2007-06-22 21:46:50 -07005988 queue_delayed_work(priv->workqueue, &priv->rf_kill,
Anton Blanchardbe84e3d2007-10-15 00:38:01 -05005989 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06005990 goto exit_unlock;
5991 }
5992
5993 /* RF Kill is now disabled, so bring the device back up */
5994
5995 if (!(priv->status & STATUS_RF_KILL_MASK)) {
5996 IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
5997 "device\n");
5998 schedule_reset(priv);
5999 } else
6000 IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
6001 "enabled\n");
6002
James Ketrenosee8e3652005-09-14 09:47:29 -05006003 exit_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -06006004 spin_unlock_irqrestore(&priv->low_lock, flags);
6005}
6006
6007static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
6008
6009/* Look into using netdev destructor to shutdown ieee80211? */
6010
James Ketrenosee8e3652005-09-14 09:47:29 -05006011static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
6012 void __iomem * base_addr,
6013 unsigned long mem_start,
6014 unsigned long mem_len)
James Ketrenos2c86c272005-03-23 17:32:29 -06006015{
6016 struct ipw2100_priv *priv;
6017 struct net_device *dev;
6018
6019 dev = alloc_ieee80211(sizeof(struct ipw2100_priv));
6020 if (!dev)
6021 return NULL;
6022 priv = ieee80211_priv(dev);
6023 priv->ieee = netdev_priv(dev);
6024 priv->pci_dev = pci_dev;
6025 priv->net_dev = dev;
6026
6027 priv->ieee->hard_start_xmit = ipw2100_tx;
6028 priv->ieee->set_security = shim__set_security;
6029
James Ketrenos82328352005-08-24 22:33:31 -05006030 priv->ieee->perfect_rssi = -20;
6031 priv->ieee->worst_rssi = -85;
6032
James Ketrenos2c86c272005-03-23 17:32:29 -06006033 dev->open = ipw2100_open;
6034 dev->stop = ipw2100_close;
6035 dev->init = ipw2100_net_init;
James Ketrenos2c86c272005-03-23 17:32:29 -06006036 dev->ethtool_ops = &ipw2100_ethtool_ops;
6037 dev->tx_timeout = ipw2100_tx_timeout;
6038 dev->wireless_handlers = &ipw2100_wx_handler_def;
James Ketrenoseaf8f532005-11-12 12:50:12 -06006039 priv->wireless_data.ieee80211 = priv->ieee;
6040 dev->wireless_data = &priv->wireless_data;
James Ketrenos2c86c272005-03-23 17:32:29 -06006041 dev->set_mac_address = ipw2100_set_address;
James Ketrenosee8e3652005-09-14 09:47:29 -05006042 dev->watchdog_timeo = 3 * HZ;
James Ketrenos2c86c272005-03-23 17:32:29 -06006043 dev->irq = 0;
6044
6045 dev->base_addr = (unsigned long)base_addr;
6046 dev->mem_start = mem_start;
6047 dev->mem_end = dev->mem_start + mem_len - 1;
6048
6049 /* NOTE: We don't use the wireless_handlers hook
6050 * in dev as the system will start throwing WX requests
6051 * to us before we're actually initialized and it just
6052 * ends up causing problems. So, we just handle
6053 * the WX extensions through the ipw2100_ioctl interface */
6054
Jean Delvarec03983a2007-10-19 23:22:55 +02006055 /* memset() puts everything to 0, so we only have explicitly set
James Ketrenos2c86c272005-03-23 17:32:29 -06006056 * those values that need to be something else */
6057
6058 /* If power management is turned on, default to AUTO mode */
6059 priv->power_mode = IPW_POWER_AUTO;
6060
James Ketrenos82328352005-08-24 22:33:31 -05006061#ifdef CONFIG_IPW2100_MONITOR
6062 priv->config |= CFG_CRC_CHECK;
6063#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06006064 priv->ieee->wpa_enabled = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06006065 priv->ieee->drop_unencrypted = 0;
6066 priv->ieee->privacy_invoked = 0;
6067 priv->ieee->ieee802_1x = 1;
James Ketrenos2c86c272005-03-23 17:32:29 -06006068
6069 /* Set module parameters */
6070 switch (mode) {
6071 case 1:
6072 priv->ieee->iw_mode = IW_MODE_ADHOC;
6073 break;
6074#ifdef CONFIG_IPW2100_MONITOR
6075 case 2:
6076 priv->ieee->iw_mode = IW_MODE_MONITOR;
6077 break;
6078#endif
6079 default:
6080 case 0:
6081 priv->ieee->iw_mode = IW_MODE_INFRA;
6082 break;
6083 }
6084
6085 if (disable == 1)
6086 priv->status |= STATUS_RF_KILL_SW;
6087
6088 if (channel != 0 &&
James Ketrenosee8e3652005-09-14 09:47:29 -05006089 ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006090 priv->config |= CFG_STATIC_CHANNEL;
6091 priv->channel = channel;
6092 }
6093
6094 if (associate)
6095 priv->config |= CFG_ASSOCIATE;
6096
6097 priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
6098 priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
6099 priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
6100 priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED;
6101 priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED;
6102 priv->tx_power = IPW_TX_POWER_DEFAULT;
6103 priv->tx_rates = DEFAULT_TX_RATES;
6104
6105 strcpy(priv->nick, "ipw2100");
6106
6107 spin_lock_init(&priv->low_lock);
Ingo Molnar752e3772006-02-28 07:20:54 +08006108 mutex_init(&priv->action_mutex);
6109 mutex_init(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006110
6111 init_waitqueue_head(&priv->wait_command_queue);
6112
6113 netif_carrier_off(dev);
6114
6115 INIT_LIST_HEAD(&priv->msg_free_list);
6116 INIT_LIST_HEAD(&priv->msg_pend_list);
6117 INIT_STAT(&priv->msg_free_stat);
6118 INIT_STAT(&priv->msg_pend_stat);
6119
6120 INIT_LIST_HEAD(&priv->tx_free_list);
6121 INIT_LIST_HEAD(&priv->tx_pend_list);
6122 INIT_STAT(&priv->tx_free_stat);
6123 INIT_STAT(&priv->tx_pend_stat);
6124
6125 INIT_LIST_HEAD(&priv->fw_pend_list);
6126 INIT_STAT(&priv->fw_pend_stat);
6127
James Ketrenos2c86c272005-03-23 17:32:29 -06006128 priv->workqueue = create_workqueue(DRV_NAME);
James Ketrenos392d0f62005-09-07 18:39:03 -05006129
David Howellsc4028952006-11-22 14:57:56 +00006130 INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter);
6131 INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work);
6132 INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
6133 INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
6134 INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
Dan Williamsd20c6782007-10-10 12:28:07 -04006135 INIT_WORK(&priv->scan_event_now, ipw2100_scan_event_now);
6136 INIT_DELAYED_WORK(&priv->scan_event_later, ipw2100_scan_event_later);
James Ketrenos2c86c272005-03-23 17:32:29 -06006137
6138 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
6139 ipw2100_irq_tasklet, (unsigned long)priv);
6140
6141 /* NOTE: We do not start the deferred work for status checks yet */
6142 priv->stop_rf_kill = 1;
6143 priv->stop_hang_check = 1;
6144
6145 return dev;
6146}
6147
James Ketrenos2c86c272005-03-23 17:32:29 -06006148static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
6149 const struct pci_device_id *ent)
6150{
6151 unsigned long mem_start, mem_len, mem_flags;
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01006152 void __iomem *base_addr = NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06006153 struct net_device *dev = NULL;
6154 struct ipw2100_priv *priv = NULL;
6155 int err = 0;
6156 int registered = 0;
6157 u32 val;
6158
6159 IPW_DEBUG_INFO("enter\n");
6160
6161 mem_start = pci_resource_start(pci_dev, 0);
6162 mem_len = pci_resource_len(pci_dev, 0);
6163 mem_flags = pci_resource_flags(pci_dev, 0);
6164
6165 if ((mem_flags & IORESOURCE_MEM) != IORESOURCE_MEM) {
6166 IPW_DEBUG_INFO("weird - resource type is not memory\n");
6167 err = -ENODEV;
6168 goto fail;
6169 }
6170
6171 base_addr = ioremap_nocache(mem_start, mem_len);
6172 if (!base_addr) {
6173 printk(KERN_WARNING DRV_NAME
6174 "Error calling ioremap_nocache.\n");
6175 err = -EIO;
6176 goto fail;
6177 }
6178
6179 /* allocate and initialize our net_device */
6180 dev = ipw2100_alloc_device(pci_dev, base_addr, mem_start, mem_len);
6181 if (!dev) {
6182 printk(KERN_WARNING DRV_NAME
6183 "Error calling ipw2100_alloc_device.\n");
6184 err = -ENOMEM;
6185 goto fail;
6186 }
6187
6188 /* set up PCI mappings for device */
6189 err = pci_enable_device(pci_dev);
6190 if (err) {
6191 printk(KERN_WARNING DRV_NAME
6192 "Error calling pci_enable_device.\n");
6193 return err;
6194 }
6195
6196 priv = ieee80211_priv(dev);
6197
6198 pci_set_master(pci_dev);
6199 pci_set_drvdata(pci_dev, priv);
6200
Tobias Klauser05743d12005-06-20 14:28:40 -07006201 err = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK);
James Ketrenos2c86c272005-03-23 17:32:29 -06006202 if (err) {
6203 printk(KERN_WARNING DRV_NAME
6204 "Error calling pci_set_dma_mask.\n");
6205 pci_disable_device(pci_dev);
6206 return err;
6207 }
6208
6209 err = pci_request_regions(pci_dev, DRV_NAME);
6210 if (err) {
6211 printk(KERN_WARNING DRV_NAME
6212 "Error calling pci_request_regions.\n");
6213 pci_disable_device(pci_dev);
6214 return err;
6215 }
6216
James Ketrenosee8e3652005-09-14 09:47:29 -05006217 /* We disable the RETRY_TIMEOUT register (0x41) to keep
James Ketrenos2c86c272005-03-23 17:32:29 -06006218 * PCI Tx retries from interfering with C3 CPU state */
6219 pci_read_config_dword(pci_dev, 0x40, &val);
6220 if ((val & 0x0000ff00) != 0)
6221 pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
6222
Pavel Machek8724a112005-06-20 14:28:43 -07006223 pci_set_power_state(pci_dev, PCI_D0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006224
6225 if (!ipw2100_hw_is_adapter_in_system(dev)) {
6226 printk(KERN_WARNING DRV_NAME
6227 "Device not found via register read.\n");
6228 err = -ENODEV;
6229 goto fail;
6230 }
6231
6232 SET_NETDEV_DEV(dev, &pci_dev->dev);
6233
6234 /* Force interrupts to be shut off on the device */
6235 priv->status |= STATUS_INT_ENABLED;
6236 ipw2100_disable_interrupts(priv);
6237
6238 /* Allocate and initialize the Tx/Rx queues and lists */
6239 if (ipw2100_queues_allocate(priv)) {
6240 printk(KERN_WARNING DRV_NAME
Zhu Yi90c009a2006-12-05 14:41:32 +08006241 "Error calling ipw2100_queues_allocate.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06006242 err = -ENOMEM;
6243 goto fail;
6244 }
6245 ipw2100_queues_initialize(priv);
6246
6247 err = request_irq(pci_dev->irq,
Thomas Gleixner1fb9df52006-07-01 19:29:39 -07006248 ipw2100_interrupt, IRQF_SHARED, dev->name, priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006249 if (err) {
6250 printk(KERN_WARNING DRV_NAME
James Ketrenosee8e3652005-09-14 09:47:29 -05006251 "Error calling request_irq: %d.\n", pci_dev->irq);
James Ketrenos2c86c272005-03-23 17:32:29 -06006252 goto fail;
6253 }
6254 dev->irq = pci_dev->irq;
6255
6256 IPW_DEBUG_INFO("Attempting to register device...\n");
6257
James Ketrenos2c86c272005-03-23 17:32:29 -06006258 printk(KERN_INFO DRV_NAME
6259 ": Detected Intel PRO/Wireless 2100 Network Connection\n");
6260
6261 /* Bring up the interface. Pre 0.46, after we registered the
6262 * network device we would call ipw2100_up. This introduced a race
6263 * condition with newer hotplug configurations (network was coming
6264 * up and making calls before the device was initialized).
6265 *
6266 * If we called ipw2100_up before we registered the device, then the
6267 * device name wasn't registered. So, we instead use the net_dev->init
6268 * member to call a function that then just turns and calls ipw2100_up.
6269 * net_dev->init is called after name allocation but before the
6270 * notifier chain is called */
James Ketrenos2c86c272005-03-23 17:32:29 -06006271 err = register_netdev(dev);
6272 if (err) {
6273 printk(KERN_WARNING DRV_NAME
6274 "Error calling register_netdev.\n");
Zhu Yiefbd8092006-08-21 11:38:52 +08006275 goto fail;
James Ketrenos2c86c272005-03-23 17:32:29 -06006276 }
Zhu Yiefbd8092006-08-21 11:38:52 +08006277
6278 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006279 registered = 1;
6280
6281 IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
6282
6283 /* perform this after register_netdev so that dev->name is set */
Jeff Garzikde897882006-10-01 07:31:09 -04006284 err = sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
6285 if (err)
6286 goto fail_unlock;
James Ketrenos2c86c272005-03-23 17:32:29 -06006287
6288 /* If the RF Kill switch is disabled, go ahead and complete the
6289 * startup sequence */
6290 if (!(priv->status & STATUS_RF_KILL_MASK)) {
6291 /* Enable the adapter - sends HOST_COMPLETE */
6292 if (ipw2100_enable_adapter(priv)) {
6293 printk(KERN_WARNING DRV_NAME
6294 ": %s: failed in call to enable adapter.\n",
6295 priv->net_dev->name);
6296 ipw2100_hw_stop_adapter(priv);
6297 err = -EIO;
6298 goto fail_unlock;
6299 }
6300
6301 /* Start a scan . . . */
6302 ipw2100_set_scan_options(priv);
6303 ipw2100_start_scan(priv);
6304 }
6305
6306 IPW_DEBUG_INFO("exit\n");
6307
6308 priv->status |= STATUS_INITIALIZED;
6309
Ingo Molnar752e3772006-02-28 07:20:54 +08006310 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006311
6312 return 0;
6313
James Ketrenosee8e3652005-09-14 09:47:29 -05006314 fail_unlock:
Ingo Molnar752e3772006-02-28 07:20:54 +08006315 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006316
James Ketrenosee8e3652005-09-14 09:47:29 -05006317 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06006318 if (dev) {
6319 if (registered)
6320 unregister_netdev(dev);
6321
6322 ipw2100_hw_stop_adapter(priv);
6323
6324 ipw2100_disable_interrupts(priv);
6325
6326 if (dev->irq)
6327 free_irq(dev->irq, priv);
6328
6329 ipw2100_kill_workqueue(priv);
6330
6331 /* These are safe to call even if they weren't allocated */
6332 ipw2100_queues_free(priv);
James Ketrenosee8e3652005-09-14 09:47:29 -05006333 sysfs_remove_group(&pci_dev->dev.kobj,
6334 &ipw2100_attribute_group);
James Ketrenos2c86c272005-03-23 17:32:29 -06006335
6336 free_ieee80211(dev);
6337 pci_set_drvdata(pci_dev, NULL);
6338 }
6339
6340 if (base_addr)
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01006341 iounmap(base_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06006342
6343 pci_release_regions(pci_dev);
6344 pci_disable_device(pci_dev);
6345
6346 return err;
6347}
6348
6349static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
6350{
6351 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6352 struct net_device *dev;
6353
6354 if (priv) {
Ingo Molnar752e3772006-02-28 07:20:54 +08006355 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006356
6357 priv->status &= ~STATUS_INITIALIZED;
6358
6359 dev = priv->net_dev;
James Ketrenosee8e3652005-09-14 09:47:29 -05006360 sysfs_remove_group(&pci_dev->dev.kobj,
6361 &ipw2100_attribute_group);
James Ketrenos2c86c272005-03-23 17:32:29 -06006362
6363#ifdef CONFIG_PM
6364 if (ipw2100_firmware.version)
6365 ipw2100_release_firmware(priv, &ipw2100_firmware);
6366#endif
6367 /* Take down the hardware */
6368 ipw2100_down(priv);
6369
Ingo Molnar752e3772006-02-28 07:20:54 +08006370 /* Release the mutex so that the network subsystem can
James Ketrenos2c86c272005-03-23 17:32:29 -06006371 * complete any needed calls into the driver... */
Ingo Molnar752e3772006-02-28 07:20:54 +08006372 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006373
6374 /* Unregister the device first - this results in close()
6375 * being called if the device is open. If we free storage
6376 * first, then close() will crash. */
6377 unregister_netdev(dev);
6378
6379 /* ipw2100_down will ensure that there is no more pending work
6380 * in the workqueue's, so we can safely remove them now. */
6381 ipw2100_kill_workqueue(priv);
6382
6383 ipw2100_queues_free(priv);
6384
6385 /* Free potential debugging firmware snapshot */
6386 ipw2100_snapshot_free(priv);
6387
6388 if (dev->irq)
6389 free_irq(dev->irq, priv);
6390
6391 if (dev->base_addr)
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01006392 iounmap((void __iomem *)dev->base_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06006393
6394 free_ieee80211(dev);
6395 }
6396
6397 pci_release_regions(pci_dev);
6398 pci_disable_device(pci_dev);
6399
6400 IPW_DEBUG_INFO("exit\n");
6401}
6402
James Ketrenos2c86c272005-03-23 17:32:29 -06006403#ifdef CONFIG_PM
James Ketrenos2c86c272005-03-23 17:32:29 -06006404static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state)
James Ketrenos2c86c272005-03-23 17:32:29 -06006405{
6406 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6407 struct net_device *dev = priv->net_dev;
6408
James Ketrenosee8e3652005-09-14 09:47:29 -05006409 IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06006410
Ingo Molnar752e3772006-02-28 07:20:54 +08006411 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006412 if (priv->status & STATUS_INITIALIZED) {
6413 /* Take down the device; powers it off, etc. */
6414 ipw2100_down(priv);
6415 }
6416
6417 /* Remove the PRESENT state of the device */
6418 netif_device_detach(dev);
6419
James Ketrenos2c86c272005-03-23 17:32:29 -06006420 pci_save_state(pci_dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05006421 pci_disable_device(pci_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006422 pci_set_power_state(pci_dev, PCI_D3hot);
James Ketrenos2c86c272005-03-23 17:32:29 -06006423
Dan Williamsc3d72b92009-02-11 13:26:06 -05006424 priv->suspend_at = get_seconds();
6425
Ingo Molnar752e3772006-02-28 07:20:54 +08006426 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006427
6428 return 0;
6429}
6430
6431static int ipw2100_resume(struct pci_dev *pci_dev)
6432{
6433 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6434 struct net_device *dev = priv->net_dev;
John W. Linville02e0e5e2006-11-07 20:53:48 -05006435 int err;
James Ketrenos2c86c272005-03-23 17:32:29 -06006436 u32 val;
6437
6438 if (IPW2100_PM_DISABLED)
6439 return 0;
6440
Ingo Molnar752e3772006-02-28 07:20:54 +08006441 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006442
James Ketrenosee8e3652005-09-14 09:47:29 -05006443 IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06006444
James Ketrenos2c86c272005-03-23 17:32:29 -06006445 pci_set_power_state(pci_dev, PCI_D0);
John W. Linville02e0e5e2006-11-07 20:53:48 -05006446 err = pci_enable_device(pci_dev);
6447 if (err) {
6448 printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
6449 dev->name);
Julia Lawall80c42af2008-07-21 09:58:11 +02006450 mutex_unlock(&priv->action_mutex);
John W. Linville02e0e5e2006-11-07 20:53:48 -05006451 return err;
6452 }
James Ketrenos2c86c272005-03-23 17:32:29 -06006453 pci_restore_state(pci_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006454
6455 /*
6456 * Suspend/Resume resets the PCI configuration space, so we have to
6457 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
6458 * from interfering with C3 CPU state. pci_restore_state won't help
6459 * here since it only restores the first 64 bytes pci config header.
6460 */
6461 pci_read_config_dword(pci_dev, 0x40, &val);
6462 if ((val & 0x0000ff00) != 0)
6463 pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
6464
6465 /* Set the device back into the PRESENT state; this will also wake
6466 * the queue of needed */
6467 netif_device_attach(dev);
6468
Dan Williamsc3d72b92009-02-11 13:26:06 -05006469 priv->suspend_time = get_seconds() - priv->suspend_at;
6470
James Ketrenosee8e3652005-09-14 09:47:29 -05006471 /* Bring the device back up */
6472 if (!(priv->status & STATUS_RF_KILL_SW))
6473 ipw2100_up(priv, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006474
Ingo Molnar752e3772006-02-28 07:20:54 +08006475 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006476
6477 return 0;
6478}
6479#endif
6480
James Ketrenos2c86c272005-03-23 17:32:29 -06006481#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
6482
6483static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = {
James Ketrenosee8e3652005-09-14 09:47:29 -05006484 IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
6485 IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
6486 IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
6487 IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
6488 IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
6489 IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
6490 IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
6491 IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
6492 IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
6493 IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
6494 IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
6495 IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
6496 IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
James Ketrenos2c86c272005-03-23 17:32:29 -06006497
James Ketrenosee8e3652005-09-14 09:47:29 -05006498 IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
6499 IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
6500 IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
6501 IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
6502 IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006503
James Ketrenosee8e3652005-09-14 09:47:29 -05006504 IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
6505 IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
6506 IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
6507 IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
6508 IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
6509 IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
6510 IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
James Ketrenos2c86c272005-03-23 17:32:29 -06006511
James Ketrenosee8e3652005-09-14 09:47:29 -05006512 IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006513
James Ketrenosee8e3652005-09-14 09:47:29 -05006514 IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
6515 IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
6516 IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
6517 IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
6518 IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
6519 IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
6520 IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006521
James Ketrenosee8e3652005-09-14 09:47:29 -05006522 IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
6523 IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
6524 IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
6525 IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
6526 IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
6527 IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006528
James Ketrenosee8e3652005-09-14 09:47:29 -05006529 IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006530 {0,},
6531};
6532
6533MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table);
6534
6535static struct pci_driver ipw2100_pci_driver = {
6536 .name = DRV_NAME,
6537 .id_table = ipw2100_pci_id_table,
6538 .probe = ipw2100_pci_init_one,
6539 .remove = __devexit_p(ipw2100_pci_remove_one),
6540#ifdef CONFIG_PM
6541 .suspend = ipw2100_suspend,
6542 .resume = ipw2100_resume,
6543#endif
6544};
6545
James Ketrenos2c86c272005-03-23 17:32:29 -06006546/**
6547 * Initialize the ipw2100 driver/module
6548 *
6549 * @returns 0 if ok, < 0 errno node con error.
6550 *
6551 * Note: we cannot init the /proc stuff until the PCI driver is there,
6552 * or we risk an unlikely race condition on someone accessing
6553 * uninitialized data in the PCI dev struct through /proc.
6554 */
6555static int __init ipw2100_init(void)
6556{
6557 int ret;
6558
6559 printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
6560 printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
6561
Jeff Garzik29917622006-08-19 17:48:59 -04006562 ret = pci_register_driver(&ipw2100_pci_driver);
Jeff Garzikde897882006-10-01 07:31:09 -04006563 if (ret)
6564 goto out;
James Ketrenos2c86c272005-03-23 17:32:29 -06006565
Mark Grossf011e2e2008-02-04 22:30:09 -08006566 pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100",
6567 PM_QOS_DEFAULT_VALUE);
Brice Goglin0f52bf92005-12-01 01:41:46 -08006568#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06006569 ipw2100_debug_level = debug;
Jeff Garzikde897882006-10-01 07:31:09 -04006570 ret = driver_create_file(&ipw2100_pci_driver.driver,
6571 &driver_attr_debug_level);
James Ketrenos2c86c272005-03-23 17:32:29 -06006572#endif
6573
Jeff Garzikde897882006-10-01 07:31:09 -04006574out:
James Ketrenos2c86c272005-03-23 17:32:29 -06006575 return ret;
6576}
6577
James Ketrenos2c86c272005-03-23 17:32:29 -06006578/**
6579 * Cleanup ipw2100 driver registration
6580 */
6581static void __exit ipw2100_exit(void)
6582{
6583 /* FIXME: IPG: check that we have no instances of the devices open */
Brice Goglin0f52bf92005-12-01 01:41:46 -08006584#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06006585 driver_remove_file(&ipw2100_pci_driver.driver,
6586 &driver_attr_debug_level);
6587#endif
6588 pci_unregister_driver(&ipw2100_pci_driver);
Mark Grossf011e2e2008-02-04 22:30:09 -08006589 pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100");
James Ketrenos2c86c272005-03-23 17:32:29 -06006590}
6591
6592module_init(ipw2100_init);
6593module_exit(ipw2100_exit);
6594
6595#define WEXT_USECHANNELS 1
6596
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006597static const long ipw2100_frequencies[] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006598 2412, 2417, 2422, 2427,
6599 2432, 2437, 2442, 2447,
6600 2452, 2457, 2462, 2467,
6601 2472, 2484
6602};
6603
Alejandro Martinez Ruizc00acf42007-10-18 10:16:33 +02006604#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies)
James Ketrenos2c86c272005-03-23 17:32:29 -06006605
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006606static const long ipw2100_rates_11b[] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006607 1000000,
6608 2000000,
6609 5500000,
6610 11000000
6611};
6612
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02006613#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b)
James Ketrenos2c86c272005-03-23 17:32:29 -06006614
6615static int ipw2100_wx_get_name(struct net_device *dev,
6616 struct iw_request_info *info,
6617 union iwreq_data *wrqu, char *extra)
6618{
6619 /*
6620 * This can be called at any time. No action lock required
6621 */
6622
6623 struct ipw2100_priv *priv = ieee80211_priv(dev);
6624 if (!(priv->status & STATUS_ASSOCIATED))
6625 strcpy(wrqu->name, "unassociated");
6626 else
6627 snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
6628
6629 IPW_DEBUG_WX("Name: %s\n", wrqu->name);
6630 return 0;
6631}
6632
James Ketrenos2c86c272005-03-23 17:32:29 -06006633static int ipw2100_wx_set_freq(struct net_device *dev,
6634 struct iw_request_info *info,
6635 union iwreq_data *wrqu, char *extra)
6636{
6637 struct ipw2100_priv *priv = ieee80211_priv(dev);
6638 struct iw_freq *fwrq = &wrqu->freq;
6639 int err = 0;
6640
6641 if (priv->ieee->iw_mode == IW_MODE_INFRA)
6642 return -EOPNOTSUPP;
6643
Ingo Molnar752e3772006-02-28 07:20:54 +08006644 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006645 if (!(priv->status & STATUS_INITIALIZED)) {
6646 err = -EIO;
6647 goto done;
6648 }
6649
6650 /* if setting by freq convert to channel */
6651 if (fwrq->e == 1) {
James Ketrenosee8e3652005-09-14 09:47:29 -05006652 if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006653 int f = fwrq->m / 100000;
6654 int c = 0;
6655
6656 while ((c < REG_MAX_CHANNEL) &&
6657 (f != ipw2100_frequencies[c]))
6658 c++;
6659
6660 /* hack to fall through */
6661 fwrq->e = 0;
6662 fwrq->m = c + 1;
6663 }
6664 }
6665
James Ketrenos82328352005-08-24 22:33:31 -05006666 if (fwrq->e > 0 || fwrq->m > 1000) {
6667 err = -EOPNOTSUPP;
6668 goto done;
6669 } else { /* Set the channel */
James Ketrenos2c86c272005-03-23 17:32:29 -06006670 IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
6671 err = ipw2100_set_channel(priv, fwrq->m, 0);
6672 }
6673
James Ketrenosee8e3652005-09-14 09:47:29 -05006674 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006675 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006676 return err;
6677}
6678
James Ketrenos2c86c272005-03-23 17:32:29 -06006679static int ipw2100_wx_get_freq(struct net_device *dev,
6680 struct iw_request_info *info,
6681 union iwreq_data *wrqu, char *extra)
6682{
6683 /*
6684 * This can be called at any time. No action lock required
6685 */
6686
6687 struct ipw2100_priv *priv = ieee80211_priv(dev);
6688
6689 wrqu->freq.e = 0;
6690
6691 /* If we are associated, trying to associate, or have a statically
6692 * configured CHANNEL then return that; otherwise return ANY */
6693 if (priv->config & CFG_STATIC_CHANNEL ||
6694 priv->status & STATUS_ASSOCIATED)
6695 wrqu->freq.m = priv->channel;
6696 else
6697 wrqu->freq.m = 0;
6698
6699 IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
6700 return 0;
6701
6702}
6703
6704static int ipw2100_wx_set_mode(struct net_device *dev,
6705 struct iw_request_info *info,
6706 union iwreq_data *wrqu, char *extra)
6707{
6708 struct ipw2100_priv *priv = ieee80211_priv(dev);
6709 int err = 0;
6710
6711 IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode);
6712
6713 if (wrqu->mode == priv->ieee->iw_mode)
6714 return 0;
6715
Ingo Molnar752e3772006-02-28 07:20:54 +08006716 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006717 if (!(priv->status & STATUS_INITIALIZED)) {
6718 err = -EIO;
6719 goto done;
6720 }
6721
6722 switch (wrqu->mode) {
6723#ifdef CONFIG_IPW2100_MONITOR
6724 case IW_MODE_MONITOR:
6725 err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
6726 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05006727#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06006728 case IW_MODE_ADHOC:
6729 err = ipw2100_switch_mode(priv, IW_MODE_ADHOC);
6730 break;
6731 case IW_MODE_INFRA:
6732 case IW_MODE_AUTO:
6733 default:
6734 err = ipw2100_switch_mode(priv, IW_MODE_INFRA);
6735 break;
6736 }
6737
James Ketrenosee8e3652005-09-14 09:47:29 -05006738 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006739 mutex_unlock(&priv->action_mutex);
James Ketrenosee8e3652005-09-14 09:47:29 -05006740 return err;
James Ketrenos2c86c272005-03-23 17:32:29 -06006741}
6742
6743static int ipw2100_wx_get_mode(struct net_device *dev,
6744 struct iw_request_info *info,
6745 union iwreq_data *wrqu, char *extra)
6746{
6747 /*
6748 * This can be called at any time. No action lock required
6749 */
6750
6751 struct ipw2100_priv *priv = ieee80211_priv(dev);
6752
6753 wrqu->mode = priv->ieee->iw_mode;
6754 IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode);
6755
6756 return 0;
6757}
6758
James Ketrenos2c86c272005-03-23 17:32:29 -06006759#define POWER_MODES 5
6760
6761/* Values are in microsecond */
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006762static const s32 timeout_duration[POWER_MODES] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006763 350000,
6764 250000,
6765 75000,
6766 37000,
6767 25000,
6768};
6769
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006770static const s32 period_duration[POWER_MODES] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006771 400000,
6772 700000,
6773 1000000,
6774 1000000,
6775 1000000
6776};
6777
6778static int ipw2100_wx_get_range(struct net_device *dev,
6779 struct iw_request_info *info,
6780 union iwreq_data *wrqu, char *extra)
6781{
6782 /*
6783 * This can be called at any time. No action lock required
6784 */
6785
6786 struct ipw2100_priv *priv = ieee80211_priv(dev);
6787 struct iw_range *range = (struct iw_range *)extra;
6788 u16 val;
6789 int i, level;
6790
6791 wrqu->data.length = sizeof(*range);
6792 memset(range, 0, sizeof(*range));
6793
6794 /* Let's try to keep this struct in the same order as in
6795 * linux/include/wireless.h
6796 */
6797
6798 /* TODO: See what values we can set, and remove the ones we can't
6799 * set, or fill them with some default data.
6800 */
6801
6802 /* ~5 Mb/s real (802.11b) */
6803 range->throughput = 5 * 1000 * 1000;
6804
James Ketrenosee8e3652005-09-14 09:47:29 -05006805// range->sensitivity; /* signal level threshold range */
James Ketrenos2c86c272005-03-23 17:32:29 -06006806
6807 range->max_qual.qual = 100;
6808 /* TODO: Find real max RSSI and stick here */
6809 range->max_qual.level = 0;
6810 range->max_qual.noise = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05006811 range->max_qual.updated = 7; /* Updated all three */
James Ketrenos2c86c272005-03-23 17:32:29 -06006812
James Ketrenosee8e3652005-09-14 09:47:29 -05006813 range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
James Ketrenos2c86c272005-03-23 17:32:29 -06006814 /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
6815 range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
6816 range->avg_qual.noise = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05006817 range->avg_qual.updated = 7; /* Updated all three */
James Ketrenos2c86c272005-03-23 17:32:29 -06006818
6819 range->num_bitrates = RATE_COUNT;
6820
6821 for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
6822 range->bitrate[i] = ipw2100_rates_11b[i];
6823 }
6824
6825 range->min_rts = MIN_RTS_THRESHOLD;
6826 range->max_rts = MAX_RTS_THRESHOLD;
6827 range->min_frag = MIN_FRAG_THRESHOLD;
6828 range->max_frag = MAX_FRAG_THRESHOLD;
6829
6830 range->min_pmp = period_duration[0]; /* Minimal PM period */
James Ketrenosee8e3652005-09-14 09:47:29 -05006831 range->max_pmp = period_duration[POWER_MODES - 1]; /* Maximal PM period */
6832 range->min_pmt = timeout_duration[POWER_MODES - 1]; /* Minimal PM timeout */
6833 range->max_pmt = timeout_duration[0]; /* Maximal PM timeout */
James Ketrenos2c86c272005-03-23 17:32:29 -06006834
James Ketrenosee8e3652005-09-14 09:47:29 -05006835 /* How to decode max/min PM period */
James Ketrenos2c86c272005-03-23 17:32:29 -06006836 range->pmp_flags = IW_POWER_PERIOD;
James Ketrenosee8e3652005-09-14 09:47:29 -05006837 /* How to decode max/min PM period */
James Ketrenos2c86c272005-03-23 17:32:29 -06006838 range->pmt_flags = IW_POWER_TIMEOUT;
6839 /* What PM options are supported */
6840 range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD;
6841
6842 range->encoding_size[0] = 5;
James Ketrenosee8e3652005-09-14 09:47:29 -05006843 range->encoding_size[1] = 13; /* Different token sizes */
6844 range->num_encoding_sizes = 2; /* Number of entry in the list */
6845 range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */
6846// range->encoding_login_index; /* token index for login token */
James Ketrenos2c86c272005-03-23 17:32:29 -06006847
6848 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
6849 range->txpower_capa = IW_TXPOW_DBM;
6850 range->num_txpower = IW_MAX_TXPOWER;
James Ketrenosee8e3652005-09-14 09:47:29 -05006851 for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16);
6852 i < IW_MAX_TXPOWER;
6853 i++, level -=
6854 ((IPW_TX_POWER_MAX_DBM -
6855 IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1))
James Ketrenos2c86c272005-03-23 17:32:29 -06006856 range->txpower[i] = level / 16;
6857 } else {
6858 range->txpower_capa = 0;
6859 range->num_txpower = 0;
6860 }
6861
James Ketrenos2c86c272005-03-23 17:32:29 -06006862 /* Set the Wireless Extension versions */
6863 range->we_version_compiled = WIRELESS_EXT;
Dan Williams166c3432006-01-09 11:04:31 -05006864 range->we_version_source = 18;
James Ketrenos2c86c272005-03-23 17:32:29 -06006865
James Ketrenosee8e3652005-09-14 09:47:29 -05006866// range->retry_capa; /* What retry options are supported */
6867// range->retry_flags; /* How to decode max/min retry limit */
6868// range->r_time_flags; /* How to decode max/min retry life */
6869// range->min_retry; /* Minimal number of retries */
6870// range->max_retry; /* Maximal number of retries */
6871// range->min_r_time; /* Minimal retry lifetime */
6872// range->max_r_time; /* Maximal retry lifetime */
James Ketrenos2c86c272005-03-23 17:32:29 -06006873
James Ketrenosee8e3652005-09-14 09:47:29 -05006874 range->num_channels = FREQ_COUNT;
James Ketrenos2c86c272005-03-23 17:32:29 -06006875
6876 val = 0;
6877 for (i = 0; i < FREQ_COUNT; i++) {
6878 // TODO: Include only legal frequencies for some countries
James Ketrenosee8e3652005-09-14 09:47:29 -05006879// if (local->channel_mask & (1 << i)) {
6880 range->freq[val].i = i + 1;
6881 range->freq[val].m = ipw2100_frequencies[i] * 100000;
6882 range->freq[val].e = 1;
6883 val++;
6884// }
James Ketrenos2c86c272005-03-23 17:32:29 -06006885 if (val == IW_MAX_FREQUENCIES)
James Ketrenosee8e3652005-09-14 09:47:29 -05006886 break;
James Ketrenos2c86c272005-03-23 17:32:29 -06006887 }
6888 range->num_frequency = val;
6889
James Ketrenoseaf8f532005-11-12 12:50:12 -06006890 /* Event capability (kernel + driver) */
6891 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
6892 IW_EVENT_CAPA_MASK(SIOCGIWAP));
6893 range->event_capa[1] = IW_EVENT_CAPA_K_1;
6894
Dan Williams166c3432006-01-09 11:04:31 -05006895 range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
6896 IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
6897
James Ketrenos2c86c272005-03-23 17:32:29 -06006898 IPW_DEBUG_WX("GET Range\n");
6899
6900 return 0;
6901}
6902
6903static int ipw2100_wx_set_wap(struct net_device *dev,
6904 struct iw_request_info *info,
6905 union iwreq_data *wrqu, char *extra)
6906{
6907 struct ipw2100_priv *priv = ieee80211_priv(dev);
6908 int err = 0;
6909
6910 static const unsigned char any[] = {
6911 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
6912 };
6913 static const unsigned char off[] = {
6914 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6915 };
6916
6917 // sanity checks
6918 if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
6919 return -EINVAL;
6920
Ingo Molnar752e3772006-02-28 07:20:54 +08006921 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006922 if (!(priv->status & STATUS_INITIALIZED)) {
6923 err = -EIO;
6924 goto done;
6925 }
6926
6927 if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
6928 !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
6929 /* we disable mandatory BSSID association */
6930 IPW_DEBUG_WX("exit - disable mandatory BSSID\n");
6931 priv->config &= ~CFG_STATIC_BSSID;
6932 err = ipw2100_set_mandatory_bssid(priv, NULL, 0);
6933 goto done;
6934 }
6935
6936 priv->config |= CFG_STATIC_BSSID;
6937 memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN);
6938
6939 err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
6940
Johannes Berge1749612008-10-27 15:59:26 -07006941 IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data);
James Ketrenos2c86c272005-03-23 17:32:29 -06006942
James Ketrenosee8e3652005-09-14 09:47:29 -05006943 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006944 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006945 return err;
6946}
6947
6948static int ipw2100_wx_get_wap(struct net_device *dev,
6949 struct iw_request_info *info,
6950 union iwreq_data *wrqu, char *extra)
6951{
6952 /*
6953 * This can be called at any time. No action lock required
6954 */
6955
6956 struct ipw2100_priv *priv = ieee80211_priv(dev);
6957
6958 /* If we are associated, trying to associate, or have a statically
6959 * configured BSSID then return that; otherwise return ANY */
James Ketrenosee8e3652005-09-14 09:47:29 -05006960 if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006961 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
James Ketrenos82328352005-08-24 22:33:31 -05006962 memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06006963 } else
6964 memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
6965
Johannes Berge1749612008-10-27 15:59:26 -07006966 IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data);
James Ketrenos2c86c272005-03-23 17:32:29 -06006967 return 0;
6968}
6969
6970static int ipw2100_wx_set_essid(struct net_device *dev,
6971 struct iw_request_info *info,
6972 union iwreq_data *wrqu, char *extra)
6973{
6974 struct ipw2100_priv *priv = ieee80211_priv(dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05006975 char *essid = ""; /* ANY */
James Ketrenos2c86c272005-03-23 17:32:29 -06006976 int length = 0;
6977 int err = 0;
John W. Linville9387b7c2008-09-30 20:59:05 -04006978 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06006979
Ingo Molnar752e3772006-02-28 07:20:54 +08006980 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006981 if (!(priv->status & STATUS_INITIALIZED)) {
6982 err = -EIO;
6983 goto done;
6984 }
6985
6986 if (wrqu->essid.flags && wrqu->essid.length) {
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07006987 length = wrqu->essid.length;
James Ketrenos2c86c272005-03-23 17:32:29 -06006988 essid = extra;
6989 }
6990
6991 if (length == 0) {
6992 IPW_DEBUG_WX("Setting ESSID to ANY\n");
6993 priv->config &= ~CFG_STATIC_ESSID;
6994 err = ipw2100_set_essid(priv, NULL, 0, 0);
6995 goto done;
6996 }
6997
6998 length = min(length, IW_ESSID_MAX_SIZE);
6999
7000 priv->config |= CFG_STATIC_ESSID;
7001
7002 if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
7003 IPW_DEBUG_WX("ESSID set to current ESSID.\n");
7004 err = 0;
7005 goto done;
7006 }
7007
John W. Linville9387b7c2008-09-30 20:59:05 -04007008 IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
7009 print_ssid(ssid, essid, length), length);
James Ketrenos2c86c272005-03-23 17:32:29 -06007010
7011 priv->essid_len = length;
7012 memcpy(priv->essid, essid, priv->essid_len);
7013
7014 err = ipw2100_set_essid(priv, essid, length, 0);
7015
James Ketrenosee8e3652005-09-14 09:47:29 -05007016 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007017 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007018 return err;
7019}
7020
7021static int ipw2100_wx_get_essid(struct net_device *dev,
7022 struct iw_request_info *info,
7023 union iwreq_data *wrqu, char *extra)
7024{
7025 /*
7026 * This can be called at any time. No action lock required
7027 */
7028
7029 struct ipw2100_priv *priv = ieee80211_priv(dev);
John W. Linville9387b7c2008-09-30 20:59:05 -04007030 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06007031
7032 /* If we are associated, trying to associate, or have a statically
7033 * configured ESSID then return that; otherwise return ANY */
James Ketrenosee8e3652005-09-14 09:47:29 -05007034 if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007035 IPW_DEBUG_WX("Getting essid: '%s'\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04007036 print_ssid(ssid, priv->essid, priv->essid_len));
James Ketrenos2c86c272005-03-23 17:32:29 -06007037 memcpy(extra, priv->essid, priv->essid_len);
7038 wrqu->essid.length = priv->essid_len;
James Ketrenosee8e3652005-09-14 09:47:29 -05007039 wrqu->essid.flags = 1; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007040 } else {
7041 IPW_DEBUG_WX("Getting essid: ANY\n");
7042 wrqu->essid.length = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05007043 wrqu->essid.flags = 0; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007044 }
7045
7046 return 0;
7047}
7048
7049static int ipw2100_wx_set_nick(struct net_device *dev,
7050 struct iw_request_info *info,
7051 union iwreq_data *wrqu, char *extra)
7052{
7053 /*
7054 * This can be called at any time. No action lock required
7055 */
7056
7057 struct ipw2100_priv *priv = ieee80211_priv(dev);
7058
7059 if (wrqu->data.length > IW_ESSID_MAX_SIZE)
7060 return -E2BIG;
7061
James Ketrenosee8e3652005-09-14 09:47:29 -05007062 wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
James Ketrenos2c86c272005-03-23 17:32:29 -06007063 memset(priv->nick, 0, sizeof(priv->nick));
James Ketrenosee8e3652005-09-14 09:47:29 -05007064 memcpy(priv->nick, extra, wrqu->data.length);
James Ketrenos2c86c272005-03-23 17:32:29 -06007065
7066 IPW_DEBUG_WX("SET Nickname -> %s \n", priv->nick);
7067
7068 return 0;
7069}
7070
7071static int ipw2100_wx_get_nick(struct net_device *dev,
7072 struct iw_request_info *info,
7073 union iwreq_data *wrqu, char *extra)
7074{
7075 /*
7076 * This can be called at any time. No action lock required
7077 */
7078
7079 struct ipw2100_priv *priv = ieee80211_priv(dev);
7080
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007081 wrqu->data.length = strlen(priv->nick);
James Ketrenos2c86c272005-03-23 17:32:29 -06007082 memcpy(extra, priv->nick, wrqu->data.length);
James Ketrenosee8e3652005-09-14 09:47:29 -05007083 wrqu->data.flags = 1; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007084
7085 IPW_DEBUG_WX("GET Nickname -> %s \n", extra);
7086
7087 return 0;
7088}
7089
7090static int ipw2100_wx_set_rate(struct net_device *dev,
7091 struct iw_request_info *info,
7092 union iwreq_data *wrqu, char *extra)
7093{
7094 struct ipw2100_priv *priv = ieee80211_priv(dev);
7095 u32 target_rate = wrqu->bitrate.value;
7096 u32 rate;
7097 int err = 0;
7098
Ingo Molnar752e3772006-02-28 07:20:54 +08007099 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007100 if (!(priv->status & STATUS_INITIALIZED)) {
7101 err = -EIO;
7102 goto done;
7103 }
7104
7105 rate = 0;
7106
7107 if (target_rate == 1000000 ||
7108 (!wrqu->bitrate.fixed && target_rate > 1000000))
7109 rate |= TX_RATE_1_MBIT;
7110 if (target_rate == 2000000 ||
7111 (!wrqu->bitrate.fixed && target_rate > 2000000))
7112 rate |= TX_RATE_2_MBIT;
7113 if (target_rate == 5500000 ||
7114 (!wrqu->bitrate.fixed && target_rate > 5500000))
7115 rate |= TX_RATE_5_5_MBIT;
7116 if (target_rate == 11000000 ||
7117 (!wrqu->bitrate.fixed && target_rate > 11000000))
7118 rate |= TX_RATE_11_MBIT;
7119 if (rate == 0)
7120 rate = DEFAULT_TX_RATES;
7121
7122 err = ipw2100_set_tx_rates(priv, rate, 0);
7123
7124 IPW_DEBUG_WX("SET Rate -> %04X \n", rate);
James Ketrenosee8e3652005-09-14 09:47:29 -05007125 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007126 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007127 return err;
7128}
7129
James Ketrenos2c86c272005-03-23 17:32:29 -06007130static int ipw2100_wx_get_rate(struct net_device *dev,
7131 struct iw_request_info *info,
7132 union iwreq_data *wrqu, char *extra)
7133{
7134 struct ipw2100_priv *priv = ieee80211_priv(dev);
7135 int val;
Hannes Ederb9da9e92009-02-14 11:50:26 +00007136 unsigned int len = sizeof(val);
James Ketrenos2c86c272005-03-23 17:32:29 -06007137 int err = 0;
7138
7139 if (!(priv->status & STATUS_ENABLED) ||
7140 priv->status & STATUS_RF_KILL_MASK ||
7141 !(priv->status & STATUS_ASSOCIATED)) {
7142 wrqu->bitrate.value = 0;
7143 return 0;
7144 }
7145
Ingo Molnar752e3772006-02-28 07:20:54 +08007146 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007147 if (!(priv->status & STATUS_INITIALIZED)) {
7148 err = -EIO;
7149 goto done;
7150 }
7151
7152 err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len);
7153 if (err) {
7154 IPW_DEBUG_WX("failed querying ordinals.\n");
Julia Lawall80c42af2008-07-21 09:58:11 +02007155 goto done;
James Ketrenos2c86c272005-03-23 17:32:29 -06007156 }
7157
7158 switch (val & TX_RATE_MASK) {
7159 case TX_RATE_1_MBIT:
7160 wrqu->bitrate.value = 1000000;
7161 break;
7162 case TX_RATE_2_MBIT:
7163 wrqu->bitrate.value = 2000000;
7164 break;
7165 case TX_RATE_5_5_MBIT:
7166 wrqu->bitrate.value = 5500000;
7167 break;
7168 case TX_RATE_11_MBIT:
7169 wrqu->bitrate.value = 11000000;
7170 break;
7171 default:
7172 wrqu->bitrate.value = 0;
7173 }
7174
7175 IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
7176
James Ketrenosee8e3652005-09-14 09:47:29 -05007177 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007178 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007179 return err;
7180}
7181
7182static int ipw2100_wx_set_rts(struct net_device *dev,
7183 struct iw_request_info *info,
7184 union iwreq_data *wrqu, char *extra)
7185{
7186 struct ipw2100_priv *priv = ieee80211_priv(dev);
7187 int value, err;
7188
7189 /* Auto RTS not yet supported */
7190 if (wrqu->rts.fixed == 0)
7191 return -EINVAL;
7192
Ingo Molnar752e3772006-02-28 07:20:54 +08007193 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007194 if (!(priv->status & STATUS_INITIALIZED)) {
7195 err = -EIO;
7196 goto done;
7197 }
7198
7199 if (wrqu->rts.disabled)
7200 value = priv->rts_threshold | RTS_DISABLED;
7201 else {
James Ketrenosee8e3652005-09-14 09:47:29 -05007202 if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007203 err = -EINVAL;
7204 goto done;
7205 }
7206 value = wrqu->rts.value;
7207 }
7208
7209 err = ipw2100_set_rts_threshold(priv, value);
7210
7211 IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value);
James Ketrenosee8e3652005-09-14 09:47:29 -05007212 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007213 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007214 return err;
7215}
7216
7217static int ipw2100_wx_get_rts(struct net_device *dev,
7218 struct iw_request_info *info,
7219 union iwreq_data *wrqu, char *extra)
7220{
7221 /*
7222 * This can be called at any time. No action lock required
7223 */
7224
7225 struct ipw2100_priv *priv = ieee80211_priv(dev);
7226
7227 wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
James Ketrenosee8e3652005-09-14 09:47:29 -05007228 wrqu->rts.fixed = 1; /* no auto select */
James Ketrenos2c86c272005-03-23 17:32:29 -06007229
7230 /* If RTS is set to the default value, then it is disabled */
7231 wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
7232
7233 IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X \n", wrqu->rts.value);
7234
7235 return 0;
7236}
7237
7238static int ipw2100_wx_set_txpow(struct net_device *dev,
7239 struct iw_request_info *info,
7240 union iwreq_data *wrqu, char *extra)
7241{
7242 struct ipw2100_priv *priv = ieee80211_priv(dev);
7243 int err = 0, value;
Zhu Yib6e4da72006-01-24 13:49:32 +08007244
7245 if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled))
7246 return -EINPROGRESS;
James Ketrenos2c86c272005-03-23 17:32:29 -06007247
7248 if (priv->ieee->iw_mode != IW_MODE_ADHOC)
Zhu Yib6e4da72006-01-24 13:49:32 +08007249 return 0;
7250
7251 if ((wrqu->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
James Ketrenos2c86c272005-03-23 17:32:29 -06007252 return -EINVAL;
7253
Zhu Yib6e4da72006-01-24 13:49:32 +08007254 if (wrqu->txpower.fixed == 0)
James Ketrenos2c86c272005-03-23 17:32:29 -06007255 value = IPW_TX_POWER_DEFAULT;
7256 else {
7257 if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM ||
7258 wrqu->txpower.value > IPW_TX_POWER_MAX_DBM)
7259 return -EINVAL;
7260
Liu Hongf75459e2005-07-13 12:29:21 -05007261 value = wrqu->txpower.value;
James Ketrenos2c86c272005-03-23 17:32:29 -06007262 }
7263
Ingo Molnar752e3772006-02-28 07:20:54 +08007264 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007265 if (!(priv->status & STATUS_INITIALIZED)) {
7266 err = -EIO;
7267 goto done;
7268 }
7269
7270 err = ipw2100_set_tx_power(priv, value);
7271
7272 IPW_DEBUG_WX("SET TX Power -> %d \n", value);
7273
James Ketrenosee8e3652005-09-14 09:47:29 -05007274 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007275 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007276 return err;
7277}
7278
7279static int ipw2100_wx_get_txpow(struct net_device *dev,
7280 struct iw_request_info *info,
7281 union iwreq_data *wrqu, char *extra)
7282{
7283 /*
7284 * This can be called at any time. No action lock required
7285 */
7286
7287 struct ipw2100_priv *priv = ieee80211_priv(dev);
7288
Zhu Yib6e4da72006-01-24 13:49:32 +08007289 wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06007290
7291 if (priv->tx_power == IPW_TX_POWER_DEFAULT) {
Zhu Yib6e4da72006-01-24 13:49:32 +08007292 wrqu->txpower.fixed = 0;
7293 wrqu->txpower.value = IPW_TX_POWER_MAX_DBM;
James Ketrenos2c86c272005-03-23 17:32:29 -06007294 } else {
Zhu Yib6e4da72006-01-24 13:49:32 +08007295 wrqu->txpower.fixed = 1;
7296 wrqu->txpower.value = priv->tx_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06007297 }
7298
Zhu Yib6e4da72006-01-24 13:49:32 +08007299 wrqu->txpower.flags = IW_TXPOW_DBM;
James Ketrenos2c86c272005-03-23 17:32:29 -06007300
Zhu Yib6e4da72006-01-24 13:49:32 +08007301 IPW_DEBUG_WX("GET TX Power -> %d \n", wrqu->txpower.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007302
7303 return 0;
7304}
7305
7306static int ipw2100_wx_set_frag(struct net_device *dev,
7307 struct iw_request_info *info,
7308 union iwreq_data *wrqu, char *extra)
7309{
7310 /*
7311 * This can be called at any time. No action lock required
7312 */
7313
7314 struct ipw2100_priv *priv = ieee80211_priv(dev);
7315
7316 if (!wrqu->frag.fixed)
7317 return -EINVAL;
7318
7319 if (wrqu->frag.disabled) {
7320 priv->frag_threshold |= FRAG_DISABLED;
7321 priv->ieee->fts = DEFAULT_FTS;
7322 } else {
7323 if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
7324 wrqu->frag.value > MAX_FRAG_THRESHOLD)
7325 return -EINVAL;
7326
7327 priv->ieee->fts = wrqu->frag.value & ~0x1;
7328 priv->frag_threshold = priv->ieee->fts;
7329 }
7330
7331 IPW_DEBUG_WX("SET Frag Threshold -> %d \n", priv->ieee->fts);
7332
7333 return 0;
7334}
7335
7336static int ipw2100_wx_get_frag(struct net_device *dev,
7337 struct iw_request_info *info,
7338 union iwreq_data *wrqu, char *extra)
7339{
7340 /*
7341 * This can be called at any time. No action lock required
7342 */
7343
7344 struct ipw2100_priv *priv = ieee80211_priv(dev);
7345 wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED;
7346 wrqu->frag.fixed = 0; /* no auto select */
7347 wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
7348
7349 IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
7350
7351 return 0;
7352}
7353
7354static int ipw2100_wx_set_retry(struct net_device *dev,
7355 struct iw_request_info *info,
7356 union iwreq_data *wrqu, char *extra)
7357{
7358 struct ipw2100_priv *priv = ieee80211_priv(dev);
7359 int err = 0;
7360
James Ketrenosee8e3652005-09-14 09:47:29 -05007361 if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
James Ketrenos2c86c272005-03-23 17:32:29 -06007362 return -EINVAL;
7363
7364 if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
7365 return 0;
7366
Ingo Molnar752e3772006-02-28 07:20:54 +08007367 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007368 if (!(priv->status & STATUS_INITIALIZED)) {
7369 err = -EIO;
7370 goto done;
7371 }
7372
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007373 if (wrqu->retry.flags & IW_RETRY_SHORT) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007374 err = ipw2100_set_short_retry(priv, wrqu->retry.value);
7375 IPW_DEBUG_WX("SET Short Retry Limit -> %d \n",
James Ketrenosee8e3652005-09-14 09:47:29 -05007376 wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007377 goto done;
7378 }
7379
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007380 if (wrqu->retry.flags & IW_RETRY_LONG) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007381 err = ipw2100_set_long_retry(priv, wrqu->retry.value);
7382 IPW_DEBUG_WX("SET Long Retry Limit -> %d \n",
James Ketrenosee8e3652005-09-14 09:47:29 -05007383 wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007384 goto done;
7385 }
7386
7387 err = ipw2100_set_short_retry(priv, wrqu->retry.value);
7388 if (!err)
7389 err = ipw2100_set_long_retry(priv, wrqu->retry.value);
7390
7391 IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value);
7392
James Ketrenosee8e3652005-09-14 09:47:29 -05007393 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007394 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007395 return err;
7396}
7397
7398static int ipw2100_wx_get_retry(struct net_device *dev,
7399 struct iw_request_info *info,
7400 union iwreq_data *wrqu, char *extra)
7401{
7402 /*
7403 * This can be called at any time. No action lock required
7404 */
7405
7406 struct ipw2100_priv *priv = ieee80211_priv(dev);
7407
James Ketrenosee8e3652005-09-14 09:47:29 -05007408 wrqu->retry.disabled = 0; /* can't be disabled */
James Ketrenos2c86c272005-03-23 17:32:29 -06007409
James Ketrenosee8e3652005-09-14 09:47:29 -05007410 if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
James Ketrenos2c86c272005-03-23 17:32:29 -06007411 return -EINVAL;
7412
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007413 if (wrqu->retry.flags & IW_RETRY_LONG) {
7414 wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
James Ketrenos2c86c272005-03-23 17:32:29 -06007415 wrqu->retry.value = priv->long_retry_limit;
7416 } else {
7417 wrqu->retry.flags =
7418 (priv->short_retry_limit !=
7419 priv->long_retry_limit) ?
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007420 IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT;
James Ketrenos2c86c272005-03-23 17:32:29 -06007421
7422 wrqu->retry.value = priv->short_retry_limit;
7423 }
7424
7425 IPW_DEBUG_WX("GET Retry -> %d \n", wrqu->retry.value);
7426
7427 return 0;
7428}
7429
7430static int ipw2100_wx_set_scan(struct net_device *dev,
7431 struct iw_request_info *info,
7432 union iwreq_data *wrqu, char *extra)
7433{
7434 struct ipw2100_priv *priv = ieee80211_priv(dev);
7435 int err = 0;
7436
Ingo Molnar752e3772006-02-28 07:20:54 +08007437 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007438 if (!(priv->status & STATUS_INITIALIZED)) {
7439 err = -EIO;
7440 goto done;
7441 }
7442
7443 IPW_DEBUG_WX("Initiating scan...\n");
Dan Williamsd20c6782007-10-10 12:28:07 -04007444
7445 priv->user_requested_scan = 1;
James Ketrenosee8e3652005-09-14 09:47:29 -05007446 if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007447 IPW_DEBUG_WX("Start scan failed.\n");
7448
7449 /* TODO: Mark a scan as pending so when hardware initialized
7450 * a scan starts */
7451 }
7452
James Ketrenosee8e3652005-09-14 09:47:29 -05007453 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007454 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007455 return err;
7456}
7457
7458static int ipw2100_wx_get_scan(struct net_device *dev,
7459 struct iw_request_info *info,
7460 union iwreq_data *wrqu, char *extra)
7461{
7462 /*
7463 * This can be called at any time. No action lock required
7464 */
7465
7466 struct ipw2100_priv *priv = ieee80211_priv(dev);
7467 return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra);
7468}
7469
James Ketrenos2c86c272005-03-23 17:32:29 -06007470/*
7471 * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c
7472 */
7473static int ipw2100_wx_set_encode(struct net_device *dev,
7474 struct iw_request_info *info,
7475 union iwreq_data *wrqu, char *key)
7476{
7477 /*
7478 * No check of STATUS_INITIALIZED required
7479 */
7480
7481 struct ipw2100_priv *priv = ieee80211_priv(dev);
7482 return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
7483}
7484
7485static int ipw2100_wx_get_encode(struct net_device *dev,
7486 struct iw_request_info *info,
7487 union iwreq_data *wrqu, char *key)
7488{
7489 /*
7490 * This can be called at any time. No action lock required
7491 */
7492
7493 struct ipw2100_priv *priv = ieee80211_priv(dev);
7494 return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key);
7495}
7496
7497static int ipw2100_wx_set_power(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05007498 struct iw_request_info *info,
7499 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007500{
7501 struct ipw2100_priv *priv = ieee80211_priv(dev);
7502 int err = 0;
7503
Ingo Molnar752e3772006-02-28 07:20:54 +08007504 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007505 if (!(priv->status & STATUS_INITIALIZED)) {
7506 err = -EIO;
7507 goto done;
7508 }
7509
7510 if (wrqu->power.disabled) {
7511 priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
7512 err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
7513 IPW_DEBUG_WX("SET Power Management Mode -> off\n");
7514 goto done;
7515 }
7516
7517 switch (wrqu->power.flags & IW_POWER_MODE) {
James Ketrenosee8e3652005-09-14 09:47:29 -05007518 case IW_POWER_ON: /* If not specified */
7519 case IW_POWER_MODE: /* If set all mask */
Jean Delvarec03983a2007-10-19 23:22:55 +02007520 case IW_POWER_ALL_R: /* If explicitly state all */
James Ketrenos2c86c272005-03-23 17:32:29 -06007521 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05007522 default: /* Otherwise we don't support it */
James Ketrenos2c86c272005-03-23 17:32:29 -06007523 IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
7524 wrqu->power.flags);
7525 err = -EOPNOTSUPP;
7526 goto done;
7527 }
7528
7529 /* If the user hasn't specified a power management mode yet, default
7530 * to BATTERY */
7531 priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
7532 err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
7533
James Ketrenosee8e3652005-09-14 09:47:29 -05007534 IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06007535
James Ketrenosee8e3652005-09-14 09:47:29 -05007536 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007537 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007538 return err;
7539
7540}
7541
7542static int ipw2100_wx_get_power(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05007543 struct iw_request_info *info,
7544 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007545{
7546 /*
7547 * This can be called at any time. No action lock required
7548 */
7549
7550 struct ipw2100_priv *priv = ieee80211_priv(dev);
7551
James Ketrenos82328352005-08-24 22:33:31 -05007552 if (!(priv->power_mode & IPW_POWER_ENABLED))
James Ketrenos2c86c272005-03-23 17:32:29 -06007553 wrqu->power.disabled = 1;
James Ketrenos82328352005-08-24 22:33:31 -05007554 else {
James Ketrenos2c86c272005-03-23 17:32:29 -06007555 wrqu->power.disabled = 0;
7556 wrqu->power.flags = 0;
7557 }
7558
7559 IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
7560
7561 return 0;
7562}
7563
James Ketrenos82328352005-08-24 22:33:31 -05007564/*
7565 * WE-18 WPA support
7566 */
7567
7568/* SIOCSIWGENIE */
7569static int ipw2100_wx_set_genie(struct net_device *dev,
7570 struct iw_request_info *info,
7571 union iwreq_data *wrqu, char *extra)
7572{
7573
7574 struct ipw2100_priv *priv = ieee80211_priv(dev);
7575 struct ieee80211_device *ieee = priv->ieee;
7576 u8 *buf;
7577
7578 if (!ieee->wpa_enabled)
7579 return -EOPNOTSUPP;
7580
7581 if (wrqu->data.length > MAX_WPA_IE_LEN ||
7582 (wrqu->data.length && extra == NULL))
7583 return -EINVAL;
7584
7585 if (wrqu->data.length) {
Eric Sesterhennc3a93922006-10-23 22:20:15 +02007586 buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
James Ketrenos82328352005-08-24 22:33:31 -05007587 if (buf == NULL)
7588 return -ENOMEM;
7589
James Ketrenos82328352005-08-24 22:33:31 -05007590 kfree(ieee->wpa_ie);
7591 ieee->wpa_ie = buf;
7592 ieee->wpa_ie_len = wrqu->data.length;
7593 } else {
7594 kfree(ieee->wpa_ie);
7595 ieee->wpa_ie = NULL;
7596 ieee->wpa_ie_len = 0;
7597 }
7598
7599 ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
7600
7601 return 0;
7602}
7603
7604/* SIOCGIWGENIE */
7605static int ipw2100_wx_get_genie(struct net_device *dev,
7606 struct iw_request_info *info,
7607 union iwreq_data *wrqu, char *extra)
7608{
7609 struct ipw2100_priv *priv = ieee80211_priv(dev);
7610 struct ieee80211_device *ieee = priv->ieee;
7611
7612 if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
7613 wrqu->data.length = 0;
7614 return 0;
7615 }
7616
7617 if (wrqu->data.length < ieee->wpa_ie_len)
7618 return -E2BIG;
7619
7620 wrqu->data.length = ieee->wpa_ie_len;
7621 memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
7622
7623 return 0;
7624}
7625
7626/* SIOCSIWAUTH */
7627static int ipw2100_wx_set_auth(struct net_device *dev,
7628 struct iw_request_info *info,
7629 union iwreq_data *wrqu, char *extra)
7630{
7631 struct ipw2100_priv *priv = ieee80211_priv(dev);
7632 struct ieee80211_device *ieee = priv->ieee;
7633 struct iw_param *param = &wrqu->param;
John W. Linville274bfb82008-10-29 11:35:05 -04007634 struct lib80211_crypt_data *crypt;
James Ketrenos82328352005-08-24 22:33:31 -05007635 unsigned long flags;
7636 int ret = 0;
7637
7638 switch (param->flags & IW_AUTH_INDEX) {
7639 case IW_AUTH_WPA_VERSION:
7640 case IW_AUTH_CIPHER_PAIRWISE:
7641 case IW_AUTH_CIPHER_GROUP:
7642 case IW_AUTH_KEY_MGMT:
7643 /*
7644 * ipw2200 does not use these parameters
7645 */
7646 break;
7647
7648 case IW_AUTH_TKIP_COUNTERMEASURES:
John W. Linville274bfb82008-10-29 11:35:05 -04007649 crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
James Ketrenos991d1cc2005-10-13 09:26:48 +00007650 if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
James Ketrenos82328352005-08-24 22:33:31 -05007651 break;
James Ketrenos82328352005-08-24 22:33:31 -05007652
7653 flags = crypt->ops->get_flags(crypt->priv);
7654
7655 if (param->value)
7656 flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
7657 else
7658 flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
7659
7660 crypt->ops->set_flags(flags, crypt->priv);
7661
7662 break;
7663
7664 case IW_AUTH_DROP_UNENCRYPTED:{
7665 /* HACK:
7666 *
7667 * wpa_supplicant calls set_wpa_enabled when the driver
7668 * is loaded and unloaded, regardless of if WPA is being
7669 * used. No other calls are made which can be used to
7670 * determine if encryption will be used or not prior to
7671 * association being expected. If encryption is not being
7672 * used, drop_unencrypted is set to false, else true -- we
7673 * can use this to determine if the CAP_PRIVACY_ON bit should
7674 * be set.
7675 */
7676 struct ieee80211_security sec = {
7677 .flags = SEC_ENABLED,
7678 .enabled = param->value,
7679 };
7680 priv->ieee->drop_unencrypted = param->value;
7681 /* We only change SEC_LEVEL for open mode. Others
7682 * are set by ipw_wpa_set_encryption.
7683 */
7684 if (!param->value) {
7685 sec.flags |= SEC_LEVEL;
7686 sec.level = SEC_LEVEL_0;
7687 } else {
7688 sec.flags |= SEC_LEVEL;
7689 sec.level = SEC_LEVEL_1;
7690 }
7691 if (priv->ieee->set_security)
7692 priv->ieee->set_security(priv->ieee->dev, &sec);
7693 break;
7694 }
7695
7696 case IW_AUTH_80211_AUTH_ALG:
7697 ret = ipw2100_wpa_set_auth_algs(priv, param->value);
7698 break;
7699
7700 case IW_AUTH_WPA_ENABLED:
7701 ret = ipw2100_wpa_enable(priv, param->value);
7702 break;
7703
7704 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
7705 ieee->ieee802_1x = param->value;
7706 break;
7707
7708 //case IW_AUTH_ROAMING_CONTROL:
7709 case IW_AUTH_PRIVACY_INVOKED:
7710 ieee->privacy_invoked = param->value;
7711 break;
7712
7713 default:
7714 return -EOPNOTSUPP;
7715 }
7716 return ret;
7717}
7718
7719/* SIOCGIWAUTH */
7720static int ipw2100_wx_get_auth(struct net_device *dev,
7721 struct iw_request_info *info,
7722 union iwreq_data *wrqu, char *extra)
7723{
7724 struct ipw2100_priv *priv = ieee80211_priv(dev);
7725 struct ieee80211_device *ieee = priv->ieee;
John W. Linville274bfb82008-10-29 11:35:05 -04007726 struct lib80211_crypt_data *crypt;
James Ketrenos82328352005-08-24 22:33:31 -05007727 struct iw_param *param = &wrqu->param;
7728 int ret = 0;
7729
7730 switch (param->flags & IW_AUTH_INDEX) {
7731 case IW_AUTH_WPA_VERSION:
7732 case IW_AUTH_CIPHER_PAIRWISE:
7733 case IW_AUTH_CIPHER_GROUP:
7734 case IW_AUTH_KEY_MGMT:
7735 /*
7736 * wpa_supplicant will control these internally
7737 */
7738 ret = -EOPNOTSUPP;
7739 break;
7740
7741 case IW_AUTH_TKIP_COUNTERMEASURES:
John W. Linville274bfb82008-10-29 11:35:05 -04007742 crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
James Ketrenos82328352005-08-24 22:33:31 -05007743 if (!crypt || !crypt->ops->get_flags) {
7744 IPW_DEBUG_WARNING("Can't get TKIP countermeasures: "
7745 "crypt not set!\n");
7746 break;
7747 }
7748
7749 param->value = (crypt->ops->get_flags(crypt->priv) &
7750 IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
7751
7752 break;
7753
7754 case IW_AUTH_DROP_UNENCRYPTED:
7755 param->value = ieee->drop_unencrypted;
7756 break;
7757
7758 case IW_AUTH_80211_AUTH_ALG:
25b645b2005-07-12 15:45:30 -05007759 param->value = priv->ieee->sec.auth_mode;
James Ketrenos82328352005-08-24 22:33:31 -05007760 break;
7761
7762 case IW_AUTH_WPA_ENABLED:
7763 param->value = ieee->wpa_enabled;
7764 break;
7765
7766 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
7767 param->value = ieee->ieee802_1x;
7768 break;
7769
7770 case IW_AUTH_ROAMING_CONTROL:
7771 case IW_AUTH_PRIVACY_INVOKED:
7772 param->value = ieee->privacy_invoked;
7773 break;
7774
7775 default:
7776 return -EOPNOTSUPP;
7777 }
7778 return 0;
7779}
7780
7781/* SIOCSIWENCODEEXT */
7782static int ipw2100_wx_set_encodeext(struct net_device *dev,
7783 struct iw_request_info *info,
7784 union iwreq_data *wrqu, char *extra)
7785{
7786 struct ipw2100_priv *priv = ieee80211_priv(dev);
7787 return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra);
7788}
7789
7790/* SIOCGIWENCODEEXT */
7791static int ipw2100_wx_get_encodeext(struct net_device *dev,
7792 struct iw_request_info *info,
7793 union iwreq_data *wrqu, char *extra)
7794{
7795 struct ipw2100_priv *priv = ieee80211_priv(dev);
7796 return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra);
7797}
7798
7799/* SIOCSIWMLME */
7800static int ipw2100_wx_set_mlme(struct net_device *dev,
7801 struct iw_request_info *info,
7802 union iwreq_data *wrqu, char *extra)
7803{
7804 struct ipw2100_priv *priv = ieee80211_priv(dev);
7805 struct iw_mlme *mlme = (struct iw_mlme *)extra;
Al Viro1edd3a52007-12-21 00:15:18 -05007806 __le16 reason;
James Ketrenos82328352005-08-24 22:33:31 -05007807
7808 reason = cpu_to_le16(mlme->reason_code);
7809
7810 switch (mlme->cmd) {
7811 case IW_MLME_DEAUTH:
7812 // silently ignore
7813 break;
7814
7815 case IW_MLME_DISASSOC:
7816 ipw2100_disassociate_bssid(priv);
7817 break;
7818
7819 default:
7820 return -EOPNOTSUPP;
7821 }
7822 return 0;
7823}
James Ketrenos2c86c272005-03-23 17:32:29 -06007824
7825/*
7826 *
7827 * IWPRIV handlers
7828 *
7829 */
7830#ifdef CONFIG_IPW2100_MONITOR
7831static int ipw2100_wx_set_promisc(struct net_device *dev,
7832 struct iw_request_info *info,
7833 union iwreq_data *wrqu, char *extra)
7834{
7835 struct ipw2100_priv *priv = ieee80211_priv(dev);
7836 int *parms = (int *)extra;
7837 int enable = (parms[0] > 0);
7838 int err = 0;
7839
Ingo Molnar752e3772006-02-28 07:20:54 +08007840 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007841 if (!(priv->status & STATUS_INITIALIZED)) {
7842 err = -EIO;
7843 goto done;
7844 }
7845
7846 if (enable) {
7847 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
7848 err = ipw2100_set_channel(priv, parms[1], 0);
7849 goto done;
7850 }
7851 priv->channel = parms[1];
7852 err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
7853 } else {
7854 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
7855 err = ipw2100_switch_mode(priv, priv->last_mode);
7856 }
James Ketrenosee8e3652005-09-14 09:47:29 -05007857 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007858 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007859 return err;
7860}
7861
7862static int ipw2100_wx_reset(struct net_device *dev,
7863 struct iw_request_info *info,
7864 union iwreq_data *wrqu, char *extra)
7865{
7866 struct ipw2100_priv *priv = ieee80211_priv(dev);
7867 if (priv->status & STATUS_INITIALIZED)
7868 schedule_reset(priv);
7869 return 0;
7870}
7871
7872#endif
7873
7874static int ipw2100_wx_set_powermode(struct net_device *dev,
7875 struct iw_request_info *info,
7876 union iwreq_data *wrqu, char *extra)
7877{
7878 struct ipw2100_priv *priv = ieee80211_priv(dev);
7879 int err = 0, mode = *(int *)extra;
7880
Ingo Molnar752e3772006-02-28 07:20:54 +08007881 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007882 if (!(priv->status & STATUS_INITIALIZED)) {
7883 err = -EIO;
7884 goto done;
7885 }
7886
Zhu Yi9f3b2412007-07-12 16:09:24 +08007887 if ((mode < 0) || (mode > POWER_MODES))
James Ketrenos2c86c272005-03-23 17:32:29 -06007888 mode = IPW_POWER_AUTO;
7889
Zhu Yi9f3b2412007-07-12 16:09:24 +08007890 if (IPW_POWER_LEVEL(priv->power_mode) != mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06007891 err = ipw2100_set_power_mode(priv, mode);
James Ketrenosee8e3652005-09-14 09:47:29 -05007892 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007893 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007894 return err;
7895}
7896
7897#define MAX_POWER_STRING 80
7898static int ipw2100_wx_get_powermode(struct net_device *dev,
7899 struct iw_request_info *info,
7900 union iwreq_data *wrqu, char *extra)
7901{
7902 /*
7903 * This can be called at any time. No action lock required
7904 */
7905
7906 struct ipw2100_priv *priv = ieee80211_priv(dev);
7907 int level = IPW_POWER_LEVEL(priv->power_mode);
7908 s32 timeout, period;
7909
7910 if (!(priv->power_mode & IPW_POWER_ENABLED)) {
7911 snprintf(extra, MAX_POWER_STRING,
7912 "Power save level: %d (Off)", level);
7913 } else {
7914 switch (level) {
7915 case IPW_POWER_MODE_CAM:
7916 snprintf(extra, MAX_POWER_STRING,
7917 "Power save level: %d (None)", level);
7918 break;
7919 case IPW_POWER_AUTO:
James Ketrenosee8e3652005-09-14 09:47:29 -05007920 snprintf(extra, MAX_POWER_STRING,
Zhu Yi9f3b2412007-07-12 16:09:24 +08007921 "Power save level: %d (Auto)", level);
James Ketrenos2c86c272005-03-23 17:32:29 -06007922 break;
7923 default:
7924 timeout = timeout_duration[level - 1] / 1000;
7925 period = period_duration[level - 1] / 1000;
7926 snprintf(extra, MAX_POWER_STRING,
7927 "Power save level: %d "
7928 "(Timeout %dms, Period %dms)",
7929 level, timeout, period);
7930 }
7931 }
7932
7933 wrqu->data.length = strlen(extra) + 1;
7934
7935 return 0;
7936}
7937
James Ketrenos2c86c272005-03-23 17:32:29 -06007938static int ipw2100_wx_set_preamble(struct net_device *dev,
7939 struct iw_request_info *info,
7940 union iwreq_data *wrqu, char *extra)
7941{
7942 struct ipw2100_priv *priv = ieee80211_priv(dev);
7943 int err, mode = *(int *)extra;
7944
Ingo Molnar752e3772006-02-28 07:20:54 +08007945 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007946 if (!(priv->status & STATUS_INITIALIZED)) {
7947 err = -EIO;
7948 goto done;
7949 }
7950
7951 if (mode == 1)
7952 priv->config |= CFG_LONG_PREAMBLE;
7953 else if (mode == 0)
7954 priv->config &= ~CFG_LONG_PREAMBLE;
7955 else {
7956 err = -EINVAL;
7957 goto done;
7958 }
7959
7960 err = ipw2100_system_config(priv, 0);
7961
James Ketrenosee8e3652005-09-14 09:47:29 -05007962 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007963 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007964 return err;
7965}
7966
7967static int ipw2100_wx_get_preamble(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05007968 struct iw_request_info *info,
7969 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007970{
7971 /*
7972 * This can be called at any time. No action lock required
7973 */
7974
7975 struct ipw2100_priv *priv = ieee80211_priv(dev);
7976
7977 if (priv->config & CFG_LONG_PREAMBLE)
7978 snprintf(wrqu->name, IFNAMSIZ, "long (1)");
7979 else
7980 snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
7981
7982 return 0;
7983}
7984
James Ketrenos82328352005-08-24 22:33:31 -05007985#ifdef CONFIG_IPW2100_MONITOR
7986static int ipw2100_wx_set_crc_check(struct net_device *dev,
7987 struct iw_request_info *info,
7988 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007989{
James Ketrenos82328352005-08-24 22:33:31 -05007990 struct ipw2100_priv *priv = ieee80211_priv(dev);
7991 int err, mode = *(int *)extra;
7992
Ingo Molnar752e3772006-02-28 07:20:54 +08007993 mutex_lock(&priv->action_mutex);
James Ketrenos82328352005-08-24 22:33:31 -05007994 if (!(priv->status & STATUS_INITIALIZED)) {
7995 err = -EIO;
7996 goto done;
7997 }
7998
7999 if (mode == 1)
8000 priv->config |= CFG_CRC_CHECK;
8001 else if (mode == 0)
8002 priv->config &= ~CFG_CRC_CHECK;
8003 else {
8004 err = -EINVAL;
8005 goto done;
8006 }
8007 err = 0;
8008
8009 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08008010 mutex_unlock(&priv->action_mutex);
James Ketrenos82328352005-08-24 22:33:31 -05008011 return err;
8012}
8013
8014static int ipw2100_wx_get_crc_check(struct net_device *dev,
8015 struct iw_request_info *info,
8016 union iwreq_data *wrqu, char *extra)
8017{
8018 /*
8019 * This can be called at any time. No action lock required
8020 */
8021
8022 struct ipw2100_priv *priv = ieee80211_priv(dev);
8023
8024 if (priv->config & CFG_CRC_CHECK)
8025 snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)");
8026 else
8027 snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)");
8028
8029 return 0;
8030}
8031#endif /* CONFIG_IPW2100_MONITOR */
8032
James Ketrenosee8e3652005-09-14 09:47:29 -05008033static iw_handler ipw2100_wx_handlers[] = {
8034 NULL, /* SIOCSIWCOMMIT */
8035 ipw2100_wx_get_name, /* SIOCGIWNAME */
8036 NULL, /* SIOCSIWNWID */
8037 NULL, /* SIOCGIWNWID */
8038 ipw2100_wx_set_freq, /* SIOCSIWFREQ */
8039 ipw2100_wx_get_freq, /* SIOCGIWFREQ */
8040 ipw2100_wx_set_mode, /* SIOCSIWMODE */
8041 ipw2100_wx_get_mode, /* SIOCGIWMODE */
8042 NULL, /* SIOCSIWSENS */
8043 NULL, /* SIOCGIWSENS */
8044 NULL, /* SIOCSIWRANGE */
8045 ipw2100_wx_get_range, /* SIOCGIWRANGE */
8046 NULL, /* SIOCSIWPRIV */
8047 NULL, /* SIOCGIWPRIV */
8048 NULL, /* SIOCSIWSTATS */
8049 NULL, /* SIOCGIWSTATS */
8050 NULL, /* SIOCSIWSPY */
8051 NULL, /* SIOCGIWSPY */
8052 NULL, /* SIOCGIWTHRSPY */
8053 NULL, /* SIOCWIWTHRSPY */
8054 ipw2100_wx_set_wap, /* SIOCSIWAP */
8055 ipw2100_wx_get_wap, /* SIOCGIWAP */
James Ketrenos82328352005-08-24 22:33:31 -05008056 ipw2100_wx_set_mlme, /* SIOCSIWMLME */
James Ketrenosee8e3652005-09-14 09:47:29 -05008057 NULL, /* SIOCGIWAPLIST -- deprecated */
8058 ipw2100_wx_set_scan, /* SIOCSIWSCAN */
8059 ipw2100_wx_get_scan, /* SIOCGIWSCAN */
8060 ipw2100_wx_set_essid, /* SIOCSIWESSID */
8061 ipw2100_wx_get_essid, /* SIOCGIWESSID */
8062 ipw2100_wx_set_nick, /* SIOCSIWNICKN */
8063 ipw2100_wx_get_nick, /* SIOCGIWNICKN */
8064 NULL, /* -- hole -- */
8065 NULL, /* -- hole -- */
8066 ipw2100_wx_set_rate, /* SIOCSIWRATE */
8067 ipw2100_wx_get_rate, /* SIOCGIWRATE */
8068 ipw2100_wx_set_rts, /* SIOCSIWRTS */
8069 ipw2100_wx_get_rts, /* SIOCGIWRTS */
8070 ipw2100_wx_set_frag, /* SIOCSIWFRAG */
8071 ipw2100_wx_get_frag, /* SIOCGIWFRAG */
8072 ipw2100_wx_set_txpow, /* SIOCSIWTXPOW */
8073 ipw2100_wx_get_txpow, /* SIOCGIWTXPOW */
8074 ipw2100_wx_set_retry, /* SIOCSIWRETRY */
8075 ipw2100_wx_get_retry, /* SIOCGIWRETRY */
8076 ipw2100_wx_set_encode, /* SIOCSIWENCODE */
8077 ipw2100_wx_get_encode, /* SIOCGIWENCODE */
8078 ipw2100_wx_set_power, /* SIOCSIWPOWER */
8079 ipw2100_wx_get_power, /* SIOCGIWPOWER */
James Ketrenos82328352005-08-24 22:33:31 -05008080 NULL, /* -- hole -- */
8081 NULL, /* -- hole -- */
8082 ipw2100_wx_set_genie, /* SIOCSIWGENIE */
8083 ipw2100_wx_get_genie, /* SIOCGIWGENIE */
8084 ipw2100_wx_set_auth, /* SIOCSIWAUTH */
8085 ipw2100_wx_get_auth, /* SIOCGIWAUTH */
8086 ipw2100_wx_set_encodeext, /* SIOCSIWENCODEEXT */
8087 ipw2100_wx_get_encodeext, /* SIOCGIWENCODEEXT */
8088 NULL, /* SIOCSIWPMKSA */
James Ketrenos2c86c272005-03-23 17:32:29 -06008089};
8090
8091#define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV
8092#define IPW2100_PRIV_RESET SIOCIWFIRSTPRIV+1
8093#define IPW2100_PRIV_SET_POWER SIOCIWFIRSTPRIV+2
8094#define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3
8095#define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4
8096#define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5
James Ketrenos82328352005-08-24 22:33:31 -05008097#define IPW2100_PRIV_SET_CRC_CHECK SIOCIWFIRSTPRIV+6
8098#define IPW2100_PRIV_GET_CRC_CHECK SIOCIWFIRSTPRIV+7
James Ketrenos2c86c272005-03-23 17:32:29 -06008099
8100static const struct iw_priv_args ipw2100_private_args[] = {
8101
8102#ifdef CONFIG_IPW2100_MONITOR
8103 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008104 IPW2100_PRIV_SET_MONITOR,
8105 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008106 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008107 IPW2100_PRIV_RESET,
8108 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
8109#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008110
8111 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008112 IPW2100_PRIV_SET_POWER,
8113 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008114 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008115 IPW2100_PRIV_GET_POWER,
8116 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING,
8117 "get_power"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008118 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008119 IPW2100_PRIV_SET_LONGPREAMBLE,
8120 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008121 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008122 IPW2100_PRIV_GET_LONGPREAMBLE,
8123 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"},
James Ketrenos82328352005-08-24 22:33:31 -05008124#ifdef CONFIG_IPW2100_MONITOR
8125 {
8126 IPW2100_PRIV_SET_CRC_CHECK,
8127 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"},
8128 {
8129 IPW2100_PRIV_GET_CRC_CHECK,
8130 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"},
8131#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008132};
8133
8134static iw_handler ipw2100_private_handler[] = {
8135#ifdef CONFIG_IPW2100_MONITOR
8136 ipw2100_wx_set_promisc,
8137 ipw2100_wx_reset,
James Ketrenosee8e3652005-09-14 09:47:29 -05008138#else /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008139 NULL,
8140 NULL,
James Ketrenosee8e3652005-09-14 09:47:29 -05008141#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008142 ipw2100_wx_set_powermode,
8143 ipw2100_wx_get_powermode,
8144 ipw2100_wx_set_preamble,
8145 ipw2100_wx_get_preamble,
James Ketrenos82328352005-08-24 22:33:31 -05008146#ifdef CONFIG_IPW2100_MONITOR
8147 ipw2100_wx_set_crc_check,
8148 ipw2100_wx_get_crc_check,
8149#else /* CONFIG_IPW2100_MONITOR */
8150 NULL,
8151 NULL,
8152#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008153};
8154
James Ketrenos2c86c272005-03-23 17:32:29 -06008155/*
8156 * Get wireless statistics.
8157 * Called by /proc/net/wireless
8158 * Also called by SIOCGIWSTATS
8159 */
James Ketrenosee8e3652005-09-14 09:47:29 -05008160static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
James Ketrenos2c86c272005-03-23 17:32:29 -06008161{
8162 enum {
8163 POOR = 30,
8164 FAIR = 60,
8165 GOOD = 80,
8166 VERY_GOOD = 90,
8167 EXCELLENT = 95,
8168 PERFECT = 100
8169 };
8170 int rssi_qual;
8171 int tx_qual;
8172 int beacon_qual;
8173
8174 struct ipw2100_priv *priv = ieee80211_priv(dev);
8175 struct iw_statistics *wstats;
8176 u32 rssi, quality, tx_retries, missed_beacons, tx_failures;
8177 u32 ord_len = sizeof(u32);
8178
8179 if (!priv)
James Ketrenosee8e3652005-09-14 09:47:29 -05008180 return (struct iw_statistics *)NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06008181
8182 wstats = &priv->wstats;
8183
8184 /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
8185 * ipw2100_wx_wireless_stats seems to be called before fw is
8186 * initialized. STATUS_ASSOCIATED will only be set if the hw is up
8187 * and associated; if not associcated, the values are all meaningless
8188 * anyway, so set them all to NULL and INVALID */
8189 if (!(priv->status & STATUS_ASSOCIATED)) {
8190 wstats->miss.beacon = 0;
8191 wstats->discard.retries = 0;
8192 wstats->qual.qual = 0;
8193 wstats->qual.level = 0;
8194 wstats->qual.noise = 0;
8195 wstats->qual.updated = 7;
8196 wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
James Ketrenosee8e3652005-09-14 09:47:29 -05008197 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
James Ketrenos2c86c272005-03-23 17:32:29 -06008198 return wstats;
8199 }
8200
8201 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS,
8202 &missed_beacons, &ord_len))
8203 goto fail_get_ordinal;
8204
James Ketrenosee8e3652005-09-14 09:47:29 -05008205 /* If we don't have a connection the quality and level is 0 */
James Ketrenos2c86c272005-03-23 17:32:29 -06008206 if (!(priv->status & STATUS_ASSOCIATED)) {
8207 wstats->qual.qual = 0;
8208 wstats->qual.level = 0;
8209 } else {
8210 if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR,
8211 &rssi, &ord_len))
8212 goto fail_get_ordinal;
8213 wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
8214 if (rssi < 10)
8215 rssi_qual = rssi * POOR / 10;
8216 else if (rssi < 15)
8217 rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR;
8218 else if (rssi < 20)
8219 rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR;
8220 else if (rssi < 30)
8221 rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008222 10 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008223 else
8224 rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008225 10 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008226
8227 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES,
8228 &tx_retries, &ord_len))
8229 goto fail_get_ordinal;
8230
8231 if (tx_retries > 75)
8232 tx_qual = (90 - tx_retries) * POOR / 15;
8233 else if (tx_retries > 70)
8234 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
8235 else if (tx_retries > 65)
8236 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
8237 else if (tx_retries > 50)
8238 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008239 15 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008240 else
8241 tx_qual = (50 - tx_retries) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008242 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008243
8244 if (missed_beacons > 50)
8245 beacon_qual = (60 - missed_beacons) * POOR / 10;
8246 else if (missed_beacons > 40)
8247 beacon_qual = (50 - missed_beacons) * (FAIR - POOR) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008248 10 + POOR;
James Ketrenos2c86c272005-03-23 17:32:29 -06008249 else if (missed_beacons > 32)
8250 beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008251 18 + FAIR;
James Ketrenos2c86c272005-03-23 17:32:29 -06008252 else if (missed_beacons > 20)
8253 beacon_qual = (32 - missed_beacons) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008254 (VERY_GOOD - GOOD) / 20 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008255 else
8256 beacon_qual = (20 - missed_beacons) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008257 (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008258
8259 quality = min(beacon_qual, min(tx_qual, rssi_qual));
8260
Brice Goglin0f52bf92005-12-01 01:41:46 -08008261#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06008262 if (beacon_qual == quality)
8263 IPW_DEBUG_WX("Quality clamped by Missed Beacons\n");
8264 else if (tx_qual == quality)
8265 IPW_DEBUG_WX("Quality clamped by Tx Retries\n");
8266 else if (quality != 100)
8267 IPW_DEBUG_WX("Quality clamped by Signal Strength\n");
8268 else
8269 IPW_DEBUG_WX("Quality not clamped.\n");
8270#endif
8271
8272 wstats->qual.qual = quality;
8273 wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
8274 }
8275
8276 wstats->qual.noise = 0;
8277 wstats->qual.updated = 7;
8278 wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
8279
James Ketrenosee8e3652005-09-14 09:47:29 -05008280 /* FIXME: this is percent and not a # */
James Ketrenos2c86c272005-03-23 17:32:29 -06008281 wstats->miss.beacon = missed_beacons;
8282
8283 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES,
8284 &tx_failures, &ord_len))
8285 goto fail_get_ordinal;
8286 wstats->discard.retries = tx_failures;
8287
8288 return wstats;
8289
James Ketrenosee8e3652005-09-14 09:47:29 -05008290 fail_get_ordinal:
James Ketrenos2c86c272005-03-23 17:32:29 -06008291 IPW_DEBUG_WX("failed querying ordinals.\n");
8292
James Ketrenosee8e3652005-09-14 09:47:29 -05008293 return (struct iw_statistics *)NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06008294}
8295
James Ketrenoseaf8f532005-11-12 12:50:12 -06008296static struct iw_handler_def ipw2100_wx_handler_def = {
8297 .standard = ipw2100_wx_handlers,
Denis Chengff8ac602007-09-02 18:30:18 +08008298 .num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
8299 .num_private = ARRAY_SIZE(ipw2100_private_handler),
8300 .num_private_args = ARRAY_SIZE(ipw2100_private_args),
James Ketrenoseaf8f532005-11-12 12:50:12 -06008301 .private = (iw_handler *) ipw2100_private_handler,
8302 .private_args = (struct iw_priv_args *)ipw2100_private_args,
8303 .get_wireless_stats = ipw2100_wx_wireless_stats,
8304};
8305
David Howellsc4028952006-11-22 14:57:56 +00008306static void ipw2100_wx_event_work(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06008307{
David Howellsc4028952006-11-22 14:57:56 +00008308 struct ipw2100_priv *priv =
8309 container_of(work, struct ipw2100_priv, wx_event_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06008310 union iwreq_data wrqu;
Hannes Ederb9da9e92009-02-14 11:50:26 +00008311 unsigned int len = ETH_ALEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06008312
8313 if (priv->status & STATUS_STOPPING)
8314 return;
8315
Ingo Molnar752e3772006-02-28 07:20:54 +08008316 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008317
8318 IPW_DEBUG_WX("enter\n");
8319
Ingo Molnar752e3772006-02-28 07:20:54 +08008320 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008321
8322 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
8323
8324 /* Fetch BSSID from the hardware */
8325 if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) ||
8326 priv->status & STATUS_RF_KILL_MASK ||
8327 ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
James Ketrenosee8e3652005-09-14 09:47:29 -05008328 &priv->bssid, &len)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06008329 memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
8330 } else {
8331 /* We now have the BSSID, so can finish setting to the full
8332 * associated state */
8333 memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
James Ketrenos82328352005-08-24 22:33:31 -05008334 memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06008335 priv->status &= ~STATUS_ASSOCIATING;
8336 priv->status |= STATUS_ASSOCIATED;
8337 netif_carrier_on(priv->net_dev);
James Ketrenos82328352005-08-24 22:33:31 -05008338 netif_wake_queue(priv->net_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008339 }
8340
8341 if (!(priv->status & STATUS_ASSOCIATED)) {
8342 IPW_DEBUG_WX("Configuring ESSID\n");
Ingo Molnar752e3772006-02-28 07:20:54 +08008343 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008344 /* This is a disassociation event, so kick the firmware to
8345 * look for another AP */
8346 if (priv->config & CFG_STATIC_ESSID)
James Ketrenosee8e3652005-09-14 09:47:29 -05008347 ipw2100_set_essid(priv, priv->essid, priv->essid_len,
8348 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06008349 else
8350 ipw2100_set_essid(priv, NULL, 0, 0);
Ingo Molnar752e3772006-02-28 07:20:54 +08008351 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008352 }
8353
8354 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
8355}
8356
8357#define IPW2100_FW_MAJOR_VERSION 1
8358#define IPW2100_FW_MINOR_VERSION 3
8359
8360#define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8)
8361#define IPW2100_FW_MAJOR(x) (x & 0xff)
8362
8363#define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \
8364 IPW2100_FW_MAJOR_VERSION)
8365
8366#define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \
8367"." __stringify(IPW2100_FW_MINOR_VERSION)
8368
8369#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw"
8370
James Ketrenos2c86c272005-03-23 17:32:29 -06008371/*
8372
8373BINARY FIRMWARE HEADER FORMAT
8374
8375offset length desc
83760 2 version
83772 2 mode == 0:BSS,1:IBSS,2:MONITOR
83784 4 fw_len
83798 4 uc_len
8380C fw_len firmware data
838112 + fw_len uc_len microcode data
8382
8383*/
8384
8385struct ipw2100_fw_header {
8386 short version;
8387 short mode;
8388 unsigned int fw_size;
8389 unsigned int uc_size;
8390} __attribute__ ((packed));
8391
James Ketrenos2c86c272005-03-23 17:32:29 -06008392static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
8393{
8394 struct ipw2100_fw_header *h =
James Ketrenosee8e3652005-09-14 09:47:29 -05008395 (struct ipw2100_fw_header *)fw->fw_entry->data;
James Ketrenos2c86c272005-03-23 17:32:29 -06008396
8397 if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008398 printk(KERN_WARNING DRV_NAME ": Firmware image not compatible "
James Ketrenos2c86c272005-03-23 17:32:29 -06008399 "(detected version id of %u). "
8400 "See Documentation/networking/README.ipw2100\n",
8401 h->version);
8402 return 1;
8403 }
8404
8405 fw->version = h->version;
8406 fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header);
8407 fw->fw.size = h->fw_size;
8408 fw->uc.data = fw->fw.data + h->fw_size;
8409 fw->uc.size = h->uc_size;
8410
8411 return 0;
8412}
8413
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008414static int ipw2100_get_firmware(struct ipw2100_priv *priv,
8415 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008416{
8417 char *fw_name;
8418 int rc;
8419
8420 IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05008421 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06008422
8423 switch (priv->ieee->iw_mode) {
8424 case IW_MODE_ADHOC:
8425 fw_name = IPW2100_FW_NAME("-i");
8426 break;
8427#ifdef CONFIG_IPW2100_MONITOR
8428 case IW_MODE_MONITOR:
8429 fw_name = IPW2100_FW_NAME("-p");
8430 break;
8431#endif
8432 case IW_MODE_INFRA:
8433 default:
8434 fw_name = IPW2100_FW_NAME("");
8435 break;
8436 }
8437
8438 rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev);
8439
8440 if (rc < 0) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008441 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06008442 "%s: Firmware '%s' not available or load failed.\n",
8443 priv->net_dev->name, fw_name);
8444 return rc;
8445 }
Jiri Bencaaa4d302005-06-07 14:58:41 +02008446 IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data,
James Ketrenosee8e3652005-09-14 09:47:29 -05008447 fw->fw_entry->size);
James Ketrenos2c86c272005-03-23 17:32:29 -06008448
8449 ipw2100_mod_firmware_load(fw);
8450
8451 return 0;
8452}
8453
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008454static void ipw2100_release_firmware(struct ipw2100_priv *priv,
8455 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008456{
8457 fw->version = 0;
8458 if (fw->fw_entry)
8459 release_firmware(fw->fw_entry);
8460 fw->fw_entry = NULL;
8461}
8462
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008463static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
8464 size_t max)
James Ketrenos2c86c272005-03-23 17:32:29 -06008465{
8466 char ver[MAX_FW_VERSION_LEN];
8467 u32 len = MAX_FW_VERSION_LEN;
8468 u32 tmp;
8469 int i;
8470 /* firmware version is an ascii string (max len of 14) */
James Ketrenosee8e3652005-09-14 09:47:29 -05008471 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len))
James Ketrenos2c86c272005-03-23 17:32:29 -06008472 return -EIO;
8473 tmp = max;
8474 if (len >= max)
8475 len = max - 1;
8476 for (i = 0; i < len; i++)
8477 buf[i] = ver[i];
8478 buf[i] = '\0';
8479 return tmp;
8480}
8481
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008482static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
8483 size_t max)
James Ketrenos2c86c272005-03-23 17:32:29 -06008484{
8485 u32 ver;
8486 u32 len = sizeof(ver);
8487 /* microcode version is a 32 bit integer */
James Ketrenosee8e3652005-09-14 09:47:29 -05008488 if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len))
James Ketrenos2c86c272005-03-23 17:32:29 -06008489 return -EIO;
8490 return snprintf(buf, max, "%08X", ver);
8491}
8492
8493/*
8494 * On exit, the firmware will have been freed from the fw list
8495 */
James Ketrenosee8e3652005-09-14 09:47:29 -05008496static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008497{
8498 /* firmware is constructed of N contiguous entries, each entry is
8499 * structured as:
8500 *
8501 * offset sie desc
8502 * 0 4 address to write to
8503 * 4 2 length of data run
James Ketrenosee8e3652005-09-14 09:47:29 -05008504 * 6 length data
James Ketrenos2c86c272005-03-23 17:32:29 -06008505 */
8506 unsigned int addr;
8507 unsigned short len;
8508
8509 const unsigned char *firmware_data = fw->fw.data;
8510 unsigned int firmware_data_left = fw->fw.size;
8511
8512 while (firmware_data_left > 0) {
James Ketrenosee8e3652005-09-14 09:47:29 -05008513 addr = *(u32 *) (firmware_data);
8514 firmware_data += 4;
James Ketrenos2c86c272005-03-23 17:32:29 -06008515 firmware_data_left -= 4;
8516
James Ketrenosee8e3652005-09-14 09:47:29 -05008517 len = *(u16 *) (firmware_data);
8518 firmware_data += 2;
James Ketrenos2c86c272005-03-23 17:32:29 -06008519 firmware_data_left -= 2;
8520
8521 if (len > 32) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008522 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06008523 "Invalid firmware run-length of %d bytes\n",
8524 len);
8525 return -EINVAL;
8526 }
8527
8528 write_nic_memory(priv->net_dev, addr, len, firmware_data);
James Ketrenosee8e3652005-09-14 09:47:29 -05008529 firmware_data += len;
James Ketrenos2c86c272005-03-23 17:32:29 -06008530 firmware_data_left -= len;
8531 }
8532
8533 return 0;
8534}
8535
8536struct symbol_alive_response {
8537 u8 cmd_id;
8538 u8 seq_num;
8539 u8 ucode_rev;
8540 u8 eeprom_valid;
8541 u16 valid_flags;
8542 u8 IEEE_addr[6];
8543 u16 flags;
8544 u16 pcb_rev;
8545 u16 clock_settle_time; // 1us LSB
8546 u16 powerup_settle_time; // 1us LSB
8547 u16 hop_settle_time; // 1us LSB
8548 u8 date[3]; // month, day, year
8549 u8 time[2]; // hours, minutes
8550 u8 ucode_valid;
8551};
8552
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008553static int ipw2100_ucode_download(struct ipw2100_priv *priv,
8554 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008555{
8556 struct net_device *dev = priv->net_dev;
8557 const unsigned char *microcode_data = fw->uc.data;
8558 unsigned int microcode_data_left = fw->uc.size;
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008559 void __iomem *reg = (void __iomem *)dev->base_addr;
James Ketrenos2c86c272005-03-23 17:32:29 -06008560
8561 struct symbol_alive_response response;
8562 int i, j;
8563 u8 data;
8564
8565 /* Symbol control */
8566 write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008567 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008568 write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008569 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008570
8571 /* HW config */
8572 write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008573 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008574 write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008575 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008576
8577 /* EN_CS_ACCESS bit to reset control store pointer */
8578 write_nic_byte(dev, 0x210000, 0x40);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008579 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008580 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008581 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008582 write_nic_byte(dev, 0x210000, 0x40);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008583 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008584
8585 /* copy microcode from buffer into Symbol */
8586
8587 while (microcode_data_left > 0) {
8588 write_nic_byte(dev, 0x210010, *microcode_data++);
8589 write_nic_byte(dev, 0x210010, *microcode_data++);
8590 microcode_data_left -= 2;
8591 }
8592
8593 /* EN_CS_ACCESS bit to reset the control store pointer */
8594 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008595 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008596
8597 /* Enable System (Reg 0)
8598 * first enable causes garbage in RX FIFO */
8599 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008600 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008601 write_nic_byte(dev, 0x210000, 0x80);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008602 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008603
8604 /* Reset External Baseband Reg */
8605 write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008606 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008607 write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008608 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008609
8610 /* HW Config (Reg 5) */
8611 write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008612 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008613 write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008614 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008615
8616 /* Enable System (Reg 0)
8617 * second enable should be OK */
8618 write_nic_byte(dev, 0x210000, 0x00); // clear enable system
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008619 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008620 write_nic_byte(dev, 0x210000, 0x80); // set enable system
8621
8622 /* check Symbol is enabled - upped this from 5 as it wasn't always
8623 * catching the update */
8624 for (i = 0; i < 10; i++) {
8625 udelay(10);
8626
8627 /* check Dino is enabled bit */
8628 read_nic_byte(dev, 0x210000, &data);
8629 if (data & 0x1)
8630 break;
8631 }
8632
8633 if (i == 10) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008634 printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06008635 dev->name);
8636 return -EIO;
8637 }
8638
8639 /* Get Symbol alive response */
8640 for (i = 0; i < 30; i++) {
8641 /* Read alive response structure */
8642 for (j = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05008643 j < (sizeof(struct symbol_alive_response) >> 1); j++)
8644 read_nic_word(dev, 0x210004, ((u16 *) & response) + j);
James Ketrenos2c86c272005-03-23 17:32:29 -06008645
James Ketrenosee8e3652005-09-14 09:47:29 -05008646 if ((response.cmd_id == 1) && (response.ucode_valid == 0x1))
James Ketrenos2c86c272005-03-23 17:32:29 -06008647 break;
8648 udelay(10);
8649 }
8650
8651 if (i == 30) {
James Ketrenosee8e3652005-09-14 09:47:29 -05008652 printk(KERN_ERR DRV_NAME
8653 ": %s: No response from Symbol - hw not alive\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06008654 dev->name);
James Ketrenosee8e3652005-09-14 09:47:29 -05008655 printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response));
James Ketrenos2c86c272005-03-23 17:32:29 -06008656 return -EIO;
8657 }
8658
8659 return 0;
8660}