blob: 52b1cf5160f7c1cf40e8ebce5b19a507303d5b8a [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
1695 /* Quite if manually disabled. */
1696 if (priv->status & STATUS_RF_KILL_SW) {
1697 IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "
1698 "switch\n", priv->net_dev->name);
1699 return 0;
1700 }
1701
Arjan van de Ven5c875792006-09-30 23:27:17 -07001702 /* the ipw2100 hardware really doesn't want power management delays
1703 * longer than 175usec
1704 */
Mark Grossf011e2e2008-02-04 22:30:09 -08001705 pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", 175);
Arjan van de Ven5c875792006-09-30 23:27:17 -07001706
James Ketrenos2c86c272005-03-23 17:32:29 -06001707 /* If the interrupt is enabled, turn it off... */
1708 spin_lock_irqsave(&priv->low_lock, flags);
1709 ipw2100_disable_interrupts(priv);
1710
1711 /* Reset any fatal_error conditions */
1712 ipw2100_reset_fatalerror(priv);
1713 spin_unlock_irqrestore(&priv->low_lock, flags);
1714
1715 if (priv->status & STATUS_POWERED ||
1716 (priv->status & STATUS_RESET_PENDING)) {
1717 /* Power cycle the card ... */
1718 if (ipw2100_power_cycle_adapter(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001719 printk(KERN_WARNING DRV_NAME
1720 ": %s: Could not cycle adapter.\n",
1721 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001722 rc = 1;
1723 goto exit;
1724 }
1725 } else
1726 priv->status |= STATUS_POWERED;
1727
Pavel Machek8724a112005-06-20 14:28:43 -07001728 /* Load the firmware, start the clocks, etc. */
James Ketrenos2c86c272005-03-23 17:32:29 -06001729 if (ipw2100_start_adapter(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001730 printk(KERN_ERR DRV_NAME
1731 ": %s: Failed to start the firmware.\n",
1732 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001733 rc = 1;
1734 goto exit;
1735 }
1736
1737 ipw2100_initialize_ordinals(priv);
1738
1739 /* Determine capabilities of this particular HW configuration */
1740 if (ipw2100_get_hw_features(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001741 printk(KERN_ERR DRV_NAME
1742 ": %s: Failed to determine HW features.\n",
1743 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001744 rc = 1;
1745 goto exit;
1746 }
1747
Zhu Yibe6b3b12006-01-24 13:49:08 +08001748 /* Initialize the geo */
1749 if (ieee80211_set_geo(priv->ieee, &ipw_geos[0])) {
1750 printk(KERN_WARNING DRV_NAME "Could not set geo\n");
1751 return 0;
1752 }
1753 priv->ieee->freq_band = IEEE80211_24GHZ_BAND;
1754
James Ketrenos2c86c272005-03-23 17:32:29 -06001755 lock = LOCK_NONE;
1756 if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001757 printk(KERN_ERR DRV_NAME
1758 ": %s: Failed to clear ordinal lock.\n",
1759 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001760 rc = 1;
1761 goto exit;
1762 }
1763
1764 priv->status &= ~STATUS_SCANNING;
1765
1766 if (rf_kill_active(priv)) {
1767 printk(KERN_INFO "%s: Radio is disabled by RF switch.\n",
1768 priv->net_dev->name);
1769
1770 if (priv->stop_rf_kill) {
1771 priv->stop_rf_kill = 0;
Stephen Hemmingera62056f2007-06-22 21:46:50 -07001772 queue_delayed_work(priv->workqueue, &priv->rf_kill,
Anton Blanchardbe84e3d2007-10-15 00:38:01 -05001773 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06001774 }
1775
1776 deferred = 1;
1777 }
1778
1779 /* Turn on the interrupt so that commands can be processed */
1780 ipw2100_enable_interrupts(priv);
1781
1782 /* Send all of the commands that must be sent prior to
1783 * HOST_COMPLETE */
1784 if (ipw2100_adapter_setup(priv)) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001785 printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001786 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001787 rc = 1;
1788 goto exit;
1789 }
1790
1791 if (!deferred) {
1792 /* Enable the adapter - sends HOST_COMPLETE */
1793 if (ipw2100_enable_adapter(priv)) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001794 printk(KERN_ERR DRV_NAME ": "
James Ketrenosee8e3652005-09-14 09:47:29 -05001795 "%s: failed in call to enable adapter.\n",
1796 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001797 ipw2100_hw_stop_adapter(priv);
1798 rc = 1;
1799 goto exit;
1800 }
1801
James Ketrenos2c86c272005-03-23 17:32:29 -06001802 /* Start a scan . . . */
1803 ipw2100_set_scan_options(priv);
1804 ipw2100_start_scan(priv);
1805 }
1806
James Ketrenosee8e3652005-09-14 09:47:29 -05001807 exit:
James Ketrenos2c86c272005-03-23 17:32:29 -06001808 return rc;
1809}
1810
1811/* Called by register_netdev() */
1812static int ipw2100_net_init(struct net_device *dev)
1813{
1814 struct ipw2100_priv *priv = ieee80211_priv(dev);
1815 return ipw2100_up(priv, 1);
1816}
1817
1818static void ipw2100_down(struct ipw2100_priv *priv)
1819{
1820 unsigned long flags;
1821 union iwreq_data wrqu = {
1822 .ap_addr = {
James Ketrenosee8e3652005-09-14 09:47:29 -05001823 .sa_family = ARPHRD_ETHER}
James Ketrenos2c86c272005-03-23 17:32:29 -06001824 };
1825 int associated = priv->status & STATUS_ASSOCIATED;
1826
1827 /* Kill the RF switch timer */
1828 if (!priv->stop_rf_kill) {
1829 priv->stop_rf_kill = 1;
1830 cancel_delayed_work(&priv->rf_kill);
1831 }
1832
Nick Andrew44072452009-01-03 18:52:40 +11001833 /* Kill the firmware hang check timer */
James Ketrenos2c86c272005-03-23 17:32:29 -06001834 if (!priv->stop_hang_check) {
1835 priv->stop_hang_check = 1;
1836 cancel_delayed_work(&priv->hang_check);
1837 }
1838
1839 /* Kill any pending resets */
1840 if (priv->status & STATUS_RESET_PENDING)
1841 cancel_delayed_work(&priv->reset_work);
1842
1843 /* Make sure the interrupt is on so that FW commands will be
1844 * processed correctly */
1845 spin_lock_irqsave(&priv->low_lock, flags);
1846 ipw2100_enable_interrupts(priv);
1847 spin_unlock_irqrestore(&priv->low_lock, flags);
1848
1849 if (ipw2100_hw_stop_adapter(priv))
Jiri Benc797b4f72005-08-25 20:03:27 -04001850 printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001851 priv->net_dev->name);
1852
1853 /* Do not disable the interrupt until _after_ we disable
1854 * the adaptor. Otherwise the CARD_DISABLE command will never
1855 * be ack'd by the firmware */
1856 spin_lock_irqsave(&priv->low_lock, flags);
1857 ipw2100_disable_interrupts(priv);
1858 spin_unlock_irqrestore(&priv->low_lock, flags);
1859
Mark Grossf011e2e2008-02-04 22:30:09 -08001860 pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100",
1861 PM_QOS_DEFAULT_VALUE);
Arjan van de Ven5c875792006-09-30 23:27:17 -07001862
James Ketrenos2c86c272005-03-23 17:32:29 -06001863 /* We have to signal any supplicant if we are disassociating */
1864 if (associated)
1865 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
1866
1867 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1868 netif_carrier_off(priv->net_dev);
1869 netif_stop_queue(priv->net_dev);
1870}
1871
David Howellsc4028952006-11-22 14:57:56 +00001872static void ipw2100_reset_adapter(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06001873{
David Howellsc4028952006-11-22 14:57:56 +00001874 struct ipw2100_priv *priv =
1875 container_of(work, struct ipw2100_priv, reset_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06001876 unsigned long flags;
1877 union iwreq_data wrqu = {
1878 .ap_addr = {
James Ketrenosee8e3652005-09-14 09:47:29 -05001879 .sa_family = ARPHRD_ETHER}
James Ketrenos2c86c272005-03-23 17:32:29 -06001880 };
1881 int associated = priv->status & STATUS_ASSOCIATED;
1882
1883 spin_lock_irqsave(&priv->low_lock, flags);
Zhu Yia1e695a2005-07-04 14:06:00 +08001884 IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001885 priv->resets++;
1886 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1887 priv->status |= STATUS_SECURITY_UPDATED;
1888
1889 /* Force a power cycle even if interface hasn't been opened
1890 * yet */
1891 cancel_delayed_work(&priv->reset_work);
1892 priv->status |= STATUS_RESET_PENDING;
1893 spin_unlock_irqrestore(&priv->low_lock, flags);
1894
Ingo Molnar752e3772006-02-28 07:20:54 +08001895 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001896 /* stop timed checks so that they don't interfere with reset */
1897 priv->stop_hang_check = 1;
1898 cancel_delayed_work(&priv->hang_check);
1899
1900 /* We have to signal any supplicant if we are disassociating */
1901 if (associated)
1902 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
1903
1904 ipw2100_up(priv, 0);
Ingo Molnar752e3772006-02-28 07:20:54 +08001905 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001906
1907}
1908
James Ketrenos2c86c272005-03-23 17:32:29 -06001909static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
1910{
1911
1912#define MAC_ASSOCIATION_READ_DELAY (HZ)
Hannes Ederb9da9e92009-02-14 11:50:26 +00001913 int ret;
1914 unsigned int len, essid_len;
James Ketrenos2c86c272005-03-23 17:32:29 -06001915 char essid[IW_ESSID_MAX_SIZE];
1916 u32 txrate;
1917 u32 chan;
1918 char *txratename;
James Ketrenosee8e3652005-09-14 09:47:29 -05001919 u8 bssid[ETH_ALEN];
John W. Linville9387b7c2008-09-30 20:59:05 -04001920 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06001921
1922 /*
1923 * TBD: BSSID is usually 00:00:00:00:00:00 here and not
1924 * an actual MAC of the AP. Seems like FW sets this
1925 * address too late. Read it later and expose through
1926 * /proc or schedule a later task to query and update
1927 */
1928
1929 essid_len = IW_ESSID_MAX_SIZE;
1930 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID,
1931 essid, &essid_len);
1932 if (ret) {
1933 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001934 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06001935 return;
1936 }
1937
1938 len = sizeof(u32);
James Ketrenosee8e3652005-09-14 09:47:29 -05001939 ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06001940 if (ret) {
1941 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001942 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06001943 return;
1944 }
1945
1946 len = sizeof(u32);
1947 ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len);
1948 if (ret) {
1949 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001950 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06001951 return;
1952 }
1953 len = ETH_ALEN;
James Ketrenosee8e3652005-09-14 09:47:29 -05001954 ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06001955 if (ret) {
1956 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001957 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06001958 return;
1959 }
1960 memcpy(priv->ieee->bssid, bssid, ETH_ALEN);
1961
James Ketrenos2c86c272005-03-23 17:32:29 -06001962 switch (txrate) {
1963 case TX_RATE_1_MBIT:
1964 txratename = "1Mbps";
1965 break;
1966 case TX_RATE_2_MBIT:
1967 txratename = "2Mbsp";
1968 break;
1969 case TX_RATE_5_5_MBIT:
1970 txratename = "5.5Mbps";
1971 break;
1972 case TX_RATE_11_MBIT:
1973 txratename = "11Mbps";
1974 break;
1975 default:
1976 IPW_DEBUG_INFO("Unknown rate: %d\n", txrate);
1977 txratename = "unknown rate";
1978 break;
1979 }
1980
Johannes Berge1749612008-10-27 15:59:26 -07001981 IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04001982 priv->net_dev->name, print_ssid(ssid, essid, essid_len),
Johannes Berge1749612008-10-27 15:59:26 -07001983 txratename, chan, bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06001984
1985 /* now we copy read ssid into dev */
1986 if (!(priv->config & CFG_STATIC_ESSID)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001987 priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE);
James Ketrenos2c86c272005-03-23 17:32:29 -06001988 memcpy(priv->essid, essid, priv->essid_len);
1989 }
1990 priv->channel = chan;
1991 memcpy(priv->bssid, bssid, ETH_ALEN);
1992
1993 priv->status |= STATUS_ASSOCIATING;
1994 priv->connect_start = get_seconds();
1995
1996 queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10);
1997}
1998
Jiri Bencc4aee8c2005-08-25 20:04:43 -04001999static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
2000 int length, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06002001{
2002 int ssid_len = min(length, IW_ESSID_MAX_SIZE);
2003 struct host_command cmd = {
2004 .host_command = SSID,
2005 .host_command_sequence = 0,
2006 .host_command_length = ssid_len
2007 };
2008 int err;
John W. Linville9387b7c2008-09-30 20:59:05 -04002009 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002010
John W. Linville9387b7c2008-09-30 20:59:05 -04002011 IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len));
James Ketrenos2c86c272005-03-23 17:32:29 -06002012
2013 if (ssid_len)
James Ketrenos82328352005-08-24 22:33:31 -05002014 memcpy(cmd.host_command_parameters, essid, ssid_len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002015
2016 if (!batch_mode) {
2017 err = ipw2100_disable_adapter(priv);
2018 if (err)
2019 return err;
2020 }
2021
2022 /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to
2023 * disable auto association -- so we cheat by setting a bogus SSID */
2024 if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) {
2025 int i;
James Ketrenosee8e3652005-09-14 09:47:29 -05002026 u8 *bogus = (u8 *) cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06002027 for (i = 0; i < IW_ESSID_MAX_SIZE; i++)
2028 bogus[i] = 0x18 + i;
2029 cmd.host_command_length = IW_ESSID_MAX_SIZE;
2030 }
2031
2032 /* NOTE: We always send the SSID command even if the provided ESSID is
2033 * the same as what we currently think is set. */
2034
2035 err = ipw2100_hw_send_command(priv, &cmd);
2036 if (!err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002037 memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002038 memcpy(priv->essid, essid, ssid_len);
2039 priv->essid_len = ssid_len;
2040 }
2041
2042 if (!batch_mode) {
2043 if (ipw2100_enable_adapter(priv))
2044 err = -EIO;
2045 }
2046
2047 return err;
2048}
2049
2050static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
2051{
John W. Linville9387b7c2008-09-30 20:59:05 -04002052 DECLARE_SSID_BUF(ssid);
2053
James Ketrenos2c86c272005-03-23 17:32:29 -06002054 IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
Johannes Berge1749612008-10-27 15:59:26 -07002055 "disassociated: '%s' %pM \n",
John W. Linville9387b7c2008-09-30 20:59:05 -04002056 print_ssid(ssid, priv->essid, priv->essid_len),
Johannes Berge1749612008-10-27 15:59:26 -07002057 priv->bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002058
2059 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
2060
2061 if (priv->status & STATUS_STOPPING) {
2062 IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n");
2063 return;
2064 }
2065
2066 memset(priv->bssid, 0, ETH_ALEN);
2067 memset(priv->ieee->bssid, 0, ETH_ALEN);
2068
2069 netif_carrier_off(priv->net_dev);
2070 netif_stop_queue(priv->net_dev);
2071
2072 if (!(priv->status & STATUS_RUNNING))
2073 return;
2074
2075 if (priv->status & STATUS_SECURITY_UPDATED)
David Howellsc4028952006-11-22 14:57:56 +00002076 queue_delayed_work(priv->workqueue, &priv->security_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06002077
David Howellsc4028952006-11-22 14:57:56 +00002078 queue_delayed_work(priv->workqueue, &priv->wx_event_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06002079}
2080
2081static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
2082{
2083 IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002084 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002085
2086 /* RF_KILL is now enabled (else we wouldn't be here) */
2087 priv->status |= STATUS_RF_KILL_HW;
2088
James Ketrenos2c86c272005-03-23 17:32:29 -06002089 /* Make sure the RF Kill check timer is running */
2090 priv->stop_rf_kill = 0;
2091 cancel_delayed_work(&priv->rf_kill);
Anton Blanchardbe84e3d2007-10-15 00:38:01 -05002092 queue_delayed_work(priv->workqueue, &priv->rf_kill,
2093 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06002094}
2095
Dan Williamsd20c6782007-10-10 12:28:07 -04002096static void send_scan_event(void *data)
2097{
2098 struct ipw2100_priv *priv = data;
2099 union iwreq_data wrqu;
2100
2101 wrqu.data.length = 0;
2102 wrqu.data.flags = 0;
2103 wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
2104}
2105
2106static void ipw2100_scan_event_later(struct work_struct *work)
2107{
2108 send_scan_event(container_of(work, struct ipw2100_priv,
2109 scan_event_later.work));
2110}
2111
2112static void ipw2100_scan_event_now(struct work_struct *work)
2113{
2114 send_scan_event(container_of(work, struct ipw2100_priv,
2115 scan_event_now));
2116}
2117
James Ketrenos2c86c272005-03-23 17:32:29 -06002118static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
2119{
2120 IPW_DEBUG_SCAN("scan complete\n");
2121 /* Age the scan results... */
2122 priv->ieee->scans++;
2123 priv->status &= ~STATUS_SCANNING;
Dan Williamsd20c6782007-10-10 12:28:07 -04002124
2125 /* Only userspace-requested scan completion events go out immediately */
2126 if (!priv->user_requested_scan) {
2127 if (!delayed_work_pending(&priv->scan_event_later))
2128 queue_delayed_work(priv->workqueue,
2129 &priv->scan_event_later,
Anton Blanchardbe84e3d2007-10-15 00:38:01 -05002130 round_jiffies_relative(msecs_to_jiffies(4000)));
Dan Williamsd20c6782007-10-10 12:28:07 -04002131 } else {
2132 priv->user_requested_scan = 0;
2133 cancel_delayed_work(&priv->scan_event_later);
2134 queue_work(priv->workqueue, &priv->scan_event_now);
2135 }
James Ketrenos2c86c272005-03-23 17:32:29 -06002136}
2137
Brice Goglin0f52bf92005-12-01 01:41:46 -08002138#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002139#define IPW2100_HANDLER(v, f) { v, f, # v }
2140struct ipw2100_status_indicator {
2141 int status;
James Ketrenosee8e3652005-09-14 09:47:29 -05002142 void (*cb) (struct ipw2100_priv * priv, u32 status);
James Ketrenos2c86c272005-03-23 17:32:29 -06002143 char *name;
2144};
2145#else
2146#define IPW2100_HANDLER(v, f) { v, f }
2147struct ipw2100_status_indicator {
2148 int status;
James Ketrenosee8e3652005-09-14 09:47:29 -05002149 void (*cb) (struct ipw2100_priv * priv, u32 status);
James Ketrenos2c86c272005-03-23 17:32:29 -06002150};
Brice Goglin0f52bf92005-12-01 01:41:46 -08002151#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -06002152
2153static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
2154{
2155 IPW_DEBUG_SCAN("Scanning...\n");
2156 priv->status |= STATUS_SCANNING;
2157}
2158
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002159static const struct ipw2100_status_indicator status_handlers[] = {
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002160 IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL),
2161 IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002162 IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated),
2163 IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002164 IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002165 IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002166 IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL),
2167 IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002168 IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002169 IPW2100_HANDLER(IPW_STATE_DISABLED, NULL),
2170 IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002171 IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002172 IPW2100_HANDLER(-1, NULL)
James Ketrenos2c86c272005-03-23 17:32:29 -06002173};
2174
James Ketrenos2c86c272005-03-23 17:32:29 -06002175static void isr_status_change(struct ipw2100_priv *priv, int status)
2176{
2177 int i;
2178
2179 if (status == IPW_STATE_SCANNING &&
2180 priv->status & STATUS_ASSOCIATED &&
2181 !(priv->status & STATUS_SCANNING)) {
2182 IPW_DEBUG_INFO("Scan detected while associated, with "
2183 "no scan request. Restarting firmware.\n");
2184
2185 /* Wake up any sleeping jobs */
2186 schedule_reset(priv);
2187 }
2188
2189 for (i = 0; status_handlers[i].status != -1; i++) {
2190 if (status == status_handlers[i].status) {
2191 IPW_DEBUG_NOTIF("Status change: %s\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002192 status_handlers[i].name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002193 if (status_handlers[i].cb)
2194 status_handlers[i].cb(priv, status);
2195 priv->wstats.status = status;
2196 return;
2197 }
2198 }
2199
2200 IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);
2201}
2202
James Ketrenosee8e3652005-09-14 09:47:29 -05002203static void isr_rx_complete_command(struct ipw2100_priv *priv,
2204 struct ipw2100_cmd_header *cmd)
James Ketrenos2c86c272005-03-23 17:32:29 -06002205{
Brice Goglin0f52bf92005-12-01 01:41:46 -08002206#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002207 if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
2208 IPW_DEBUG_HC("Command completed '%s (%d)'\n",
2209 command_types[cmd->host_command_reg],
2210 cmd->host_command_reg);
2211 }
2212#endif
2213 if (cmd->host_command_reg == HOST_COMPLETE)
2214 priv->status |= STATUS_ENABLED;
2215
2216 if (cmd->host_command_reg == CARD_DISABLE)
2217 priv->status &= ~STATUS_ENABLED;
2218
2219 priv->status &= ~STATUS_CMD_ACTIVE;
2220
2221 wake_up_interruptible(&priv->wait_command_queue);
2222}
2223
Brice Goglin0f52bf92005-12-01 01:41:46 -08002224#ifdef CONFIG_IPW2100_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002225static const char *frame_types[] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06002226 "COMMAND_STATUS_VAL",
2227 "STATUS_CHANGE_VAL",
2228 "P80211_DATA_VAL",
2229 "P8023_DATA_VAL",
2230 "HOST_NOTIFICATION_VAL"
2231};
2232#endif
2233
Arjan van de Ven858119e2006-01-14 13:20:43 -08002234static int ipw2100_alloc_skb(struct ipw2100_priv *priv,
James Ketrenosee8e3652005-09-14 09:47:29 -05002235 struct ipw2100_rx_packet *packet)
James Ketrenos2c86c272005-03-23 17:32:29 -06002236{
2237 packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
2238 if (!packet->skb)
2239 return -ENOMEM;
2240
2241 packet->rxp = (struct ipw2100_rx *)packet->skb->data;
2242 packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data,
2243 sizeof(struct ipw2100_rx),
2244 PCI_DMA_FROMDEVICE);
2245 /* NOTE: pci_map_single does not return an error code, and 0 is a valid
2246 * dma_addr */
2247
2248 return 0;
2249}
2250
James Ketrenos2c86c272005-03-23 17:32:29 -06002251#define SEARCH_ERROR 0xffffffff
2252#define SEARCH_FAIL 0xfffffffe
2253#define SEARCH_SUCCESS 0xfffffff0
2254#define SEARCH_DISCARD 0
2255#define SEARCH_SNAPSHOT 1
2256
2257#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
Zhu Yi3c5eca52006-01-24 13:49:26 +08002258static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
2259{
2260 int i;
2261 if (!priv->snapshot[0])
2262 return;
2263 for (i = 0; i < 0x30; i++)
2264 kfree(priv->snapshot[i]);
2265 priv->snapshot[0] = NULL;
2266}
2267
Robert P. J. Dayae800312007-01-31 02:39:40 -05002268#ifdef IPW2100_DEBUG_C3
Arjan van de Ven858119e2006-01-14 13:20:43 -08002269static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002270{
2271 int i;
2272 if (priv->snapshot[0])
2273 return 1;
2274 for (i = 0; i < 0x30; i++) {
Robert P. J. Day5cbded52006-12-13 00:35:56 -08002275 priv->snapshot[i] = kmalloc(0x1000, GFP_ATOMIC);
James Ketrenos2c86c272005-03-23 17:32:29 -06002276 if (!priv->snapshot[i]) {
2277 IPW_DEBUG_INFO("%s: Error allocating snapshot "
James Ketrenosee8e3652005-09-14 09:47:29 -05002278 "buffer %d\n", priv->net_dev->name, i);
James Ketrenos2c86c272005-03-23 17:32:29 -06002279 while (i > 0)
2280 kfree(priv->snapshot[--i]);
2281 priv->snapshot[0] = NULL;
2282 return 0;
2283 }
2284 }
2285
2286 return 1;
2287}
2288
Arjan van de Ven858119e2006-01-14 13:20:43 -08002289static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
James Ketrenos2c86c272005-03-23 17:32:29 -06002290 size_t len, int mode)
2291{
2292 u32 i, j;
2293 u32 tmp;
2294 u8 *s, *d;
2295 u32 ret;
2296
2297 s = in_buf;
2298 if (mode == SEARCH_SNAPSHOT) {
2299 if (!ipw2100_snapshot_alloc(priv))
2300 mode = SEARCH_DISCARD;
2301 }
2302
2303 for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) {
2304 read_nic_dword(priv->net_dev, i, &tmp);
2305 if (mode == SEARCH_SNAPSHOT)
James Ketrenosee8e3652005-09-14 09:47:29 -05002306 *(u32 *) SNAPSHOT_ADDR(i) = tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06002307 if (ret == SEARCH_FAIL) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002308 d = (u8 *) & tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06002309 for (j = 0; j < 4; j++) {
2310 if (*s != *d) {
2311 s = in_buf;
2312 continue;
2313 }
2314
2315 s++;
2316 d++;
2317
2318 if ((s - in_buf) == len)
2319 ret = (i + j) - len + 1;
2320 }
2321 } else if (mode == SEARCH_DISCARD)
2322 return ret;
2323 }
2324
2325 return ret;
2326}
Zhu Yi3c5eca52006-01-24 13:49:26 +08002327#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06002328
2329/*
2330 *
2331 * 0) Disconnect the SKB from the firmware (just unmap)
2332 * 1) Pack the ETH header into the SKB
2333 * 2) Pass the SKB to the network stack
2334 *
2335 * When packet is provided by the firmware, it contains the following:
2336 *
2337 * . ieee80211_hdr
2338 * . ieee80211_snap_hdr
2339 *
2340 * The size of the constructed ethernet
2341 *
2342 */
Robert P. J. Dayae800312007-01-31 02:39:40 -05002343#ifdef IPW2100_RX_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002344static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
James Ketrenos2c86c272005-03-23 17:32:29 -06002345#endif
2346
Arjan van de Ven858119e2006-01-14 13:20:43 -08002347static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
James Ketrenos2c86c272005-03-23 17:32:29 -06002348{
Robert P. J. Dayae800312007-01-31 02:39:40 -05002349#ifdef IPW2100_DEBUG_C3
James Ketrenos2c86c272005-03-23 17:32:29 -06002350 struct ipw2100_status *status = &priv->status_queue.drv[i];
2351 u32 match, reg;
2352 int j;
2353#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06002354
Zhu Yia1e695a2005-07-04 14:06:00 +08002355 IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n",
2356 i * sizeof(struct ipw2100_status));
James Ketrenos2c86c272005-03-23 17:32:29 -06002357
Robert P. J. Dayae800312007-01-31 02:39:40 -05002358#ifdef IPW2100_DEBUG_C3
James Ketrenos2c86c272005-03-23 17:32:29 -06002359 /* Halt the fimrware so we can get a good image */
2360 write_register(priv->net_dev, IPW_REG_RESET_REG,
2361 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
2362 j = 5;
2363 do {
2364 udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
2365 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
2366
2367 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
2368 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05002369 } while (j--);
James Ketrenos2c86c272005-03-23 17:32:29 -06002370
James Ketrenosee8e3652005-09-14 09:47:29 -05002371 match = ipw2100_match_buf(priv, (u8 *) status,
James Ketrenos2c86c272005-03-23 17:32:29 -06002372 sizeof(struct ipw2100_status),
2373 SEARCH_SNAPSHOT);
2374 if (match < SEARCH_SUCCESS)
2375 IPW_DEBUG_INFO("%s: DMA status match in Firmware at "
2376 "offset 0x%06X, length %d:\n",
2377 priv->net_dev->name, match,
2378 sizeof(struct ipw2100_status));
2379 else
2380 IPW_DEBUG_INFO("%s: No DMA status match in "
2381 "Firmware.\n", priv->net_dev->name);
2382
James Ketrenosee8e3652005-09-14 09:47:29 -05002383 printk_buf((u8 *) priv->status_queue.drv,
James Ketrenos2c86c272005-03-23 17:32:29 -06002384 sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);
2385#endif
2386
2387 priv->fatal_error = IPW2100_ERR_C3_CORRUPTION;
2388 priv->ieee->stats.rx_errors++;
2389 schedule_reset(priv);
2390}
2391
Arjan van de Ven858119e2006-01-14 13:20:43 -08002392static void isr_rx(struct ipw2100_priv *priv, int i,
James Ketrenos2c86c272005-03-23 17:32:29 -06002393 struct ieee80211_rx_stats *stats)
2394{
2395 struct ipw2100_status *status = &priv->status_queue.drv[i];
2396 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
2397
2398 IPW_DEBUG_RX("Handler...\n");
2399
2400 if (unlikely(status->frame_size > skb_tailroom(packet->skb))) {
2401 IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
2402 " Dropping.\n",
2403 priv->net_dev->name,
2404 status->frame_size, skb_tailroom(packet->skb));
2405 priv->ieee->stats.rx_errors++;
2406 return;
2407 }
2408
2409 if (unlikely(!netif_running(priv->net_dev))) {
2410 priv->ieee->stats.rx_errors++;
2411 priv->wstats.discard.misc++;
2412 IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
2413 return;
2414 }
James Ketrenos2c86c272005-03-23 17:32:29 -06002415
2416 if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
James Ketrenosee8e3652005-09-14 09:47:29 -05002417 !(priv->status & STATUS_ASSOCIATED))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002418 IPW_DEBUG_DROP("Dropping packet while not associated.\n");
2419 priv->wstats.discard.misc++;
2420 return;
2421 }
2422
James Ketrenos2c86c272005-03-23 17:32:29 -06002423 pci_unmap_single(priv->pci_dev,
2424 packet->dma_addr,
James Ketrenosee8e3652005-09-14 09:47:29 -05002425 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002426
2427 skb_put(packet->skb, status->frame_size);
2428
Robert P. J. Dayae800312007-01-31 02:39:40 -05002429#ifdef IPW2100_RX_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002430 /* Make a copy of the frame so we can dump it to the logs if
2431 * ieee80211_rx fails */
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03002432 skb_copy_from_linear_data(packet->skb, packet_data,
2433 min_t(u32, status->frame_size,
2434 IPW_RX_NIC_BUFFER_LENGTH));
James Ketrenos2c86c272005-03-23 17:32:29 -06002435#endif
2436
2437 if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
Robert P. J. Dayae800312007-01-31 02:39:40 -05002438#ifdef IPW2100_RX_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002439 IPW_DEBUG_DROP("%s: Non consumed packet:\n",
2440 priv->net_dev->name);
2441 printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
2442#endif
2443 priv->ieee->stats.rx_errors++;
2444
2445 /* ieee80211_rx failed, so it didn't free the SKB */
2446 dev_kfree_skb_any(packet->skb);
2447 packet->skb = NULL;
2448 }
2449
2450 /* We need to allocate a new SKB and attach it to the RDB. */
2451 if (unlikely(ipw2100_alloc_skb(priv, packet))) {
Jiri Benc797b4f72005-08-25 20:03:27 -04002452 printk(KERN_WARNING DRV_NAME ": "
James Ketrenosee8e3652005-09-14 09:47:29 -05002453 "%s: Unable to allocate SKB onto RBD ring - disabling "
2454 "adapter.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002455 /* TODO: schedule adapter shutdown */
2456 IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
2457 }
2458
2459 /* Update the RDB entry */
2460 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
2461}
2462
Stefan Rompf15745a72006-02-21 18:36:17 +08002463#ifdef CONFIG_IPW2100_MONITOR
2464
2465static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
2466 struct ieee80211_rx_stats *stats)
2467{
2468 struct ipw2100_status *status = &priv->status_queue.drv[i];
2469 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
2470
Stefan Rompf15745a72006-02-21 18:36:17 +08002471 /* Magic struct that slots into the radiotap header -- no reason
2472 * to build this manually element by element, we can write it much
2473 * more efficiently than we can parse it. ORDER MATTERS HERE */
2474 struct ipw_rt_hdr {
2475 struct ieee80211_radiotap_header rt_hdr;
2476 s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
2477 } *ipw_rt;
2478
Zhu Yicae16292006-02-21 18:41:14 +08002479 IPW_DEBUG_RX("Handler...\n");
2480
2481 if (unlikely(status->frame_size > skb_tailroom(packet->skb) -
2482 sizeof(struct ipw_rt_hdr))) {
Stefan Rompf15745a72006-02-21 18:36:17 +08002483 IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
2484 " Dropping.\n",
2485 priv->net_dev->name,
Zhu Yicae16292006-02-21 18:41:14 +08002486 status->frame_size,
2487 skb_tailroom(packet->skb));
Stefan Rompf15745a72006-02-21 18:36:17 +08002488 priv->ieee->stats.rx_errors++;
2489 return;
2490 }
2491
2492 if (unlikely(!netif_running(priv->net_dev))) {
2493 priv->ieee->stats.rx_errors++;
2494 priv->wstats.discard.misc++;
2495 IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
2496 return;
2497 }
2498
2499 if (unlikely(priv->config & CFG_CRC_CHECK &&
2500 status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
2501 IPW_DEBUG_RX("CRC error in packet. Dropping.\n");
2502 priv->ieee->stats.rx_errors++;
2503 return;
2504 }
2505
Zhu Yicae16292006-02-21 18:41:14 +08002506 pci_unmap_single(priv->pci_dev, packet->dma_addr,
Stefan Rompf15745a72006-02-21 18:36:17 +08002507 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
2508 memmove(packet->skb->data + sizeof(struct ipw_rt_hdr),
2509 packet->skb->data, status->frame_size);
2510
2511 ipw_rt = (struct ipw_rt_hdr *) packet->skb->data;
2512
2513 ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
2514 ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
Al Viro1edd3a52007-12-21 00:15:18 -05002515 ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total hdr+data */
Stefan Rompf15745a72006-02-21 18:36:17 +08002516
Al Viro1edd3a52007-12-21 00:15:18 -05002517 ipw_rt->rt_hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
Stefan Rompf15745a72006-02-21 18:36:17 +08002518
2519 ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM;
2520
2521 skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr));
2522
2523 if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
2524 priv->ieee->stats.rx_errors++;
2525
2526 /* ieee80211_rx failed, so it didn't free the SKB */
2527 dev_kfree_skb_any(packet->skb);
2528 packet->skb = NULL;
2529 }
2530
2531 /* We need to allocate a new SKB and attach it to the RDB. */
2532 if (unlikely(ipw2100_alloc_skb(priv, packet))) {
2533 IPW_DEBUG_WARNING(
2534 "%s: Unable to allocate SKB onto RBD ring - disabling "
2535 "adapter.\n", priv->net_dev->name);
2536 /* TODO: schedule adapter shutdown */
2537 IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
2538 }
2539
2540 /* Update the RDB entry */
2541 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
2542}
2543
2544#endif
2545
Arjan van de Ven858119e2006-01-14 13:20:43 -08002546static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
James Ketrenos2c86c272005-03-23 17:32:29 -06002547{
2548 struct ipw2100_status *status = &priv->status_queue.drv[i];
2549 struct ipw2100_rx *u = priv->rx_buffers[i].rxp;
2550 u16 frame_type = status->status_fields & STATUS_TYPE_MASK;
2551
2552 switch (frame_type) {
2553 case COMMAND_STATUS_VAL:
2554 return (status->frame_size != sizeof(u->rx_data.command));
2555 case STATUS_CHANGE_VAL:
2556 return (status->frame_size != sizeof(u->rx_data.status));
2557 case HOST_NOTIFICATION_VAL:
2558 return (status->frame_size < sizeof(u->rx_data.notification));
2559 case P80211_DATA_VAL:
2560 case P8023_DATA_VAL:
2561#ifdef CONFIG_IPW2100_MONITOR
2562 return 0;
2563#else
Al Viro1edd3a52007-12-21 00:15:18 -05002564 switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002565 case IEEE80211_FTYPE_MGMT:
2566 case IEEE80211_FTYPE_CTL:
2567 return 0;
2568 case IEEE80211_FTYPE_DATA:
2569 return (status->frame_size >
2570 IPW_MAX_802_11_PAYLOAD_LENGTH);
2571 }
2572#endif
2573 }
2574
2575 return 1;
2576}
2577
2578/*
2579 * ipw2100 interrupts are disabled at this point, and the ISR
2580 * is the only code that calls this method. So, we do not need
2581 * to play with any locks.
2582 *
2583 * RX Queue works as follows:
2584 *
2585 * Read index - firmware places packet in entry identified by the
2586 * Read index and advances Read index. In this manner,
2587 * Read index will always point to the next packet to
2588 * be filled--but not yet valid.
2589 *
2590 * Write index - driver fills this entry with an unused RBD entry.
2591 * This entry has not filled by the firmware yet.
2592 *
2593 * In between the W and R indexes are the RBDs that have been received
2594 * but not yet processed.
2595 *
2596 * The process of handling packets will start at WRITE + 1 and advance
2597 * until it reaches the READ index.
2598 *
2599 * The WRITE index is cached in the variable 'priv->rx_queue.next'.
2600 *
2601 */
Arjan van de Ven858119e2006-01-14 13:20:43 -08002602static void __ipw2100_rx_process(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002603{
2604 struct ipw2100_bd_queue *rxq = &priv->rx_queue;
2605 struct ipw2100_status_queue *sq = &priv->status_queue;
2606 struct ipw2100_rx_packet *packet;
2607 u16 frame_type;
2608 u32 r, w, i, s;
2609 struct ipw2100_rx *u;
2610 struct ieee80211_rx_stats stats = {
2611 .mac_time = jiffies,
2612 };
2613
2614 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r);
2615 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w);
2616
2617 if (r >= rxq->entries) {
2618 IPW_DEBUG_RX("exit - bad read index\n");
2619 return;
2620 }
2621
2622 i = (rxq->next + 1) % rxq->entries;
2623 s = i;
2624 while (i != r) {
2625 /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n",
2626 r, rxq->next, i); */
2627
2628 packet = &priv->rx_buffers[i];
2629
2630 /* Sync the DMA for the STATUS buffer so CPU is sure to get
2631 * the correct values */
James Ketrenosee8e3652005-09-14 09:47:29 -05002632 pci_dma_sync_single_for_cpu(priv->pci_dev,
2633 sq->nic +
2634 sizeof(struct ipw2100_status) * i,
2635 sizeof(struct ipw2100_status),
2636 PCI_DMA_FROMDEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002637
2638 /* Sync the DMA for the RX buffer so CPU is sure to get
2639 * the correct values */
2640 pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr,
2641 sizeof(struct ipw2100_rx),
2642 PCI_DMA_FROMDEVICE);
2643
2644 if (unlikely(ipw2100_corruption_check(priv, i))) {
2645 ipw2100_corruption_detected(priv, i);
2646 goto increment;
2647 }
2648
2649 u = packet->rxp;
James Ketrenosee8e3652005-09-14 09:47:29 -05002650 frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK;
James Ketrenos2c86c272005-03-23 17:32:29 -06002651 stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM;
2652 stats.len = sq->drv[i].frame_size;
2653
2654 stats.mask = 0;
2655 if (stats.rssi != 0)
2656 stats.mask |= IEEE80211_STATMASK_RSSI;
2657 stats.freq = IEEE80211_24GHZ_BAND;
2658
James Ketrenosee8e3652005-09-14 09:47:29 -05002659 IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n",
2660 priv->net_dev->name, frame_types[frame_type],
2661 stats.len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002662
2663 switch (frame_type) {
2664 case COMMAND_STATUS_VAL:
2665 /* Reset Rx watchdog */
James Ketrenosee8e3652005-09-14 09:47:29 -05002666 isr_rx_complete_command(priv, &u->rx_data.command);
James Ketrenos2c86c272005-03-23 17:32:29 -06002667 break;
2668
2669 case STATUS_CHANGE_VAL:
2670 isr_status_change(priv, u->rx_data.status);
2671 break;
2672
2673 case P80211_DATA_VAL:
2674 case P8023_DATA_VAL:
2675#ifdef CONFIG_IPW2100_MONITOR
2676 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
Stefan Rompf15745a72006-02-21 18:36:17 +08002677 isr_rx_monitor(priv, i, &stats);
James Ketrenos2c86c272005-03-23 17:32:29 -06002678 break;
2679 }
2680#endif
Zhu Yife5f8e22006-12-20 16:11:58 +08002681 if (stats.len < sizeof(struct ieee80211_hdr_3addr))
James Ketrenos2c86c272005-03-23 17:32:29 -06002682 break;
Al Viro1edd3a52007-12-21 00:15:18 -05002683 switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002684 case IEEE80211_FTYPE_MGMT:
2685 ieee80211_rx_mgt(priv->ieee,
James Ketrenosee8e3652005-09-14 09:47:29 -05002686 &u->rx_data.header, &stats);
James Ketrenos2c86c272005-03-23 17:32:29 -06002687 break;
2688
2689 case IEEE80211_FTYPE_CTL:
2690 break;
2691
2692 case IEEE80211_FTYPE_DATA:
2693 isr_rx(priv, i, &stats);
2694 break;
2695
2696 }
2697 break;
2698 }
2699
James Ketrenosee8e3652005-09-14 09:47:29 -05002700 increment:
James Ketrenos2c86c272005-03-23 17:32:29 -06002701 /* clear status field associated with this RBD */
2702 rxq->drv[i].status.info.field = 0;
2703
2704 i = (i + 1) % rxq->entries;
2705 }
2706
2707 if (i != s) {
2708 /* backtrack one entry, wrapping to end if at 0 */
2709 rxq->next = (i ? i : rxq->entries) - 1;
2710
2711 write_register(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05002712 IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next);
James Ketrenos2c86c272005-03-23 17:32:29 -06002713 }
2714}
2715
James Ketrenos2c86c272005-03-23 17:32:29 -06002716/*
2717 * __ipw2100_tx_process
2718 *
2719 * This routine will determine whether the next packet on
2720 * the fw_pend_list has been processed by the firmware yet.
2721 *
2722 * If not, then it does nothing and returns.
2723 *
2724 * If so, then it removes the item from the fw_pend_list, frees
2725 * any associated storage, and places the item back on the
2726 * free list of its source (either msg_free_list or tx_free_list)
2727 *
2728 * TX Queue works as follows:
2729 *
2730 * Read index - points to the next TBD that the firmware will
2731 * process. The firmware will read the data, and once
2732 * done processing, it will advance the Read index.
2733 *
2734 * Write index - driver fills this entry with an constructed TBD
2735 * entry. The Write index is not advanced until the
2736 * packet has been configured.
2737 *
2738 * In between the W and R indexes are the TBDs that have NOT been
2739 * processed. Lagging behind the R index are packets that have
2740 * been processed but have not been freed by the driver.
2741 *
2742 * In order to free old storage, an internal index will be maintained
2743 * that points to the next packet to be freed. When all used
2744 * packets have been freed, the oldest index will be the same as the
2745 * firmware's read index.
2746 *
2747 * The OLDEST index is cached in the variable 'priv->tx_queue.oldest'
2748 *
2749 * Because the TBD structure can not contain arbitrary data, the
2750 * driver must keep an internal queue of cached allocations such that
2751 * it can put that data back into the tx_free_list and msg_free_list
2752 * for use by future command and data packets.
2753 *
2754 */
Arjan van de Ven858119e2006-01-14 13:20:43 -08002755static int __ipw2100_tx_process(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002756{
2757 struct ipw2100_bd_queue *txq = &priv->tx_queue;
James Ketrenosee8e3652005-09-14 09:47:29 -05002758 struct ipw2100_bd *tbd;
James Ketrenos2c86c272005-03-23 17:32:29 -06002759 struct list_head *element;
2760 struct ipw2100_tx_packet *packet;
2761 int descriptors_used;
2762 int e, i;
2763 u32 r, w, frag_num = 0;
2764
2765 if (list_empty(&priv->fw_pend_list))
2766 return 0;
2767
2768 element = priv->fw_pend_list.next;
2769
2770 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenosee8e3652005-09-14 09:47:29 -05002771 tbd = &txq->drv[packet->index];
James Ketrenos2c86c272005-03-23 17:32:29 -06002772
2773 /* Determine how many TBD entries must be finished... */
2774 switch (packet->type) {
2775 case COMMAND:
2776 /* COMMAND uses only one slot; don't advance */
2777 descriptors_used = 1;
2778 e = txq->oldest;
2779 break;
2780
2781 case DATA:
2782 /* DATA uses two slots; advance and loop position. */
2783 descriptors_used = tbd->num_fragments;
James Ketrenosee8e3652005-09-14 09:47:29 -05002784 frag_num = tbd->num_fragments - 1;
James Ketrenos2c86c272005-03-23 17:32:29 -06002785 e = txq->oldest + frag_num;
2786 e %= txq->entries;
2787 break;
2788
2789 default:
Jiri Benc797b4f72005-08-25 20:03:27 -04002790 printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002791 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002792 return 0;
2793 }
2794
2795 /* if the last TBD is not done by NIC yet, then packet is
2796 * not ready to be released.
2797 *
2798 */
2799 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
2800 &r);
2801 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
2802 &w);
2803 if (w != txq->next)
Jiri Benc797b4f72005-08-25 20:03:27 -04002804 printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06002805 priv->net_dev->name);
2806
James Ketrenosee8e3652005-09-14 09:47:29 -05002807 /*
James Ketrenos2c86c272005-03-23 17:32:29 -06002808 * txq->next is the index of the last packet written txq->oldest is
2809 * the index of the r is the index of the next packet to be read by
2810 * firmware
2811 */
2812
James Ketrenos2c86c272005-03-23 17:32:29 -06002813 /*
2814 * Quick graphic to help you visualize the following
2815 * if / else statement
2816 *
2817 * ===>| s---->|===============
2818 * e>|
2819 * | a | b | c | d | e | f | g | h | i | j | k | l
2820 * r---->|
2821 * w
2822 *
2823 * w - updated by driver
2824 * r - updated by firmware
2825 * s - start of oldest BD entry (txq->oldest)
2826 * e - end of oldest BD entry
2827 *
2828 */
2829 if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) {
2830 IPW_DEBUG_TX("exit - no processed packets ready to release.\n");
2831 return 0;
2832 }
2833
2834 list_del(element);
2835 DEC_STAT(&priv->fw_pend_stat);
2836
Brice Goglin0f52bf92005-12-01 01:41:46 -08002837#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002838 {
2839 int i = txq->oldest;
James Ketrenosee8e3652005-09-14 09:47:29 -05002840 IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
2841 &txq->drv[i],
2842 (u32) (txq->nic + i * sizeof(struct ipw2100_bd)),
2843 txq->drv[i].host_addr, txq->drv[i].buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002844
2845 if (packet->type == DATA) {
2846 i = (i + 1) % txq->entries;
2847
James Ketrenosee8e3652005-09-14 09:47:29 -05002848 IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
2849 &txq->drv[i],
2850 (u32) (txq->nic + i *
2851 sizeof(struct ipw2100_bd)),
2852 (u32) txq->drv[i].host_addr,
2853 txq->drv[i].buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002854 }
2855 }
2856#endif
2857
2858 switch (packet->type) {
2859 case DATA:
2860 if (txq->drv[txq->oldest].status.info.fields.txType != 0)
Jiri Benc797b4f72005-08-25 20:03:27 -04002861 printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
James Ketrenos2c86c272005-03-23 17:32:29 -06002862 "Expecting DATA TBD but pulled "
2863 "something else: ids %d=%d.\n",
2864 priv->net_dev->name, txq->oldest, packet->index);
2865
2866 /* DATA packet; we have to unmap and free the SKB */
James Ketrenos2c86c272005-03-23 17:32:29 -06002867 for (i = 0; i < frag_num; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002868 tbd = &txq->drv[(packet->index + 1 + i) % txq->entries];
James Ketrenos2c86c272005-03-23 17:32:29 -06002869
James Ketrenosee8e3652005-09-14 09:47:29 -05002870 IPW_DEBUG_TX("TX%d P=%08x L=%d\n",
2871 (packet->index + 1 + i) % txq->entries,
2872 tbd->host_addr, tbd->buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002873
2874 pci_unmap_single(priv->pci_dev,
2875 tbd->host_addr,
James Ketrenosee8e3652005-09-14 09:47:29 -05002876 tbd->buf_length, PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002877 }
2878
James Ketrenos2c86c272005-03-23 17:32:29 -06002879 ieee80211_txb_free(packet->info.d_struct.txb);
2880 packet->info.d_struct.txb = NULL;
2881
2882 list_add_tail(element, &priv->tx_free_list);
2883 INC_STAT(&priv->tx_free_stat);
2884
2885 /* We have a free slot in the Tx queue, so wake up the
2886 * transmit layer if it is stopped. */
James Ketrenos82328352005-08-24 22:33:31 -05002887 if (priv->status & STATUS_ASSOCIATED)
James Ketrenos2c86c272005-03-23 17:32:29 -06002888 netif_wake_queue(priv->net_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06002889
2890 /* A packet was processed by the hardware, so update the
2891 * watchdog */
2892 priv->net_dev->trans_start = jiffies;
2893
2894 break;
2895
2896 case COMMAND:
2897 if (txq->drv[txq->oldest].status.info.fields.txType != 1)
Jiri Benc797b4f72005-08-25 20:03:27 -04002898 printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
James Ketrenos2c86c272005-03-23 17:32:29 -06002899 "Expecting COMMAND TBD but pulled "
2900 "something else: ids %d=%d.\n",
2901 priv->net_dev->name, txq->oldest, packet->index);
2902
Brice Goglin0f52bf92005-12-01 01:41:46 -08002903#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002904 if (packet->info.c_struct.cmd->host_command_reg <
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02002905 ARRAY_SIZE(command_types))
James Ketrenosee8e3652005-09-14 09:47:29 -05002906 IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n",
2907 command_types[packet->info.c_struct.cmd->
2908 host_command_reg],
2909 packet->info.c_struct.cmd->
2910 host_command_reg,
2911 packet->info.c_struct.cmd->cmd_status_reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06002912#endif
2913
2914 list_add_tail(element, &priv->msg_free_list);
2915 INC_STAT(&priv->msg_free_stat);
2916 break;
2917 }
2918
2919 /* advance oldest used TBD pointer to start of next entry */
2920 txq->oldest = (e + 1) % txq->entries;
2921 /* increase available TBDs number */
2922 txq->available += descriptors_used;
2923 SET_STAT(&priv->txq_stat, txq->available);
2924
2925 IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002926 jiffies - packet->jiffy_start);
James Ketrenos2c86c272005-03-23 17:32:29 -06002927
2928 return (!list_empty(&priv->fw_pend_list));
2929}
2930
James Ketrenos2c86c272005-03-23 17:32:29 -06002931static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
2932{
2933 int i = 0;
2934
James Ketrenosee8e3652005-09-14 09:47:29 -05002935 while (__ipw2100_tx_process(priv) && i < 200)
2936 i++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002937
2938 if (i == 200) {
Jiri Benc19f7f742005-08-25 20:02:10 -04002939 printk(KERN_WARNING DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06002940 "%s: Driver is running slow (%d iters).\n",
2941 priv->net_dev->name, i);
2942 }
2943}
2944
Jiri Benc19f7f742005-08-25 20:02:10 -04002945static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002946{
2947 struct list_head *element;
2948 struct ipw2100_tx_packet *packet;
2949 struct ipw2100_bd_queue *txq = &priv->tx_queue;
2950 struct ipw2100_bd *tbd;
2951 int next = txq->next;
2952
2953 while (!list_empty(&priv->msg_pend_list)) {
2954 /* if there isn't enough space in TBD queue, then
2955 * don't stuff a new one in.
2956 * NOTE: 3 are needed as a command will take one,
2957 * and there is a minimum of 2 that must be
2958 * maintained between the r and w indexes
2959 */
2960 if (txq->available <= 3) {
2961 IPW_DEBUG_TX("no room in tx_queue\n");
2962 break;
2963 }
2964
2965 element = priv->msg_pend_list.next;
2966 list_del(element);
2967 DEC_STAT(&priv->msg_pend_stat);
2968
James Ketrenosee8e3652005-09-14 09:47:29 -05002969 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06002970
2971 IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002972 &txq->drv[txq->next],
2973 (void *)(txq->nic + txq->next *
2974 sizeof(struct ipw2100_bd)));
James Ketrenos2c86c272005-03-23 17:32:29 -06002975
2976 packet->index = txq->next;
2977
2978 tbd = &txq->drv[txq->next];
2979
2980 /* initialize TBD */
2981 tbd->host_addr = packet->info.c_struct.cmd_phys;
2982 tbd->buf_length = sizeof(struct ipw2100_cmd_header);
2983 /* not marking number of fragments causes problems
2984 * with f/w debug version */
2985 tbd->num_fragments = 1;
2986 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05002987 IPW_BD_STATUS_TX_FRAME_COMMAND |
2988 IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06002989
2990 /* update TBD queue counters */
2991 txq->next++;
2992 txq->next %= txq->entries;
2993 txq->available--;
2994 DEC_STAT(&priv->txq_stat);
2995
2996 list_add_tail(element, &priv->fw_pend_list);
2997 INC_STAT(&priv->fw_pend_stat);
2998 }
2999
3000 if (txq->next != next) {
3001 /* kick off the DMA by notifying firmware the
3002 * write index has moved; make sure TBD stores are sync'd */
3003 wmb();
3004 write_register(priv->net_dev,
3005 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
3006 txq->next);
3007 }
3008}
3009
James Ketrenos2c86c272005-03-23 17:32:29 -06003010/*
Jiri Benc19f7f742005-08-25 20:02:10 -04003011 * ipw2100_tx_send_data
James Ketrenos2c86c272005-03-23 17:32:29 -06003012 *
3013 */
Jiri Benc19f7f742005-08-25 20:02:10 -04003014static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06003015{
3016 struct list_head *element;
3017 struct ipw2100_tx_packet *packet;
3018 struct ipw2100_bd_queue *txq = &priv->tx_queue;
3019 struct ipw2100_bd *tbd;
3020 int next = txq->next;
James Ketrenosee8e3652005-09-14 09:47:29 -05003021 int i = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06003022 struct ipw2100_data_header *ipw_hdr;
James Ketrenos99a4b232005-09-21 12:23:25 -05003023 struct ieee80211_hdr_3addr *hdr;
James Ketrenos2c86c272005-03-23 17:32:29 -06003024
3025 while (!list_empty(&priv->tx_pend_list)) {
3026 /* if there isn't enough space in TBD queue, then
3027 * don't stuff a new one in.
3028 * NOTE: 4 are needed as a data will take two,
3029 * and there is a minimum of 2 that must be
3030 * maintained between the r and w indexes
3031 */
3032 element = priv->tx_pend_list.next;
James Ketrenosee8e3652005-09-14 09:47:29 -05003033 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06003034
3035 if (unlikely(1 + packet->info.d_struct.txb->nr_frags >
3036 IPW_MAX_BDS)) {
3037 /* TODO: Support merging buffers if more than
3038 * IPW_MAX_BDS are used */
James Ketrenosee8e3652005-09-14 09:47:29 -05003039 IPW_DEBUG_INFO("%s: Maximum BD theshold exceeded. "
3040 "Increase fragmentation level.\n",
3041 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003042 }
3043
James Ketrenosee8e3652005-09-14 09:47:29 -05003044 if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003045 IPW_DEBUG_TX("no room in tx_queue\n");
3046 break;
3047 }
3048
3049 list_del(element);
3050 DEC_STAT(&priv->tx_pend_stat);
3051
3052 tbd = &txq->drv[txq->next];
3053
3054 packet->index = txq->next;
3055
3056 ipw_hdr = packet->info.d_struct.data;
James Ketrenos99a4b232005-09-21 12:23:25 -05003057 hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb->
James Ketrenosee8e3652005-09-14 09:47:29 -05003058 fragments[0]->data;
James Ketrenos2c86c272005-03-23 17:32:29 -06003059
3060 if (priv->ieee->iw_mode == IW_MODE_INFRA) {
3061 /* To DS: Addr1 = BSSID, Addr2 = SA,
3062 Addr3 = DA */
3063 memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
3064 memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN);
3065 } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
3066 /* not From/To DS: Addr1 = DA, Addr2 = SA,
3067 Addr3 = BSSID */
3068 memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
3069 memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN);
3070 }
3071
3072 ipw_hdr->host_command_reg = SEND;
3073 ipw_hdr->host_command_reg1 = 0;
3074
3075 /* For now we only support host based encryption */
3076 ipw_hdr->needs_encryption = 0;
3077 ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted;
3078 if (packet->info.d_struct.txb->nr_frags > 1)
3079 ipw_hdr->fragment_size =
James Ketrenosee8e3652005-09-14 09:47:29 -05003080 packet->info.d_struct.txb->frag_size -
3081 IEEE80211_3ADDR_LEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06003082 else
3083 ipw_hdr->fragment_size = 0;
3084
3085 tbd->host_addr = packet->info.d_struct.data_phys;
3086 tbd->buf_length = sizeof(struct ipw2100_data_header);
3087 tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags;
3088 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003089 IPW_BD_STATUS_TX_FRAME_802_3 |
3090 IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
James Ketrenos2c86c272005-03-23 17:32:29 -06003091 txq->next++;
3092 txq->next %= txq->entries;
3093
James Ketrenosee8e3652005-09-14 09:47:29 -05003094 IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n",
3095 packet->index, tbd->host_addr, tbd->buf_length);
Brice Goglin0f52bf92005-12-01 01:41:46 -08003096#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06003097 if (packet->info.d_struct.txb->nr_frags > 1)
3098 IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
3099 packet->info.d_struct.txb->nr_frags);
3100#endif
3101
James Ketrenosee8e3652005-09-14 09:47:29 -05003102 for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
3103 tbd = &txq->drv[txq->next];
James Ketrenos2c86c272005-03-23 17:32:29 -06003104 if (i == packet->info.d_struct.txb->nr_frags - 1)
3105 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003106 IPW_BD_STATUS_TX_FRAME_802_3 |
3107 IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06003108 else
3109 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003110 IPW_BD_STATUS_TX_FRAME_802_3 |
3111 IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
James Ketrenos2c86c272005-03-23 17:32:29 -06003112
3113 tbd->buf_length = packet->info.d_struct.txb->
James Ketrenosee8e3652005-09-14 09:47:29 -05003114 fragments[i]->len - IEEE80211_3ADDR_LEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06003115
James Ketrenosee8e3652005-09-14 09:47:29 -05003116 tbd->host_addr = pci_map_single(priv->pci_dev,
3117 packet->info.d_struct.
3118 txb->fragments[i]->
3119 data +
3120 IEEE80211_3ADDR_LEN,
3121 tbd->buf_length,
3122 PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003123
James Ketrenosee8e3652005-09-14 09:47:29 -05003124 IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n",
3125 txq->next, tbd->host_addr,
3126 tbd->buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06003127
James Ketrenosee8e3652005-09-14 09:47:29 -05003128 pci_dma_sync_single_for_device(priv->pci_dev,
3129 tbd->host_addr,
3130 tbd->buf_length,
3131 PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003132
3133 txq->next++;
3134 txq->next %= txq->entries;
James Ketrenosee8e3652005-09-14 09:47:29 -05003135 }
James Ketrenos2c86c272005-03-23 17:32:29 -06003136
3137 txq->available -= 1 + packet->info.d_struct.txb->nr_frags;
3138 SET_STAT(&priv->txq_stat, txq->available);
3139
3140 list_add_tail(element, &priv->fw_pend_list);
3141 INC_STAT(&priv->fw_pend_stat);
3142 }
3143
3144 if (txq->next != next) {
3145 /* kick off the DMA by notifying firmware the
3146 * write index has moved; make sure TBD stores are sync'd */
3147 write_register(priv->net_dev,
3148 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
3149 txq->next);
3150 }
James Ketrenosee8e3652005-09-14 09:47:29 -05003151 return;
James Ketrenos2c86c272005-03-23 17:32:29 -06003152}
3153
3154static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
3155{
3156 struct net_device *dev = priv->net_dev;
3157 unsigned long flags;
3158 u32 inta, tmp;
3159
3160 spin_lock_irqsave(&priv->low_lock, flags);
3161 ipw2100_disable_interrupts(priv);
3162
3163 read_register(dev, IPW_REG_INTA, &inta);
3164
3165 IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n",
3166 (unsigned long)inta & IPW_INTERRUPT_MASK);
3167
3168 priv->in_isr++;
3169 priv->interrupts++;
3170
3171 /* We do not loop and keep polling for more interrupts as this
3172 * is frowned upon and doesn't play nicely with other potentially
3173 * chained IRQs */
3174 IPW_DEBUG_ISR("INTA: 0x%08lX\n",
3175 (unsigned long)inta & IPW_INTERRUPT_MASK);
3176
3177 if (inta & IPW2100_INTA_FATAL_ERROR) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003178 printk(KERN_WARNING DRV_NAME
James Ketrenosee8e3652005-09-14 09:47:29 -05003179 ": Fatal interrupt. Scheduling firmware restart.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003180 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003181 write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003182
3183 read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error);
3184 IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n",
3185 priv->net_dev->name, priv->fatal_error);
3186
3187 read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp);
3188 IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n",
3189 priv->net_dev->name, tmp);
3190
3191 /* Wake up any sleeping jobs */
3192 schedule_reset(priv);
3193 }
3194
3195 if (inta & IPW2100_INTA_PARITY_ERROR) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003196 printk(KERN_ERR DRV_NAME
3197 ": ***** PARITY ERROR INTERRUPT !!!! \n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003198 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003199 write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003200 }
3201
3202 if (inta & IPW2100_INTA_RX_TRANSFER) {
3203 IPW_DEBUG_ISR("RX interrupt\n");
3204
3205 priv->rx_interrupts++;
3206
James Ketrenosee8e3652005-09-14 09:47:29 -05003207 write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER);
James Ketrenos2c86c272005-03-23 17:32:29 -06003208
3209 __ipw2100_rx_process(priv);
3210 __ipw2100_tx_complete(priv);
3211 }
3212
3213 if (inta & IPW2100_INTA_TX_TRANSFER) {
3214 IPW_DEBUG_ISR("TX interrupt\n");
3215
3216 priv->tx_interrupts++;
3217
James Ketrenosee8e3652005-09-14 09:47:29 -05003218 write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER);
James Ketrenos2c86c272005-03-23 17:32:29 -06003219
3220 __ipw2100_tx_complete(priv);
Jiri Benc19f7f742005-08-25 20:02:10 -04003221 ipw2100_tx_send_commands(priv);
3222 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06003223 }
3224
3225 if (inta & IPW2100_INTA_TX_COMPLETE) {
3226 IPW_DEBUG_ISR("TX complete\n");
3227 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003228 write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003229
3230 __ipw2100_tx_complete(priv);
3231 }
3232
3233 if (inta & IPW2100_INTA_EVENT_INTERRUPT) {
3234 /* ipw2100_handle_event(dev); */
3235 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003236 write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT);
James Ketrenos2c86c272005-03-23 17:32:29 -06003237 }
3238
3239 if (inta & IPW2100_INTA_FW_INIT_DONE) {
3240 IPW_DEBUG_ISR("FW init done interrupt\n");
3241 priv->inta_other++;
3242
3243 read_register(dev, IPW_REG_INTA, &tmp);
3244 if (tmp & (IPW2100_INTA_FATAL_ERROR |
3245 IPW2100_INTA_PARITY_ERROR)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003246 write_register(dev, IPW_REG_INTA,
3247 IPW2100_INTA_FATAL_ERROR |
3248 IPW2100_INTA_PARITY_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003249 }
3250
James Ketrenosee8e3652005-09-14 09:47:29 -05003251 write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003252 }
3253
3254 if (inta & IPW2100_INTA_STATUS_CHANGE) {
3255 IPW_DEBUG_ISR("Status change interrupt\n");
3256 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003257 write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003258 }
3259
3260 if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) {
3261 IPW_DEBUG_ISR("slave host mode interrupt\n");
3262 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003263 write_register(dev, IPW_REG_INTA,
3264 IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003265 }
3266
3267 priv->in_isr--;
3268 ipw2100_enable_interrupts(priv);
3269
3270 spin_unlock_irqrestore(&priv->low_lock, flags);
3271
3272 IPW_DEBUG_ISR("exit\n");
3273}
3274
David Howells7d12e782006-10-05 14:55:46 +01003275static irqreturn_t ipw2100_interrupt(int irq, void *data)
James Ketrenos2c86c272005-03-23 17:32:29 -06003276{
3277 struct ipw2100_priv *priv = data;
3278 u32 inta, inta_mask;
3279
3280 if (!data)
3281 return IRQ_NONE;
3282
James Ketrenosee8e3652005-09-14 09:47:29 -05003283 spin_lock(&priv->low_lock);
James Ketrenos2c86c272005-03-23 17:32:29 -06003284
3285 /* We check to see if we should be ignoring interrupts before
3286 * we touch the hardware. During ucode load if we try and handle
3287 * an interrupt we can cause keyboard problems as well as cause
3288 * the ucode to fail to initialize */
3289 if (!(priv->status & STATUS_INT_ENABLED)) {
3290 /* Shared IRQ */
3291 goto none;
3292 }
3293
3294 read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
3295 read_register(priv->net_dev, IPW_REG_INTA, &inta);
3296
3297 if (inta == 0xFFFFFFFF) {
3298 /* Hardware disappeared */
Jiri Benc797b4f72005-08-25 20:03:27 -04003299 printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003300 goto none;
3301 }
3302
3303 inta &= IPW_INTERRUPT_MASK;
3304
3305 if (!(inta & inta_mask)) {
3306 /* Shared interrupt */
3307 goto none;
3308 }
3309
3310 /* We disable the hardware interrupt here just to prevent unneeded
3311 * calls to be made. We disable this again within the actual
3312 * work tasklet, so if another part of the code re-enables the
3313 * interrupt, that is fine */
3314 ipw2100_disable_interrupts(priv);
3315
3316 tasklet_schedule(&priv->irq_tasklet);
James Ketrenosee8e3652005-09-14 09:47:29 -05003317 spin_unlock(&priv->low_lock);
James Ketrenos2c86c272005-03-23 17:32:29 -06003318
3319 return IRQ_HANDLED;
James Ketrenosee8e3652005-09-14 09:47:29 -05003320 none:
James Ketrenos2c86c272005-03-23 17:32:29 -06003321 spin_unlock(&priv->low_lock);
3322 return IRQ_NONE;
3323}
3324
James Ketrenos3a5becf2005-09-21 12:23:37 -05003325static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev,
3326 int pri)
James Ketrenos2c86c272005-03-23 17:32:29 -06003327{
3328 struct ipw2100_priv *priv = ieee80211_priv(dev);
3329 struct list_head *element;
3330 struct ipw2100_tx_packet *packet;
3331 unsigned long flags;
3332
3333 spin_lock_irqsave(&priv->low_lock, flags);
3334
3335 if (!(priv->status & STATUS_ASSOCIATED)) {
3336 IPW_DEBUG_INFO("Can not transmit when not connected.\n");
3337 priv->ieee->stats.tx_carrier_errors++;
3338 netif_stop_queue(dev);
3339 goto fail_unlock;
3340 }
3341
3342 if (list_empty(&priv->tx_free_list))
3343 goto fail_unlock;
3344
3345 element = priv->tx_free_list.next;
3346 packet = list_entry(element, struct ipw2100_tx_packet, list);
3347
3348 packet->info.d_struct.txb = txb;
3349
James Ketrenosee8e3652005-09-14 09:47:29 -05003350 IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len);
3351 printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len);
James Ketrenos2c86c272005-03-23 17:32:29 -06003352
3353 packet->jiffy_start = jiffies;
3354
3355 list_del(element);
3356 DEC_STAT(&priv->tx_free_stat);
3357
3358 list_add_tail(element, &priv->tx_pend_list);
3359 INC_STAT(&priv->tx_pend_stat);
3360
Jiri Benc19f7f742005-08-25 20:02:10 -04003361 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06003362
3363 spin_unlock_irqrestore(&priv->low_lock, flags);
3364 return 0;
3365
James Ketrenosee8e3652005-09-14 09:47:29 -05003366 fail_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -06003367 netif_stop_queue(dev);
3368 spin_unlock_irqrestore(&priv->low_lock, flags);
3369 return 1;
3370}
3371
James Ketrenos2c86c272005-03-23 17:32:29 -06003372static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
3373{
3374 int i, j, err = -EINVAL;
3375 void *v;
3376 dma_addr_t p;
3377
James Ketrenosee8e3652005-09-14 09:47:29 -05003378 priv->msg_buffers =
3379 (struct ipw2100_tx_packet *)kmalloc(IPW_COMMAND_POOL_SIZE *
3380 sizeof(struct
3381 ipw2100_tx_packet),
3382 GFP_KERNEL);
James Ketrenos2c86c272005-03-23 17:32:29 -06003383 if (!priv->msg_buffers) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003384 printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg "
James Ketrenos2c86c272005-03-23 17:32:29 -06003385 "buffers.\n", priv->net_dev->name);
3386 return -ENOMEM;
3387 }
3388
3389 for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003390 v = pci_alloc_consistent(priv->pci_dev,
3391 sizeof(struct ipw2100_cmd_header), &p);
James Ketrenos2c86c272005-03-23 17:32:29 -06003392 if (!v) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003393 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06003394 "%s: PCI alloc failed for msg "
James Ketrenosee8e3652005-09-14 09:47:29 -05003395 "buffers.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003396 err = -ENOMEM;
3397 break;
3398 }
3399
3400 memset(v, 0, sizeof(struct ipw2100_cmd_header));
3401
3402 priv->msg_buffers[i].type = COMMAND;
3403 priv->msg_buffers[i].info.c_struct.cmd =
James Ketrenosee8e3652005-09-14 09:47:29 -05003404 (struct ipw2100_cmd_header *)v;
James Ketrenos2c86c272005-03-23 17:32:29 -06003405 priv->msg_buffers[i].info.c_struct.cmd_phys = p;
3406 }
3407
3408 if (i == IPW_COMMAND_POOL_SIZE)
3409 return 0;
3410
3411 for (j = 0; j < i; j++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003412 pci_free_consistent(priv->pci_dev,
3413 sizeof(struct ipw2100_cmd_header),
3414 priv->msg_buffers[j].info.c_struct.cmd,
3415 priv->msg_buffers[j].info.c_struct.
3416 cmd_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06003417 }
3418
3419 kfree(priv->msg_buffers);
3420 priv->msg_buffers = NULL;
3421
3422 return err;
3423}
3424
3425static int ipw2100_msg_initialize(struct ipw2100_priv *priv)
3426{
3427 int i;
3428
3429 INIT_LIST_HEAD(&priv->msg_free_list);
3430 INIT_LIST_HEAD(&priv->msg_pend_list);
3431
3432 for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++)
3433 list_add_tail(&priv->msg_buffers[i].list, &priv->msg_free_list);
3434 SET_STAT(&priv->msg_free_stat, i);
3435
3436 return 0;
3437}
3438
3439static void ipw2100_msg_free(struct ipw2100_priv *priv)
3440{
3441 int i;
3442
3443 if (!priv->msg_buffers)
3444 return;
3445
3446 for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
3447 pci_free_consistent(priv->pci_dev,
3448 sizeof(struct ipw2100_cmd_header),
3449 priv->msg_buffers[i].info.c_struct.cmd,
James Ketrenosee8e3652005-09-14 09:47:29 -05003450 priv->msg_buffers[i].info.c_struct.
3451 cmd_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06003452 }
3453
3454 kfree(priv->msg_buffers);
3455 priv->msg_buffers = NULL;
3456}
3457
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003458static ssize_t show_pci(struct device *d, struct device_attribute *attr,
3459 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003460{
3461 struct pci_dev *pci_dev = container_of(d, struct pci_dev, dev);
3462 char *out = buf;
3463 int i, j;
3464 u32 val;
3465
3466 for (i = 0; i < 16; i++) {
3467 out += sprintf(out, "[%08X] ", i * 16);
3468 for (j = 0; j < 16; j += 4) {
3469 pci_read_config_dword(pci_dev, i * 16 + j, &val);
3470 out += sprintf(out, "%08X ", val);
3471 }
3472 out += sprintf(out, "\n");
3473 }
3474
3475 return out - buf;
3476}
James Ketrenosee8e3652005-09-14 09:47:29 -05003477
James Ketrenos2c86c272005-03-23 17:32:29 -06003478static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL);
3479
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003480static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
3481 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003482{
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003483 struct ipw2100_priv *p = d->driver_data;
James Ketrenos2c86c272005-03-23 17:32:29 -06003484 return sprintf(buf, "0x%08x\n", (int)p->config);
3485}
James Ketrenosee8e3652005-09-14 09:47:29 -05003486
James Ketrenos2c86c272005-03-23 17:32:29 -06003487static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
3488
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003489static ssize_t show_status(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003490 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003491{
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003492 struct ipw2100_priv *p = d->driver_data;
James Ketrenos2c86c272005-03-23 17:32:29 -06003493 return sprintf(buf, "0x%08x\n", (int)p->status);
3494}
James Ketrenosee8e3652005-09-14 09:47:29 -05003495
James Ketrenos2c86c272005-03-23 17:32:29 -06003496static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
3497
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003498static ssize_t show_capability(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003499 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003500{
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003501 struct ipw2100_priv *p = d->driver_data;
James Ketrenos2c86c272005-03-23 17:32:29 -06003502 return sprintf(buf, "0x%08x\n", (int)p->capability);
3503}
James Ketrenos2c86c272005-03-23 17:32:29 -06003504
James Ketrenosee8e3652005-09-14 09:47:29 -05003505static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL);
James Ketrenos2c86c272005-03-23 17:32:29 -06003506
3507#define IPW2100_REG(x) { IPW_ ##x, #x }
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003508static const struct {
James Ketrenos2c86c272005-03-23 17:32:29 -06003509 u32 addr;
3510 const char *name;
3511} hw_data[] = {
James Ketrenosee8e3652005-09-14 09:47:29 -05003512IPW2100_REG(REG_GP_CNTRL),
3513 IPW2100_REG(REG_GPIO),
3514 IPW2100_REG(REG_INTA),
3515 IPW2100_REG(REG_INTA_MASK), IPW2100_REG(REG_RESET_REG),};
James Ketrenos2c86c272005-03-23 17:32:29 -06003516#define IPW2100_NIC(x, s) { x, #x, s }
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003517static const struct {
James Ketrenos2c86c272005-03-23 17:32:29 -06003518 u32 addr;
3519 const char *name;
3520 size_t size;
3521} nic_data[] = {
James Ketrenosee8e3652005-09-14 09:47:29 -05003522IPW2100_NIC(IPW2100_CONTROL_REG, 2),
3523 IPW2100_NIC(0x210014, 1), IPW2100_NIC(0x210000, 1),};
James Ketrenos2c86c272005-03-23 17:32:29 -06003524#define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d }
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003525static const struct {
James Ketrenos2c86c272005-03-23 17:32:29 -06003526 u8 index;
3527 const char *name;
3528 const char *desc;
3529} ord_data[] = {
James Ketrenosee8e3652005-09-14 09:47:29 -05003530IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
3531 IPW2100_ORD(STAT_TX_HOST_COMPLETE,
3532 "successful Host Tx's (MSDU)"),
3533 IPW2100_ORD(STAT_TX_DIR_DATA,
3534 "successful Directed Tx's (MSDU)"),
3535 IPW2100_ORD(STAT_TX_DIR_DATA1,
3536 "successful Directed Tx's (MSDU) @ 1MB"),
3537 IPW2100_ORD(STAT_TX_DIR_DATA2,
3538 "successful Directed Tx's (MSDU) @ 2MB"),
3539 IPW2100_ORD(STAT_TX_DIR_DATA5_5,
3540 "successful Directed Tx's (MSDU) @ 5_5MB"),
3541 IPW2100_ORD(STAT_TX_DIR_DATA11,
3542 "successful Directed Tx's (MSDU) @ 11MB"),
3543 IPW2100_ORD(STAT_TX_NODIR_DATA1,
3544 "successful Non_Directed Tx's (MSDU) @ 1MB"),
3545 IPW2100_ORD(STAT_TX_NODIR_DATA2,
3546 "successful Non_Directed Tx's (MSDU) @ 2MB"),
3547 IPW2100_ORD(STAT_TX_NODIR_DATA5_5,
3548 "successful Non_Directed Tx's (MSDU) @ 5.5MB"),
3549 IPW2100_ORD(STAT_TX_NODIR_DATA11,
3550 "successful Non_Directed Tx's (MSDU) @ 11MB"),
3551 IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"),
3552 IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"),
3553 IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"),
3554 IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"),
3555 IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"),
3556 IPW2100_ORD(STAT_TX_ASSN_RESP,
3557 "successful Association response Tx's"),
3558 IPW2100_ORD(STAT_TX_REASSN,
3559 "successful Reassociation Tx's"),
3560 IPW2100_ORD(STAT_TX_REASSN_RESP,
3561 "successful Reassociation response Tx's"),
3562 IPW2100_ORD(STAT_TX_PROBE,
3563 "probes successfully transmitted"),
3564 IPW2100_ORD(STAT_TX_PROBE_RESP,
3565 "probe responses successfully transmitted"),
3566 IPW2100_ORD(STAT_TX_BEACON, "tx beacon"),
3567 IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"),
3568 IPW2100_ORD(STAT_TX_DISASSN,
3569 "successful Disassociation TX"),
3570 IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"),
3571 IPW2100_ORD(STAT_TX_DEAUTH,
3572 "successful Deauthentication TX"),
3573 IPW2100_ORD(STAT_TX_TOTAL_BYTES,
3574 "Total successful Tx data bytes"),
3575 IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"),
3576 IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"),
3577 IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"),
3578 IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"),
3579 IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"),
3580 IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"),
3581 IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,
3582 "times max tries in a hop failed"),
3583 IPW2100_ORD(STAT_TX_DISASSN_FAIL,
3584 "times disassociation failed"),
3585 IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"),
3586 IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"),
3587 IPW2100_ORD(STAT_RX_HOST, "packets passed to host"),
3588 IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"),
3589 IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"),
3590 IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"),
3591 IPW2100_ORD(STAT_RX_DIR_DATA5_5,
3592 "directed packets at 5.5MB"),
3593 IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"),
3594 IPW2100_ORD(STAT_RX_NODIR_DATA, "nondirected packets"),
3595 IPW2100_ORD(STAT_RX_NODIR_DATA1,
3596 "nondirected packets at 1MB"),
3597 IPW2100_ORD(STAT_RX_NODIR_DATA2,
3598 "nondirected packets at 2MB"),
3599 IPW2100_ORD(STAT_RX_NODIR_DATA5_5,
3600 "nondirected packets at 5.5MB"),
3601 IPW2100_ORD(STAT_RX_NODIR_DATA11,
3602 "nondirected packets at 11MB"),
3603 IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"),
3604 IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), IPW2100_ORD(STAT_RX_CTS,
3605 "Rx CTS"),
3606 IPW2100_ORD(STAT_RX_ACK, "Rx ACK"),
3607 IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"),
3608 IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"),
3609 IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"),
3610 IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"),
3611 IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"),
3612 IPW2100_ORD(STAT_RX_REASSN_RESP,
3613 "Reassociation response Rx's"),
3614 IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"),
3615 IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"),
3616 IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"),
3617 IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"),
3618 IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"),
3619 IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"),
3620 IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"),
3621 IPW2100_ORD(STAT_RX_TOTAL_BYTES,
3622 "Total rx data bytes received"),
3623 IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"),
3624 IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"),
3625 IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"),
3626 IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"),
3627 IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"),
3628 IPW2100_ORD(STAT_RX_DUPLICATE1,
3629 "duplicate rx packets at 1MB"),
3630 IPW2100_ORD(STAT_RX_DUPLICATE2,
3631 "duplicate rx packets at 2MB"),
3632 IPW2100_ORD(STAT_RX_DUPLICATE5_5,
3633 "duplicate rx packets at 5.5MB"),
3634 IPW2100_ORD(STAT_RX_DUPLICATE11,
3635 "duplicate rx packets at 11MB"),
3636 IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
3637 IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"),
3638 IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"),
3639 IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"),
3640 IPW2100_ORD(STAT_RX_INVALID_PROTOCOL,
3641 "rx frames with invalid protocol"),
3642 IPW2100_ORD(SYS_BOOT_TIME, "Boot time"),
3643 IPW2100_ORD(STAT_RX_NO_BUFFER,
3644 "rx frames rejected due to no buffer"),
3645 IPW2100_ORD(STAT_RX_MISSING_FRAG,
3646 "rx frames dropped due to missing fragment"),
3647 IPW2100_ORD(STAT_RX_ORPHAN_FRAG,
3648 "rx frames dropped due to non-sequential fragment"),
3649 IPW2100_ORD(STAT_RX_ORPHAN_FRAME,
3650 "rx frames dropped due to unmatched 1st frame"),
3651 IPW2100_ORD(STAT_RX_FRAG_AGEOUT,
3652 "rx frames dropped due to uncompleted frame"),
3653 IPW2100_ORD(STAT_RX_ICV_ERRORS,
3654 "ICV errors during decryption"),
3655 IPW2100_ORD(STAT_PSP_SUSPENSION, "times adapter suspended"),
3656 IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"),
3657 IPW2100_ORD(STAT_PSP_POLL_TIMEOUT,
3658 "poll response timeouts"),
3659 IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT,
3660 "timeouts waiting for last {broad,multi}cast pkt"),
3661 IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"),
3662 IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"),
3663 IPW2100_ORD(STAT_PSP_STATION_ID, "PSP Station ID"),
3664 IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"),
3665 IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,
3666 "current calculation of % missed beacons"),
3667 IPW2100_ORD(STAT_PERCENT_RETRIES,
3668 "current calculation of % missed tx retries"),
3669 IPW2100_ORD(ASSOCIATED_AP_PTR,
3670 "0 if not associated, else pointer to AP table entry"),
3671 IPW2100_ORD(AVAILABLE_AP_CNT,
3672 "AP's decsribed in the AP table"),
3673 IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"),
3674 IPW2100_ORD(STAT_AP_ASSNS, "associations"),
3675 IPW2100_ORD(STAT_ASSN_FAIL, "association failures"),
3676 IPW2100_ORD(STAT_ASSN_RESP_FAIL,
3677 "failures due to response fail"),
3678 IPW2100_ORD(STAT_FULL_SCANS, "full scans"),
3679 IPW2100_ORD(CARD_DISABLED, "Card Disabled"),
3680 IPW2100_ORD(STAT_ROAM_INHIBIT,
3681 "times roaming was inhibited due to activity"),
3682 IPW2100_ORD(RSSI_AT_ASSN,
3683 "RSSI of associated AP at time of association"),
3684 IPW2100_ORD(STAT_ASSN_CAUSE1,
3685 "reassociation: no probe response or TX on hop"),
3686 IPW2100_ORD(STAT_ASSN_CAUSE2,
3687 "reassociation: poor tx/rx quality"),
3688 IPW2100_ORD(STAT_ASSN_CAUSE3,
3689 "reassociation: tx/rx quality (excessive AP load"),
3690 IPW2100_ORD(STAT_ASSN_CAUSE4,
3691 "reassociation: AP RSSI level"),
3692 IPW2100_ORD(STAT_ASSN_CAUSE5,
3693 "reassociations due to load leveling"),
3694 IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"),
3695 IPW2100_ORD(STAT_AUTH_RESP_FAIL,
3696 "times authentication response failed"),
3697 IPW2100_ORD(STATION_TABLE_CNT,
3698 "entries in association table"),
3699 IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"),
3700 IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"),
3701 IPW2100_ORD(COUNTRY_CODE,
3702 "IEEE country code as recv'd from beacon"),
3703 IPW2100_ORD(COUNTRY_CHANNELS,
3704 "channels suported by country"),
3705 IPW2100_ORD(RESET_CNT, "adapter resets (warm)"),
3706 IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"),
3707 IPW2100_ORD(ANTENNA_DIVERSITY,
3708 "TRUE if antenna diversity is disabled"),
3709 IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"),
3710 IPW2100_ORD(OUR_FREQ,
3711 "current radio freq lower digits - channel ID"),
3712 IPW2100_ORD(RTC_TIME, "current RTC time"),
3713 IPW2100_ORD(PORT_TYPE, "operating mode"),
3714 IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"),
3715 IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"),
3716 IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"),
3717 IPW2100_ORD(BASIC_RATES, "basic tx rates"),
3718 IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"),
3719 IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"),
3720 IPW2100_ORD(CAPABILITIES,
3721 "Management frame capability field"),
3722 IPW2100_ORD(AUTH_TYPE, "Type of authentication"),
3723 IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"),
3724 IPW2100_ORD(RTS_THRESHOLD,
3725 "Min packet length for RTS handshaking"),
3726 IPW2100_ORD(INT_MODE, "International mode"),
3727 IPW2100_ORD(FRAGMENTATION_THRESHOLD,
3728 "protocol frag threshold"),
3729 IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
3730 "EEPROM offset in SRAM"),
3731 IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE,
3732 "EEPROM size in SRAM"),
3733 IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"),
3734 IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS,
3735 "EEPROM IBSS 11b channel set"),
3736 IPW2100_ORD(MAC_VERSION, "MAC Version"),
3737 IPW2100_ORD(MAC_REVISION, "MAC Revision"),
3738 IPW2100_ORD(RADIO_VERSION, "Radio Version"),
3739 IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"),
3740 IPW2100_ORD(UCODE_VERSION, "Ucode Version"),};
James Ketrenos2c86c272005-03-23 17:32:29 -06003741
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003742static ssize_t show_registers(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003743 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003744{
3745 int i;
3746 struct ipw2100_priv *priv = dev_get_drvdata(d);
3747 struct net_device *dev = priv->net_dev;
James Ketrenosee8e3652005-09-14 09:47:29 -05003748 char *out = buf;
James Ketrenos2c86c272005-03-23 17:32:29 -06003749 u32 val = 0;
3750
3751 out += sprintf(out, "%30s [Address ] : Hex\n", "Register");
3752
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003753 for (i = 0; i < ARRAY_SIZE(hw_data); i++) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003754 read_register(dev, hw_data[i].addr, &val);
3755 out += sprintf(out, "%30s [%08X] : %08X\n",
3756 hw_data[i].name, hw_data[i].addr, val);
3757 }
3758
3759 return out - buf;
3760}
James Ketrenosee8e3652005-09-14 09:47:29 -05003761
James Ketrenos2c86c272005-03-23 17:32:29 -06003762static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
3763
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003764static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003765 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003766{
3767 struct ipw2100_priv *priv = dev_get_drvdata(d);
3768 struct net_device *dev = priv->net_dev;
James Ketrenosee8e3652005-09-14 09:47:29 -05003769 char *out = buf;
James Ketrenos2c86c272005-03-23 17:32:29 -06003770 int i;
3771
3772 out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry");
3773
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003774 for (i = 0; i < ARRAY_SIZE(nic_data); i++) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003775 u8 tmp8;
3776 u16 tmp16;
3777 u32 tmp32;
3778
3779 switch (nic_data[i].size) {
3780 case 1:
3781 read_nic_byte(dev, nic_data[i].addr, &tmp8);
3782 out += sprintf(out, "%30s [%08X] : %02X\n",
3783 nic_data[i].name, nic_data[i].addr,
3784 tmp8);
3785 break;
3786 case 2:
3787 read_nic_word(dev, nic_data[i].addr, &tmp16);
3788 out += sprintf(out, "%30s [%08X] : %04X\n",
3789 nic_data[i].name, nic_data[i].addr,
3790 tmp16);
3791 break;
3792 case 4:
3793 read_nic_dword(dev, nic_data[i].addr, &tmp32);
3794 out += sprintf(out, "%30s [%08X] : %08X\n",
3795 nic_data[i].name, nic_data[i].addr,
3796 tmp32);
3797 break;
3798 }
3799 }
3800 return out - buf;
3801}
James Ketrenosee8e3652005-09-14 09:47:29 -05003802
James Ketrenos2c86c272005-03-23 17:32:29 -06003803static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
3804
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003805static ssize_t show_memory(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003806 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003807{
3808 struct ipw2100_priv *priv = dev_get_drvdata(d);
3809 struct net_device *dev = priv->net_dev;
3810 static unsigned long loop = 0;
3811 int len = 0;
3812 u32 buffer[4];
3813 int i;
3814 char line[81];
3815
3816 if (loop >= 0x30000)
3817 loop = 0;
3818
3819 /* sysfs provides us PAGE_SIZE buffer */
3820 while (len < PAGE_SIZE - 128 && loop < 0x30000) {
3821
James Ketrenosee8e3652005-09-14 09:47:29 -05003822 if (priv->snapshot[0])
3823 for (i = 0; i < 4; i++)
3824 buffer[i] =
3825 *(u32 *) SNAPSHOT_ADDR(loop + i * 4);
3826 else
3827 for (i = 0; i < 4; i++)
3828 read_nic_dword(dev, loop + i * 4, &buffer[i]);
James Ketrenos2c86c272005-03-23 17:32:29 -06003829
3830 if (priv->dump_raw)
3831 len += sprintf(buf + len,
3832 "%c%c%c%c"
3833 "%c%c%c%c"
3834 "%c%c%c%c"
3835 "%c%c%c%c",
James Ketrenosee8e3652005-09-14 09:47:29 -05003836 ((u8 *) buffer)[0x0],
3837 ((u8 *) buffer)[0x1],
3838 ((u8 *) buffer)[0x2],
3839 ((u8 *) buffer)[0x3],
3840 ((u8 *) buffer)[0x4],
3841 ((u8 *) buffer)[0x5],
3842 ((u8 *) buffer)[0x6],
3843 ((u8 *) buffer)[0x7],
3844 ((u8 *) buffer)[0x8],
3845 ((u8 *) buffer)[0x9],
3846 ((u8 *) buffer)[0xa],
3847 ((u8 *) buffer)[0xb],
3848 ((u8 *) buffer)[0xc],
3849 ((u8 *) buffer)[0xd],
3850 ((u8 *) buffer)[0xe],
3851 ((u8 *) buffer)[0xf]);
James Ketrenos2c86c272005-03-23 17:32:29 -06003852 else
3853 len += sprintf(buf + len, "%s\n",
3854 snprint_line(line, sizeof(line),
James Ketrenosee8e3652005-09-14 09:47:29 -05003855 (u8 *) buffer, 16, loop));
James Ketrenos2c86c272005-03-23 17:32:29 -06003856 loop += 16;
3857 }
3858
3859 return len;
3860}
3861
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003862static ssize_t store_memory(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003863 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06003864{
3865 struct ipw2100_priv *priv = dev_get_drvdata(d);
3866 struct net_device *dev = priv->net_dev;
3867 const char *p = buf;
3868
Zhu Yi8ed55a42006-01-24 13:49:20 +08003869 (void)dev; /* kill unused-var warning for debug-only code */
Jeff Garzikc2a8fad2005-11-09 00:49:38 -05003870
James Ketrenos2c86c272005-03-23 17:32:29 -06003871 if (count < 1)
3872 return count;
3873
3874 if (p[0] == '1' ||
3875 (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) {
3876 IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003877 dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003878 priv->dump_raw = 1;
3879
3880 } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' &&
James Ketrenosee8e3652005-09-14 09:47:29 -05003881 tolower(p[1]) == 'f')) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003882 IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003883 dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003884 priv->dump_raw = 0;
3885
3886 } else if (tolower(p[0]) == 'r') {
James Ketrenosee8e3652005-09-14 09:47:29 -05003887 IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003888 ipw2100_snapshot_free(priv);
3889
3890 } else
3891 IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, "
James Ketrenosee8e3652005-09-14 09:47:29 -05003892 "reset = clear memory snapshot\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003893
3894 return count;
3895}
James Ketrenos2c86c272005-03-23 17:32:29 -06003896
James Ketrenosee8e3652005-09-14 09:47:29 -05003897static DEVICE_ATTR(memory, S_IWUSR | S_IRUGO, show_memory, store_memory);
James Ketrenos2c86c272005-03-23 17:32:29 -06003898
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003899static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003900 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003901{
3902 struct ipw2100_priv *priv = dev_get_drvdata(d);
3903 u32 val = 0;
3904 int len = 0;
3905 u32 val_len;
3906 static int loop = 0;
3907
James Ketrenos82328352005-08-24 22:33:31 -05003908 if (priv->status & STATUS_RF_KILL_MASK)
3909 return 0;
3910
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003911 if (loop >= ARRAY_SIZE(ord_data))
James Ketrenos2c86c272005-03-23 17:32:29 -06003912 loop = 0;
3913
3914 /* sysfs provides us PAGE_SIZE buffer */
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003915 while (len < PAGE_SIZE - 128 && loop < ARRAY_SIZE(ord_data)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003916 val_len = sizeof(u32);
3917
3918 if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val,
3919 &val_len))
3920 len += sprintf(buf + len, "[0x%02X] = ERROR %s\n",
3921 ord_data[loop].index,
3922 ord_data[loop].desc);
3923 else
3924 len += sprintf(buf + len, "[0x%02X] = 0x%08X %s\n",
3925 ord_data[loop].index, val,
3926 ord_data[loop].desc);
3927 loop++;
3928 }
3929
3930 return len;
3931}
James Ketrenosee8e3652005-09-14 09:47:29 -05003932
James Ketrenos2c86c272005-03-23 17:32:29 -06003933static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL);
3934
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003935static ssize_t show_stats(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003936 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003937{
3938 struct ipw2100_priv *priv = dev_get_drvdata(d);
James Ketrenosee8e3652005-09-14 09:47:29 -05003939 char *out = buf;
James Ketrenos2c86c272005-03-23 17:32:29 -06003940
3941 out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n",
3942 priv->interrupts, priv->tx_interrupts,
3943 priv->rx_interrupts, priv->inta_other);
3944 out += sprintf(out, "firmware resets: %d\n", priv->resets);
3945 out += sprintf(out, "firmware hangs: %d\n", priv->hangs);
Brice Goglin0f52bf92005-12-01 01:41:46 -08003946#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06003947 out += sprintf(out, "packet mismatch image: %s\n",
3948 priv->snapshot[0] ? "YES" : "NO");
3949#endif
3950
3951 return out - buf;
3952}
James Ketrenos2c86c272005-03-23 17:32:29 -06003953
James Ketrenosee8e3652005-09-14 09:47:29 -05003954static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL);
James Ketrenos2c86c272005-03-23 17:32:29 -06003955
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003956static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06003957{
3958 int err;
3959
3960 if (mode == priv->ieee->iw_mode)
3961 return 0;
3962
3963 err = ipw2100_disable_adapter(priv);
3964 if (err) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003965 printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06003966 priv->net_dev->name, err);
3967 return err;
3968 }
3969
3970 switch (mode) {
3971 case IW_MODE_INFRA:
3972 priv->net_dev->type = ARPHRD_ETHER;
3973 break;
3974 case IW_MODE_ADHOC:
3975 priv->net_dev->type = ARPHRD_ETHER;
3976 break;
3977#ifdef CONFIG_IPW2100_MONITOR
3978 case IW_MODE_MONITOR:
3979 priv->last_mode = priv->ieee->iw_mode;
Stefan Rompf15745a72006-02-21 18:36:17 +08003980 priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
James Ketrenos2c86c272005-03-23 17:32:29 -06003981 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05003982#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06003983 }
3984
3985 priv->ieee->iw_mode = mode;
3986
3987#ifdef CONFIG_PM
James Ketrenosee8e3652005-09-14 09:47:29 -05003988 /* Indicate ipw2100_download_firmware download firmware
James Ketrenos2c86c272005-03-23 17:32:29 -06003989 * from disk instead of memory. */
3990 ipw2100_firmware.version = 0;
3991#endif
3992
James Ketrenosee8e3652005-09-14 09:47:29 -05003993 printk(KERN_INFO "%s: Reseting on mode change.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003994 priv->reset_backoff = 0;
3995 schedule_reset(priv);
3996
3997 return 0;
3998}
3999
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004000static ssize_t show_internals(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004001 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004002{
4003 struct ipw2100_priv *priv = dev_get_drvdata(d);
4004 int len = 0;
4005
James Ketrenosee8e3652005-09-14 09:47:29 -05004006#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x)
James Ketrenos2c86c272005-03-23 17:32:29 -06004007
4008 if (priv->status & STATUS_ASSOCIATED)
4009 len += sprintf(buf + len, "connected: %lu\n",
4010 get_seconds() - priv->connect_start);
4011 else
4012 len += sprintf(buf + len, "not connected\n");
4013
John W. Linville274bfb82008-10-29 11:35:05 -04004014 DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p");
James Ketrenosee8e3652005-09-14 09:47:29 -05004015 DUMP_VAR(status, "08lx");
4016 DUMP_VAR(config, "08lx");
4017 DUMP_VAR(capability, "08lx");
James Ketrenos2c86c272005-03-23 17:32:29 -06004018
James Ketrenosee8e3652005-09-14 09:47:29 -05004019 len +=
4020 sprintf(buf + len, "last_rtc: %lu\n",
4021 (unsigned long)priv->last_rtc);
James Ketrenos2c86c272005-03-23 17:32:29 -06004022
James Ketrenosee8e3652005-09-14 09:47:29 -05004023 DUMP_VAR(fatal_error, "d");
4024 DUMP_VAR(stop_hang_check, "d");
4025 DUMP_VAR(stop_rf_kill, "d");
4026 DUMP_VAR(messages_sent, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004027
James Ketrenosee8e3652005-09-14 09:47:29 -05004028 DUMP_VAR(tx_pend_stat.value, "d");
4029 DUMP_VAR(tx_pend_stat.hi, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004030
James Ketrenosee8e3652005-09-14 09:47:29 -05004031 DUMP_VAR(tx_free_stat.value, "d");
4032 DUMP_VAR(tx_free_stat.lo, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004033
James Ketrenosee8e3652005-09-14 09:47:29 -05004034 DUMP_VAR(msg_free_stat.value, "d");
4035 DUMP_VAR(msg_free_stat.lo, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004036
James Ketrenosee8e3652005-09-14 09:47:29 -05004037 DUMP_VAR(msg_pend_stat.value, "d");
4038 DUMP_VAR(msg_pend_stat.hi, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004039
James Ketrenosee8e3652005-09-14 09:47:29 -05004040 DUMP_VAR(fw_pend_stat.value, "d");
4041 DUMP_VAR(fw_pend_stat.hi, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004042
James Ketrenosee8e3652005-09-14 09:47:29 -05004043 DUMP_VAR(txq_stat.value, "d");
4044 DUMP_VAR(txq_stat.lo, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004045
James Ketrenosee8e3652005-09-14 09:47:29 -05004046 DUMP_VAR(ieee->scans, "d");
4047 DUMP_VAR(reset_backoff, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004048
4049 return len;
4050}
James Ketrenosee8e3652005-09-14 09:47:29 -05004051
James Ketrenos2c86c272005-03-23 17:32:29 -06004052static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL);
4053
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004054static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004055 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004056{
4057 struct ipw2100_priv *priv = dev_get_drvdata(d);
4058 char essid[IW_ESSID_MAX_SIZE + 1];
4059 u8 bssid[ETH_ALEN];
4060 u32 chan = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05004061 char *out = buf;
Hannes Ederb9da9e92009-02-14 11:50:26 +00004062 unsigned int length;
James Ketrenos2c86c272005-03-23 17:32:29 -06004063 int ret;
4064
James Ketrenos82328352005-08-24 22:33:31 -05004065 if (priv->status & STATUS_RF_KILL_MASK)
4066 return 0;
4067
James Ketrenos2c86c272005-03-23 17:32:29 -06004068 memset(essid, 0, sizeof(essid));
4069 memset(bssid, 0, sizeof(bssid));
4070
4071 length = IW_ESSID_MAX_SIZE;
4072 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &length);
4073 if (ret)
4074 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
4075 __LINE__);
4076
4077 length = sizeof(bssid);
4078 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
4079 bssid, &length);
4080 if (ret)
4081 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
4082 __LINE__);
4083
4084 length = sizeof(u32);
4085 ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &length);
4086 if (ret)
4087 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
4088 __LINE__);
4089
4090 out += sprintf(out, "ESSID: %s\n", essid);
Johannes Berge1749612008-10-27 15:59:26 -07004091 out += sprintf(out, "BSSID: %pM\n", bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06004092 out += sprintf(out, "Channel: %d\n", chan);
4093
4094 return out - buf;
4095}
James Ketrenos2c86c272005-03-23 17:32:29 -06004096
James Ketrenosee8e3652005-09-14 09:47:29 -05004097static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
James Ketrenos2c86c272005-03-23 17:32:29 -06004098
Brice Goglin0f52bf92005-12-01 01:41:46 -08004099#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06004100static ssize_t show_debug_level(struct device_driver *d, char *buf)
4101{
4102 return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
4103}
4104
James Ketrenos82328352005-08-24 22:33:31 -05004105static ssize_t store_debug_level(struct device_driver *d,
4106 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004107{
4108 char *p = (char *)buf;
4109 u32 val;
4110
4111 if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
4112 p++;
4113 if (p[0] == 'x' || p[0] == 'X')
4114 p++;
4115 val = simple_strtoul(p, &p, 16);
4116 } else
4117 val = simple_strtoul(p, &p, 10);
4118 if (p == buf)
Zhu Yia1e695a2005-07-04 14:06:00 +08004119 IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf);
James Ketrenos2c86c272005-03-23 17:32:29 -06004120 else
4121 ipw2100_debug_level = val;
4122
4123 return strnlen(buf, count);
4124}
James Ketrenosee8e3652005-09-14 09:47:29 -05004125
James Ketrenos2c86c272005-03-23 17:32:29 -06004126static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level,
4127 store_debug_level);
Brice Goglin0f52bf92005-12-01 01:41:46 -08004128#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -06004129
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004130static ssize_t show_fatal_error(struct device *d,
James Ketrenosee8e3652005-09-14 09:47:29 -05004131 struct device_attribute *attr, char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004132{
4133 struct ipw2100_priv *priv = dev_get_drvdata(d);
4134 char *out = buf;
4135 int i;
4136
4137 if (priv->fatal_error)
James Ketrenosee8e3652005-09-14 09:47:29 -05004138 out += sprintf(out, "0x%08X\n", priv->fatal_error);
James Ketrenos2c86c272005-03-23 17:32:29 -06004139 else
4140 out += sprintf(out, "0\n");
4141
4142 for (i = 1; i <= IPW2100_ERROR_QUEUE; i++) {
4143 if (!priv->fatal_errors[(priv->fatal_index - i) %
4144 IPW2100_ERROR_QUEUE])
4145 continue;
4146
4147 out += sprintf(out, "%d. 0x%08X\n", i,
4148 priv->fatal_errors[(priv->fatal_index - i) %
4149 IPW2100_ERROR_QUEUE]);
4150 }
4151
4152 return out - buf;
4153}
4154
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004155static ssize_t store_fatal_error(struct device *d,
James Ketrenosee8e3652005-09-14 09:47:29 -05004156 struct device_attribute *attr, const char *buf,
4157 size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004158{
4159 struct ipw2100_priv *priv = dev_get_drvdata(d);
4160 schedule_reset(priv);
4161 return count;
4162}
James Ketrenos2c86c272005-03-23 17:32:29 -06004163
James Ketrenosee8e3652005-09-14 09:47:29 -05004164static DEVICE_ATTR(fatal_error, S_IWUSR | S_IRUGO, show_fatal_error,
4165 store_fatal_error);
James Ketrenos2c86c272005-03-23 17:32:29 -06004166
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004167static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004168 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004169{
4170 struct ipw2100_priv *priv = dev_get_drvdata(d);
4171 return sprintf(buf, "%d\n", priv->ieee->scan_age);
4172}
4173
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004174static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004175 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004176{
4177 struct ipw2100_priv *priv = dev_get_drvdata(d);
4178 struct net_device *dev = priv->net_dev;
4179 char buffer[] = "00000000";
4180 unsigned long len =
4181 (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
4182 unsigned long val;
4183 char *p = buffer;
4184
Zhu Yi8ed55a42006-01-24 13:49:20 +08004185 (void)dev; /* kill unused-var warning for debug-only code */
Jeff Garzikc2a8fad2005-11-09 00:49:38 -05004186
James Ketrenos2c86c272005-03-23 17:32:29 -06004187 IPW_DEBUG_INFO("enter\n");
4188
4189 strncpy(buffer, buf, len);
4190 buffer[len] = 0;
4191
4192 if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
4193 p++;
4194 if (p[0] == 'x' || p[0] == 'X')
4195 p++;
4196 val = simple_strtoul(p, &p, 16);
4197 } else
4198 val = simple_strtoul(p, &p, 10);
4199 if (p == buffer) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004200 IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004201 } else {
4202 priv->ieee->scan_age = val;
4203 IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
4204 }
4205
4206 IPW_DEBUG_INFO("exit\n");
4207 return len;
4208}
James Ketrenosee8e3652005-09-14 09:47:29 -05004209
James Ketrenos2c86c272005-03-23 17:32:29 -06004210static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
4211
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004212static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004213 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004214{
4215 /* 0 - RF kill not enabled
4216 1 - SW based RF kill active (sysfs)
4217 2 - HW based RF kill active
4218 3 - Both HW and SW baed RF kill active */
4219 struct ipw2100_priv *priv = (struct ipw2100_priv *)d->driver_data;
4220 int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
James Ketrenosee8e3652005-09-14 09:47:29 -05004221 (rf_kill_active(priv) ? 0x2 : 0x0);
James Ketrenos2c86c272005-03-23 17:32:29 -06004222 return sprintf(buf, "%i\n", val);
4223}
4224
4225static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
4226{
4227 if ((disable_radio ? 1 : 0) ==
4228 (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
James Ketrenosee8e3652005-09-14 09:47:29 -05004229 return 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06004230
4231 IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
4232 disable_radio ? "OFF" : "ON");
4233
Ingo Molnar752e3772006-02-28 07:20:54 +08004234 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06004235
4236 if (disable_radio) {
4237 priv->status |= STATUS_RF_KILL_SW;
4238 ipw2100_down(priv);
4239 } else {
4240 priv->status &= ~STATUS_RF_KILL_SW;
4241 if (rf_kill_active(priv)) {
4242 IPW_DEBUG_RF_KILL("Can not turn radio back on - "
4243 "disabled by HW switch\n");
4244 /* Make sure the RF_KILL check timer is running */
4245 priv->stop_rf_kill = 0;
4246 cancel_delayed_work(&priv->rf_kill);
Stephen Hemmingera62056f2007-06-22 21:46:50 -07004247 queue_delayed_work(priv->workqueue, &priv->rf_kill,
Anton Blanchardbe84e3d2007-10-15 00:38:01 -05004248 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06004249 } else
4250 schedule_reset(priv);
4251 }
4252
Ingo Molnar752e3772006-02-28 07:20:54 +08004253 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06004254 return 1;
4255}
4256
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004257static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004258 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004259{
4260 struct ipw2100_priv *priv = dev_get_drvdata(d);
4261 ipw_radio_kill_sw(priv, buf[0] == '1');
4262 return count;
4263}
James Ketrenos2c86c272005-03-23 17:32:29 -06004264
James Ketrenosee8e3652005-09-14 09:47:29 -05004265static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
James Ketrenos2c86c272005-03-23 17:32:29 -06004266
4267static struct attribute *ipw2100_sysfs_entries[] = {
4268 &dev_attr_hardware.attr,
4269 &dev_attr_registers.attr,
4270 &dev_attr_ordinals.attr,
4271 &dev_attr_pci.attr,
4272 &dev_attr_stats.attr,
4273 &dev_attr_internals.attr,
4274 &dev_attr_bssinfo.attr,
4275 &dev_attr_memory.attr,
4276 &dev_attr_scan_age.attr,
4277 &dev_attr_fatal_error.attr,
4278 &dev_attr_rf_kill.attr,
4279 &dev_attr_cfg.attr,
4280 &dev_attr_status.attr,
4281 &dev_attr_capability.attr,
4282 NULL,
4283};
4284
4285static struct attribute_group ipw2100_attribute_group = {
4286 .attrs = ipw2100_sysfs_entries,
4287};
4288
James Ketrenos2c86c272005-03-23 17:32:29 -06004289static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
4290{
4291 struct ipw2100_status_queue *q = &priv->status_queue;
4292
4293 IPW_DEBUG_INFO("enter\n");
4294
4295 q->size = entries * sizeof(struct ipw2100_status);
James Ketrenosee8e3652005-09-14 09:47:29 -05004296 q->drv =
4297 (struct ipw2100_status *)pci_alloc_consistent(priv->pci_dev,
4298 q->size, &q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004299 if (!q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004300 IPW_DEBUG_WARNING("Can not allocate status queue.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06004301 return -ENOMEM;
4302 }
4303
4304 memset(q->drv, 0, q->size);
4305
4306 IPW_DEBUG_INFO("exit\n");
4307
4308 return 0;
4309}
4310
4311static void status_queue_free(struct ipw2100_priv *priv)
4312{
4313 IPW_DEBUG_INFO("enter\n");
4314
4315 if (priv->status_queue.drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004316 pci_free_consistent(priv->pci_dev, priv->status_queue.size,
4317 priv->status_queue.drv,
4318 priv->status_queue.nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004319 priv->status_queue.drv = NULL;
4320 }
4321
4322 IPW_DEBUG_INFO("exit\n");
4323}
4324
4325static int bd_queue_allocate(struct ipw2100_priv *priv,
4326 struct ipw2100_bd_queue *q, int entries)
4327{
4328 IPW_DEBUG_INFO("enter\n");
4329
4330 memset(q, 0, sizeof(struct ipw2100_bd_queue));
4331
4332 q->entries = entries;
4333 q->size = entries * sizeof(struct ipw2100_bd);
4334 q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic);
4335 if (!q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004336 IPW_DEBUG_INFO
4337 ("can't allocate shared memory for buffer descriptors\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06004338 return -ENOMEM;
4339 }
4340 memset(q->drv, 0, q->size);
4341
4342 IPW_DEBUG_INFO("exit\n");
4343
4344 return 0;
4345}
4346
James Ketrenosee8e3652005-09-14 09:47:29 -05004347static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q)
James Ketrenos2c86c272005-03-23 17:32:29 -06004348{
4349 IPW_DEBUG_INFO("enter\n");
4350
4351 if (!q)
4352 return;
4353
4354 if (q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004355 pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004356 q->drv = NULL;
4357 }
4358
4359 IPW_DEBUG_INFO("exit\n");
4360}
4361
James Ketrenosee8e3652005-09-14 09:47:29 -05004362static void bd_queue_initialize(struct ipw2100_priv *priv,
4363 struct ipw2100_bd_queue *q, u32 base, u32 size,
4364 u32 r, u32 w)
James Ketrenos2c86c272005-03-23 17:32:29 -06004365{
4366 IPW_DEBUG_INFO("enter\n");
4367
James Ketrenosee8e3652005-09-14 09:47:29 -05004368 IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv,
4369 (u32) q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004370
4371 write_register(priv->net_dev, base, q->nic);
4372 write_register(priv->net_dev, size, q->entries);
4373 write_register(priv->net_dev, r, q->oldest);
4374 write_register(priv->net_dev, w, q->next);
4375
4376 IPW_DEBUG_INFO("exit\n");
4377}
4378
4379static void ipw2100_kill_workqueue(struct ipw2100_priv *priv)
4380{
4381 if (priv->workqueue) {
4382 priv->stop_rf_kill = 1;
4383 priv->stop_hang_check = 1;
4384 cancel_delayed_work(&priv->reset_work);
4385 cancel_delayed_work(&priv->security_work);
4386 cancel_delayed_work(&priv->wx_event_work);
4387 cancel_delayed_work(&priv->hang_check);
4388 cancel_delayed_work(&priv->rf_kill);
Dan Williamsd20c6782007-10-10 12:28:07 -04004389 cancel_delayed_work(&priv->scan_event_later);
James Ketrenos2c86c272005-03-23 17:32:29 -06004390 destroy_workqueue(priv->workqueue);
4391 priv->workqueue = NULL;
4392 }
4393}
4394
4395static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
4396{
4397 int i, j, err = -EINVAL;
4398 void *v;
4399 dma_addr_t p;
4400
4401 IPW_DEBUG_INFO("enter\n");
4402
4403 err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH);
4404 if (err) {
4405 IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05004406 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004407 return err;
4408 }
4409
James Ketrenosee8e3652005-09-14 09:47:29 -05004410 priv->tx_buffers =
4411 (struct ipw2100_tx_packet *)kmalloc(TX_PENDED_QUEUE_LENGTH *
4412 sizeof(struct
4413 ipw2100_tx_packet),
4414 GFP_ATOMIC);
James Ketrenos2c86c272005-03-23 17:32:29 -06004415 if (!priv->tx_buffers) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004416 printk(KERN_ERR DRV_NAME
4417 ": %s: alloc failed form tx buffers.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06004418 priv->net_dev->name);
4419 bd_queue_free(priv, &priv->tx_queue);
4420 return -ENOMEM;
4421 }
4422
4423 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004424 v = pci_alloc_consistent(priv->pci_dev,
4425 sizeof(struct ipw2100_data_header),
4426 &p);
James Ketrenos2c86c272005-03-23 17:32:29 -06004427 if (!v) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004428 printk(KERN_ERR DRV_NAME
4429 ": %s: PCI alloc failed for tx " "buffers.\n",
4430 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004431 err = -ENOMEM;
4432 break;
4433 }
4434
4435 priv->tx_buffers[i].type = DATA;
James Ketrenosee8e3652005-09-14 09:47:29 -05004436 priv->tx_buffers[i].info.d_struct.data =
4437 (struct ipw2100_data_header *)v;
James Ketrenos2c86c272005-03-23 17:32:29 -06004438 priv->tx_buffers[i].info.d_struct.data_phys = p;
4439 priv->tx_buffers[i].info.d_struct.txb = NULL;
4440 }
4441
4442 if (i == TX_PENDED_QUEUE_LENGTH)
4443 return 0;
4444
4445 for (j = 0; j < i; j++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004446 pci_free_consistent(priv->pci_dev,
4447 sizeof(struct ipw2100_data_header),
4448 priv->tx_buffers[j].info.d_struct.data,
4449 priv->tx_buffers[j].info.d_struct.
4450 data_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06004451 }
4452
4453 kfree(priv->tx_buffers);
4454 priv->tx_buffers = NULL;
4455
4456 return err;
4457}
4458
4459static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
4460{
4461 int i;
4462
4463 IPW_DEBUG_INFO("enter\n");
4464
4465 /*
4466 * reinitialize packet info lists
4467 */
4468 INIT_LIST_HEAD(&priv->fw_pend_list);
4469 INIT_STAT(&priv->fw_pend_stat);
4470
4471 /*
4472 * reinitialize lists
4473 */
4474 INIT_LIST_HEAD(&priv->tx_pend_list);
4475 INIT_LIST_HEAD(&priv->tx_free_list);
4476 INIT_STAT(&priv->tx_pend_stat);
4477 INIT_STAT(&priv->tx_free_stat);
4478
4479 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
4480 /* We simply drop any SKBs that have been queued for
4481 * transmit */
4482 if (priv->tx_buffers[i].info.d_struct.txb) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004483 ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.
4484 txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06004485 priv->tx_buffers[i].info.d_struct.txb = NULL;
4486 }
4487
4488 list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list);
4489 }
4490
4491 SET_STAT(&priv->tx_free_stat, i);
4492
4493 priv->tx_queue.oldest = 0;
4494 priv->tx_queue.available = priv->tx_queue.entries;
4495 priv->tx_queue.next = 0;
4496 INIT_STAT(&priv->txq_stat);
4497 SET_STAT(&priv->txq_stat, priv->tx_queue.available);
4498
4499 bd_queue_initialize(priv, &priv->tx_queue,
4500 IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE,
4501 IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE,
4502 IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
4503 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX);
4504
4505 IPW_DEBUG_INFO("exit\n");
4506
4507}
4508
4509static void ipw2100_tx_free(struct ipw2100_priv *priv)
4510{
4511 int i;
4512
4513 IPW_DEBUG_INFO("enter\n");
4514
4515 bd_queue_free(priv, &priv->tx_queue);
4516
4517 if (!priv->tx_buffers)
4518 return;
4519
4520 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
4521 if (priv->tx_buffers[i].info.d_struct.txb) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004522 ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.
4523 txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06004524 priv->tx_buffers[i].info.d_struct.txb = NULL;
4525 }
4526 if (priv->tx_buffers[i].info.d_struct.data)
James Ketrenosee8e3652005-09-14 09:47:29 -05004527 pci_free_consistent(priv->pci_dev,
4528 sizeof(struct ipw2100_data_header),
4529 priv->tx_buffers[i].info.d_struct.
4530 data,
4531 priv->tx_buffers[i].info.d_struct.
4532 data_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06004533 }
4534
4535 kfree(priv->tx_buffers);
4536 priv->tx_buffers = NULL;
4537
4538 IPW_DEBUG_INFO("exit\n");
4539}
4540
James Ketrenos2c86c272005-03-23 17:32:29 -06004541static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
4542{
4543 int i, j, err = -EINVAL;
4544
4545 IPW_DEBUG_INFO("enter\n");
4546
4547 err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH);
4548 if (err) {
4549 IPW_DEBUG_INFO("failed bd_queue_allocate\n");
4550 return err;
4551 }
4552
4553 err = status_queue_allocate(priv, RX_QUEUE_LENGTH);
4554 if (err) {
4555 IPW_DEBUG_INFO("failed status_queue_allocate\n");
4556 bd_queue_free(priv, &priv->rx_queue);
4557 return err;
4558 }
4559
4560 /*
4561 * allocate packets
4562 */
4563 priv->rx_buffers = (struct ipw2100_rx_packet *)
4564 kmalloc(RX_QUEUE_LENGTH * sizeof(struct ipw2100_rx_packet),
4565 GFP_KERNEL);
4566 if (!priv->rx_buffers) {
4567 IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
4568
4569 bd_queue_free(priv, &priv->rx_queue);
4570
4571 status_queue_free(priv);
4572
4573 return -ENOMEM;
4574 }
4575
4576 for (i = 0; i < RX_QUEUE_LENGTH; i++) {
4577 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
4578
4579 err = ipw2100_alloc_skb(priv, packet);
4580 if (unlikely(err)) {
4581 err = -ENOMEM;
4582 break;
4583 }
4584
4585 /* The BD holds the cache aligned address */
4586 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
4587 priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH;
4588 priv->status_queue.drv[i].status_fields = 0;
4589 }
4590
4591 if (i == RX_QUEUE_LENGTH)
4592 return 0;
4593
4594 for (j = 0; j < i; j++) {
4595 pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr,
4596 sizeof(struct ipw2100_rx_packet),
4597 PCI_DMA_FROMDEVICE);
4598 dev_kfree_skb(priv->rx_buffers[j].skb);
4599 }
4600
4601 kfree(priv->rx_buffers);
4602 priv->rx_buffers = NULL;
4603
4604 bd_queue_free(priv, &priv->rx_queue);
4605
4606 status_queue_free(priv);
4607
4608 return err;
4609}
4610
4611static void ipw2100_rx_initialize(struct ipw2100_priv *priv)
4612{
4613 IPW_DEBUG_INFO("enter\n");
4614
4615 priv->rx_queue.oldest = 0;
4616 priv->rx_queue.available = priv->rx_queue.entries - 1;
4617 priv->rx_queue.next = priv->rx_queue.entries - 1;
4618
4619 INIT_STAT(&priv->rxq_stat);
4620 SET_STAT(&priv->rxq_stat, priv->rx_queue.available);
4621
4622 bd_queue_initialize(priv, &priv->rx_queue,
4623 IPW_MEM_HOST_SHARED_RX_BD_BASE,
4624 IPW_MEM_HOST_SHARED_RX_BD_SIZE,
4625 IPW_MEM_HOST_SHARED_RX_READ_INDEX,
4626 IPW_MEM_HOST_SHARED_RX_WRITE_INDEX);
4627
4628 /* set up the status queue */
4629 write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE,
4630 priv->status_queue.nic);
4631
4632 IPW_DEBUG_INFO("exit\n");
4633}
4634
4635static void ipw2100_rx_free(struct ipw2100_priv *priv)
4636{
4637 int i;
4638
4639 IPW_DEBUG_INFO("enter\n");
4640
4641 bd_queue_free(priv, &priv->rx_queue);
4642 status_queue_free(priv);
4643
4644 if (!priv->rx_buffers)
4645 return;
4646
4647 for (i = 0; i < RX_QUEUE_LENGTH; i++) {
4648 if (priv->rx_buffers[i].rxp) {
4649 pci_unmap_single(priv->pci_dev,
4650 priv->rx_buffers[i].dma_addr,
4651 sizeof(struct ipw2100_rx),
4652 PCI_DMA_FROMDEVICE);
4653 dev_kfree_skb(priv->rx_buffers[i].skb);
4654 }
4655 }
4656
4657 kfree(priv->rx_buffers);
4658 priv->rx_buffers = NULL;
4659
4660 IPW_DEBUG_INFO("exit\n");
4661}
4662
4663static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
4664{
4665 u32 length = ETH_ALEN;
Joe Perches0795af52007-10-03 17:59:30 -07004666 u8 addr[ETH_ALEN];
James Ketrenos2c86c272005-03-23 17:32:29 -06004667
4668 int err;
4669
Joe Perches0795af52007-10-03 17:59:30 -07004670 err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
James Ketrenos2c86c272005-03-23 17:32:29 -06004671 if (err) {
4672 IPW_DEBUG_INFO("MAC address read failed\n");
4673 return -EIO;
4674 }
James Ketrenos2c86c272005-03-23 17:32:29 -06004675
Joe Perches0795af52007-10-03 17:59:30 -07004676 memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN);
Johannes Berge1749612008-10-27 15:59:26 -07004677 IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06004678
4679 return 0;
4680}
4681
4682/********************************************************************
4683 *
4684 * Firmware Commands
4685 *
4686 ********************************************************************/
4687
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004688static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004689{
4690 struct host_command cmd = {
4691 .host_command = ADAPTER_ADDRESS,
4692 .host_command_sequence = 0,
4693 .host_command_length = ETH_ALEN
4694 };
4695 int err;
4696
4697 IPW_DEBUG_HC("SET_MAC_ADDRESS\n");
4698
4699 IPW_DEBUG_INFO("enter\n");
4700
4701 if (priv->config & CFG_CUSTOM_MAC) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004702 memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06004703 memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
4704 } else
4705 memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr,
4706 ETH_ALEN);
4707
4708 err = ipw2100_hw_send_command(priv, &cmd);
4709
4710 IPW_DEBUG_INFO("exit\n");
4711 return err;
4712}
4713
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004714static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type,
James Ketrenos2c86c272005-03-23 17:32:29 -06004715 int batch_mode)
4716{
4717 struct host_command cmd = {
4718 .host_command = PORT_TYPE,
4719 .host_command_sequence = 0,
4720 .host_command_length = sizeof(u32)
4721 };
4722 int err;
4723
4724 switch (port_type) {
4725 case IW_MODE_INFRA:
4726 cmd.host_command_parameters[0] = IPW_BSS;
4727 break;
4728 case IW_MODE_ADHOC:
4729 cmd.host_command_parameters[0] = IPW_IBSS;
4730 break;
4731 }
4732
4733 IPW_DEBUG_HC("PORT_TYPE: %s\n",
4734 port_type == IPW_IBSS ? "Ad-Hoc" : "Managed");
4735
4736 if (!batch_mode) {
4737 err = ipw2100_disable_adapter(priv);
4738 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004739 printk(KERN_ERR DRV_NAME
4740 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06004741 priv->net_dev->name, err);
4742 return err;
4743 }
4744 }
4745
4746 /* send cmd to firmware */
4747 err = ipw2100_hw_send_command(priv, &cmd);
4748
4749 if (!batch_mode)
4750 ipw2100_enable_adapter(priv);
4751
4752 return err;
4753}
4754
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004755static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
4756 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004757{
4758 struct host_command cmd = {
4759 .host_command = CHANNEL,
4760 .host_command_sequence = 0,
4761 .host_command_length = sizeof(u32)
4762 };
4763 int err;
4764
4765 cmd.host_command_parameters[0] = channel;
4766
4767 IPW_DEBUG_HC("CHANNEL: %d\n", channel);
4768
4769 /* If BSS then we don't support channel selection */
4770 if (priv->ieee->iw_mode == IW_MODE_INFRA)
4771 return 0;
4772
4773 if ((channel != 0) &&
4774 ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL)))
4775 return -EINVAL;
4776
4777 if (!batch_mode) {
4778 err = ipw2100_disable_adapter(priv);
4779 if (err)
4780 return err;
4781 }
4782
4783 err = ipw2100_hw_send_command(priv, &cmd);
4784 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004785 IPW_DEBUG_INFO("Failed to set channel to %d", channel);
James Ketrenos2c86c272005-03-23 17:32:29 -06004786 return err;
4787 }
4788
4789 if (channel)
4790 priv->config |= CFG_STATIC_CHANNEL;
4791 else
4792 priv->config &= ~CFG_STATIC_CHANNEL;
4793
4794 priv->channel = channel;
4795
4796 if (!batch_mode) {
4797 err = ipw2100_enable_adapter(priv);
4798 if (err)
4799 return err;
4800 }
4801
4802 return 0;
4803}
4804
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004805static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004806{
4807 struct host_command cmd = {
4808 .host_command = SYSTEM_CONFIG,
4809 .host_command_sequence = 0,
4810 .host_command_length = 12,
4811 };
4812 u32 ibss_mask, len = sizeof(u32);
4813 int err;
4814
4815 /* Set system configuration */
4816
4817 if (!batch_mode) {
4818 err = ipw2100_disable_adapter(priv);
4819 if (err)
4820 return err;
4821 }
4822
4823 if (priv->ieee->iw_mode == IW_MODE_ADHOC)
4824 cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START;
4825
4826 cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK |
James Ketrenosee8e3652005-09-14 09:47:29 -05004827 IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06004828
4829 if (!(priv->config & CFG_LONG_PREAMBLE))
4830 cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO;
4831
4832 err = ipw2100_get_ordinal(priv,
4833 IPW_ORD_EEPROM_IBSS_11B_CHANNELS,
James Ketrenosee8e3652005-09-14 09:47:29 -05004834 &ibss_mask, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06004835 if (err)
4836 ibss_mask = IPW_IBSS_11B_DEFAULT_MASK;
4837
4838 cmd.host_command_parameters[1] = REG_CHANNEL_MASK;
4839 cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask;
4840
4841 /* 11b only */
James Ketrenosee8e3652005-09-14 09:47:29 -05004842 /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */
James Ketrenos2c86c272005-03-23 17:32:29 -06004843
4844 err = ipw2100_hw_send_command(priv, &cmd);
4845 if (err)
4846 return err;
4847
4848/* If IPv6 is configured in the kernel then we don't want to filter out all
4849 * of the multicast packets as IPv6 needs some. */
4850#if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE)
4851 cmd.host_command = ADD_MULTICAST;
4852 cmd.host_command_sequence = 0;
4853 cmd.host_command_length = 0;
4854
4855 ipw2100_hw_send_command(priv, &cmd);
4856#endif
4857 if (!batch_mode) {
4858 err = ipw2100_enable_adapter(priv);
4859 if (err)
4860 return err;
4861 }
4862
4863 return 0;
4864}
4865
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004866static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate,
4867 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004868{
4869 struct host_command cmd = {
4870 .host_command = BASIC_TX_RATES,
4871 .host_command_sequence = 0,
4872 .host_command_length = 4
4873 };
4874 int err;
4875
4876 cmd.host_command_parameters[0] = rate & TX_RATE_MASK;
4877
4878 if (!batch_mode) {
4879 err = ipw2100_disable_adapter(priv);
4880 if (err)
4881 return err;
4882 }
4883
4884 /* Set BASIC TX Rate first */
4885 ipw2100_hw_send_command(priv, &cmd);
4886
4887 /* Set TX Rate */
4888 cmd.host_command = TX_RATES;
4889 ipw2100_hw_send_command(priv, &cmd);
4890
4891 /* Set MSDU TX Rate */
4892 cmd.host_command = MSDU_TX_RATES;
4893 ipw2100_hw_send_command(priv, &cmd);
4894
4895 if (!batch_mode) {
4896 err = ipw2100_enable_adapter(priv);
4897 if (err)
4898 return err;
4899 }
4900
4901 priv->tx_rates = rate;
4902
4903 return 0;
4904}
4905
James Ketrenosee8e3652005-09-14 09:47:29 -05004906static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
James Ketrenos2c86c272005-03-23 17:32:29 -06004907{
4908 struct host_command cmd = {
4909 .host_command = POWER_MODE,
4910 .host_command_sequence = 0,
4911 .host_command_length = 4
4912 };
4913 int err;
4914
4915 cmd.host_command_parameters[0] = power_level;
4916
4917 err = ipw2100_hw_send_command(priv, &cmd);
4918 if (err)
4919 return err;
4920
4921 if (power_level == IPW_POWER_MODE_CAM)
4922 priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
4923 else
4924 priv->power_mode = IPW_POWER_ENABLED | power_level;
4925
Robert P. J. Dayae800312007-01-31 02:39:40 -05004926#ifdef IPW2100_TX_POWER
James Ketrenosee8e3652005-09-14 09:47:29 -05004927 if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
James Ketrenos2c86c272005-03-23 17:32:29 -06004928 /* Set beacon interval */
4929 cmd.host_command = TX_POWER_INDEX;
James Ketrenosee8e3652005-09-14 09:47:29 -05004930 cmd.host_command_parameters[0] = (u32) priv->adhoc_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06004931
4932 err = ipw2100_hw_send_command(priv, &cmd);
4933 if (err)
4934 return err;
4935 }
4936#endif
4937
4938 return 0;
4939}
4940
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004941static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold)
James Ketrenos2c86c272005-03-23 17:32:29 -06004942{
4943 struct host_command cmd = {
4944 .host_command = RTS_THRESHOLD,
4945 .host_command_sequence = 0,
4946 .host_command_length = 4
4947 };
4948 int err;
4949
4950 if (threshold & RTS_DISABLED)
4951 cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD;
4952 else
4953 cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED;
4954
4955 err = ipw2100_hw_send_command(priv, &cmd);
4956 if (err)
4957 return err;
4958
4959 priv->rts_threshold = threshold;
4960
4961 return 0;
4962}
4963
4964#if 0
4965int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv,
4966 u32 threshold, int batch_mode)
4967{
4968 struct host_command cmd = {
4969 .host_command = FRAG_THRESHOLD,
4970 .host_command_sequence = 0,
4971 .host_command_length = 4,
4972 .host_command_parameters[0] = 0,
4973 };
4974 int err;
4975
4976 if (!batch_mode) {
4977 err = ipw2100_disable_adapter(priv);
4978 if (err)
4979 return err;
4980 }
4981
4982 if (threshold == 0)
4983 threshold = DEFAULT_FRAG_THRESHOLD;
4984 else {
4985 threshold = max(threshold, MIN_FRAG_THRESHOLD);
4986 threshold = min(threshold, MAX_FRAG_THRESHOLD);
4987 }
4988
4989 cmd.host_command_parameters[0] = threshold;
4990
4991 IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold);
4992
4993 err = ipw2100_hw_send_command(priv, &cmd);
4994
4995 if (!batch_mode)
4996 ipw2100_enable_adapter(priv);
4997
4998 if (!err)
4999 priv->frag_threshold = threshold;
5000
5001 return err;
5002}
5003#endif
5004
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005005static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry)
James Ketrenos2c86c272005-03-23 17:32:29 -06005006{
5007 struct host_command cmd = {
5008 .host_command = SHORT_RETRY_LIMIT,
5009 .host_command_sequence = 0,
5010 .host_command_length = 4
5011 };
5012 int err;
5013
5014 cmd.host_command_parameters[0] = retry;
5015
5016 err = ipw2100_hw_send_command(priv, &cmd);
5017 if (err)
5018 return err;
5019
5020 priv->short_retry_limit = retry;
5021
5022 return 0;
5023}
5024
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005025static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry)
James Ketrenos2c86c272005-03-23 17:32:29 -06005026{
5027 struct host_command cmd = {
5028 .host_command = LONG_RETRY_LIMIT,
5029 .host_command_sequence = 0,
5030 .host_command_length = 4
5031 };
5032 int err;
5033
5034 cmd.host_command_parameters[0] = retry;
5035
5036 err = ipw2100_hw_send_command(priv, &cmd);
5037 if (err)
5038 return err;
5039
5040 priv->long_retry_limit = retry;
5041
5042 return 0;
5043}
5044
James Ketrenosee8e3652005-09-14 09:47:29 -05005045static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005046 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005047{
5048 struct host_command cmd = {
5049 .host_command = MANDATORY_BSSID,
5050 .host_command_sequence = 0,
5051 .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN
5052 };
5053 int err;
5054
Brice Goglin0f52bf92005-12-01 01:41:46 -08005055#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06005056 if (bssid != NULL)
Johannes Berge1749612008-10-27 15:59:26 -07005057 IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06005058 else
5059 IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
5060#endif
5061 /* if BSSID is empty then we disable mandatory bssid mode */
5062 if (bssid != NULL)
James Ketrenos82328352005-08-24 22:33:31 -05005063 memcpy(cmd.host_command_parameters, bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06005064
5065 if (!batch_mode) {
5066 err = ipw2100_disable_adapter(priv);
5067 if (err)
5068 return err;
5069 }
5070
5071 err = ipw2100_hw_send_command(priv, &cmd);
5072
5073 if (!batch_mode)
5074 ipw2100_enable_adapter(priv);
5075
5076 return err;
5077}
5078
James Ketrenos2c86c272005-03-23 17:32:29 -06005079static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
5080{
5081 struct host_command cmd = {
5082 .host_command = DISASSOCIATION_BSSID,
5083 .host_command_sequence = 0,
5084 .host_command_length = ETH_ALEN
5085 };
5086 int err;
5087 int len;
5088
5089 IPW_DEBUG_HC("DISASSOCIATION_BSSID\n");
5090
5091 len = ETH_ALEN;
5092 /* The Firmware currently ignores the BSSID and just disassociates from
5093 * the currently associated AP -- but in the off chance that a future
5094 * firmware does use the BSSID provided here, we go ahead and try and
5095 * set it to the currently associated AP's BSSID */
5096 memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN);
5097
5098 err = ipw2100_hw_send_command(priv, &cmd);
5099
5100 return err;
5101}
James Ketrenos2c86c272005-03-23 17:32:29 -06005102
5103static int ipw2100_set_wpa_ie(struct ipw2100_priv *,
5104 struct ipw2100_wpa_assoc_frame *, int)
James Ketrenosee8e3652005-09-14 09:47:29 -05005105 __attribute__ ((unused));
James Ketrenos2c86c272005-03-23 17:32:29 -06005106
5107static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv,
5108 struct ipw2100_wpa_assoc_frame *wpa_frame,
5109 int batch_mode)
5110{
5111 struct host_command cmd = {
5112 .host_command = SET_WPA_IE,
5113 .host_command_sequence = 0,
5114 .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame),
5115 };
5116 int err;
5117
5118 IPW_DEBUG_HC("SET_WPA_IE\n");
5119
5120 if (!batch_mode) {
5121 err = ipw2100_disable_adapter(priv);
5122 if (err)
5123 return err;
5124 }
5125
5126 memcpy(cmd.host_command_parameters, wpa_frame,
5127 sizeof(struct ipw2100_wpa_assoc_frame));
5128
5129 err = ipw2100_hw_send_command(priv, &cmd);
5130
5131 if (!batch_mode) {
5132 if (ipw2100_enable_adapter(priv))
5133 err = -EIO;
5134 }
5135
5136 return err;
5137}
5138
5139struct security_info_params {
5140 u32 allowed_ciphers;
5141 u16 version;
5142 u8 auth_mode;
5143 u8 replay_counters_number;
5144 u8 unicast_using_group;
5145} __attribute__ ((packed));
5146
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005147static int ipw2100_set_security_information(struct ipw2100_priv *priv,
5148 int auth_mode,
5149 int security_level,
5150 int unicast_using_group,
5151 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005152{
5153 struct host_command cmd = {
5154 .host_command = SET_SECURITY_INFORMATION,
5155 .host_command_sequence = 0,
5156 .host_command_length = sizeof(struct security_info_params)
5157 };
5158 struct security_info_params *security =
James Ketrenosee8e3652005-09-14 09:47:29 -05005159 (struct security_info_params *)&cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06005160 int err;
5161 memset(security, 0, sizeof(*security));
5162
5163 /* If shared key AP authentication is turned on, then we need to
5164 * configure the firmware to try and use it.
5165 *
5166 * Actual data encryption/decryption is handled by the host. */
5167 security->auth_mode = auth_mode;
5168 security->unicast_using_group = unicast_using_group;
5169
5170 switch (security_level) {
5171 default:
5172 case SEC_LEVEL_0:
5173 security->allowed_ciphers = IPW_NONE_CIPHER;
5174 break;
5175 case SEC_LEVEL_1:
5176 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005177 IPW_WEP104_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005178 break;
5179 case SEC_LEVEL_2:
5180 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005181 IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005182 break;
5183 case SEC_LEVEL_2_CKIP:
5184 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005185 IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005186 break;
5187 case SEC_LEVEL_3:
5188 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005189 IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005190 break;
5191 }
5192
James Ketrenosee8e3652005-09-14 09:47:29 -05005193 IPW_DEBUG_HC
5194 ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
5195 security->auth_mode, security->allowed_ciphers, security_level);
James Ketrenos2c86c272005-03-23 17:32:29 -06005196
5197 security->replay_counters_number = 0;
5198
5199 if (!batch_mode) {
5200 err = ipw2100_disable_adapter(priv);
5201 if (err)
5202 return err;
5203 }
5204
5205 err = ipw2100_hw_send_command(priv, &cmd);
5206
5207 if (!batch_mode)
5208 ipw2100_enable_adapter(priv);
5209
5210 return err;
5211}
5212
James Ketrenosee8e3652005-09-14 09:47:29 -05005213static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power)
James Ketrenos2c86c272005-03-23 17:32:29 -06005214{
5215 struct host_command cmd = {
5216 .host_command = TX_POWER_INDEX,
5217 .host_command_sequence = 0,
5218 .host_command_length = 4
5219 };
5220 int err = 0;
Zhu Yi3173ca02006-01-24 13:49:01 +08005221 u32 tmp = tx_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06005222
Liu Hongf75459e2005-07-13 12:29:21 -05005223 if (tx_power != IPW_TX_POWER_DEFAULT)
Zhu Yi3173ca02006-01-24 13:49:01 +08005224 tmp = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 /
5225 (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
Liu Hongf75459e2005-07-13 12:29:21 -05005226
Zhu Yi3173ca02006-01-24 13:49:01 +08005227 cmd.host_command_parameters[0] = tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06005228
5229 if (priv->ieee->iw_mode == IW_MODE_ADHOC)
5230 err = ipw2100_hw_send_command(priv, &cmd);
5231 if (!err)
5232 priv->tx_power = tx_power;
5233
5234 return 0;
5235}
5236
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005237static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv,
5238 u32 interval, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005239{
5240 struct host_command cmd = {
5241 .host_command = BEACON_INTERVAL,
5242 .host_command_sequence = 0,
5243 .host_command_length = 4
5244 };
5245 int err;
5246
5247 cmd.host_command_parameters[0] = interval;
5248
5249 IPW_DEBUG_INFO("enter\n");
5250
5251 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
5252 if (!batch_mode) {
5253 err = ipw2100_disable_adapter(priv);
5254 if (err)
5255 return err;
5256 }
5257
5258 ipw2100_hw_send_command(priv, &cmd);
5259
5260 if (!batch_mode) {
5261 err = ipw2100_enable_adapter(priv);
5262 if (err)
5263 return err;
5264 }
5265 }
5266
5267 IPW_DEBUG_INFO("exit\n");
5268
5269 return 0;
5270}
5271
Hannes Edera3d1fd22008-12-26 00:14:41 -08005272static void ipw2100_queues_initialize(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005273{
5274 ipw2100_tx_initialize(priv);
5275 ipw2100_rx_initialize(priv);
5276 ipw2100_msg_initialize(priv);
5277}
5278
Hannes Edera3d1fd22008-12-26 00:14:41 -08005279static void ipw2100_queues_free(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005280{
5281 ipw2100_tx_free(priv);
5282 ipw2100_rx_free(priv);
5283 ipw2100_msg_free(priv);
5284}
5285
Hannes Edera3d1fd22008-12-26 00:14:41 -08005286static int ipw2100_queues_allocate(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005287{
5288 if (ipw2100_tx_allocate(priv) ||
James Ketrenosee8e3652005-09-14 09:47:29 -05005289 ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv))
James Ketrenos2c86c272005-03-23 17:32:29 -06005290 goto fail;
5291
5292 return 0;
5293
James Ketrenosee8e3652005-09-14 09:47:29 -05005294 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06005295 ipw2100_tx_free(priv);
5296 ipw2100_rx_free(priv);
5297 ipw2100_msg_free(priv);
5298 return -ENOMEM;
5299}
5300
5301#define IPW_PRIVACY_CAPABLE 0x0008
5302
5303static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags,
5304 int batch_mode)
5305{
5306 struct host_command cmd = {
5307 .host_command = WEP_FLAGS,
5308 .host_command_sequence = 0,
5309 .host_command_length = 4
5310 };
5311 int err;
5312
5313 cmd.host_command_parameters[0] = flags;
5314
5315 IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags);
5316
5317 if (!batch_mode) {
5318 err = ipw2100_disable_adapter(priv);
5319 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005320 printk(KERN_ERR DRV_NAME
5321 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005322 priv->net_dev->name, err);
5323 return err;
5324 }
5325 }
5326
5327 /* send cmd to firmware */
5328 err = ipw2100_hw_send_command(priv, &cmd);
5329
5330 if (!batch_mode)
5331 ipw2100_enable_adapter(priv);
5332
5333 return err;
5334}
5335
5336struct ipw2100_wep_key {
5337 u8 idx;
5338 u8 len;
5339 u8 key[13];
5340};
5341
5342/* Macros to ease up priting WEP keys */
5343#define WEP_FMT_64 "%02X%02X%02X%02X-%02X"
5344#define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X"
5345#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4]
5346#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]
5347
James Ketrenos2c86c272005-03-23 17:32:29 -06005348/**
5349 * Set a the wep key
5350 *
5351 * @priv: struct to work on
5352 * @idx: index of the key we want to set
5353 * @key: ptr to the key data to set
5354 * @len: length of the buffer at @key
5355 * @batch_mode: FIXME perform the operation in batch mode, not
5356 * disabling the device.
5357 *
5358 * @returns 0 if OK, < 0 errno code on error.
5359 *
5360 * Fill out a command structure with the new wep key, length an
5361 * index and send it down the wire.
5362 */
5363static int ipw2100_set_key(struct ipw2100_priv *priv,
5364 int idx, char *key, int len, int batch_mode)
5365{
5366 int keylen = len ? (len <= 5 ? 5 : 13) : 0;
5367 struct host_command cmd = {
5368 .host_command = WEP_KEY_INFO,
5369 .host_command_sequence = 0,
5370 .host_command_length = sizeof(struct ipw2100_wep_key),
5371 };
James Ketrenosee8e3652005-09-14 09:47:29 -05005372 struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06005373 int err;
5374
5375 IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005376 idx, keylen, len);
James Ketrenos2c86c272005-03-23 17:32:29 -06005377
5378 /* NOTE: We don't check cached values in case the firmware was reset
Adrian Bunk80f72282006-06-30 18:27:16 +02005379 * or some other problem is occurring. If the user is setting the key,
James Ketrenos2c86c272005-03-23 17:32:29 -06005380 * then we push the change */
5381
5382 wep_key->idx = idx;
5383 wep_key->len = keylen;
5384
5385 if (keylen) {
5386 memcpy(wep_key->key, key, len);
5387 memset(wep_key->key + len, 0, keylen - len);
5388 }
5389
5390 /* Will be optimized out on debug not being configured in */
5391 if (keylen == 0)
5392 IPW_DEBUG_WEP("%s: Clearing key %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005393 priv->net_dev->name, wep_key->idx);
James Ketrenos2c86c272005-03-23 17:32:29 -06005394 else if (keylen == 5)
5395 IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005396 priv->net_dev->name, wep_key->idx, wep_key->len,
5397 WEP_STR_64(wep_key->key));
James Ketrenos2c86c272005-03-23 17:32:29 -06005398 else
5399 IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128
James Ketrenosee8e3652005-09-14 09:47:29 -05005400 "\n",
5401 priv->net_dev->name, wep_key->idx, wep_key->len,
5402 WEP_STR_128(wep_key->key));
James Ketrenos2c86c272005-03-23 17:32:29 -06005403
5404 if (!batch_mode) {
5405 err = ipw2100_disable_adapter(priv);
5406 /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */
5407 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005408 printk(KERN_ERR DRV_NAME
5409 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005410 priv->net_dev->name, err);
5411 return err;
5412 }
5413 }
5414
5415 /* send cmd to firmware */
5416 err = ipw2100_hw_send_command(priv, &cmd);
5417
5418 if (!batch_mode) {
5419 int err2 = ipw2100_enable_adapter(priv);
5420 if (err == 0)
5421 err = err2;
5422 }
5423 return err;
5424}
5425
5426static int ipw2100_set_key_index(struct ipw2100_priv *priv,
5427 int idx, int batch_mode)
5428{
5429 struct host_command cmd = {
5430 .host_command = WEP_KEY_INDEX,
5431 .host_command_sequence = 0,
5432 .host_command_length = 4,
James Ketrenosee8e3652005-09-14 09:47:29 -05005433 .host_command_parameters = {idx},
James Ketrenos2c86c272005-03-23 17:32:29 -06005434 };
5435 int err;
5436
5437 IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx);
5438
5439 if (idx < 0 || idx > 3)
5440 return -EINVAL;
5441
5442 if (!batch_mode) {
5443 err = ipw2100_disable_adapter(priv);
5444 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005445 printk(KERN_ERR DRV_NAME
5446 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005447 priv->net_dev->name, err);
5448 return err;
5449 }
5450 }
5451
5452 /* send cmd to firmware */
5453 err = ipw2100_hw_send_command(priv, &cmd);
5454
5455 if (!batch_mode)
5456 ipw2100_enable_adapter(priv);
5457
5458 return err;
5459}
5460
James Ketrenosee8e3652005-09-14 09:47:29 -05005461static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005462{
5463 int i, err, auth_mode, sec_level, use_group;
5464
5465 if (!(priv->status & STATUS_RUNNING))
5466 return 0;
5467
5468 if (!batch_mode) {
5469 err = ipw2100_disable_adapter(priv);
5470 if (err)
5471 return err;
5472 }
5473
25b645b2005-07-12 15:45:30 -05005474 if (!priv->ieee->sec.enabled) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005475 err =
5476 ipw2100_set_security_information(priv, IPW_AUTH_OPEN,
5477 SEC_LEVEL_0, 0, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005478 } else {
5479 auth_mode = IPW_AUTH_OPEN;
Zhu Yicbbdd032006-01-24 13:48:53 +08005480 if (priv->ieee->sec.flags & SEC_AUTH_MODE) {
5481 if (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)
5482 auth_mode = IPW_AUTH_SHARED;
5483 else if (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)
5484 auth_mode = IPW_AUTH_LEAP_CISCO_ID;
5485 }
James Ketrenos2c86c272005-03-23 17:32:29 -06005486
5487 sec_level = SEC_LEVEL_0;
25b645b2005-07-12 15:45:30 -05005488 if (priv->ieee->sec.flags & SEC_LEVEL)
5489 sec_level = priv->ieee->sec.level;
James Ketrenos2c86c272005-03-23 17:32:29 -06005490
5491 use_group = 0;
25b645b2005-07-12 15:45:30 -05005492 if (priv->ieee->sec.flags & SEC_UNICAST_GROUP)
5493 use_group = priv->ieee->sec.unicast_uses_group;
James Ketrenos2c86c272005-03-23 17:32:29 -06005494
James Ketrenosee8e3652005-09-14 09:47:29 -05005495 err =
5496 ipw2100_set_security_information(priv, auth_mode, sec_level,
5497 use_group, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005498 }
5499
5500 if (err)
5501 goto exit;
5502
25b645b2005-07-12 15:45:30 -05005503 if (priv->ieee->sec.enabled) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005504 for (i = 0; i < 4; i++) {
25b645b2005-07-12 15:45:30 -05005505 if (!(priv->ieee->sec.flags & (1 << i))) {
5506 memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN);
5507 priv->ieee->sec.key_sizes[i] = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005508 } else {
5509 err = ipw2100_set_key(priv, i,
25b645b2005-07-12 15:45:30 -05005510 priv->ieee->sec.keys[i],
5511 priv->ieee->sec.
5512 key_sizes[i], 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005513 if (err)
5514 goto exit;
5515 }
5516 }
5517
John W. Linville274bfb82008-10-29 11:35:05 -04005518 ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005519 }
5520
5521 /* Always enable privacy so the Host can filter WEP packets if
5522 * encrypted data is sent up */
James Ketrenosee8e3652005-09-14 09:47:29 -05005523 err =
5524 ipw2100_set_wep_flags(priv,
25b645b2005-07-12 15:45:30 -05005525 priv->ieee->sec.
5526 enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005527 if (err)
5528 goto exit;
5529
5530 priv->status &= ~STATUS_SECURITY_UPDATED;
5531
James Ketrenosee8e3652005-09-14 09:47:29 -05005532 exit:
James Ketrenos2c86c272005-03-23 17:32:29 -06005533 if (!batch_mode)
5534 ipw2100_enable_adapter(priv);
5535
5536 return err;
5537}
5538
David Howellsc4028952006-11-22 14:57:56 +00005539static void ipw2100_security_work(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06005540{
David Howellsc4028952006-11-22 14:57:56 +00005541 struct ipw2100_priv *priv =
5542 container_of(work, struct ipw2100_priv, security_work.work);
5543
James Ketrenos2c86c272005-03-23 17:32:29 -06005544 /* If we happen to have reconnected before we get a chance to
5545 * process this, then update the security settings--which causes
5546 * a disassociation to occur */
5547 if (!(priv->status & STATUS_ASSOCIATED) &&
5548 priv->status & STATUS_SECURITY_UPDATED)
5549 ipw2100_configure_security(priv, 0);
5550}
5551
5552static void shim__set_security(struct net_device *dev,
5553 struct ieee80211_security *sec)
5554{
5555 struct ipw2100_priv *priv = ieee80211_priv(dev);
5556 int i, force_update = 0;
5557
Ingo Molnar752e3772006-02-28 07:20:54 +08005558 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005559 if (!(priv->status & STATUS_INITIALIZED))
5560 goto done;
5561
5562 for (i = 0; i < 4; i++) {
5563 if (sec->flags & (1 << i)) {
25b645b2005-07-12 15:45:30 -05005564 priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
James Ketrenos2c86c272005-03-23 17:32:29 -06005565 if (sec->key_sizes[i] == 0)
25b645b2005-07-12 15:45:30 -05005566 priv->ieee->sec.flags &= ~(1 << i);
James Ketrenos2c86c272005-03-23 17:32:29 -06005567 else
25b645b2005-07-12 15:45:30 -05005568 memcpy(priv->ieee->sec.keys[i], sec->keys[i],
James Ketrenos2c86c272005-03-23 17:32:29 -06005569 sec->key_sizes[i]);
Hong Liu054b08d2005-08-25 17:45:49 +08005570 if (sec->level == SEC_LEVEL_1) {
5571 priv->ieee->sec.flags |= (1 << i);
5572 priv->status |= STATUS_SECURITY_UPDATED;
5573 } else
5574 priv->ieee->sec.flags &= ~(1 << i);
James Ketrenos2c86c272005-03-23 17:32:29 -06005575 }
5576 }
5577
5578 if ((sec->flags & SEC_ACTIVE_KEY) &&
25b645b2005-07-12 15:45:30 -05005579 priv->ieee->sec.active_key != sec->active_key) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005580 if (sec->active_key <= 3) {
25b645b2005-07-12 15:45:30 -05005581 priv->ieee->sec.active_key = sec->active_key;
5582 priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
James Ketrenos2c86c272005-03-23 17:32:29 -06005583 } else
25b645b2005-07-12 15:45:30 -05005584 priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
James Ketrenos2c86c272005-03-23 17:32:29 -06005585
5586 priv->status |= STATUS_SECURITY_UPDATED;
5587 }
5588
5589 if ((sec->flags & SEC_AUTH_MODE) &&
25b645b2005-07-12 15:45:30 -05005590 (priv->ieee->sec.auth_mode != sec->auth_mode)) {
5591 priv->ieee->sec.auth_mode = sec->auth_mode;
5592 priv->ieee->sec.flags |= SEC_AUTH_MODE;
James Ketrenos2c86c272005-03-23 17:32:29 -06005593 priv->status |= STATUS_SECURITY_UPDATED;
5594 }
5595
25b645b2005-07-12 15:45:30 -05005596 if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
5597 priv->ieee->sec.flags |= SEC_ENABLED;
5598 priv->ieee->sec.enabled = sec->enabled;
James Ketrenos2c86c272005-03-23 17:32:29 -06005599 priv->status |= STATUS_SECURITY_UPDATED;
5600 force_update = 1;
5601 }
5602
25b645b2005-07-12 15:45:30 -05005603 if (sec->flags & SEC_ENCRYPT)
5604 priv->ieee->sec.encrypt = sec->encrypt;
5605
5606 if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
5607 priv->ieee->sec.level = sec->level;
5608 priv->ieee->sec.flags |= SEC_LEVEL;
James Ketrenos2c86c272005-03-23 17:32:29 -06005609 priv->status |= STATUS_SECURITY_UPDATED;
5610 }
5611
5612 IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n",
25b645b2005-07-12 15:45:30 -05005613 priv->ieee->sec.flags & (1 << 8) ? '1' : '0',
5614 priv->ieee->sec.flags & (1 << 7) ? '1' : '0',
5615 priv->ieee->sec.flags & (1 << 6) ? '1' : '0',
5616 priv->ieee->sec.flags & (1 << 5) ? '1' : '0',
5617 priv->ieee->sec.flags & (1 << 4) ? '1' : '0',
5618 priv->ieee->sec.flags & (1 << 3) ? '1' : '0',
5619 priv->ieee->sec.flags & (1 << 2) ? '1' : '0',
5620 priv->ieee->sec.flags & (1 << 1) ? '1' : '0',
5621 priv->ieee->sec.flags & (1 << 0) ? '1' : '0');
James Ketrenos2c86c272005-03-23 17:32:29 -06005622
5623/* As a temporary work around to enable WPA until we figure out why
5624 * wpa_supplicant toggles the security capability of the driver, which
5625 * forces a disassocation with force_update...
5626 *
5627 * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/
5628 if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
5629 ipw2100_configure_security(priv, 0);
James Ketrenosee8e3652005-09-14 09:47:29 -05005630 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08005631 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005632}
5633
5634static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
5635{
5636 int err;
5637 int batch_mode = 1;
5638 u8 *bssid;
5639
5640 IPW_DEBUG_INFO("enter\n");
5641
5642 err = ipw2100_disable_adapter(priv);
5643 if (err)
5644 return err;
5645#ifdef CONFIG_IPW2100_MONITOR
5646 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
5647 err = ipw2100_set_channel(priv, priv->channel, batch_mode);
5648 if (err)
5649 return err;
5650
5651 IPW_DEBUG_INFO("exit\n");
5652
5653 return 0;
5654 }
James Ketrenosee8e3652005-09-14 09:47:29 -05005655#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06005656
5657 err = ipw2100_read_mac_address(priv);
5658 if (err)
5659 return -EIO;
5660
5661 err = ipw2100_set_mac_address(priv, batch_mode);
5662 if (err)
5663 return err;
5664
5665 err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode);
5666 if (err)
5667 return err;
5668
5669 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
5670 err = ipw2100_set_channel(priv, priv->channel, batch_mode);
5671 if (err)
5672 return err;
5673 }
5674
James Ketrenosee8e3652005-09-14 09:47:29 -05005675 err = ipw2100_system_config(priv, batch_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06005676 if (err)
5677 return err;
5678
5679 err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode);
5680 if (err)
5681 return err;
5682
5683 /* Default to power mode OFF */
5684 err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
5685 if (err)
5686 return err;
5687
5688 err = ipw2100_set_rts_threshold(priv, priv->rts_threshold);
5689 if (err)
5690 return err;
5691
5692 if (priv->config & CFG_STATIC_BSSID)
5693 bssid = priv->bssid;
5694 else
5695 bssid = NULL;
5696 err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode);
5697 if (err)
5698 return err;
5699
5700 if (priv->config & CFG_STATIC_ESSID)
5701 err = ipw2100_set_essid(priv, priv->essid, priv->essid_len,
5702 batch_mode);
5703 else
5704 err = ipw2100_set_essid(priv, NULL, 0, batch_mode);
5705 if (err)
5706 return err;
5707
5708 err = ipw2100_configure_security(priv, batch_mode);
5709 if (err)
5710 return err;
5711
5712 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005713 err =
5714 ipw2100_set_ibss_beacon_interval(priv,
5715 priv->beacon_interval,
5716 batch_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06005717 if (err)
5718 return err;
5719
5720 err = ipw2100_set_tx_power(priv, priv->tx_power);
5721 if (err)
5722 return err;
5723 }
5724
5725 /*
James Ketrenosee8e3652005-09-14 09:47:29 -05005726 err = ipw2100_set_fragmentation_threshold(
5727 priv, priv->frag_threshold, batch_mode);
5728 if (err)
5729 return err;
5730 */
James Ketrenos2c86c272005-03-23 17:32:29 -06005731
5732 IPW_DEBUG_INFO("exit\n");
5733
5734 return 0;
5735}
5736
James Ketrenos2c86c272005-03-23 17:32:29 -06005737/*************************************************************************
5738 *
5739 * EXTERNALLY CALLED METHODS
5740 *
5741 *************************************************************************/
5742
5743/* This method is called by the network layer -- not to be confused with
5744 * ipw2100_set_mac_address() declared above called by this driver (and this
5745 * method as well) to talk to the firmware */
5746static int ipw2100_set_address(struct net_device *dev, void *p)
5747{
5748 struct ipw2100_priv *priv = ieee80211_priv(dev);
5749 struct sockaddr *addr = p;
5750 int err = 0;
5751
5752 if (!is_valid_ether_addr(addr->sa_data))
5753 return -EADDRNOTAVAIL;
5754
Ingo Molnar752e3772006-02-28 07:20:54 +08005755 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005756
5757 priv->config |= CFG_CUSTOM_MAC;
5758 memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
5759
5760 err = ipw2100_set_mac_address(priv, 0);
5761 if (err)
5762 goto done;
5763
5764 priv->reset_backoff = 0;
Ingo Molnar752e3772006-02-28 07:20:54 +08005765 mutex_unlock(&priv->action_mutex);
David Howellsc4028952006-11-22 14:57:56 +00005766 ipw2100_reset_adapter(&priv->reset_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06005767 return 0;
5768
James Ketrenosee8e3652005-09-14 09:47:29 -05005769 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08005770 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005771 return err;
5772}
5773
5774static int ipw2100_open(struct net_device *dev)
5775{
5776 struct ipw2100_priv *priv = ieee80211_priv(dev);
5777 unsigned long flags;
5778 IPW_DEBUG_INFO("dev->open\n");
5779
5780 spin_lock_irqsave(&priv->low_lock, flags);
Jiri Benc3ce329c2005-08-25 20:07:01 -04005781 if (priv->status & STATUS_ASSOCIATED) {
5782 netif_carrier_on(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005783 netif_start_queue(dev);
Jiri Benc3ce329c2005-08-25 20:07:01 -04005784 }
James Ketrenos2c86c272005-03-23 17:32:29 -06005785 spin_unlock_irqrestore(&priv->low_lock, flags);
5786
5787 return 0;
5788}
5789
5790static int ipw2100_close(struct net_device *dev)
5791{
5792 struct ipw2100_priv *priv = ieee80211_priv(dev);
5793 unsigned long flags;
5794 struct list_head *element;
5795 struct ipw2100_tx_packet *packet;
5796
5797 IPW_DEBUG_INFO("enter\n");
5798
5799 spin_lock_irqsave(&priv->low_lock, flags);
5800
5801 if (priv->status & STATUS_ASSOCIATED)
5802 netif_carrier_off(dev);
5803 netif_stop_queue(dev);
5804
5805 /* Flush the TX queue ... */
5806 while (!list_empty(&priv->tx_pend_list)) {
5807 element = priv->tx_pend_list.next;
James Ketrenosee8e3652005-09-14 09:47:29 -05005808 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06005809
5810 list_del(element);
5811 DEC_STAT(&priv->tx_pend_stat);
5812
5813 ieee80211_txb_free(packet->info.d_struct.txb);
5814 packet->info.d_struct.txb = NULL;
5815
5816 list_add_tail(element, &priv->tx_free_list);
5817 INC_STAT(&priv->tx_free_stat);
5818 }
5819 spin_unlock_irqrestore(&priv->low_lock, flags);
5820
5821 IPW_DEBUG_INFO("exit\n");
5822
5823 return 0;
5824}
5825
James Ketrenos2c86c272005-03-23 17:32:29 -06005826/*
5827 * TODO: Fix this function... its just wrong
5828 */
5829static void ipw2100_tx_timeout(struct net_device *dev)
5830{
5831 struct ipw2100_priv *priv = ieee80211_priv(dev);
5832
5833 priv->ieee->stats.tx_errors++;
5834
5835#ifdef CONFIG_IPW2100_MONITOR
5836 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
5837 return;
5838#endif
5839
5840 IPW_DEBUG_INFO("%s: TX timed out. Scheduling firmware restart.\n",
5841 dev->name);
5842 schedule_reset(priv);
5843}
5844
James Ketrenosee8e3652005-09-14 09:47:29 -05005845static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value)
5846{
James Ketrenos82328352005-08-24 22:33:31 -05005847 /* This is called when wpa_supplicant loads and closes the driver
5848 * interface. */
5849 priv->ieee->wpa_enabled = value;
5850 return 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005851}
5852
James Ketrenosee8e3652005-09-14 09:47:29 -05005853static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value)
5854{
James Ketrenos2c86c272005-03-23 17:32:29 -06005855
5856 struct ieee80211_device *ieee = priv->ieee;
5857 struct ieee80211_security sec = {
5858 .flags = SEC_AUTH_MODE,
5859 };
5860 int ret = 0;
5861
James Ketrenos82328352005-08-24 22:33:31 -05005862 if (value & IW_AUTH_ALG_SHARED_KEY) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005863 sec.auth_mode = WLAN_AUTH_SHARED_KEY;
5864 ieee->open_wep = 0;
James Ketrenos82328352005-08-24 22:33:31 -05005865 } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005866 sec.auth_mode = WLAN_AUTH_OPEN;
5867 ieee->open_wep = 1;
Zhu Yicbbdd032006-01-24 13:48:53 +08005868 } else if (value & IW_AUTH_ALG_LEAP) {
5869 sec.auth_mode = WLAN_AUTH_LEAP;
5870 ieee->open_wep = 1;
James Ketrenos82328352005-08-24 22:33:31 -05005871 } else
5872 return -EINVAL;
James Ketrenos2c86c272005-03-23 17:32:29 -06005873
5874 if (ieee->set_security)
5875 ieee->set_security(ieee->dev, &sec);
5876 else
5877 ret = -EOPNOTSUPP;
5878
5879 return ret;
5880}
5881
Adrian Bunk3c398b82006-01-21 01:36:36 +01005882static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
5883 char *wpa_ie, int wpa_ie_len)
James Ketrenosee8e3652005-09-14 09:47:29 -05005884{
James Ketrenos2c86c272005-03-23 17:32:29 -06005885
5886 struct ipw2100_wpa_assoc_frame frame;
5887
5888 frame.fixed_ie_mask = 0;
5889
5890 /* copy WPA IE */
5891 memcpy(frame.var_ie, wpa_ie, wpa_ie_len);
5892 frame.var_ie_len = wpa_ie_len;
5893
5894 /* make sure WPA is enabled */
5895 ipw2100_wpa_enable(priv, 1);
5896 ipw2100_set_wpa_ie(priv, &frame, 0);
5897}
5898
James Ketrenos2c86c272005-03-23 17:32:29 -06005899static void ipw_ethtool_get_drvinfo(struct net_device *dev,
5900 struct ethtool_drvinfo *info)
5901{
5902 struct ipw2100_priv *priv = ieee80211_priv(dev);
5903 char fw_ver[64], ucode_ver[64];
5904
5905 strcpy(info->driver, DRV_NAME);
5906 strcpy(info->version, DRV_VERSION);
5907
5908 ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver));
5909 ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver));
5910
5911 snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s",
5912 fw_ver, priv->eeprom_version, ucode_ver);
5913
5914 strcpy(info->bus_info, pci_name(priv->pci_dev));
5915}
5916
5917static u32 ipw2100_ethtool_get_link(struct net_device *dev)
5918{
James Ketrenosee8e3652005-09-14 09:47:29 -05005919 struct ipw2100_priv *priv = ieee80211_priv(dev);
5920 return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005921}
5922
Jeff Garzik7282d492006-09-13 14:30:00 -04005923static const struct ethtool_ops ipw2100_ethtool_ops = {
James Ketrenosee8e3652005-09-14 09:47:29 -05005924 .get_link = ipw2100_ethtool_get_link,
5925 .get_drvinfo = ipw_ethtool_get_drvinfo,
James Ketrenos2c86c272005-03-23 17:32:29 -06005926};
5927
David Howellsc4028952006-11-22 14:57:56 +00005928static void ipw2100_hang_check(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06005929{
David Howellsc4028952006-11-22 14:57:56 +00005930 struct ipw2100_priv *priv =
5931 container_of(work, struct ipw2100_priv, hang_check.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06005932 unsigned long flags;
5933 u32 rtc = 0xa5a5a5a5;
5934 u32 len = sizeof(rtc);
5935 int restart = 0;
5936
5937 spin_lock_irqsave(&priv->low_lock, flags);
5938
5939 if (priv->fatal_error != 0) {
5940 /* If fatal_error is set then we need to restart */
5941 IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n",
5942 priv->net_dev->name);
5943
5944 restart = 1;
5945 } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) ||
5946 (rtc == priv->last_rtc)) {
5947 /* Check if firmware is hung */
5948 IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n",
5949 priv->net_dev->name);
5950
5951 restart = 1;
5952 }
5953
5954 if (restart) {
5955 /* Kill timer */
5956 priv->stop_hang_check = 1;
5957 priv->hangs++;
5958
5959 /* Restart the NIC */
5960 schedule_reset(priv);
5961 }
5962
5963 priv->last_rtc = rtc;
5964
5965 if (!priv->stop_hang_check)
5966 queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
5967
5968 spin_unlock_irqrestore(&priv->low_lock, flags);
5969}
5970
David Howellsc4028952006-11-22 14:57:56 +00005971static void ipw2100_rf_kill(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06005972{
David Howellsc4028952006-11-22 14:57:56 +00005973 struct ipw2100_priv *priv =
5974 container_of(work, struct ipw2100_priv, rf_kill.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06005975 unsigned long flags;
5976
5977 spin_lock_irqsave(&priv->low_lock, flags);
5978
5979 if (rf_kill_active(priv)) {
5980 IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
5981 if (!priv->stop_rf_kill)
Stephen Hemmingera62056f2007-06-22 21:46:50 -07005982 queue_delayed_work(priv->workqueue, &priv->rf_kill,
Anton Blanchardbe84e3d2007-10-15 00:38:01 -05005983 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06005984 goto exit_unlock;
5985 }
5986
5987 /* RF Kill is now disabled, so bring the device back up */
5988
5989 if (!(priv->status & STATUS_RF_KILL_MASK)) {
5990 IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
5991 "device\n");
5992 schedule_reset(priv);
5993 } else
5994 IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
5995 "enabled\n");
5996
James Ketrenosee8e3652005-09-14 09:47:29 -05005997 exit_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -06005998 spin_unlock_irqrestore(&priv->low_lock, flags);
5999}
6000
6001static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
6002
6003/* Look into using netdev destructor to shutdown ieee80211? */
6004
James Ketrenosee8e3652005-09-14 09:47:29 -05006005static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
6006 void __iomem * base_addr,
6007 unsigned long mem_start,
6008 unsigned long mem_len)
James Ketrenos2c86c272005-03-23 17:32:29 -06006009{
6010 struct ipw2100_priv *priv;
6011 struct net_device *dev;
6012
6013 dev = alloc_ieee80211(sizeof(struct ipw2100_priv));
6014 if (!dev)
6015 return NULL;
6016 priv = ieee80211_priv(dev);
6017 priv->ieee = netdev_priv(dev);
6018 priv->pci_dev = pci_dev;
6019 priv->net_dev = dev;
6020
6021 priv->ieee->hard_start_xmit = ipw2100_tx;
6022 priv->ieee->set_security = shim__set_security;
6023
James Ketrenos82328352005-08-24 22:33:31 -05006024 priv->ieee->perfect_rssi = -20;
6025 priv->ieee->worst_rssi = -85;
6026
James Ketrenos2c86c272005-03-23 17:32:29 -06006027 dev->open = ipw2100_open;
6028 dev->stop = ipw2100_close;
6029 dev->init = ipw2100_net_init;
James Ketrenos2c86c272005-03-23 17:32:29 -06006030 dev->ethtool_ops = &ipw2100_ethtool_ops;
6031 dev->tx_timeout = ipw2100_tx_timeout;
6032 dev->wireless_handlers = &ipw2100_wx_handler_def;
James Ketrenoseaf8f53b2005-11-12 12:50:12 -06006033 priv->wireless_data.ieee80211 = priv->ieee;
6034 dev->wireless_data = &priv->wireless_data;
James Ketrenos2c86c272005-03-23 17:32:29 -06006035 dev->set_mac_address = ipw2100_set_address;
James Ketrenosee8e3652005-09-14 09:47:29 -05006036 dev->watchdog_timeo = 3 * HZ;
James Ketrenos2c86c272005-03-23 17:32:29 -06006037 dev->irq = 0;
6038
6039 dev->base_addr = (unsigned long)base_addr;
6040 dev->mem_start = mem_start;
6041 dev->mem_end = dev->mem_start + mem_len - 1;
6042
6043 /* NOTE: We don't use the wireless_handlers hook
6044 * in dev as the system will start throwing WX requests
6045 * to us before we're actually initialized and it just
6046 * ends up causing problems. So, we just handle
6047 * the WX extensions through the ipw2100_ioctl interface */
6048
Jean Delvarec03983a2007-10-19 23:22:55 +02006049 /* memset() puts everything to 0, so we only have explicitly set
James Ketrenos2c86c272005-03-23 17:32:29 -06006050 * those values that need to be something else */
6051
6052 /* If power management is turned on, default to AUTO mode */
6053 priv->power_mode = IPW_POWER_AUTO;
6054
James Ketrenos82328352005-08-24 22:33:31 -05006055#ifdef CONFIG_IPW2100_MONITOR
6056 priv->config |= CFG_CRC_CHECK;
6057#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06006058 priv->ieee->wpa_enabled = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06006059 priv->ieee->drop_unencrypted = 0;
6060 priv->ieee->privacy_invoked = 0;
6061 priv->ieee->ieee802_1x = 1;
James Ketrenos2c86c272005-03-23 17:32:29 -06006062
6063 /* Set module parameters */
6064 switch (mode) {
6065 case 1:
6066 priv->ieee->iw_mode = IW_MODE_ADHOC;
6067 break;
6068#ifdef CONFIG_IPW2100_MONITOR
6069 case 2:
6070 priv->ieee->iw_mode = IW_MODE_MONITOR;
6071 break;
6072#endif
6073 default:
6074 case 0:
6075 priv->ieee->iw_mode = IW_MODE_INFRA;
6076 break;
6077 }
6078
6079 if (disable == 1)
6080 priv->status |= STATUS_RF_KILL_SW;
6081
6082 if (channel != 0 &&
James Ketrenosee8e3652005-09-14 09:47:29 -05006083 ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006084 priv->config |= CFG_STATIC_CHANNEL;
6085 priv->channel = channel;
6086 }
6087
6088 if (associate)
6089 priv->config |= CFG_ASSOCIATE;
6090
6091 priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
6092 priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
6093 priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
6094 priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED;
6095 priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED;
6096 priv->tx_power = IPW_TX_POWER_DEFAULT;
6097 priv->tx_rates = DEFAULT_TX_RATES;
6098
6099 strcpy(priv->nick, "ipw2100");
6100
6101 spin_lock_init(&priv->low_lock);
Ingo Molnar752e3772006-02-28 07:20:54 +08006102 mutex_init(&priv->action_mutex);
6103 mutex_init(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006104
6105 init_waitqueue_head(&priv->wait_command_queue);
6106
6107 netif_carrier_off(dev);
6108
6109 INIT_LIST_HEAD(&priv->msg_free_list);
6110 INIT_LIST_HEAD(&priv->msg_pend_list);
6111 INIT_STAT(&priv->msg_free_stat);
6112 INIT_STAT(&priv->msg_pend_stat);
6113
6114 INIT_LIST_HEAD(&priv->tx_free_list);
6115 INIT_LIST_HEAD(&priv->tx_pend_list);
6116 INIT_STAT(&priv->tx_free_stat);
6117 INIT_STAT(&priv->tx_pend_stat);
6118
6119 INIT_LIST_HEAD(&priv->fw_pend_list);
6120 INIT_STAT(&priv->fw_pend_stat);
6121
James Ketrenos2c86c272005-03-23 17:32:29 -06006122 priv->workqueue = create_workqueue(DRV_NAME);
James Ketrenos392d0f62005-09-07 18:39:03 -05006123
David Howellsc4028952006-11-22 14:57:56 +00006124 INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter);
6125 INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work);
6126 INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
6127 INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
6128 INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
Dan Williamsd20c6782007-10-10 12:28:07 -04006129 INIT_WORK(&priv->scan_event_now, ipw2100_scan_event_now);
6130 INIT_DELAYED_WORK(&priv->scan_event_later, ipw2100_scan_event_later);
James Ketrenos2c86c272005-03-23 17:32:29 -06006131
6132 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
6133 ipw2100_irq_tasklet, (unsigned long)priv);
6134
6135 /* NOTE: We do not start the deferred work for status checks yet */
6136 priv->stop_rf_kill = 1;
6137 priv->stop_hang_check = 1;
6138
6139 return dev;
6140}
6141
James Ketrenos2c86c272005-03-23 17:32:29 -06006142static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
6143 const struct pci_device_id *ent)
6144{
6145 unsigned long mem_start, mem_len, mem_flags;
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01006146 void __iomem *base_addr = NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06006147 struct net_device *dev = NULL;
6148 struct ipw2100_priv *priv = NULL;
6149 int err = 0;
6150 int registered = 0;
6151 u32 val;
6152
6153 IPW_DEBUG_INFO("enter\n");
6154
6155 mem_start = pci_resource_start(pci_dev, 0);
6156 mem_len = pci_resource_len(pci_dev, 0);
6157 mem_flags = pci_resource_flags(pci_dev, 0);
6158
6159 if ((mem_flags & IORESOURCE_MEM) != IORESOURCE_MEM) {
6160 IPW_DEBUG_INFO("weird - resource type is not memory\n");
6161 err = -ENODEV;
6162 goto fail;
6163 }
6164
6165 base_addr = ioremap_nocache(mem_start, mem_len);
6166 if (!base_addr) {
6167 printk(KERN_WARNING DRV_NAME
6168 "Error calling ioremap_nocache.\n");
6169 err = -EIO;
6170 goto fail;
6171 }
6172
6173 /* allocate and initialize our net_device */
6174 dev = ipw2100_alloc_device(pci_dev, base_addr, mem_start, mem_len);
6175 if (!dev) {
6176 printk(KERN_WARNING DRV_NAME
6177 "Error calling ipw2100_alloc_device.\n");
6178 err = -ENOMEM;
6179 goto fail;
6180 }
6181
6182 /* set up PCI mappings for device */
6183 err = pci_enable_device(pci_dev);
6184 if (err) {
6185 printk(KERN_WARNING DRV_NAME
6186 "Error calling pci_enable_device.\n");
6187 return err;
6188 }
6189
6190 priv = ieee80211_priv(dev);
6191
6192 pci_set_master(pci_dev);
6193 pci_set_drvdata(pci_dev, priv);
6194
Tobias Klauser05743d12005-06-20 14:28:40 -07006195 err = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK);
James Ketrenos2c86c272005-03-23 17:32:29 -06006196 if (err) {
6197 printk(KERN_WARNING DRV_NAME
6198 "Error calling pci_set_dma_mask.\n");
6199 pci_disable_device(pci_dev);
6200 return err;
6201 }
6202
6203 err = pci_request_regions(pci_dev, DRV_NAME);
6204 if (err) {
6205 printk(KERN_WARNING DRV_NAME
6206 "Error calling pci_request_regions.\n");
6207 pci_disable_device(pci_dev);
6208 return err;
6209 }
6210
James Ketrenosee8e3652005-09-14 09:47:29 -05006211 /* We disable the RETRY_TIMEOUT register (0x41) to keep
James Ketrenos2c86c272005-03-23 17:32:29 -06006212 * PCI Tx retries from interfering with C3 CPU state */
6213 pci_read_config_dword(pci_dev, 0x40, &val);
6214 if ((val & 0x0000ff00) != 0)
6215 pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
6216
Pavel Machek8724a112005-06-20 14:28:43 -07006217 pci_set_power_state(pci_dev, PCI_D0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006218
6219 if (!ipw2100_hw_is_adapter_in_system(dev)) {
6220 printk(KERN_WARNING DRV_NAME
6221 "Device not found via register read.\n");
6222 err = -ENODEV;
6223 goto fail;
6224 }
6225
6226 SET_NETDEV_DEV(dev, &pci_dev->dev);
6227
6228 /* Force interrupts to be shut off on the device */
6229 priv->status |= STATUS_INT_ENABLED;
6230 ipw2100_disable_interrupts(priv);
6231
6232 /* Allocate and initialize the Tx/Rx queues and lists */
6233 if (ipw2100_queues_allocate(priv)) {
6234 printk(KERN_WARNING DRV_NAME
Zhu Yi90c009a2006-12-05 14:41:32 +08006235 "Error calling ipw2100_queues_allocate.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06006236 err = -ENOMEM;
6237 goto fail;
6238 }
6239 ipw2100_queues_initialize(priv);
6240
6241 err = request_irq(pci_dev->irq,
Thomas Gleixner1fb9df52006-07-01 19:29:39 -07006242 ipw2100_interrupt, IRQF_SHARED, dev->name, priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006243 if (err) {
6244 printk(KERN_WARNING DRV_NAME
James Ketrenosee8e3652005-09-14 09:47:29 -05006245 "Error calling request_irq: %d.\n", pci_dev->irq);
James Ketrenos2c86c272005-03-23 17:32:29 -06006246 goto fail;
6247 }
6248 dev->irq = pci_dev->irq;
6249
6250 IPW_DEBUG_INFO("Attempting to register device...\n");
6251
James Ketrenos2c86c272005-03-23 17:32:29 -06006252 printk(KERN_INFO DRV_NAME
6253 ": Detected Intel PRO/Wireless 2100 Network Connection\n");
6254
6255 /* Bring up the interface. Pre 0.46, after we registered the
6256 * network device we would call ipw2100_up. This introduced a race
6257 * condition with newer hotplug configurations (network was coming
6258 * up and making calls before the device was initialized).
6259 *
6260 * If we called ipw2100_up before we registered the device, then the
6261 * device name wasn't registered. So, we instead use the net_dev->init
6262 * member to call a function that then just turns and calls ipw2100_up.
6263 * net_dev->init is called after name allocation but before the
6264 * notifier chain is called */
James Ketrenos2c86c272005-03-23 17:32:29 -06006265 err = register_netdev(dev);
6266 if (err) {
6267 printk(KERN_WARNING DRV_NAME
6268 "Error calling register_netdev.\n");
Zhu Yiefbd8092006-08-21 11:38:52 +08006269 goto fail;
James Ketrenos2c86c272005-03-23 17:32:29 -06006270 }
Zhu Yiefbd8092006-08-21 11:38:52 +08006271
6272 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006273 registered = 1;
6274
6275 IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
6276
6277 /* perform this after register_netdev so that dev->name is set */
Jeff Garzikde897882006-10-01 07:31:09 -04006278 err = sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
6279 if (err)
6280 goto fail_unlock;
James Ketrenos2c86c272005-03-23 17:32:29 -06006281
6282 /* If the RF Kill switch is disabled, go ahead and complete the
6283 * startup sequence */
6284 if (!(priv->status & STATUS_RF_KILL_MASK)) {
6285 /* Enable the adapter - sends HOST_COMPLETE */
6286 if (ipw2100_enable_adapter(priv)) {
6287 printk(KERN_WARNING DRV_NAME
6288 ": %s: failed in call to enable adapter.\n",
6289 priv->net_dev->name);
6290 ipw2100_hw_stop_adapter(priv);
6291 err = -EIO;
6292 goto fail_unlock;
6293 }
6294
6295 /* Start a scan . . . */
6296 ipw2100_set_scan_options(priv);
6297 ipw2100_start_scan(priv);
6298 }
6299
6300 IPW_DEBUG_INFO("exit\n");
6301
6302 priv->status |= STATUS_INITIALIZED;
6303
Ingo Molnar752e3772006-02-28 07:20:54 +08006304 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006305
6306 return 0;
6307
James Ketrenosee8e3652005-09-14 09:47:29 -05006308 fail_unlock:
Ingo Molnar752e3772006-02-28 07:20:54 +08006309 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006310
James Ketrenosee8e3652005-09-14 09:47:29 -05006311 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06006312 if (dev) {
6313 if (registered)
6314 unregister_netdev(dev);
6315
6316 ipw2100_hw_stop_adapter(priv);
6317
6318 ipw2100_disable_interrupts(priv);
6319
6320 if (dev->irq)
6321 free_irq(dev->irq, priv);
6322
6323 ipw2100_kill_workqueue(priv);
6324
6325 /* These are safe to call even if they weren't allocated */
6326 ipw2100_queues_free(priv);
James Ketrenosee8e3652005-09-14 09:47:29 -05006327 sysfs_remove_group(&pci_dev->dev.kobj,
6328 &ipw2100_attribute_group);
James Ketrenos2c86c272005-03-23 17:32:29 -06006329
6330 free_ieee80211(dev);
6331 pci_set_drvdata(pci_dev, NULL);
6332 }
6333
6334 if (base_addr)
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01006335 iounmap(base_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06006336
6337 pci_release_regions(pci_dev);
6338 pci_disable_device(pci_dev);
6339
6340 return err;
6341}
6342
6343static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
6344{
6345 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6346 struct net_device *dev;
6347
6348 if (priv) {
Ingo Molnar752e3772006-02-28 07:20:54 +08006349 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006350
6351 priv->status &= ~STATUS_INITIALIZED;
6352
6353 dev = priv->net_dev;
James Ketrenosee8e3652005-09-14 09:47:29 -05006354 sysfs_remove_group(&pci_dev->dev.kobj,
6355 &ipw2100_attribute_group);
James Ketrenos2c86c272005-03-23 17:32:29 -06006356
6357#ifdef CONFIG_PM
6358 if (ipw2100_firmware.version)
6359 ipw2100_release_firmware(priv, &ipw2100_firmware);
6360#endif
6361 /* Take down the hardware */
6362 ipw2100_down(priv);
6363
Ingo Molnar752e3772006-02-28 07:20:54 +08006364 /* Release the mutex so that the network subsystem can
James Ketrenos2c86c272005-03-23 17:32:29 -06006365 * complete any needed calls into the driver... */
Ingo Molnar752e3772006-02-28 07:20:54 +08006366 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006367
6368 /* Unregister the device first - this results in close()
6369 * being called if the device is open. If we free storage
6370 * first, then close() will crash. */
6371 unregister_netdev(dev);
6372
6373 /* ipw2100_down will ensure that there is no more pending work
6374 * in the workqueue's, so we can safely remove them now. */
6375 ipw2100_kill_workqueue(priv);
6376
6377 ipw2100_queues_free(priv);
6378
6379 /* Free potential debugging firmware snapshot */
6380 ipw2100_snapshot_free(priv);
6381
6382 if (dev->irq)
6383 free_irq(dev->irq, priv);
6384
6385 if (dev->base_addr)
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01006386 iounmap((void __iomem *)dev->base_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06006387
6388 free_ieee80211(dev);
6389 }
6390
6391 pci_release_regions(pci_dev);
6392 pci_disable_device(pci_dev);
6393
6394 IPW_DEBUG_INFO("exit\n");
6395}
6396
James Ketrenos2c86c272005-03-23 17:32:29 -06006397#ifdef CONFIG_PM
James Ketrenos2c86c272005-03-23 17:32:29 -06006398static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state)
James Ketrenos2c86c272005-03-23 17:32:29 -06006399{
6400 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6401 struct net_device *dev = priv->net_dev;
6402
James Ketrenosee8e3652005-09-14 09:47:29 -05006403 IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06006404
Ingo Molnar752e3772006-02-28 07:20:54 +08006405 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006406 if (priv->status & STATUS_INITIALIZED) {
6407 /* Take down the device; powers it off, etc. */
6408 ipw2100_down(priv);
6409 }
6410
6411 /* Remove the PRESENT state of the device */
6412 netif_device_detach(dev);
6413
James Ketrenos2c86c272005-03-23 17:32:29 -06006414 pci_save_state(pci_dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05006415 pci_disable_device(pci_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006416 pci_set_power_state(pci_dev, PCI_D3hot);
James Ketrenos2c86c272005-03-23 17:32:29 -06006417
Ingo Molnar752e3772006-02-28 07:20:54 +08006418 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006419
6420 return 0;
6421}
6422
6423static int ipw2100_resume(struct pci_dev *pci_dev)
6424{
6425 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6426 struct net_device *dev = priv->net_dev;
John W. Linville02e0e5e2006-11-07 20:53:48 -05006427 int err;
James Ketrenos2c86c272005-03-23 17:32:29 -06006428 u32 val;
6429
6430 if (IPW2100_PM_DISABLED)
6431 return 0;
6432
Ingo Molnar752e3772006-02-28 07:20:54 +08006433 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006434
James Ketrenosee8e3652005-09-14 09:47:29 -05006435 IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06006436
James Ketrenos2c86c272005-03-23 17:32:29 -06006437 pci_set_power_state(pci_dev, PCI_D0);
John W. Linville02e0e5e2006-11-07 20:53:48 -05006438 err = pci_enable_device(pci_dev);
6439 if (err) {
6440 printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
6441 dev->name);
Julia Lawall80c42af2008-07-21 09:58:11 +02006442 mutex_unlock(&priv->action_mutex);
John W. Linville02e0e5e2006-11-07 20:53:48 -05006443 return err;
6444 }
James Ketrenos2c86c272005-03-23 17:32:29 -06006445 pci_restore_state(pci_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006446
6447 /*
6448 * Suspend/Resume resets the PCI configuration space, so we have to
6449 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
6450 * from interfering with C3 CPU state. pci_restore_state won't help
6451 * here since it only restores the first 64 bytes pci config header.
6452 */
6453 pci_read_config_dword(pci_dev, 0x40, &val);
6454 if ((val & 0x0000ff00) != 0)
6455 pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
6456
6457 /* Set the device back into the PRESENT state; this will also wake
6458 * the queue of needed */
6459 netif_device_attach(dev);
6460
James Ketrenosee8e3652005-09-14 09:47:29 -05006461 /* Bring the device back up */
6462 if (!(priv->status & STATUS_RF_KILL_SW))
6463 ipw2100_up(priv, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006464
Ingo Molnar752e3772006-02-28 07:20:54 +08006465 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006466
6467 return 0;
6468}
6469#endif
6470
James Ketrenos2c86c272005-03-23 17:32:29 -06006471#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
6472
6473static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = {
James Ketrenosee8e3652005-09-14 09:47:29 -05006474 IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
6475 IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
6476 IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
6477 IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
6478 IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
6479 IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
6480 IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
6481 IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
6482 IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
6483 IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
6484 IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
6485 IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
6486 IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
James Ketrenos2c86c272005-03-23 17:32:29 -06006487
James Ketrenosee8e3652005-09-14 09:47:29 -05006488 IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
6489 IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
6490 IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
6491 IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
6492 IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006493
James Ketrenosee8e3652005-09-14 09:47:29 -05006494 IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
6495 IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
6496 IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
6497 IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
6498 IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
6499 IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
6500 IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
James Ketrenos2c86c272005-03-23 17:32:29 -06006501
James Ketrenosee8e3652005-09-14 09:47:29 -05006502 IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006503
James Ketrenosee8e3652005-09-14 09:47:29 -05006504 IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
6505 IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
6506 IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
6507 IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
6508 IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
6509 IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
6510 IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006511
James Ketrenosee8e3652005-09-14 09:47:29 -05006512 IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
6513 IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
6514 IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
6515 IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
6516 IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
6517 IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006518
James Ketrenosee8e3652005-09-14 09:47:29 -05006519 IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006520 {0,},
6521};
6522
6523MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table);
6524
6525static struct pci_driver ipw2100_pci_driver = {
6526 .name = DRV_NAME,
6527 .id_table = ipw2100_pci_id_table,
6528 .probe = ipw2100_pci_init_one,
6529 .remove = __devexit_p(ipw2100_pci_remove_one),
6530#ifdef CONFIG_PM
6531 .suspend = ipw2100_suspend,
6532 .resume = ipw2100_resume,
6533#endif
6534};
6535
James Ketrenos2c86c272005-03-23 17:32:29 -06006536/**
6537 * Initialize the ipw2100 driver/module
6538 *
6539 * @returns 0 if ok, < 0 errno node con error.
6540 *
6541 * Note: we cannot init the /proc stuff until the PCI driver is there,
6542 * or we risk an unlikely race condition on someone accessing
6543 * uninitialized data in the PCI dev struct through /proc.
6544 */
6545static int __init ipw2100_init(void)
6546{
6547 int ret;
6548
6549 printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
6550 printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
6551
Jeff Garzik29917622006-08-19 17:48:59 -04006552 ret = pci_register_driver(&ipw2100_pci_driver);
Jeff Garzikde897882006-10-01 07:31:09 -04006553 if (ret)
6554 goto out;
James Ketrenos2c86c272005-03-23 17:32:29 -06006555
Mark Grossf011e2e2008-02-04 22:30:09 -08006556 pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100",
6557 PM_QOS_DEFAULT_VALUE);
Brice Goglin0f52bf92005-12-01 01:41:46 -08006558#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06006559 ipw2100_debug_level = debug;
Jeff Garzikde897882006-10-01 07:31:09 -04006560 ret = driver_create_file(&ipw2100_pci_driver.driver,
6561 &driver_attr_debug_level);
James Ketrenos2c86c272005-03-23 17:32:29 -06006562#endif
6563
Jeff Garzikde897882006-10-01 07:31:09 -04006564out:
James Ketrenos2c86c272005-03-23 17:32:29 -06006565 return ret;
6566}
6567
James Ketrenos2c86c272005-03-23 17:32:29 -06006568/**
6569 * Cleanup ipw2100 driver registration
6570 */
6571static void __exit ipw2100_exit(void)
6572{
6573 /* FIXME: IPG: check that we have no instances of the devices open */
Brice Goglin0f52bf92005-12-01 01:41:46 -08006574#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06006575 driver_remove_file(&ipw2100_pci_driver.driver,
6576 &driver_attr_debug_level);
6577#endif
6578 pci_unregister_driver(&ipw2100_pci_driver);
Mark Grossf011e2e2008-02-04 22:30:09 -08006579 pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100");
James Ketrenos2c86c272005-03-23 17:32:29 -06006580}
6581
6582module_init(ipw2100_init);
6583module_exit(ipw2100_exit);
6584
6585#define WEXT_USECHANNELS 1
6586
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006587static const long ipw2100_frequencies[] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006588 2412, 2417, 2422, 2427,
6589 2432, 2437, 2442, 2447,
6590 2452, 2457, 2462, 2467,
6591 2472, 2484
6592};
6593
Alejandro Martinez Ruizc00acf42007-10-18 10:16:33 +02006594#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies)
James Ketrenos2c86c272005-03-23 17:32:29 -06006595
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006596static const long ipw2100_rates_11b[] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006597 1000000,
6598 2000000,
6599 5500000,
6600 11000000
6601};
6602
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02006603#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b)
James Ketrenos2c86c272005-03-23 17:32:29 -06006604
6605static int ipw2100_wx_get_name(struct net_device *dev,
6606 struct iw_request_info *info,
6607 union iwreq_data *wrqu, char *extra)
6608{
6609 /*
6610 * This can be called at any time. No action lock required
6611 */
6612
6613 struct ipw2100_priv *priv = ieee80211_priv(dev);
6614 if (!(priv->status & STATUS_ASSOCIATED))
6615 strcpy(wrqu->name, "unassociated");
6616 else
6617 snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
6618
6619 IPW_DEBUG_WX("Name: %s\n", wrqu->name);
6620 return 0;
6621}
6622
James Ketrenos2c86c272005-03-23 17:32:29 -06006623static int ipw2100_wx_set_freq(struct net_device *dev,
6624 struct iw_request_info *info,
6625 union iwreq_data *wrqu, char *extra)
6626{
6627 struct ipw2100_priv *priv = ieee80211_priv(dev);
6628 struct iw_freq *fwrq = &wrqu->freq;
6629 int err = 0;
6630
6631 if (priv->ieee->iw_mode == IW_MODE_INFRA)
6632 return -EOPNOTSUPP;
6633
Ingo Molnar752e3772006-02-28 07:20:54 +08006634 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006635 if (!(priv->status & STATUS_INITIALIZED)) {
6636 err = -EIO;
6637 goto done;
6638 }
6639
6640 /* if setting by freq convert to channel */
6641 if (fwrq->e == 1) {
James Ketrenosee8e3652005-09-14 09:47:29 -05006642 if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006643 int f = fwrq->m / 100000;
6644 int c = 0;
6645
6646 while ((c < REG_MAX_CHANNEL) &&
6647 (f != ipw2100_frequencies[c]))
6648 c++;
6649
6650 /* hack to fall through */
6651 fwrq->e = 0;
6652 fwrq->m = c + 1;
6653 }
6654 }
6655
James Ketrenos82328352005-08-24 22:33:31 -05006656 if (fwrq->e > 0 || fwrq->m > 1000) {
6657 err = -EOPNOTSUPP;
6658 goto done;
6659 } else { /* Set the channel */
James Ketrenos2c86c272005-03-23 17:32:29 -06006660 IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
6661 err = ipw2100_set_channel(priv, fwrq->m, 0);
6662 }
6663
James Ketrenosee8e3652005-09-14 09:47:29 -05006664 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006665 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006666 return err;
6667}
6668
James Ketrenos2c86c272005-03-23 17:32:29 -06006669static int ipw2100_wx_get_freq(struct net_device *dev,
6670 struct iw_request_info *info,
6671 union iwreq_data *wrqu, char *extra)
6672{
6673 /*
6674 * This can be called at any time. No action lock required
6675 */
6676
6677 struct ipw2100_priv *priv = ieee80211_priv(dev);
6678
6679 wrqu->freq.e = 0;
6680
6681 /* If we are associated, trying to associate, or have a statically
6682 * configured CHANNEL then return that; otherwise return ANY */
6683 if (priv->config & CFG_STATIC_CHANNEL ||
6684 priv->status & STATUS_ASSOCIATED)
6685 wrqu->freq.m = priv->channel;
6686 else
6687 wrqu->freq.m = 0;
6688
6689 IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
6690 return 0;
6691
6692}
6693
6694static int ipw2100_wx_set_mode(struct net_device *dev,
6695 struct iw_request_info *info,
6696 union iwreq_data *wrqu, char *extra)
6697{
6698 struct ipw2100_priv *priv = ieee80211_priv(dev);
6699 int err = 0;
6700
6701 IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode);
6702
6703 if (wrqu->mode == priv->ieee->iw_mode)
6704 return 0;
6705
Ingo Molnar752e3772006-02-28 07:20:54 +08006706 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006707 if (!(priv->status & STATUS_INITIALIZED)) {
6708 err = -EIO;
6709 goto done;
6710 }
6711
6712 switch (wrqu->mode) {
6713#ifdef CONFIG_IPW2100_MONITOR
6714 case IW_MODE_MONITOR:
6715 err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
6716 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05006717#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06006718 case IW_MODE_ADHOC:
6719 err = ipw2100_switch_mode(priv, IW_MODE_ADHOC);
6720 break;
6721 case IW_MODE_INFRA:
6722 case IW_MODE_AUTO:
6723 default:
6724 err = ipw2100_switch_mode(priv, IW_MODE_INFRA);
6725 break;
6726 }
6727
James Ketrenosee8e3652005-09-14 09:47:29 -05006728 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006729 mutex_unlock(&priv->action_mutex);
James Ketrenosee8e3652005-09-14 09:47:29 -05006730 return err;
James Ketrenos2c86c272005-03-23 17:32:29 -06006731}
6732
6733static int ipw2100_wx_get_mode(struct net_device *dev,
6734 struct iw_request_info *info,
6735 union iwreq_data *wrqu, char *extra)
6736{
6737 /*
6738 * This can be called at any time. No action lock required
6739 */
6740
6741 struct ipw2100_priv *priv = ieee80211_priv(dev);
6742
6743 wrqu->mode = priv->ieee->iw_mode;
6744 IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode);
6745
6746 return 0;
6747}
6748
James Ketrenos2c86c272005-03-23 17:32:29 -06006749#define POWER_MODES 5
6750
6751/* Values are in microsecond */
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006752static const s32 timeout_duration[POWER_MODES] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006753 350000,
6754 250000,
6755 75000,
6756 37000,
6757 25000,
6758};
6759
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006760static const s32 period_duration[POWER_MODES] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006761 400000,
6762 700000,
6763 1000000,
6764 1000000,
6765 1000000
6766};
6767
6768static int ipw2100_wx_get_range(struct net_device *dev,
6769 struct iw_request_info *info,
6770 union iwreq_data *wrqu, char *extra)
6771{
6772 /*
6773 * This can be called at any time. No action lock required
6774 */
6775
6776 struct ipw2100_priv *priv = ieee80211_priv(dev);
6777 struct iw_range *range = (struct iw_range *)extra;
6778 u16 val;
6779 int i, level;
6780
6781 wrqu->data.length = sizeof(*range);
6782 memset(range, 0, sizeof(*range));
6783
6784 /* Let's try to keep this struct in the same order as in
6785 * linux/include/wireless.h
6786 */
6787
6788 /* TODO: See what values we can set, and remove the ones we can't
6789 * set, or fill them with some default data.
6790 */
6791
6792 /* ~5 Mb/s real (802.11b) */
6793 range->throughput = 5 * 1000 * 1000;
6794
James Ketrenosee8e3652005-09-14 09:47:29 -05006795// range->sensitivity; /* signal level threshold range */
James Ketrenos2c86c272005-03-23 17:32:29 -06006796
6797 range->max_qual.qual = 100;
6798 /* TODO: Find real max RSSI and stick here */
6799 range->max_qual.level = 0;
6800 range->max_qual.noise = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05006801 range->max_qual.updated = 7; /* Updated all three */
James Ketrenos2c86c272005-03-23 17:32:29 -06006802
James Ketrenosee8e3652005-09-14 09:47:29 -05006803 range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
James Ketrenos2c86c272005-03-23 17:32:29 -06006804 /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
6805 range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
6806 range->avg_qual.noise = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05006807 range->avg_qual.updated = 7; /* Updated all three */
James Ketrenos2c86c272005-03-23 17:32:29 -06006808
6809 range->num_bitrates = RATE_COUNT;
6810
6811 for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
6812 range->bitrate[i] = ipw2100_rates_11b[i];
6813 }
6814
6815 range->min_rts = MIN_RTS_THRESHOLD;
6816 range->max_rts = MAX_RTS_THRESHOLD;
6817 range->min_frag = MIN_FRAG_THRESHOLD;
6818 range->max_frag = MAX_FRAG_THRESHOLD;
6819
6820 range->min_pmp = period_duration[0]; /* Minimal PM period */
James Ketrenosee8e3652005-09-14 09:47:29 -05006821 range->max_pmp = period_duration[POWER_MODES - 1]; /* Maximal PM period */
6822 range->min_pmt = timeout_duration[POWER_MODES - 1]; /* Minimal PM timeout */
6823 range->max_pmt = timeout_duration[0]; /* Maximal PM timeout */
James Ketrenos2c86c272005-03-23 17:32:29 -06006824
James Ketrenosee8e3652005-09-14 09:47:29 -05006825 /* How to decode max/min PM period */
James Ketrenos2c86c272005-03-23 17:32:29 -06006826 range->pmp_flags = IW_POWER_PERIOD;
James Ketrenosee8e3652005-09-14 09:47:29 -05006827 /* How to decode max/min PM period */
James Ketrenos2c86c272005-03-23 17:32:29 -06006828 range->pmt_flags = IW_POWER_TIMEOUT;
6829 /* What PM options are supported */
6830 range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD;
6831
6832 range->encoding_size[0] = 5;
James Ketrenosee8e3652005-09-14 09:47:29 -05006833 range->encoding_size[1] = 13; /* Different token sizes */
6834 range->num_encoding_sizes = 2; /* Number of entry in the list */
6835 range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */
6836// range->encoding_login_index; /* token index for login token */
James Ketrenos2c86c272005-03-23 17:32:29 -06006837
6838 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
6839 range->txpower_capa = IW_TXPOW_DBM;
6840 range->num_txpower = IW_MAX_TXPOWER;
James Ketrenosee8e3652005-09-14 09:47:29 -05006841 for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16);
6842 i < IW_MAX_TXPOWER;
6843 i++, level -=
6844 ((IPW_TX_POWER_MAX_DBM -
6845 IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1))
James Ketrenos2c86c272005-03-23 17:32:29 -06006846 range->txpower[i] = level / 16;
6847 } else {
6848 range->txpower_capa = 0;
6849 range->num_txpower = 0;
6850 }
6851
James Ketrenos2c86c272005-03-23 17:32:29 -06006852 /* Set the Wireless Extension versions */
6853 range->we_version_compiled = WIRELESS_EXT;
Dan Williams166c3432006-01-09 11:04:31 -05006854 range->we_version_source = 18;
James Ketrenos2c86c272005-03-23 17:32:29 -06006855
James Ketrenosee8e3652005-09-14 09:47:29 -05006856// range->retry_capa; /* What retry options are supported */
6857// range->retry_flags; /* How to decode max/min retry limit */
6858// range->r_time_flags; /* How to decode max/min retry life */
6859// range->min_retry; /* Minimal number of retries */
6860// range->max_retry; /* Maximal number of retries */
6861// range->min_r_time; /* Minimal retry lifetime */
6862// range->max_r_time; /* Maximal retry lifetime */
James Ketrenos2c86c272005-03-23 17:32:29 -06006863
James Ketrenosee8e3652005-09-14 09:47:29 -05006864 range->num_channels = FREQ_COUNT;
James Ketrenos2c86c272005-03-23 17:32:29 -06006865
6866 val = 0;
6867 for (i = 0; i < FREQ_COUNT; i++) {
6868 // TODO: Include only legal frequencies for some countries
James Ketrenosee8e3652005-09-14 09:47:29 -05006869// if (local->channel_mask & (1 << i)) {
6870 range->freq[val].i = i + 1;
6871 range->freq[val].m = ipw2100_frequencies[i] * 100000;
6872 range->freq[val].e = 1;
6873 val++;
6874// }
James Ketrenos2c86c272005-03-23 17:32:29 -06006875 if (val == IW_MAX_FREQUENCIES)
James Ketrenosee8e3652005-09-14 09:47:29 -05006876 break;
James Ketrenos2c86c272005-03-23 17:32:29 -06006877 }
6878 range->num_frequency = val;
6879
James Ketrenoseaf8f53b2005-11-12 12:50:12 -06006880 /* Event capability (kernel + driver) */
6881 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
6882 IW_EVENT_CAPA_MASK(SIOCGIWAP));
6883 range->event_capa[1] = IW_EVENT_CAPA_K_1;
6884
Dan Williams166c3432006-01-09 11:04:31 -05006885 range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
6886 IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
6887
James Ketrenos2c86c272005-03-23 17:32:29 -06006888 IPW_DEBUG_WX("GET Range\n");
6889
6890 return 0;
6891}
6892
6893static int ipw2100_wx_set_wap(struct net_device *dev,
6894 struct iw_request_info *info,
6895 union iwreq_data *wrqu, char *extra)
6896{
6897 struct ipw2100_priv *priv = ieee80211_priv(dev);
6898 int err = 0;
6899
6900 static const unsigned char any[] = {
6901 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
6902 };
6903 static const unsigned char off[] = {
6904 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6905 };
6906
6907 // sanity checks
6908 if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
6909 return -EINVAL;
6910
Ingo Molnar752e3772006-02-28 07:20:54 +08006911 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006912 if (!(priv->status & STATUS_INITIALIZED)) {
6913 err = -EIO;
6914 goto done;
6915 }
6916
6917 if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
6918 !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
6919 /* we disable mandatory BSSID association */
6920 IPW_DEBUG_WX("exit - disable mandatory BSSID\n");
6921 priv->config &= ~CFG_STATIC_BSSID;
6922 err = ipw2100_set_mandatory_bssid(priv, NULL, 0);
6923 goto done;
6924 }
6925
6926 priv->config |= CFG_STATIC_BSSID;
6927 memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN);
6928
6929 err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
6930
Johannes Berge1749612008-10-27 15:59:26 -07006931 IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data);
James Ketrenos2c86c272005-03-23 17:32:29 -06006932
James Ketrenosee8e3652005-09-14 09:47:29 -05006933 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006934 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006935 return err;
6936}
6937
6938static int ipw2100_wx_get_wap(struct net_device *dev,
6939 struct iw_request_info *info,
6940 union iwreq_data *wrqu, char *extra)
6941{
6942 /*
6943 * This can be called at any time. No action lock required
6944 */
6945
6946 struct ipw2100_priv *priv = ieee80211_priv(dev);
6947
6948 /* If we are associated, trying to associate, or have a statically
6949 * configured BSSID then return that; otherwise return ANY */
James Ketrenosee8e3652005-09-14 09:47:29 -05006950 if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006951 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
James Ketrenos82328352005-08-24 22:33:31 -05006952 memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06006953 } else
6954 memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
6955
Johannes Berge1749612008-10-27 15:59:26 -07006956 IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data);
James Ketrenos2c86c272005-03-23 17:32:29 -06006957 return 0;
6958}
6959
6960static int ipw2100_wx_set_essid(struct net_device *dev,
6961 struct iw_request_info *info,
6962 union iwreq_data *wrqu, char *extra)
6963{
6964 struct ipw2100_priv *priv = ieee80211_priv(dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05006965 char *essid = ""; /* ANY */
James Ketrenos2c86c272005-03-23 17:32:29 -06006966 int length = 0;
6967 int err = 0;
John W. Linville9387b7c2008-09-30 20:59:05 -04006968 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06006969
Ingo Molnar752e3772006-02-28 07:20:54 +08006970 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006971 if (!(priv->status & STATUS_INITIALIZED)) {
6972 err = -EIO;
6973 goto done;
6974 }
6975
6976 if (wrqu->essid.flags && wrqu->essid.length) {
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07006977 length = wrqu->essid.length;
James Ketrenos2c86c272005-03-23 17:32:29 -06006978 essid = extra;
6979 }
6980
6981 if (length == 0) {
6982 IPW_DEBUG_WX("Setting ESSID to ANY\n");
6983 priv->config &= ~CFG_STATIC_ESSID;
6984 err = ipw2100_set_essid(priv, NULL, 0, 0);
6985 goto done;
6986 }
6987
6988 length = min(length, IW_ESSID_MAX_SIZE);
6989
6990 priv->config |= CFG_STATIC_ESSID;
6991
6992 if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
6993 IPW_DEBUG_WX("ESSID set to current ESSID.\n");
6994 err = 0;
6995 goto done;
6996 }
6997
John W. Linville9387b7c2008-09-30 20:59:05 -04006998 IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
6999 print_ssid(ssid, essid, length), length);
James Ketrenos2c86c272005-03-23 17:32:29 -06007000
7001 priv->essid_len = length;
7002 memcpy(priv->essid, essid, priv->essid_len);
7003
7004 err = ipw2100_set_essid(priv, essid, length, 0);
7005
James Ketrenosee8e3652005-09-14 09:47:29 -05007006 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007007 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007008 return err;
7009}
7010
7011static int ipw2100_wx_get_essid(struct net_device *dev,
7012 struct iw_request_info *info,
7013 union iwreq_data *wrqu, char *extra)
7014{
7015 /*
7016 * This can be called at any time. No action lock required
7017 */
7018
7019 struct ipw2100_priv *priv = ieee80211_priv(dev);
John W. Linville9387b7c2008-09-30 20:59:05 -04007020 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06007021
7022 /* If we are associated, trying to associate, or have a statically
7023 * configured ESSID then return that; otherwise return ANY */
James Ketrenosee8e3652005-09-14 09:47:29 -05007024 if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007025 IPW_DEBUG_WX("Getting essid: '%s'\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04007026 print_ssid(ssid, priv->essid, priv->essid_len));
James Ketrenos2c86c272005-03-23 17:32:29 -06007027 memcpy(extra, priv->essid, priv->essid_len);
7028 wrqu->essid.length = priv->essid_len;
James Ketrenosee8e3652005-09-14 09:47:29 -05007029 wrqu->essid.flags = 1; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007030 } else {
7031 IPW_DEBUG_WX("Getting essid: ANY\n");
7032 wrqu->essid.length = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05007033 wrqu->essid.flags = 0; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007034 }
7035
7036 return 0;
7037}
7038
7039static int ipw2100_wx_set_nick(struct net_device *dev,
7040 struct iw_request_info *info,
7041 union iwreq_data *wrqu, char *extra)
7042{
7043 /*
7044 * This can be called at any time. No action lock required
7045 */
7046
7047 struct ipw2100_priv *priv = ieee80211_priv(dev);
7048
7049 if (wrqu->data.length > IW_ESSID_MAX_SIZE)
7050 return -E2BIG;
7051
James Ketrenosee8e3652005-09-14 09:47:29 -05007052 wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
James Ketrenos2c86c272005-03-23 17:32:29 -06007053 memset(priv->nick, 0, sizeof(priv->nick));
James Ketrenosee8e3652005-09-14 09:47:29 -05007054 memcpy(priv->nick, extra, wrqu->data.length);
James Ketrenos2c86c272005-03-23 17:32:29 -06007055
7056 IPW_DEBUG_WX("SET Nickname -> %s \n", priv->nick);
7057
7058 return 0;
7059}
7060
7061static int ipw2100_wx_get_nick(struct net_device *dev,
7062 struct iw_request_info *info,
7063 union iwreq_data *wrqu, char *extra)
7064{
7065 /*
7066 * This can be called at any time. No action lock required
7067 */
7068
7069 struct ipw2100_priv *priv = ieee80211_priv(dev);
7070
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007071 wrqu->data.length = strlen(priv->nick);
James Ketrenos2c86c272005-03-23 17:32:29 -06007072 memcpy(extra, priv->nick, wrqu->data.length);
James Ketrenosee8e3652005-09-14 09:47:29 -05007073 wrqu->data.flags = 1; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007074
7075 IPW_DEBUG_WX("GET Nickname -> %s \n", extra);
7076
7077 return 0;
7078}
7079
7080static int ipw2100_wx_set_rate(struct net_device *dev,
7081 struct iw_request_info *info,
7082 union iwreq_data *wrqu, char *extra)
7083{
7084 struct ipw2100_priv *priv = ieee80211_priv(dev);
7085 u32 target_rate = wrqu->bitrate.value;
7086 u32 rate;
7087 int err = 0;
7088
Ingo Molnar752e3772006-02-28 07:20:54 +08007089 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007090 if (!(priv->status & STATUS_INITIALIZED)) {
7091 err = -EIO;
7092 goto done;
7093 }
7094
7095 rate = 0;
7096
7097 if (target_rate == 1000000 ||
7098 (!wrqu->bitrate.fixed && target_rate > 1000000))
7099 rate |= TX_RATE_1_MBIT;
7100 if (target_rate == 2000000 ||
7101 (!wrqu->bitrate.fixed && target_rate > 2000000))
7102 rate |= TX_RATE_2_MBIT;
7103 if (target_rate == 5500000 ||
7104 (!wrqu->bitrate.fixed && target_rate > 5500000))
7105 rate |= TX_RATE_5_5_MBIT;
7106 if (target_rate == 11000000 ||
7107 (!wrqu->bitrate.fixed && target_rate > 11000000))
7108 rate |= TX_RATE_11_MBIT;
7109 if (rate == 0)
7110 rate = DEFAULT_TX_RATES;
7111
7112 err = ipw2100_set_tx_rates(priv, rate, 0);
7113
7114 IPW_DEBUG_WX("SET Rate -> %04X \n", rate);
James Ketrenosee8e3652005-09-14 09:47:29 -05007115 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007116 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007117 return err;
7118}
7119
James Ketrenos2c86c272005-03-23 17:32:29 -06007120static int ipw2100_wx_get_rate(struct net_device *dev,
7121 struct iw_request_info *info,
7122 union iwreq_data *wrqu, char *extra)
7123{
7124 struct ipw2100_priv *priv = ieee80211_priv(dev);
7125 int val;
Hannes Ederb9da9e92009-02-14 11:50:26 +00007126 unsigned int len = sizeof(val);
James Ketrenos2c86c272005-03-23 17:32:29 -06007127 int err = 0;
7128
7129 if (!(priv->status & STATUS_ENABLED) ||
7130 priv->status & STATUS_RF_KILL_MASK ||
7131 !(priv->status & STATUS_ASSOCIATED)) {
7132 wrqu->bitrate.value = 0;
7133 return 0;
7134 }
7135
Ingo Molnar752e3772006-02-28 07:20:54 +08007136 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007137 if (!(priv->status & STATUS_INITIALIZED)) {
7138 err = -EIO;
7139 goto done;
7140 }
7141
7142 err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len);
7143 if (err) {
7144 IPW_DEBUG_WX("failed querying ordinals.\n");
Julia Lawall80c42af2008-07-21 09:58:11 +02007145 goto done;
James Ketrenos2c86c272005-03-23 17:32:29 -06007146 }
7147
7148 switch (val & TX_RATE_MASK) {
7149 case TX_RATE_1_MBIT:
7150 wrqu->bitrate.value = 1000000;
7151 break;
7152 case TX_RATE_2_MBIT:
7153 wrqu->bitrate.value = 2000000;
7154 break;
7155 case TX_RATE_5_5_MBIT:
7156 wrqu->bitrate.value = 5500000;
7157 break;
7158 case TX_RATE_11_MBIT:
7159 wrqu->bitrate.value = 11000000;
7160 break;
7161 default:
7162 wrqu->bitrate.value = 0;
7163 }
7164
7165 IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
7166
James Ketrenosee8e3652005-09-14 09:47:29 -05007167 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007168 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007169 return err;
7170}
7171
7172static int ipw2100_wx_set_rts(struct net_device *dev,
7173 struct iw_request_info *info,
7174 union iwreq_data *wrqu, char *extra)
7175{
7176 struct ipw2100_priv *priv = ieee80211_priv(dev);
7177 int value, err;
7178
7179 /* Auto RTS not yet supported */
7180 if (wrqu->rts.fixed == 0)
7181 return -EINVAL;
7182
Ingo Molnar752e3772006-02-28 07:20:54 +08007183 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007184 if (!(priv->status & STATUS_INITIALIZED)) {
7185 err = -EIO;
7186 goto done;
7187 }
7188
7189 if (wrqu->rts.disabled)
7190 value = priv->rts_threshold | RTS_DISABLED;
7191 else {
James Ketrenosee8e3652005-09-14 09:47:29 -05007192 if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007193 err = -EINVAL;
7194 goto done;
7195 }
7196 value = wrqu->rts.value;
7197 }
7198
7199 err = ipw2100_set_rts_threshold(priv, value);
7200
7201 IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value);
James Ketrenosee8e3652005-09-14 09:47:29 -05007202 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007203 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007204 return err;
7205}
7206
7207static int ipw2100_wx_get_rts(struct net_device *dev,
7208 struct iw_request_info *info,
7209 union iwreq_data *wrqu, char *extra)
7210{
7211 /*
7212 * This can be called at any time. No action lock required
7213 */
7214
7215 struct ipw2100_priv *priv = ieee80211_priv(dev);
7216
7217 wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
James Ketrenosee8e3652005-09-14 09:47:29 -05007218 wrqu->rts.fixed = 1; /* no auto select */
James Ketrenos2c86c272005-03-23 17:32:29 -06007219
7220 /* If RTS is set to the default value, then it is disabled */
7221 wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
7222
7223 IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X \n", wrqu->rts.value);
7224
7225 return 0;
7226}
7227
7228static int ipw2100_wx_set_txpow(struct net_device *dev,
7229 struct iw_request_info *info,
7230 union iwreq_data *wrqu, char *extra)
7231{
7232 struct ipw2100_priv *priv = ieee80211_priv(dev);
7233 int err = 0, value;
Zhu Yib6e4da72006-01-24 13:49:32 +08007234
7235 if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled))
7236 return -EINPROGRESS;
James Ketrenos2c86c272005-03-23 17:32:29 -06007237
7238 if (priv->ieee->iw_mode != IW_MODE_ADHOC)
Zhu Yib6e4da72006-01-24 13:49:32 +08007239 return 0;
7240
7241 if ((wrqu->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
James Ketrenos2c86c272005-03-23 17:32:29 -06007242 return -EINVAL;
7243
Zhu Yib6e4da72006-01-24 13:49:32 +08007244 if (wrqu->txpower.fixed == 0)
James Ketrenos2c86c272005-03-23 17:32:29 -06007245 value = IPW_TX_POWER_DEFAULT;
7246 else {
7247 if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM ||
7248 wrqu->txpower.value > IPW_TX_POWER_MAX_DBM)
7249 return -EINVAL;
7250
Liu Hongf75459e2005-07-13 12:29:21 -05007251 value = wrqu->txpower.value;
James Ketrenos2c86c272005-03-23 17:32:29 -06007252 }
7253
Ingo Molnar752e3772006-02-28 07:20:54 +08007254 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007255 if (!(priv->status & STATUS_INITIALIZED)) {
7256 err = -EIO;
7257 goto done;
7258 }
7259
7260 err = ipw2100_set_tx_power(priv, value);
7261
7262 IPW_DEBUG_WX("SET TX Power -> %d \n", value);
7263
James Ketrenosee8e3652005-09-14 09:47:29 -05007264 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007265 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007266 return err;
7267}
7268
7269static int ipw2100_wx_get_txpow(struct net_device *dev,
7270 struct iw_request_info *info,
7271 union iwreq_data *wrqu, char *extra)
7272{
7273 /*
7274 * This can be called at any time. No action lock required
7275 */
7276
7277 struct ipw2100_priv *priv = ieee80211_priv(dev);
7278
Zhu Yib6e4da72006-01-24 13:49:32 +08007279 wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06007280
7281 if (priv->tx_power == IPW_TX_POWER_DEFAULT) {
Zhu Yib6e4da72006-01-24 13:49:32 +08007282 wrqu->txpower.fixed = 0;
7283 wrqu->txpower.value = IPW_TX_POWER_MAX_DBM;
James Ketrenos2c86c272005-03-23 17:32:29 -06007284 } else {
Zhu Yib6e4da72006-01-24 13:49:32 +08007285 wrqu->txpower.fixed = 1;
7286 wrqu->txpower.value = priv->tx_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06007287 }
7288
Zhu Yib6e4da72006-01-24 13:49:32 +08007289 wrqu->txpower.flags = IW_TXPOW_DBM;
James Ketrenos2c86c272005-03-23 17:32:29 -06007290
Zhu Yib6e4da72006-01-24 13:49:32 +08007291 IPW_DEBUG_WX("GET TX Power -> %d \n", wrqu->txpower.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007292
7293 return 0;
7294}
7295
7296static int ipw2100_wx_set_frag(struct net_device *dev,
7297 struct iw_request_info *info,
7298 union iwreq_data *wrqu, char *extra)
7299{
7300 /*
7301 * This can be called at any time. No action lock required
7302 */
7303
7304 struct ipw2100_priv *priv = ieee80211_priv(dev);
7305
7306 if (!wrqu->frag.fixed)
7307 return -EINVAL;
7308
7309 if (wrqu->frag.disabled) {
7310 priv->frag_threshold |= FRAG_DISABLED;
7311 priv->ieee->fts = DEFAULT_FTS;
7312 } else {
7313 if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
7314 wrqu->frag.value > MAX_FRAG_THRESHOLD)
7315 return -EINVAL;
7316
7317 priv->ieee->fts = wrqu->frag.value & ~0x1;
7318 priv->frag_threshold = priv->ieee->fts;
7319 }
7320
7321 IPW_DEBUG_WX("SET Frag Threshold -> %d \n", priv->ieee->fts);
7322
7323 return 0;
7324}
7325
7326static int ipw2100_wx_get_frag(struct net_device *dev,
7327 struct iw_request_info *info,
7328 union iwreq_data *wrqu, char *extra)
7329{
7330 /*
7331 * This can be called at any time. No action lock required
7332 */
7333
7334 struct ipw2100_priv *priv = ieee80211_priv(dev);
7335 wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED;
7336 wrqu->frag.fixed = 0; /* no auto select */
7337 wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
7338
7339 IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
7340
7341 return 0;
7342}
7343
7344static int ipw2100_wx_set_retry(struct net_device *dev,
7345 struct iw_request_info *info,
7346 union iwreq_data *wrqu, char *extra)
7347{
7348 struct ipw2100_priv *priv = ieee80211_priv(dev);
7349 int err = 0;
7350
James Ketrenosee8e3652005-09-14 09:47:29 -05007351 if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
James Ketrenos2c86c272005-03-23 17:32:29 -06007352 return -EINVAL;
7353
7354 if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
7355 return 0;
7356
Ingo Molnar752e3772006-02-28 07:20:54 +08007357 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007358 if (!(priv->status & STATUS_INITIALIZED)) {
7359 err = -EIO;
7360 goto done;
7361 }
7362
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007363 if (wrqu->retry.flags & IW_RETRY_SHORT) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007364 err = ipw2100_set_short_retry(priv, wrqu->retry.value);
7365 IPW_DEBUG_WX("SET Short Retry Limit -> %d \n",
James Ketrenosee8e3652005-09-14 09:47:29 -05007366 wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007367 goto done;
7368 }
7369
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007370 if (wrqu->retry.flags & IW_RETRY_LONG) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007371 err = ipw2100_set_long_retry(priv, wrqu->retry.value);
7372 IPW_DEBUG_WX("SET Long Retry Limit -> %d \n",
James Ketrenosee8e3652005-09-14 09:47:29 -05007373 wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007374 goto done;
7375 }
7376
7377 err = ipw2100_set_short_retry(priv, wrqu->retry.value);
7378 if (!err)
7379 err = ipw2100_set_long_retry(priv, wrqu->retry.value);
7380
7381 IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value);
7382
James Ketrenosee8e3652005-09-14 09:47:29 -05007383 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007384 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007385 return err;
7386}
7387
7388static int ipw2100_wx_get_retry(struct net_device *dev,
7389 struct iw_request_info *info,
7390 union iwreq_data *wrqu, char *extra)
7391{
7392 /*
7393 * This can be called at any time. No action lock required
7394 */
7395
7396 struct ipw2100_priv *priv = ieee80211_priv(dev);
7397
James Ketrenosee8e3652005-09-14 09:47:29 -05007398 wrqu->retry.disabled = 0; /* can't be disabled */
James Ketrenos2c86c272005-03-23 17:32:29 -06007399
James Ketrenosee8e3652005-09-14 09:47:29 -05007400 if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
James Ketrenos2c86c272005-03-23 17:32:29 -06007401 return -EINVAL;
7402
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007403 if (wrqu->retry.flags & IW_RETRY_LONG) {
7404 wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
James Ketrenos2c86c272005-03-23 17:32:29 -06007405 wrqu->retry.value = priv->long_retry_limit;
7406 } else {
7407 wrqu->retry.flags =
7408 (priv->short_retry_limit !=
7409 priv->long_retry_limit) ?
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007410 IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT;
James Ketrenos2c86c272005-03-23 17:32:29 -06007411
7412 wrqu->retry.value = priv->short_retry_limit;
7413 }
7414
7415 IPW_DEBUG_WX("GET Retry -> %d \n", wrqu->retry.value);
7416
7417 return 0;
7418}
7419
7420static int ipw2100_wx_set_scan(struct net_device *dev,
7421 struct iw_request_info *info,
7422 union iwreq_data *wrqu, char *extra)
7423{
7424 struct ipw2100_priv *priv = ieee80211_priv(dev);
7425 int err = 0;
7426
Ingo Molnar752e3772006-02-28 07:20:54 +08007427 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007428 if (!(priv->status & STATUS_INITIALIZED)) {
7429 err = -EIO;
7430 goto done;
7431 }
7432
7433 IPW_DEBUG_WX("Initiating scan...\n");
Dan Williamsd20c6782007-10-10 12:28:07 -04007434
7435 priv->user_requested_scan = 1;
James Ketrenosee8e3652005-09-14 09:47:29 -05007436 if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007437 IPW_DEBUG_WX("Start scan failed.\n");
7438
7439 /* TODO: Mark a scan as pending so when hardware initialized
7440 * a scan starts */
7441 }
7442
James Ketrenosee8e3652005-09-14 09:47:29 -05007443 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007444 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007445 return err;
7446}
7447
7448static int ipw2100_wx_get_scan(struct net_device *dev,
7449 struct iw_request_info *info,
7450 union iwreq_data *wrqu, char *extra)
7451{
7452 /*
7453 * This can be called at any time. No action lock required
7454 */
7455
7456 struct ipw2100_priv *priv = ieee80211_priv(dev);
7457 return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra);
7458}
7459
James Ketrenos2c86c272005-03-23 17:32:29 -06007460/*
7461 * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c
7462 */
7463static int ipw2100_wx_set_encode(struct net_device *dev,
7464 struct iw_request_info *info,
7465 union iwreq_data *wrqu, char *key)
7466{
7467 /*
7468 * No check of STATUS_INITIALIZED required
7469 */
7470
7471 struct ipw2100_priv *priv = ieee80211_priv(dev);
7472 return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
7473}
7474
7475static int ipw2100_wx_get_encode(struct net_device *dev,
7476 struct iw_request_info *info,
7477 union iwreq_data *wrqu, char *key)
7478{
7479 /*
7480 * This can be called at any time. No action lock required
7481 */
7482
7483 struct ipw2100_priv *priv = ieee80211_priv(dev);
7484 return ieee80211_wx_get_encode(priv->ieee, info, wrqu, key);
7485}
7486
7487static int ipw2100_wx_set_power(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05007488 struct iw_request_info *info,
7489 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007490{
7491 struct ipw2100_priv *priv = ieee80211_priv(dev);
7492 int err = 0;
7493
Ingo Molnar752e3772006-02-28 07:20:54 +08007494 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007495 if (!(priv->status & STATUS_INITIALIZED)) {
7496 err = -EIO;
7497 goto done;
7498 }
7499
7500 if (wrqu->power.disabled) {
7501 priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
7502 err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
7503 IPW_DEBUG_WX("SET Power Management Mode -> off\n");
7504 goto done;
7505 }
7506
7507 switch (wrqu->power.flags & IW_POWER_MODE) {
James Ketrenosee8e3652005-09-14 09:47:29 -05007508 case IW_POWER_ON: /* If not specified */
7509 case IW_POWER_MODE: /* If set all mask */
Jean Delvarec03983a2007-10-19 23:22:55 +02007510 case IW_POWER_ALL_R: /* If explicitly state all */
James Ketrenos2c86c272005-03-23 17:32:29 -06007511 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05007512 default: /* Otherwise we don't support it */
James Ketrenos2c86c272005-03-23 17:32:29 -06007513 IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
7514 wrqu->power.flags);
7515 err = -EOPNOTSUPP;
7516 goto done;
7517 }
7518
7519 /* If the user hasn't specified a power management mode yet, default
7520 * to BATTERY */
7521 priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
7522 err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
7523
James Ketrenosee8e3652005-09-14 09:47:29 -05007524 IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06007525
James Ketrenosee8e3652005-09-14 09:47:29 -05007526 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007527 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007528 return err;
7529
7530}
7531
7532static int ipw2100_wx_get_power(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05007533 struct iw_request_info *info,
7534 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007535{
7536 /*
7537 * This can be called at any time. No action lock required
7538 */
7539
7540 struct ipw2100_priv *priv = ieee80211_priv(dev);
7541
James Ketrenos82328352005-08-24 22:33:31 -05007542 if (!(priv->power_mode & IPW_POWER_ENABLED))
James Ketrenos2c86c272005-03-23 17:32:29 -06007543 wrqu->power.disabled = 1;
James Ketrenos82328352005-08-24 22:33:31 -05007544 else {
James Ketrenos2c86c272005-03-23 17:32:29 -06007545 wrqu->power.disabled = 0;
7546 wrqu->power.flags = 0;
7547 }
7548
7549 IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
7550
7551 return 0;
7552}
7553
James Ketrenos82328352005-08-24 22:33:31 -05007554/*
7555 * WE-18 WPA support
7556 */
7557
7558/* SIOCSIWGENIE */
7559static int ipw2100_wx_set_genie(struct net_device *dev,
7560 struct iw_request_info *info,
7561 union iwreq_data *wrqu, char *extra)
7562{
7563
7564 struct ipw2100_priv *priv = ieee80211_priv(dev);
7565 struct ieee80211_device *ieee = priv->ieee;
7566 u8 *buf;
7567
7568 if (!ieee->wpa_enabled)
7569 return -EOPNOTSUPP;
7570
7571 if (wrqu->data.length > MAX_WPA_IE_LEN ||
7572 (wrqu->data.length && extra == NULL))
7573 return -EINVAL;
7574
7575 if (wrqu->data.length) {
Eric Sesterhennc3a9392e2006-10-23 22:20:15 +02007576 buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
James Ketrenos82328352005-08-24 22:33:31 -05007577 if (buf == NULL)
7578 return -ENOMEM;
7579
James Ketrenos82328352005-08-24 22:33:31 -05007580 kfree(ieee->wpa_ie);
7581 ieee->wpa_ie = buf;
7582 ieee->wpa_ie_len = wrqu->data.length;
7583 } else {
7584 kfree(ieee->wpa_ie);
7585 ieee->wpa_ie = NULL;
7586 ieee->wpa_ie_len = 0;
7587 }
7588
7589 ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
7590
7591 return 0;
7592}
7593
7594/* SIOCGIWGENIE */
7595static int ipw2100_wx_get_genie(struct net_device *dev,
7596 struct iw_request_info *info,
7597 union iwreq_data *wrqu, char *extra)
7598{
7599 struct ipw2100_priv *priv = ieee80211_priv(dev);
7600 struct ieee80211_device *ieee = priv->ieee;
7601
7602 if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
7603 wrqu->data.length = 0;
7604 return 0;
7605 }
7606
7607 if (wrqu->data.length < ieee->wpa_ie_len)
7608 return -E2BIG;
7609
7610 wrqu->data.length = ieee->wpa_ie_len;
7611 memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
7612
7613 return 0;
7614}
7615
7616/* SIOCSIWAUTH */
7617static int ipw2100_wx_set_auth(struct net_device *dev,
7618 struct iw_request_info *info,
7619 union iwreq_data *wrqu, char *extra)
7620{
7621 struct ipw2100_priv *priv = ieee80211_priv(dev);
7622 struct ieee80211_device *ieee = priv->ieee;
7623 struct iw_param *param = &wrqu->param;
John W. Linville274bfb82008-10-29 11:35:05 -04007624 struct lib80211_crypt_data *crypt;
James Ketrenos82328352005-08-24 22:33:31 -05007625 unsigned long flags;
7626 int ret = 0;
7627
7628 switch (param->flags & IW_AUTH_INDEX) {
7629 case IW_AUTH_WPA_VERSION:
7630 case IW_AUTH_CIPHER_PAIRWISE:
7631 case IW_AUTH_CIPHER_GROUP:
7632 case IW_AUTH_KEY_MGMT:
7633 /*
7634 * ipw2200 does not use these parameters
7635 */
7636 break;
7637
7638 case IW_AUTH_TKIP_COUNTERMEASURES:
John W. Linville274bfb82008-10-29 11:35:05 -04007639 crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
James Ketrenos991d1cc2005-10-13 09:26:48 +00007640 if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
James Ketrenos82328352005-08-24 22:33:31 -05007641 break;
James Ketrenos82328352005-08-24 22:33:31 -05007642
7643 flags = crypt->ops->get_flags(crypt->priv);
7644
7645 if (param->value)
7646 flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
7647 else
7648 flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
7649
7650 crypt->ops->set_flags(flags, crypt->priv);
7651
7652 break;
7653
7654 case IW_AUTH_DROP_UNENCRYPTED:{
7655 /* HACK:
7656 *
7657 * wpa_supplicant calls set_wpa_enabled when the driver
7658 * is loaded and unloaded, regardless of if WPA is being
7659 * used. No other calls are made which can be used to
7660 * determine if encryption will be used or not prior to
7661 * association being expected. If encryption is not being
7662 * used, drop_unencrypted is set to false, else true -- we
7663 * can use this to determine if the CAP_PRIVACY_ON bit should
7664 * be set.
7665 */
7666 struct ieee80211_security sec = {
7667 .flags = SEC_ENABLED,
7668 .enabled = param->value,
7669 };
7670 priv->ieee->drop_unencrypted = param->value;
7671 /* We only change SEC_LEVEL for open mode. Others
7672 * are set by ipw_wpa_set_encryption.
7673 */
7674 if (!param->value) {
7675 sec.flags |= SEC_LEVEL;
7676 sec.level = SEC_LEVEL_0;
7677 } else {
7678 sec.flags |= SEC_LEVEL;
7679 sec.level = SEC_LEVEL_1;
7680 }
7681 if (priv->ieee->set_security)
7682 priv->ieee->set_security(priv->ieee->dev, &sec);
7683 break;
7684 }
7685
7686 case IW_AUTH_80211_AUTH_ALG:
7687 ret = ipw2100_wpa_set_auth_algs(priv, param->value);
7688 break;
7689
7690 case IW_AUTH_WPA_ENABLED:
7691 ret = ipw2100_wpa_enable(priv, param->value);
7692 break;
7693
7694 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
7695 ieee->ieee802_1x = param->value;
7696 break;
7697
7698 //case IW_AUTH_ROAMING_CONTROL:
7699 case IW_AUTH_PRIVACY_INVOKED:
7700 ieee->privacy_invoked = param->value;
7701 break;
7702
7703 default:
7704 return -EOPNOTSUPP;
7705 }
7706 return ret;
7707}
7708
7709/* SIOCGIWAUTH */
7710static int ipw2100_wx_get_auth(struct net_device *dev,
7711 struct iw_request_info *info,
7712 union iwreq_data *wrqu, char *extra)
7713{
7714 struct ipw2100_priv *priv = ieee80211_priv(dev);
7715 struct ieee80211_device *ieee = priv->ieee;
John W. Linville274bfb82008-10-29 11:35:05 -04007716 struct lib80211_crypt_data *crypt;
James Ketrenos82328352005-08-24 22:33:31 -05007717 struct iw_param *param = &wrqu->param;
7718 int ret = 0;
7719
7720 switch (param->flags & IW_AUTH_INDEX) {
7721 case IW_AUTH_WPA_VERSION:
7722 case IW_AUTH_CIPHER_PAIRWISE:
7723 case IW_AUTH_CIPHER_GROUP:
7724 case IW_AUTH_KEY_MGMT:
7725 /*
7726 * wpa_supplicant will control these internally
7727 */
7728 ret = -EOPNOTSUPP;
7729 break;
7730
7731 case IW_AUTH_TKIP_COUNTERMEASURES:
John W. Linville274bfb82008-10-29 11:35:05 -04007732 crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
James Ketrenos82328352005-08-24 22:33:31 -05007733 if (!crypt || !crypt->ops->get_flags) {
7734 IPW_DEBUG_WARNING("Can't get TKIP countermeasures: "
7735 "crypt not set!\n");
7736 break;
7737 }
7738
7739 param->value = (crypt->ops->get_flags(crypt->priv) &
7740 IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
7741
7742 break;
7743
7744 case IW_AUTH_DROP_UNENCRYPTED:
7745 param->value = ieee->drop_unencrypted;
7746 break;
7747
7748 case IW_AUTH_80211_AUTH_ALG:
25b645b2005-07-12 15:45:30 -05007749 param->value = priv->ieee->sec.auth_mode;
James Ketrenos82328352005-08-24 22:33:31 -05007750 break;
7751
7752 case IW_AUTH_WPA_ENABLED:
7753 param->value = ieee->wpa_enabled;
7754 break;
7755
7756 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
7757 param->value = ieee->ieee802_1x;
7758 break;
7759
7760 case IW_AUTH_ROAMING_CONTROL:
7761 case IW_AUTH_PRIVACY_INVOKED:
7762 param->value = ieee->privacy_invoked;
7763 break;
7764
7765 default:
7766 return -EOPNOTSUPP;
7767 }
7768 return 0;
7769}
7770
7771/* SIOCSIWENCODEEXT */
7772static int ipw2100_wx_set_encodeext(struct net_device *dev,
7773 struct iw_request_info *info,
7774 union iwreq_data *wrqu, char *extra)
7775{
7776 struct ipw2100_priv *priv = ieee80211_priv(dev);
7777 return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra);
7778}
7779
7780/* SIOCGIWENCODEEXT */
7781static int ipw2100_wx_get_encodeext(struct net_device *dev,
7782 struct iw_request_info *info,
7783 union iwreq_data *wrqu, char *extra)
7784{
7785 struct ipw2100_priv *priv = ieee80211_priv(dev);
7786 return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra);
7787}
7788
7789/* SIOCSIWMLME */
7790static int ipw2100_wx_set_mlme(struct net_device *dev,
7791 struct iw_request_info *info,
7792 union iwreq_data *wrqu, char *extra)
7793{
7794 struct ipw2100_priv *priv = ieee80211_priv(dev);
7795 struct iw_mlme *mlme = (struct iw_mlme *)extra;
Al Viro1edd3a52007-12-21 00:15:18 -05007796 __le16 reason;
James Ketrenos82328352005-08-24 22:33:31 -05007797
7798 reason = cpu_to_le16(mlme->reason_code);
7799
7800 switch (mlme->cmd) {
7801 case IW_MLME_DEAUTH:
7802 // silently ignore
7803 break;
7804
7805 case IW_MLME_DISASSOC:
7806 ipw2100_disassociate_bssid(priv);
7807 break;
7808
7809 default:
7810 return -EOPNOTSUPP;
7811 }
7812 return 0;
7813}
James Ketrenos2c86c272005-03-23 17:32:29 -06007814
7815/*
7816 *
7817 * IWPRIV handlers
7818 *
7819 */
7820#ifdef CONFIG_IPW2100_MONITOR
7821static int ipw2100_wx_set_promisc(struct net_device *dev,
7822 struct iw_request_info *info,
7823 union iwreq_data *wrqu, char *extra)
7824{
7825 struct ipw2100_priv *priv = ieee80211_priv(dev);
7826 int *parms = (int *)extra;
7827 int enable = (parms[0] > 0);
7828 int err = 0;
7829
Ingo Molnar752e3772006-02-28 07:20:54 +08007830 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007831 if (!(priv->status & STATUS_INITIALIZED)) {
7832 err = -EIO;
7833 goto done;
7834 }
7835
7836 if (enable) {
7837 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
7838 err = ipw2100_set_channel(priv, parms[1], 0);
7839 goto done;
7840 }
7841 priv->channel = parms[1];
7842 err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
7843 } else {
7844 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
7845 err = ipw2100_switch_mode(priv, priv->last_mode);
7846 }
James Ketrenosee8e3652005-09-14 09:47:29 -05007847 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007848 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007849 return err;
7850}
7851
7852static int ipw2100_wx_reset(struct net_device *dev,
7853 struct iw_request_info *info,
7854 union iwreq_data *wrqu, char *extra)
7855{
7856 struct ipw2100_priv *priv = ieee80211_priv(dev);
7857 if (priv->status & STATUS_INITIALIZED)
7858 schedule_reset(priv);
7859 return 0;
7860}
7861
7862#endif
7863
7864static int ipw2100_wx_set_powermode(struct net_device *dev,
7865 struct iw_request_info *info,
7866 union iwreq_data *wrqu, char *extra)
7867{
7868 struct ipw2100_priv *priv = ieee80211_priv(dev);
7869 int err = 0, mode = *(int *)extra;
7870
Ingo Molnar752e3772006-02-28 07:20:54 +08007871 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007872 if (!(priv->status & STATUS_INITIALIZED)) {
7873 err = -EIO;
7874 goto done;
7875 }
7876
Zhu Yi9f3b2412007-07-12 16:09:24 +08007877 if ((mode < 0) || (mode > POWER_MODES))
James Ketrenos2c86c272005-03-23 17:32:29 -06007878 mode = IPW_POWER_AUTO;
7879
Zhu Yi9f3b2412007-07-12 16:09:24 +08007880 if (IPW_POWER_LEVEL(priv->power_mode) != mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06007881 err = ipw2100_set_power_mode(priv, mode);
James Ketrenosee8e3652005-09-14 09:47:29 -05007882 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007883 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007884 return err;
7885}
7886
7887#define MAX_POWER_STRING 80
7888static int ipw2100_wx_get_powermode(struct net_device *dev,
7889 struct iw_request_info *info,
7890 union iwreq_data *wrqu, char *extra)
7891{
7892 /*
7893 * This can be called at any time. No action lock required
7894 */
7895
7896 struct ipw2100_priv *priv = ieee80211_priv(dev);
7897 int level = IPW_POWER_LEVEL(priv->power_mode);
7898 s32 timeout, period;
7899
7900 if (!(priv->power_mode & IPW_POWER_ENABLED)) {
7901 snprintf(extra, MAX_POWER_STRING,
7902 "Power save level: %d (Off)", level);
7903 } else {
7904 switch (level) {
7905 case IPW_POWER_MODE_CAM:
7906 snprintf(extra, MAX_POWER_STRING,
7907 "Power save level: %d (None)", level);
7908 break;
7909 case IPW_POWER_AUTO:
James Ketrenosee8e3652005-09-14 09:47:29 -05007910 snprintf(extra, MAX_POWER_STRING,
Zhu Yi9f3b2412007-07-12 16:09:24 +08007911 "Power save level: %d (Auto)", level);
James Ketrenos2c86c272005-03-23 17:32:29 -06007912 break;
7913 default:
7914 timeout = timeout_duration[level - 1] / 1000;
7915 period = period_duration[level - 1] / 1000;
7916 snprintf(extra, MAX_POWER_STRING,
7917 "Power save level: %d "
7918 "(Timeout %dms, Period %dms)",
7919 level, timeout, period);
7920 }
7921 }
7922
7923 wrqu->data.length = strlen(extra) + 1;
7924
7925 return 0;
7926}
7927
James Ketrenos2c86c272005-03-23 17:32:29 -06007928static int ipw2100_wx_set_preamble(struct net_device *dev,
7929 struct iw_request_info *info,
7930 union iwreq_data *wrqu, char *extra)
7931{
7932 struct ipw2100_priv *priv = ieee80211_priv(dev);
7933 int err, mode = *(int *)extra;
7934
Ingo Molnar752e3772006-02-28 07:20:54 +08007935 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007936 if (!(priv->status & STATUS_INITIALIZED)) {
7937 err = -EIO;
7938 goto done;
7939 }
7940
7941 if (mode == 1)
7942 priv->config |= CFG_LONG_PREAMBLE;
7943 else if (mode == 0)
7944 priv->config &= ~CFG_LONG_PREAMBLE;
7945 else {
7946 err = -EINVAL;
7947 goto done;
7948 }
7949
7950 err = ipw2100_system_config(priv, 0);
7951
James Ketrenosee8e3652005-09-14 09:47:29 -05007952 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007953 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007954 return err;
7955}
7956
7957static int ipw2100_wx_get_preamble(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05007958 struct iw_request_info *info,
7959 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007960{
7961 /*
7962 * This can be called at any time. No action lock required
7963 */
7964
7965 struct ipw2100_priv *priv = ieee80211_priv(dev);
7966
7967 if (priv->config & CFG_LONG_PREAMBLE)
7968 snprintf(wrqu->name, IFNAMSIZ, "long (1)");
7969 else
7970 snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
7971
7972 return 0;
7973}
7974
James Ketrenos82328352005-08-24 22:33:31 -05007975#ifdef CONFIG_IPW2100_MONITOR
7976static int ipw2100_wx_set_crc_check(struct net_device *dev,
7977 struct iw_request_info *info,
7978 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007979{
James Ketrenos82328352005-08-24 22:33:31 -05007980 struct ipw2100_priv *priv = ieee80211_priv(dev);
7981 int err, mode = *(int *)extra;
7982
Ingo Molnar752e3772006-02-28 07:20:54 +08007983 mutex_lock(&priv->action_mutex);
James Ketrenos82328352005-08-24 22:33:31 -05007984 if (!(priv->status & STATUS_INITIALIZED)) {
7985 err = -EIO;
7986 goto done;
7987 }
7988
7989 if (mode == 1)
7990 priv->config |= CFG_CRC_CHECK;
7991 else if (mode == 0)
7992 priv->config &= ~CFG_CRC_CHECK;
7993 else {
7994 err = -EINVAL;
7995 goto done;
7996 }
7997 err = 0;
7998
7999 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08008000 mutex_unlock(&priv->action_mutex);
James Ketrenos82328352005-08-24 22:33:31 -05008001 return err;
8002}
8003
8004static int ipw2100_wx_get_crc_check(struct net_device *dev,
8005 struct iw_request_info *info,
8006 union iwreq_data *wrqu, char *extra)
8007{
8008 /*
8009 * This can be called at any time. No action lock required
8010 */
8011
8012 struct ipw2100_priv *priv = ieee80211_priv(dev);
8013
8014 if (priv->config & CFG_CRC_CHECK)
8015 snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)");
8016 else
8017 snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)");
8018
8019 return 0;
8020}
8021#endif /* CONFIG_IPW2100_MONITOR */
8022
James Ketrenosee8e3652005-09-14 09:47:29 -05008023static iw_handler ipw2100_wx_handlers[] = {
8024 NULL, /* SIOCSIWCOMMIT */
8025 ipw2100_wx_get_name, /* SIOCGIWNAME */
8026 NULL, /* SIOCSIWNWID */
8027 NULL, /* SIOCGIWNWID */
8028 ipw2100_wx_set_freq, /* SIOCSIWFREQ */
8029 ipw2100_wx_get_freq, /* SIOCGIWFREQ */
8030 ipw2100_wx_set_mode, /* SIOCSIWMODE */
8031 ipw2100_wx_get_mode, /* SIOCGIWMODE */
8032 NULL, /* SIOCSIWSENS */
8033 NULL, /* SIOCGIWSENS */
8034 NULL, /* SIOCSIWRANGE */
8035 ipw2100_wx_get_range, /* SIOCGIWRANGE */
8036 NULL, /* SIOCSIWPRIV */
8037 NULL, /* SIOCGIWPRIV */
8038 NULL, /* SIOCSIWSTATS */
8039 NULL, /* SIOCGIWSTATS */
8040 NULL, /* SIOCSIWSPY */
8041 NULL, /* SIOCGIWSPY */
8042 NULL, /* SIOCGIWTHRSPY */
8043 NULL, /* SIOCWIWTHRSPY */
8044 ipw2100_wx_set_wap, /* SIOCSIWAP */
8045 ipw2100_wx_get_wap, /* SIOCGIWAP */
James Ketrenos82328352005-08-24 22:33:31 -05008046 ipw2100_wx_set_mlme, /* SIOCSIWMLME */
James Ketrenosee8e3652005-09-14 09:47:29 -05008047 NULL, /* SIOCGIWAPLIST -- deprecated */
8048 ipw2100_wx_set_scan, /* SIOCSIWSCAN */
8049 ipw2100_wx_get_scan, /* SIOCGIWSCAN */
8050 ipw2100_wx_set_essid, /* SIOCSIWESSID */
8051 ipw2100_wx_get_essid, /* SIOCGIWESSID */
8052 ipw2100_wx_set_nick, /* SIOCSIWNICKN */
8053 ipw2100_wx_get_nick, /* SIOCGIWNICKN */
8054 NULL, /* -- hole -- */
8055 NULL, /* -- hole -- */
8056 ipw2100_wx_set_rate, /* SIOCSIWRATE */
8057 ipw2100_wx_get_rate, /* SIOCGIWRATE */
8058 ipw2100_wx_set_rts, /* SIOCSIWRTS */
8059 ipw2100_wx_get_rts, /* SIOCGIWRTS */
8060 ipw2100_wx_set_frag, /* SIOCSIWFRAG */
8061 ipw2100_wx_get_frag, /* SIOCGIWFRAG */
8062 ipw2100_wx_set_txpow, /* SIOCSIWTXPOW */
8063 ipw2100_wx_get_txpow, /* SIOCGIWTXPOW */
8064 ipw2100_wx_set_retry, /* SIOCSIWRETRY */
8065 ipw2100_wx_get_retry, /* SIOCGIWRETRY */
8066 ipw2100_wx_set_encode, /* SIOCSIWENCODE */
8067 ipw2100_wx_get_encode, /* SIOCGIWENCODE */
8068 ipw2100_wx_set_power, /* SIOCSIWPOWER */
8069 ipw2100_wx_get_power, /* SIOCGIWPOWER */
James Ketrenos82328352005-08-24 22:33:31 -05008070 NULL, /* -- hole -- */
8071 NULL, /* -- hole -- */
8072 ipw2100_wx_set_genie, /* SIOCSIWGENIE */
8073 ipw2100_wx_get_genie, /* SIOCGIWGENIE */
8074 ipw2100_wx_set_auth, /* SIOCSIWAUTH */
8075 ipw2100_wx_get_auth, /* SIOCGIWAUTH */
8076 ipw2100_wx_set_encodeext, /* SIOCSIWENCODEEXT */
8077 ipw2100_wx_get_encodeext, /* SIOCGIWENCODEEXT */
8078 NULL, /* SIOCSIWPMKSA */
James Ketrenos2c86c272005-03-23 17:32:29 -06008079};
8080
8081#define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV
8082#define IPW2100_PRIV_RESET SIOCIWFIRSTPRIV+1
8083#define IPW2100_PRIV_SET_POWER SIOCIWFIRSTPRIV+2
8084#define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3
8085#define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4
8086#define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5
James Ketrenos82328352005-08-24 22:33:31 -05008087#define IPW2100_PRIV_SET_CRC_CHECK SIOCIWFIRSTPRIV+6
8088#define IPW2100_PRIV_GET_CRC_CHECK SIOCIWFIRSTPRIV+7
James Ketrenos2c86c272005-03-23 17:32:29 -06008089
8090static const struct iw_priv_args ipw2100_private_args[] = {
8091
8092#ifdef CONFIG_IPW2100_MONITOR
8093 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008094 IPW2100_PRIV_SET_MONITOR,
8095 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008096 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008097 IPW2100_PRIV_RESET,
8098 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
8099#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008100
8101 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008102 IPW2100_PRIV_SET_POWER,
8103 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008104 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008105 IPW2100_PRIV_GET_POWER,
8106 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING,
8107 "get_power"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008108 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008109 IPW2100_PRIV_SET_LONGPREAMBLE,
8110 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008111 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008112 IPW2100_PRIV_GET_LONGPREAMBLE,
8113 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"},
James Ketrenos82328352005-08-24 22:33:31 -05008114#ifdef CONFIG_IPW2100_MONITOR
8115 {
8116 IPW2100_PRIV_SET_CRC_CHECK,
8117 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"},
8118 {
8119 IPW2100_PRIV_GET_CRC_CHECK,
8120 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"},
8121#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008122};
8123
8124static iw_handler ipw2100_private_handler[] = {
8125#ifdef CONFIG_IPW2100_MONITOR
8126 ipw2100_wx_set_promisc,
8127 ipw2100_wx_reset,
James Ketrenosee8e3652005-09-14 09:47:29 -05008128#else /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008129 NULL,
8130 NULL,
James Ketrenosee8e3652005-09-14 09:47:29 -05008131#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008132 ipw2100_wx_set_powermode,
8133 ipw2100_wx_get_powermode,
8134 ipw2100_wx_set_preamble,
8135 ipw2100_wx_get_preamble,
James Ketrenos82328352005-08-24 22:33:31 -05008136#ifdef CONFIG_IPW2100_MONITOR
8137 ipw2100_wx_set_crc_check,
8138 ipw2100_wx_get_crc_check,
8139#else /* CONFIG_IPW2100_MONITOR */
8140 NULL,
8141 NULL,
8142#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008143};
8144
James Ketrenos2c86c272005-03-23 17:32:29 -06008145/*
8146 * Get wireless statistics.
8147 * Called by /proc/net/wireless
8148 * Also called by SIOCGIWSTATS
8149 */
James Ketrenosee8e3652005-09-14 09:47:29 -05008150static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
James Ketrenos2c86c272005-03-23 17:32:29 -06008151{
8152 enum {
8153 POOR = 30,
8154 FAIR = 60,
8155 GOOD = 80,
8156 VERY_GOOD = 90,
8157 EXCELLENT = 95,
8158 PERFECT = 100
8159 };
8160 int rssi_qual;
8161 int tx_qual;
8162 int beacon_qual;
8163
8164 struct ipw2100_priv *priv = ieee80211_priv(dev);
8165 struct iw_statistics *wstats;
8166 u32 rssi, quality, tx_retries, missed_beacons, tx_failures;
8167 u32 ord_len = sizeof(u32);
8168
8169 if (!priv)
James Ketrenosee8e3652005-09-14 09:47:29 -05008170 return (struct iw_statistics *)NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06008171
8172 wstats = &priv->wstats;
8173
8174 /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
8175 * ipw2100_wx_wireless_stats seems to be called before fw is
8176 * initialized. STATUS_ASSOCIATED will only be set if the hw is up
8177 * and associated; if not associcated, the values are all meaningless
8178 * anyway, so set them all to NULL and INVALID */
8179 if (!(priv->status & STATUS_ASSOCIATED)) {
8180 wstats->miss.beacon = 0;
8181 wstats->discard.retries = 0;
8182 wstats->qual.qual = 0;
8183 wstats->qual.level = 0;
8184 wstats->qual.noise = 0;
8185 wstats->qual.updated = 7;
8186 wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
James Ketrenosee8e3652005-09-14 09:47:29 -05008187 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
James Ketrenos2c86c272005-03-23 17:32:29 -06008188 return wstats;
8189 }
8190
8191 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS,
8192 &missed_beacons, &ord_len))
8193 goto fail_get_ordinal;
8194
James Ketrenosee8e3652005-09-14 09:47:29 -05008195 /* If we don't have a connection the quality and level is 0 */
James Ketrenos2c86c272005-03-23 17:32:29 -06008196 if (!(priv->status & STATUS_ASSOCIATED)) {
8197 wstats->qual.qual = 0;
8198 wstats->qual.level = 0;
8199 } else {
8200 if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR,
8201 &rssi, &ord_len))
8202 goto fail_get_ordinal;
8203 wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
8204 if (rssi < 10)
8205 rssi_qual = rssi * POOR / 10;
8206 else if (rssi < 15)
8207 rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR;
8208 else if (rssi < 20)
8209 rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR;
8210 else if (rssi < 30)
8211 rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008212 10 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008213 else
8214 rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008215 10 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008216
8217 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES,
8218 &tx_retries, &ord_len))
8219 goto fail_get_ordinal;
8220
8221 if (tx_retries > 75)
8222 tx_qual = (90 - tx_retries) * POOR / 15;
8223 else if (tx_retries > 70)
8224 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
8225 else if (tx_retries > 65)
8226 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
8227 else if (tx_retries > 50)
8228 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008229 15 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008230 else
8231 tx_qual = (50 - tx_retries) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008232 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008233
8234 if (missed_beacons > 50)
8235 beacon_qual = (60 - missed_beacons) * POOR / 10;
8236 else if (missed_beacons > 40)
8237 beacon_qual = (50 - missed_beacons) * (FAIR - POOR) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008238 10 + POOR;
James Ketrenos2c86c272005-03-23 17:32:29 -06008239 else if (missed_beacons > 32)
8240 beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008241 18 + FAIR;
James Ketrenos2c86c272005-03-23 17:32:29 -06008242 else if (missed_beacons > 20)
8243 beacon_qual = (32 - missed_beacons) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008244 (VERY_GOOD - GOOD) / 20 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008245 else
8246 beacon_qual = (20 - missed_beacons) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008247 (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008248
8249 quality = min(beacon_qual, min(tx_qual, rssi_qual));
8250
Brice Goglin0f52bf92005-12-01 01:41:46 -08008251#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06008252 if (beacon_qual == quality)
8253 IPW_DEBUG_WX("Quality clamped by Missed Beacons\n");
8254 else if (tx_qual == quality)
8255 IPW_DEBUG_WX("Quality clamped by Tx Retries\n");
8256 else if (quality != 100)
8257 IPW_DEBUG_WX("Quality clamped by Signal Strength\n");
8258 else
8259 IPW_DEBUG_WX("Quality not clamped.\n");
8260#endif
8261
8262 wstats->qual.qual = quality;
8263 wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
8264 }
8265
8266 wstats->qual.noise = 0;
8267 wstats->qual.updated = 7;
8268 wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
8269
James Ketrenosee8e3652005-09-14 09:47:29 -05008270 /* FIXME: this is percent and not a # */
James Ketrenos2c86c272005-03-23 17:32:29 -06008271 wstats->miss.beacon = missed_beacons;
8272
8273 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES,
8274 &tx_failures, &ord_len))
8275 goto fail_get_ordinal;
8276 wstats->discard.retries = tx_failures;
8277
8278 return wstats;
8279
James Ketrenosee8e3652005-09-14 09:47:29 -05008280 fail_get_ordinal:
James Ketrenos2c86c272005-03-23 17:32:29 -06008281 IPW_DEBUG_WX("failed querying ordinals.\n");
8282
James Ketrenosee8e3652005-09-14 09:47:29 -05008283 return (struct iw_statistics *)NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06008284}
8285
James Ketrenoseaf8f53b2005-11-12 12:50:12 -06008286static struct iw_handler_def ipw2100_wx_handler_def = {
8287 .standard = ipw2100_wx_handlers,
Denis Chengff8ac602007-09-02 18:30:18 +08008288 .num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
8289 .num_private = ARRAY_SIZE(ipw2100_private_handler),
8290 .num_private_args = ARRAY_SIZE(ipw2100_private_args),
James Ketrenoseaf8f53b2005-11-12 12:50:12 -06008291 .private = (iw_handler *) ipw2100_private_handler,
8292 .private_args = (struct iw_priv_args *)ipw2100_private_args,
8293 .get_wireless_stats = ipw2100_wx_wireless_stats,
8294};
8295
David Howellsc4028952006-11-22 14:57:56 +00008296static void ipw2100_wx_event_work(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06008297{
David Howellsc4028952006-11-22 14:57:56 +00008298 struct ipw2100_priv *priv =
8299 container_of(work, struct ipw2100_priv, wx_event_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06008300 union iwreq_data wrqu;
Hannes Ederb9da9e92009-02-14 11:50:26 +00008301 unsigned int len = ETH_ALEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06008302
8303 if (priv->status & STATUS_STOPPING)
8304 return;
8305
Ingo Molnar752e3772006-02-28 07:20:54 +08008306 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008307
8308 IPW_DEBUG_WX("enter\n");
8309
Ingo Molnar752e3772006-02-28 07:20:54 +08008310 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008311
8312 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
8313
8314 /* Fetch BSSID from the hardware */
8315 if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) ||
8316 priv->status & STATUS_RF_KILL_MASK ||
8317 ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
James Ketrenosee8e3652005-09-14 09:47:29 -05008318 &priv->bssid, &len)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06008319 memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
8320 } else {
8321 /* We now have the BSSID, so can finish setting to the full
8322 * associated state */
8323 memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
James Ketrenos82328352005-08-24 22:33:31 -05008324 memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06008325 priv->status &= ~STATUS_ASSOCIATING;
8326 priv->status |= STATUS_ASSOCIATED;
8327 netif_carrier_on(priv->net_dev);
James Ketrenos82328352005-08-24 22:33:31 -05008328 netif_wake_queue(priv->net_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008329 }
8330
8331 if (!(priv->status & STATUS_ASSOCIATED)) {
8332 IPW_DEBUG_WX("Configuring ESSID\n");
Ingo Molnar752e3772006-02-28 07:20:54 +08008333 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008334 /* This is a disassociation event, so kick the firmware to
8335 * look for another AP */
8336 if (priv->config & CFG_STATIC_ESSID)
James Ketrenosee8e3652005-09-14 09:47:29 -05008337 ipw2100_set_essid(priv, priv->essid, priv->essid_len,
8338 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06008339 else
8340 ipw2100_set_essid(priv, NULL, 0, 0);
Ingo Molnar752e3772006-02-28 07:20:54 +08008341 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008342 }
8343
8344 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
8345}
8346
8347#define IPW2100_FW_MAJOR_VERSION 1
8348#define IPW2100_FW_MINOR_VERSION 3
8349
8350#define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8)
8351#define IPW2100_FW_MAJOR(x) (x & 0xff)
8352
8353#define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \
8354 IPW2100_FW_MAJOR_VERSION)
8355
8356#define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \
8357"." __stringify(IPW2100_FW_MINOR_VERSION)
8358
8359#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw"
8360
James Ketrenos2c86c272005-03-23 17:32:29 -06008361/*
8362
8363BINARY FIRMWARE HEADER FORMAT
8364
8365offset length desc
83660 2 version
83672 2 mode == 0:BSS,1:IBSS,2:MONITOR
83684 4 fw_len
83698 4 uc_len
8370C fw_len firmware data
837112 + fw_len uc_len microcode data
8372
8373*/
8374
8375struct ipw2100_fw_header {
8376 short version;
8377 short mode;
8378 unsigned int fw_size;
8379 unsigned int uc_size;
8380} __attribute__ ((packed));
8381
James Ketrenos2c86c272005-03-23 17:32:29 -06008382static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
8383{
8384 struct ipw2100_fw_header *h =
James Ketrenosee8e3652005-09-14 09:47:29 -05008385 (struct ipw2100_fw_header *)fw->fw_entry->data;
James Ketrenos2c86c272005-03-23 17:32:29 -06008386
8387 if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008388 printk(KERN_WARNING DRV_NAME ": Firmware image not compatible "
James Ketrenos2c86c272005-03-23 17:32:29 -06008389 "(detected version id of %u). "
8390 "See Documentation/networking/README.ipw2100\n",
8391 h->version);
8392 return 1;
8393 }
8394
8395 fw->version = h->version;
8396 fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header);
8397 fw->fw.size = h->fw_size;
8398 fw->uc.data = fw->fw.data + h->fw_size;
8399 fw->uc.size = h->uc_size;
8400
8401 return 0;
8402}
8403
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008404static int ipw2100_get_firmware(struct ipw2100_priv *priv,
8405 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008406{
8407 char *fw_name;
8408 int rc;
8409
8410 IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05008411 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06008412
8413 switch (priv->ieee->iw_mode) {
8414 case IW_MODE_ADHOC:
8415 fw_name = IPW2100_FW_NAME("-i");
8416 break;
8417#ifdef CONFIG_IPW2100_MONITOR
8418 case IW_MODE_MONITOR:
8419 fw_name = IPW2100_FW_NAME("-p");
8420 break;
8421#endif
8422 case IW_MODE_INFRA:
8423 default:
8424 fw_name = IPW2100_FW_NAME("");
8425 break;
8426 }
8427
8428 rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev);
8429
8430 if (rc < 0) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008431 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06008432 "%s: Firmware '%s' not available or load failed.\n",
8433 priv->net_dev->name, fw_name);
8434 return rc;
8435 }
Jiri Bencaaa4d302005-06-07 14:58:41 +02008436 IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data,
James Ketrenosee8e3652005-09-14 09:47:29 -05008437 fw->fw_entry->size);
James Ketrenos2c86c272005-03-23 17:32:29 -06008438
8439 ipw2100_mod_firmware_load(fw);
8440
8441 return 0;
8442}
8443
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008444static void ipw2100_release_firmware(struct ipw2100_priv *priv,
8445 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008446{
8447 fw->version = 0;
8448 if (fw->fw_entry)
8449 release_firmware(fw->fw_entry);
8450 fw->fw_entry = NULL;
8451}
8452
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008453static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
8454 size_t max)
James Ketrenos2c86c272005-03-23 17:32:29 -06008455{
8456 char ver[MAX_FW_VERSION_LEN];
8457 u32 len = MAX_FW_VERSION_LEN;
8458 u32 tmp;
8459 int i;
8460 /* firmware version is an ascii string (max len of 14) */
James Ketrenosee8e3652005-09-14 09:47:29 -05008461 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len))
James Ketrenos2c86c272005-03-23 17:32:29 -06008462 return -EIO;
8463 tmp = max;
8464 if (len >= max)
8465 len = max - 1;
8466 for (i = 0; i < len; i++)
8467 buf[i] = ver[i];
8468 buf[i] = '\0';
8469 return tmp;
8470}
8471
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008472static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
8473 size_t max)
James Ketrenos2c86c272005-03-23 17:32:29 -06008474{
8475 u32 ver;
8476 u32 len = sizeof(ver);
8477 /* microcode version is a 32 bit integer */
James Ketrenosee8e3652005-09-14 09:47:29 -05008478 if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len))
James Ketrenos2c86c272005-03-23 17:32:29 -06008479 return -EIO;
8480 return snprintf(buf, max, "%08X", ver);
8481}
8482
8483/*
8484 * On exit, the firmware will have been freed from the fw list
8485 */
James Ketrenosee8e3652005-09-14 09:47:29 -05008486static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008487{
8488 /* firmware is constructed of N contiguous entries, each entry is
8489 * structured as:
8490 *
8491 * offset sie desc
8492 * 0 4 address to write to
8493 * 4 2 length of data run
James Ketrenosee8e3652005-09-14 09:47:29 -05008494 * 6 length data
James Ketrenos2c86c272005-03-23 17:32:29 -06008495 */
8496 unsigned int addr;
8497 unsigned short len;
8498
8499 const unsigned char *firmware_data = fw->fw.data;
8500 unsigned int firmware_data_left = fw->fw.size;
8501
8502 while (firmware_data_left > 0) {
James Ketrenosee8e3652005-09-14 09:47:29 -05008503 addr = *(u32 *) (firmware_data);
8504 firmware_data += 4;
James Ketrenos2c86c272005-03-23 17:32:29 -06008505 firmware_data_left -= 4;
8506
James Ketrenosee8e3652005-09-14 09:47:29 -05008507 len = *(u16 *) (firmware_data);
8508 firmware_data += 2;
James Ketrenos2c86c272005-03-23 17:32:29 -06008509 firmware_data_left -= 2;
8510
8511 if (len > 32) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008512 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06008513 "Invalid firmware run-length of %d bytes\n",
8514 len);
8515 return -EINVAL;
8516 }
8517
8518 write_nic_memory(priv->net_dev, addr, len, firmware_data);
James Ketrenosee8e3652005-09-14 09:47:29 -05008519 firmware_data += len;
James Ketrenos2c86c272005-03-23 17:32:29 -06008520 firmware_data_left -= len;
8521 }
8522
8523 return 0;
8524}
8525
8526struct symbol_alive_response {
8527 u8 cmd_id;
8528 u8 seq_num;
8529 u8 ucode_rev;
8530 u8 eeprom_valid;
8531 u16 valid_flags;
8532 u8 IEEE_addr[6];
8533 u16 flags;
8534 u16 pcb_rev;
8535 u16 clock_settle_time; // 1us LSB
8536 u16 powerup_settle_time; // 1us LSB
8537 u16 hop_settle_time; // 1us LSB
8538 u8 date[3]; // month, day, year
8539 u8 time[2]; // hours, minutes
8540 u8 ucode_valid;
8541};
8542
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008543static int ipw2100_ucode_download(struct ipw2100_priv *priv,
8544 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008545{
8546 struct net_device *dev = priv->net_dev;
8547 const unsigned char *microcode_data = fw->uc.data;
8548 unsigned int microcode_data_left = fw->uc.size;
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008549 void __iomem *reg = (void __iomem *)dev->base_addr;
James Ketrenos2c86c272005-03-23 17:32:29 -06008550
8551 struct symbol_alive_response response;
8552 int i, j;
8553 u8 data;
8554
8555 /* Symbol control */
8556 write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008557 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008558 write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008559 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008560
8561 /* HW config */
8562 write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008563 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008564 write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008565 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008566
8567 /* EN_CS_ACCESS bit to reset control store pointer */
8568 write_nic_byte(dev, 0x210000, 0x40);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008569 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008570 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008571 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008572 write_nic_byte(dev, 0x210000, 0x40);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008573 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008574
8575 /* copy microcode from buffer into Symbol */
8576
8577 while (microcode_data_left > 0) {
8578 write_nic_byte(dev, 0x210010, *microcode_data++);
8579 write_nic_byte(dev, 0x210010, *microcode_data++);
8580 microcode_data_left -= 2;
8581 }
8582
8583 /* EN_CS_ACCESS bit to reset the control store pointer */
8584 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008585 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008586
8587 /* Enable System (Reg 0)
8588 * first enable causes garbage in RX FIFO */
8589 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008590 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008591 write_nic_byte(dev, 0x210000, 0x80);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008592 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008593
8594 /* Reset External Baseband Reg */
8595 write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008596 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008597 write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008598 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008599
8600 /* HW Config (Reg 5) */
8601 write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008602 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008603 write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008604 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008605
8606 /* Enable System (Reg 0)
8607 * second enable should be OK */
8608 write_nic_byte(dev, 0x210000, 0x00); // clear enable system
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008609 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008610 write_nic_byte(dev, 0x210000, 0x80); // set enable system
8611
8612 /* check Symbol is enabled - upped this from 5 as it wasn't always
8613 * catching the update */
8614 for (i = 0; i < 10; i++) {
8615 udelay(10);
8616
8617 /* check Dino is enabled bit */
8618 read_nic_byte(dev, 0x210000, &data);
8619 if (data & 0x1)
8620 break;
8621 }
8622
8623 if (i == 10) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008624 printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06008625 dev->name);
8626 return -EIO;
8627 }
8628
8629 /* Get Symbol alive response */
8630 for (i = 0; i < 30; i++) {
8631 /* Read alive response structure */
8632 for (j = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05008633 j < (sizeof(struct symbol_alive_response) >> 1); j++)
8634 read_nic_word(dev, 0x210004, ((u16 *) & response) + j);
James Ketrenos2c86c272005-03-23 17:32:29 -06008635
James Ketrenosee8e3652005-09-14 09:47:29 -05008636 if ((response.cmd_id == 1) && (response.ucode_valid == 0x1))
James Ketrenos2c86c272005-03-23 17:32:29 -06008637 break;
8638 udelay(10);
8639 }
8640
8641 if (i == 30) {
James Ketrenosee8e3652005-09-14 09:47:29 -05008642 printk(KERN_ERR DRV_NAME
8643 ": %s: No response from Symbol - hw not alive\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06008644 dev->name);
James Ketrenosee8e3652005-09-14 09:47:29 -05008645 printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response));
James Ketrenos2c86c272005-03-23 17:32:29 -06008646 return -EIO;
8647 }
8648
8649 return 0;
8650}