blob: 5d7e97e63def5a02540ded9ad0fe92efdfefdc87 [file] [log] [blame]
James Ketrenos2c86c272005-03-23 17:32:29 -06001/******************************************************************************
2
Zhu Yi171e7b22006-02-15 07:17:56 +08003 Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
James Ketrenos2c86c272005-03-23 17:32:29 -06004
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of version 2 of the GNU General Public License as
7 published by the Free Software Foundation.
8
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc., 59
16 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 The full GNU General Public License is included in this distribution in the
19 file called LICENSE.
20
21 Contact Information:
Reinette Chatrec1eb2c82009-08-21 13:34:26 -070022 Intel Linux Wireless <ilw@linux.intel.com>
James Ketrenos2c86c272005-03-23 17:32:29 -060023 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24
25 Portions of this file are based on the sample_* files provided by Wireless
26 Extensions 0.26 package and copyright (c) 1997-2003 Jean Tourrilhes
27 <jt@hpl.hp.com>
28
29 Portions of this file are based on the Host AP project,
30 Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
Jouni Malinen85d32e72007-03-24 17:15:30 -070031 <j@w1.fi>
32 Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
James Ketrenos2c86c272005-03-23 17:32:29 -060033
34 Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and
35 ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c
36 available in the 2.4.25 kernel sources, and are copyright (c) Alan Cox
37
38******************************************************************************/
39/*
40
41 Initial driver on which this is based was developed by Janusz Gorycki,
42 Maciej Urbaniak, and Maciej Sosnowski.
43
44 Promiscuous mode support added by Jacek Wysoczynski and Maciej Urbaniak.
45
46Theory of Operation
47
48Tx - Commands and Data
49
50Firmware and host share a circular queue of Transmit Buffer Descriptors (TBDs)
51Each TBD contains a pointer to the physical (dma_addr_t) address of data being
52sent to the firmware as well as the length of the data.
53
54The host writes to the TBD queue at the WRITE index. The WRITE index points
55to the _next_ packet to be written and is advanced when after the TBD has been
56filled.
57
58The firmware pulls from the TBD queue at the READ index. The READ index points
59to the currently being read entry, and is advanced once the firmware is
60done with a packet.
61
62When data is sent to the firmware, the first TBD is used to indicate to the
63firmware if a Command or Data is being sent. If it is Command, all of the
64command information is contained within the physical address referred to by the
65TBD. If it is Data, the first TBD indicates the type of data packet, number
Lucas De Marchi25985ed2011-03-30 22:57:33 -030066of fragments, etc. The next TBD then refers to the actual packet location.
James Ketrenos2c86c272005-03-23 17:32:29 -060067
68The Tx flow cycle is as follows:
69
701) ipw2100_tx() is called by kernel with SKB to transmit
712) Packet is move from the tx_free_list and appended to the transmit pending
72 list (tx_pend_list)
733) work is scheduled to move pending packets into the shared circular queue.
744) when placing packet in the circular queue, the incoming SKB is DMA mapped
75 to a physical address. That address is entered into a TBD. Two TBDs are
76 filled out. The first indicating a data packet, the second referring to the
77 actual payload data.
785) the packet is removed from tx_pend_list and placed on the end of the
79 firmware pending list (fw_pend_list)
806) firmware is notified that the WRITE index has
817) Once the firmware has processed the TBD, INTA is triggered.
828) For each Tx interrupt received from the firmware, the READ index is checked
83 to see which TBDs are done being processed.
849) For each TBD that has been processed, the ISR pulls the oldest packet
85 from the fw_pend_list.
8610)The packet structure contained in the fw_pend_list is then used
87 to unmap the DMA address and to free the SKB originally passed to the driver
88 from the kernel.
8911)The packet structure is placed onto the tx_free_list
90
91The above steps are the same for commands, only the msg_free_list/msg_pend_list
92are used instead of tx_free_list/tx_pend_list
93
94...
95
96Critical Sections / Locking :
97
98There are two locks utilized. The first is the low level lock (priv->low_lock)
99that protects the following:
100
101- Access to the Tx/Rx queue lists via priv->low_lock. The lists are as follows:
102
103 tx_free_list : Holds pre-allocated Tx buffers.
104 TAIL modified in __ipw2100_tx_process()
105 HEAD modified in ipw2100_tx()
106
107 tx_pend_list : Holds used Tx buffers waiting to go into the TBD ring
108 TAIL modified ipw2100_tx()
Jiri Benc19f7f742005-08-25 20:02:10 -0400109 HEAD modified by ipw2100_tx_send_data()
James Ketrenos2c86c272005-03-23 17:32:29 -0600110
111 msg_free_list : Holds pre-allocated Msg (Command) buffers
112 TAIL modified in __ipw2100_tx_process()
113 HEAD modified in ipw2100_hw_send_command()
114
115 msg_pend_list : Holds used Msg buffers waiting to go into the TBD ring
116 TAIL modified in ipw2100_hw_send_command()
Jiri Benc19f7f742005-08-25 20:02:10 -0400117 HEAD modified in ipw2100_tx_send_commands()
James Ketrenos2c86c272005-03-23 17:32:29 -0600118
119 The flow of data on the TX side is as follows:
120
121 MSG_FREE_LIST + COMMAND => MSG_PEND_LIST => TBD => MSG_FREE_LIST
122 TX_FREE_LIST + DATA => TX_PEND_LIST => TBD => TX_FREE_LIST
123
124 The methods that work on the TBD ring are protected via priv->low_lock.
125
126- The internal data state of the device itself
127- Access to the firmware read/write indexes for the BD queues
128 and associated logic
129
130All external entry functions are locked with the priv->action_lock to ensure
131that only one external action is invoked at a time.
132
133
134*/
135
136#include <linux/compiler.h>
James Ketrenos2c86c272005-03-23 17:32:29 -0600137#include <linux/errno.h>
138#include <linux/if_arp.h>
139#include <linux/in6.h>
140#include <linux/in.h>
141#include <linux/ip.h>
142#include <linux/kernel.h>
143#include <linux/kmod.h>
144#include <linux/module.h>
145#include <linux/netdevice.h>
146#include <linux/ethtool.h>
147#include <linux/pci.h>
Tobias Klauser05743d12005-06-20 14:28:40 -0700148#include <linux/dma-mapping.h>
James Ketrenos2c86c272005-03-23 17:32:29 -0600149#include <linux/proc_fs.h>
150#include <linux/skbuff.h>
151#include <asm/uaccess.h>
152#include <asm/io.h>
James Ketrenos2c86c272005-03-23 17:32:29 -0600153#include <linux/fs.h>
154#include <linux/mm.h>
155#include <linux/slab.h>
156#include <linux/unistd.h>
157#include <linux/stringify.h>
158#include <linux/tcp.h>
159#include <linux/types.h>
James Ketrenos2c86c272005-03-23 17:32:29 -0600160#include <linux/time.h>
161#include <linux/firmware.h>
162#include <linux/acpi.h>
163#include <linux/ctype.h>
Jean Pihete8db0be2011-08-25 15:35:03 +0200164#include <linux/pm_qos.h>
James Ketrenos2c86c272005-03-23 17:32:29 -0600165
John W. Linville9387b7c2008-09-30 20:59:05 -0400166#include <net/lib80211.h>
167
James Ketrenos2c86c272005-03-23 17:32:29 -0600168#include "ipw2100.h"
169
Zhu Yicc8279f2006-02-21 18:46:15 +0800170#define IPW2100_VERSION "git-1.2.2"
James Ketrenos2c86c272005-03-23 17:32:29 -0600171
172#define DRV_NAME "ipw2100"
173#define DRV_VERSION IPW2100_VERSION
174#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver"
Zhu Yi171e7b22006-02-15 07:17:56 +0800175#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
James Ketrenos2c86c272005-03-23 17:32:29 -0600176
Jean Pihetcc749982011-08-25 15:35:12 +0200177static struct pm_qos_request ipw2100_pm_qos_req;
Mark Grossed771342010-05-06 01:59:26 +0200178
James Ketrenos2c86c272005-03-23 17:32:29 -0600179/* Debugging stuff */
Brice Goglin0f52bf92005-12-01 01:41:46 -0800180#ifdef CONFIG_IPW2100_DEBUG
Robert P. J. Dayae800312007-01-31 02:39:40 -0500181#define IPW2100_RX_DEBUG /* Reception debugging */
James Ketrenos2c86c272005-03-23 17:32:29 -0600182#endif
183
184MODULE_DESCRIPTION(DRV_DESCRIPTION);
185MODULE_VERSION(DRV_VERSION);
186MODULE_AUTHOR(DRV_COPYRIGHT);
187MODULE_LICENSE("GPL");
188
189static int debug = 0;
Reinette Chatre21f8a732009-08-18 10:25:05 -0700190static int network_mode = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -0600191static int channel = 0;
Tim Gardner5c7f9b72008-10-14 10:38:03 -0600192static int associate = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -0600193static int disable = 0;
194#ifdef CONFIG_PM
195static struct ipw2100_fw ipw2100_firmware;
196#endif
197
198#include <linux/moduleparam.h>
199module_param(debug, int, 0444);
Reinette Chatre21f8a732009-08-18 10:25:05 -0700200module_param_named(mode, network_mode, int, 0444);
James Ketrenos2c86c272005-03-23 17:32:29 -0600201module_param(channel, int, 0444);
202module_param(associate, int, 0444);
203module_param(disable, int, 0444);
204
205MODULE_PARM_DESC(debug, "debug level");
206MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
207MODULE_PARM_DESC(channel, "channel");
Tim Gardner5c7f9b72008-10-14 10:38:03 -0600208MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
James Ketrenos2c86c272005-03-23 17:32:29 -0600209MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
210
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400211static u32 ipw2100_debug_level = IPW_DL_NONE;
212
Brice Goglin0f52bf92005-12-01 01:41:46 -0800213#ifdef CONFIG_IPW2100_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400214#define IPW_DEBUG(level, message...) \
215do { \
216 if (ipw2100_debug_level & (level)) { \
217 printk(KERN_DEBUG "ipw2100: %c %s ", \
Harvey Harrisonc94c93d2008-07-28 23:01:34 -0700218 in_interrupt() ? 'I' : 'U', __func__); \
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400219 printk(message); \
220 } \
221} while (0)
222#else
223#define IPW_DEBUG(level, message...) do {} while (0)
Brice Goglin0f52bf92005-12-01 01:41:46 -0800224#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -0600225
Brice Goglin0f52bf92005-12-01 01:41:46 -0800226#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -0600227static const char *command_types[] = {
228 "undefined",
James Ketrenosee8e3652005-09-14 09:47:29 -0500229 "unused", /* HOST_ATTENTION */
James Ketrenos2c86c272005-03-23 17:32:29 -0600230 "HOST_COMPLETE",
James Ketrenosee8e3652005-09-14 09:47:29 -0500231 "unused", /* SLEEP */
232 "unused", /* HOST_POWER_DOWN */
James Ketrenos2c86c272005-03-23 17:32:29 -0600233 "unused",
234 "SYSTEM_CONFIG",
James Ketrenosee8e3652005-09-14 09:47:29 -0500235 "unused", /* SET_IMR */
James Ketrenos2c86c272005-03-23 17:32:29 -0600236 "SSID",
237 "MANDATORY_BSSID",
238 "AUTHENTICATION_TYPE",
239 "ADAPTER_ADDRESS",
240 "PORT_TYPE",
241 "INTERNATIONAL_MODE",
242 "CHANNEL",
243 "RTS_THRESHOLD",
244 "FRAG_THRESHOLD",
245 "POWER_MODE",
246 "TX_RATES",
247 "BASIC_TX_RATES",
248 "WEP_KEY_INFO",
249 "unused",
250 "unused",
251 "unused",
252 "unused",
253 "WEP_KEY_INDEX",
254 "WEP_FLAGS",
255 "ADD_MULTICAST",
256 "CLEAR_ALL_MULTICAST",
257 "BEACON_INTERVAL",
258 "ATIM_WINDOW",
259 "CLEAR_STATISTICS",
260 "undefined",
261 "undefined",
262 "undefined",
263 "undefined",
264 "TX_POWER_INDEX",
265 "undefined",
266 "undefined",
267 "undefined",
268 "undefined",
269 "undefined",
270 "undefined",
271 "BROADCAST_SCAN",
272 "CARD_DISABLE",
273 "PREFERRED_BSSID",
274 "SET_SCAN_OPTIONS",
275 "SCAN_DWELL_TIME",
276 "SWEEP_TABLE",
277 "AP_OR_STATION_TABLE",
278 "GROUP_ORDINALS",
279 "SHORT_RETRY_LIMIT",
280 "LONG_RETRY_LIMIT",
James Ketrenosee8e3652005-09-14 09:47:29 -0500281 "unused", /* SAVE_CALIBRATION */
282 "unused", /* RESTORE_CALIBRATION */
James Ketrenos2c86c272005-03-23 17:32:29 -0600283 "undefined",
284 "undefined",
285 "undefined",
286 "HOST_PRE_POWER_DOWN",
James Ketrenosee8e3652005-09-14 09:47:29 -0500287 "unused", /* HOST_INTERRUPT_COALESCING */
James Ketrenos2c86c272005-03-23 17:32:29 -0600288 "undefined",
289 "CARD_DISABLE_PHY_OFF",
Jean Delvare96a95c12011-07-06 00:27:06 +0200290 "MSDU_TX_RATES",
James Ketrenos2c86c272005-03-23 17:32:29 -0600291 "undefined",
292 "SET_STATION_STAT_BITS",
293 "CLEAR_STATIONS_STAT_BITS",
294 "LEAP_ROGUE_MODE",
295 "SET_SECURITY_INFORMATION",
296 "DISASSOCIATION_BSSID",
297 "SET_WPA_ASS_IE"
298};
299#endif
300
Matthew Garrettc26409a2009-11-11 14:36:30 -0500301#define WEXT_USECHANNELS 1
302
303static const long ipw2100_frequencies[] = {
304 2412, 2417, 2422, 2427,
305 2432, 2437, 2442, 2447,
306 2452, 2457, 2462, 2467,
307 2472, 2484
308};
309
310#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies)
311
Matthew Garrettc26409a2009-11-11 14:36:30 -0500312static struct ieee80211_rate ipw2100_bg_rates[] = {
313 { .bitrate = 10 },
314 { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
315 { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
316 { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
317};
318
Stanislav Yakovlev4d94c152012-02-09 20:23:52 -0500319#define RATE_COUNT ARRAY_SIZE(ipw2100_bg_rates)
Matthew Garrettc26409a2009-11-11 14:36:30 -0500320
James Ketrenos2c86c272005-03-23 17:32:29 -0600321/* Pre-decl until we get the code solid and then we can clean it up */
Jiri Benc19f7f742005-08-25 20:02:10 -0400322static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
323static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
James Ketrenos2c86c272005-03-23 17:32:29 -0600324static int ipw2100_adapter_setup(struct ipw2100_priv *priv);
325
326static void ipw2100_queues_initialize(struct ipw2100_priv *priv);
327static void ipw2100_queues_free(struct ipw2100_priv *priv);
328static int ipw2100_queues_allocate(struct ipw2100_priv *priv);
329
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400330static int ipw2100_fw_download(struct ipw2100_priv *priv,
331 struct ipw2100_fw *fw);
332static int ipw2100_get_firmware(struct ipw2100_priv *priv,
333 struct ipw2100_fw *fw);
334static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
335 size_t max);
336static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
337 size_t max);
338static void ipw2100_release_firmware(struct ipw2100_priv *priv,
339 struct ipw2100_fw *fw);
340static int ipw2100_ucode_download(struct ipw2100_priv *priv,
341 struct ipw2100_fw *fw);
David Howellsc4028952006-11-22 14:57:56 +0000342static void ipw2100_wx_event_work(struct work_struct *work);
James Ketrenosee8e3652005-09-14 09:47:29 -0500343static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev);
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400344static struct iw_handler_def ipw2100_wx_handler_def;
345
James Ketrenosee8e3652005-09-14 09:47:29 -0500346static inline void read_register(struct net_device *dev, u32 reg, u32 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600347{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100348 *val = readl((void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600349 IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
350}
351
352static inline void write_register(struct net_device *dev, u32 reg, u32 val)
353{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100354 writel(val, (void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600355 IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
356}
357
James Ketrenosee8e3652005-09-14 09:47:29 -0500358static inline void read_register_word(struct net_device *dev, u32 reg,
359 u16 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600360{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100361 *val = readw((void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600362 IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
363}
364
James Ketrenosee8e3652005-09-14 09:47:29 -0500365static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600366{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100367 *val = readb((void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600368 IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
369}
370
371static inline void write_register_word(struct net_device *dev, u32 reg, u16 val)
372{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100373 writew(val, (void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600374 IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
375}
376
James Ketrenos2c86c272005-03-23 17:32:29 -0600377static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
378{
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +0100379 writeb(val, (void __iomem *)(dev->base_addr + reg));
James Ketrenos2c86c272005-03-23 17:32:29 -0600380 IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
381}
382
James Ketrenosee8e3652005-09-14 09:47:29 -0500383static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600384{
385 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
386 addr & IPW_REG_INDIRECT_ADDR_MASK);
387 read_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
388}
389
390static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val)
391{
392 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
393 addr & IPW_REG_INDIRECT_ADDR_MASK);
394 write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
395}
396
James Ketrenosee8e3652005-09-14 09:47:29 -0500397static inline void read_nic_word(struct net_device *dev, u32 addr, u16 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600398{
399 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
400 addr & IPW_REG_INDIRECT_ADDR_MASK);
401 read_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
402}
403
404static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val)
405{
406 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
407 addr & IPW_REG_INDIRECT_ADDR_MASK);
408 write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
409}
410
James Ketrenosee8e3652005-09-14 09:47:29 -0500411static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 * val)
James Ketrenos2c86c272005-03-23 17:32:29 -0600412{
413 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
414 addr & IPW_REG_INDIRECT_ADDR_MASK);
415 read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
416}
417
418static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val)
419{
420 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
421 addr & IPW_REG_INDIRECT_ADDR_MASK);
422 write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
423}
424
425static inline void write_nic_auto_inc_address(struct net_device *dev, u32 addr)
426{
427 write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
428 addr & IPW_REG_INDIRECT_ADDR_MASK);
429}
430
431static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val)
432{
433 write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val);
434}
435
Arjan van de Ven858119e2006-01-14 13:20:43 -0800436static void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
James Ketrenosee8e3652005-09-14 09:47:29 -0500437 const u8 * buf)
James Ketrenos2c86c272005-03-23 17:32:29 -0600438{
439 u32 aligned_addr;
440 u32 aligned_len;
441 u32 dif_len;
442 u32 i;
443
444 /* read first nibble byte by byte */
445 aligned_addr = addr & (~0x3);
446 dif_len = addr - aligned_addr;
447 if (dif_len) {
448 /* Start reading at aligned_addr + dif_len */
449 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
450 aligned_addr);
451 for (i = dif_len; i < 4; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500452 write_register_byte(dev,
453 IPW_REG_INDIRECT_ACCESS_DATA + i,
454 *buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600455
456 len -= dif_len;
457 aligned_addr += 4;
458 }
459
460 /* read DWs through autoincrement registers */
James Ketrenosee8e3652005-09-14 09:47:29 -0500461 write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600462 aligned_len = len & (~0x3);
463 for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
James Ketrenosee8e3652005-09-14 09:47:29 -0500464 write_register(dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *) buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600465
466 /* copy the last nibble */
467 dif_len = len - aligned_len;
468 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
469 for (i = 0; i < dif_len; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500470 write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
471 *buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600472}
473
Arjan van de Ven858119e2006-01-14 13:20:43 -0800474static void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
James Ketrenosee8e3652005-09-14 09:47:29 -0500475 u8 * buf)
James Ketrenos2c86c272005-03-23 17:32:29 -0600476{
477 u32 aligned_addr;
478 u32 aligned_len;
479 u32 dif_len;
480 u32 i;
481
482 /* read first nibble byte by byte */
483 aligned_addr = addr & (~0x3);
484 dif_len = addr - aligned_addr;
485 if (dif_len) {
486 /* Start reading at aligned_addr + dif_len */
487 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
488 aligned_addr);
489 for (i = dif_len; i < 4; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500490 read_register_byte(dev,
491 IPW_REG_INDIRECT_ACCESS_DATA + i,
492 buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600493
494 len -= dif_len;
495 aligned_addr += 4;
496 }
497
498 /* read DWs through autoincrement registers */
James Ketrenosee8e3652005-09-14 09:47:29 -0500499 write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600500 aligned_len = len & (~0x3);
501 for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
James Ketrenosee8e3652005-09-14 09:47:29 -0500502 read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600503
504 /* copy the last nibble */
505 dif_len = len - aligned_len;
James Ketrenosee8e3652005-09-14 09:47:29 -0500506 write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600507 for (i = 0; i < dif_len; i++, buf++)
James Ketrenosee8e3652005-09-14 09:47:29 -0500508 read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
James Ketrenos2c86c272005-03-23 17:32:29 -0600509}
510
511static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev)
512{
513 return (dev->base_addr &&
James Ketrenosee8e3652005-09-14 09:47:29 -0500514 (readl
515 ((void __iomem *)(dev->base_addr +
516 IPW_REG_DOA_DEBUG_AREA_START))
James Ketrenos2c86c272005-03-23 17:32:29 -0600517 == IPW_DATA_DOA_DEBUG_VALUE));
518}
519
Jiri Bencc4aee8c2005-08-25 20:04:43 -0400520static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
James Ketrenosee8e3652005-09-14 09:47:29 -0500521 void *val, u32 * len)
James Ketrenos2c86c272005-03-23 17:32:29 -0600522{
523 struct ipw2100_ordinals *ordinals = &priv->ordinals;
524 u32 addr;
525 u32 field_info;
526 u16 field_len;
527 u16 field_count;
528 u32 total_length;
529
530 if (ordinals->table1_addr == 0) {
Jiri Benc797b4f72005-08-25 20:03:27 -0400531 printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals "
James Ketrenos2c86c272005-03-23 17:32:29 -0600532 "before they have been loaded.\n");
533 return -EINVAL;
534 }
535
536 if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
537 if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) {
538 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
539
Jiri Benc797b4f72005-08-25 20:03:27 -0400540 printk(KERN_WARNING DRV_NAME
Jiri Bencaaa4d302005-06-07 14:58:41 +0200541 ": ordinal buffer length too small, need %zd\n",
James Ketrenos2c86c272005-03-23 17:32:29 -0600542 IPW_ORD_TAB_1_ENTRY_SIZE);
543
544 return -EINVAL;
545 }
546
James Ketrenosee8e3652005-09-14 09:47:29 -0500547 read_nic_dword(priv->net_dev,
548 ordinals->table1_addr + (ord << 2), &addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600549 read_nic_dword(priv->net_dev, addr, val);
550
551 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
552
553 return 0;
554 }
555
556 if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) {
557
558 ord -= IPW_START_ORD_TAB_2;
559
560 /* get the address of statistic */
James Ketrenosee8e3652005-09-14 09:47:29 -0500561 read_nic_dword(priv->net_dev,
562 ordinals->table2_addr + (ord << 3), &addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600563
564 /* get the second DW of statistics ;
565 * two 16-bit words - first is length, second is count */
566 read_nic_dword(priv->net_dev,
567 ordinals->table2_addr + (ord << 3) + sizeof(u32),
568 &field_info);
569
570 /* get each entry length */
James Ketrenosee8e3652005-09-14 09:47:29 -0500571 field_len = *((u16 *) & field_info);
James Ketrenos2c86c272005-03-23 17:32:29 -0600572
573 /* get number of entries */
James Ketrenosee8e3652005-09-14 09:47:29 -0500574 field_count = *(((u16 *) & field_info) + 1);
James Ketrenos2c86c272005-03-23 17:32:29 -0600575
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200576 /* abort if no enough memory */
James Ketrenos2c86c272005-03-23 17:32:29 -0600577 total_length = field_len * field_count;
578 if (total_length > *len) {
579 *len = total_length;
580 return -EINVAL;
581 }
582
583 *len = total_length;
584 if (!total_length)
585 return 0;
586
587 /* read the ordinal data from the SRAM */
588 read_nic_memory(priv->net_dev, addr, total_length, val);
589
590 return 0;
591 }
592
Jiri Benc797b4f72005-08-25 20:03:27 -0400593 printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor "
James Ketrenos2c86c272005-03-23 17:32:29 -0600594 "in table 2\n", ord);
595
596 return -EINVAL;
597}
598
James Ketrenosee8e3652005-09-14 09:47:29 -0500599static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val,
600 u32 * len)
James Ketrenos2c86c272005-03-23 17:32:29 -0600601{
602 struct ipw2100_ordinals *ordinals = &priv->ordinals;
603 u32 addr;
604
605 if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
606 if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) {
607 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
608 IPW_DEBUG_INFO("wrong size\n");
609 return -EINVAL;
610 }
611
James Ketrenosee8e3652005-09-14 09:47:29 -0500612 read_nic_dword(priv->net_dev,
613 ordinals->table1_addr + (ord << 2), &addr);
James Ketrenos2c86c272005-03-23 17:32:29 -0600614
615 write_nic_dword(priv->net_dev, addr, *val);
616
617 *len = IPW_ORD_TAB_1_ENTRY_SIZE;
618
619 return 0;
620 }
621
622 IPW_DEBUG_INFO("wrong table\n");
623 if (IS_ORDINAL_TABLE_TWO(ordinals, ord))
624 return -EINVAL;
625
626 return -EINVAL;
627}
628
629static char *snprint_line(char *buf, size_t count,
James Ketrenosee8e3652005-09-14 09:47:29 -0500630 const u8 * data, u32 len, u32 ofs)
James Ketrenos2c86c272005-03-23 17:32:29 -0600631{
632 int out, i, j, l;
633 char c;
634
635 out = snprintf(buf, count, "%08X", ofs);
636
637 for (l = 0, i = 0; i < 2; i++) {
638 out += snprintf(buf + out, count - out, " ");
639 for (j = 0; j < 8 && l < len; j++, l++)
640 out += snprintf(buf + out, count - out, "%02X ",
641 data[(i * 8 + j)]);
642 for (; j < 8; j++)
643 out += snprintf(buf + out, count - out, " ");
644 }
645
646 out += snprintf(buf + out, count - out, " ");
647 for (l = 0, i = 0; i < 2; i++) {
648 out += snprintf(buf + out, count - out, " ");
649 for (j = 0; j < 8 && l < len; j++, l++) {
650 c = data[(i * 8 + j)];
651 if (!isascii(c) || !isprint(c))
652 c = '.';
653
654 out += snprintf(buf + out, count - out, "%c", c);
655 }
656
657 for (; j < 8; j++)
658 out += snprintf(buf + out, count - out, " ");
659 }
660
661 return buf;
662}
663
James Ketrenosee8e3652005-09-14 09:47:29 -0500664static void printk_buf(int level, const u8 * data, u32 len)
James Ketrenos2c86c272005-03-23 17:32:29 -0600665{
666 char line[81];
667 u32 ofs = 0;
668 if (!(ipw2100_debug_level & level))
669 return;
670
671 while (len) {
672 printk(KERN_DEBUG "%s\n",
673 snprint_line(line, sizeof(line), &data[ofs],
674 min(len, 16U), ofs));
675 ofs += 16;
676 len -= min(len, 16U);
677 }
678}
679
James Ketrenos2c86c272005-03-23 17:32:29 -0600680#define MAX_RESET_BACKOFF 10
681
Arjan van de Ven858119e2006-01-14 13:20:43 -0800682static void schedule_reset(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -0600683{
684 unsigned long now = get_seconds();
685
686 /* If we haven't received a reset request within the backoff period,
687 * then we can reset the backoff interval so this reset occurs
688 * immediately */
689 if (priv->reset_backoff &&
690 (now - priv->last_reset > priv->reset_backoff))
691 priv->reset_backoff = 0;
692
693 priv->last_reset = get_seconds();
694
695 if (!(priv->status & STATUS_RESET_PENDING)) {
696 IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n",
697 priv->net_dev->name, priv->reset_backoff);
698 netif_carrier_off(priv->net_dev);
699 netif_stop_queue(priv->net_dev);
700 priv->status |= STATUS_RESET_PENDING;
701 if (priv->reset_backoff)
Tejun Heobcb6d912011-01-26 12:12:50 +0100702 schedule_delayed_work(&priv->reset_work,
703 priv->reset_backoff * HZ);
James Ketrenos2c86c272005-03-23 17:32:29 -0600704 else
Tejun Heobcb6d912011-01-26 12:12:50 +0100705 schedule_delayed_work(&priv->reset_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -0600706
707 if (priv->reset_backoff < MAX_RESET_BACKOFF)
708 priv->reset_backoff++;
709
710 wake_up_interruptible(&priv->wait_command_queue);
711 } else
712 IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n",
713 priv->net_dev->name);
714
715}
716
717#define HOST_COMPLETE_TIMEOUT (2 * HZ)
718static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
James Ketrenosee8e3652005-09-14 09:47:29 -0500719 struct host_command *cmd)
James Ketrenos2c86c272005-03-23 17:32:29 -0600720{
721 struct list_head *element;
722 struct ipw2100_tx_packet *packet;
723 unsigned long flags;
724 int err = 0;
725
726 IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
727 command_types[cmd->host_command], cmd->host_command,
728 cmd->host_command_length);
James Ketrenosee8e3652005-09-14 09:47:29 -0500729 printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters,
James Ketrenos2c86c272005-03-23 17:32:29 -0600730 cmd->host_command_length);
731
732 spin_lock_irqsave(&priv->low_lock, flags);
733
734 if (priv->fatal_error) {
James Ketrenosee8e3652005-09-14 09:47:29 -0500735 IPW_DEBUG_INFO
736 ("Attempt to send command while hardware in fatal error condition.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -0600737 err = -EIO;
738 goto fail_unlock;
739 }
740
741 if (!(priv->status & STATUS_RUNNING)) {
James Ketrenosee8e3652005-09-14 09:47:29 -0500742 IPW_DEBUG_INFO
743 ("Attempt to send command while hardware is not running.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -0600744 err = -EIO;
745 goto fail_unlock;
746 }
747
748 if (priv->status & STATUS_CMD_ACTIVE) {
James Ketrenosee8e3652005-09-14 09:47:29 -0500749 IPW_DEBUG_INFO
750 ("Attempt to send command while another command is pending.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -0600751 err = -EBUSY;
752 goto fail_unlock;
753 }
754
755 if (list_empty(&priv->msg_free_list)) {
756 IPW_DEBUG_INFO("no available msg buffers\n");
757 goto fail_unlock;
758 }
759
760 priv->status |= STATUS_CMD_ACTIVE;
761 priv->messages_sent++;
762
763 element = priv->msg_free_list.next;
764
765 packet = list_entry(element, struct ipw2100_tx_packet, list);
766 packet->jiffy_start = jiffies;
767
768 /* initialize the firmware command packet */
769 packet->info.c_struct.cmd->host_command_reg = cmd->host_command;
770 packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1;
James Ketrenosee8e3652005-09-14 09:47:29 -0500771 packet->info.c_struct.cmd->host_command_len_reg =
772 cmd->host_command_length;
James Ketrenos2c86c272005-03-23 17:32:29 -0600773 packet->info.c_struct.cmd->sequence = cmd->host_command_sequence;
774
775 memcpy(packet->info.c_struct.cmd->host_command_params_reg,
776 cmd->host_command_parameters,
777 sizeof(packet->info.c_struct.cmd->host_command_params_reg));
778
779 list_del(element);
780 DEC_STAT(&priv->msg_free_stat);
781
782 list_add_tail(element, &priv->msg_pend_list);
783 INC_STAT(&priv->msg_pend_stat);
784
Jiri Benc19f7f742005-08-25 20:02:10 -0400785 ipw2100_tx_send_commands(priv);
786 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -0600787
788 spin_unlock_irqrestore(&priv->low_lock, flags);
789
790 /*
791 * We must wait for this command to complete before another
792 * command can be sent... but if we wait more than 3 seconds
793 * then there is a problem.
794 */
795
James Ketrenosee8e3652005-09-14 09:47:29 -0500796 err =
797 wait_event_interruptible_timeout(priv->wait_command_queue,
798 !(priv->
799 status & STATUS_CMD_ACTIVE),
800 HOST_COMPLETE_TIMEOUT);
James Ketrenos2c86c272005-03-23 17:32:29 -0600801
802 if (err == 0) {
803 IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
James Ketrenos82328352005-08-24 22:33:31 -0500804 1000 * (HOST_COMPLETE_TIMEOUT / HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -0600805 priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT;
806 priv->status &= ~STATUS_CMD_ACTIVE;
807 schedule_reset(priv);
808 return -EIO;
809 }
810
811 if (priv->fatal_error) {
Jiri Benc797b4f72005-08-25 20:03:27 -0400812 printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n",
James Ketrenos2c86c272005-03-23 17:32:29 -0600813 priv->net_dev->name);
814 return -EIO;
815 }
816
817 /* !!!!! HACK TEST !!!!!
818 * When lots of debug trace statements are enabled, the driver
819 * doesn't seem to have as many firmware restart cycles...
820 *
821 * As a test, we're sticking in a 1/100s delay here */
Nishanth Aravamudan3173c892005-09-11 02:09:55 -0700822 schedule_timeout_uninterruptible(msecs_to_jiffies(10));
James Ketrenos2c86c272005-03-23 17:32:29 -0600823
824 return 0;
825
James Ketrenosee8e3652005-09-14 09:47:29 -0500826 fail_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -0600827 spin_unlock_irqrestore(&priv->low_lock, flags);
828
829 return err;
830}
831
James Ketrenos2c86c272005-03-23 17:32:29 -0600832/*
833 * Verify the values and data access of the hardware
834 * No locks needed or used. No functions called.
835 */
836static int ipw2100_verify(struct ipw2100_priv *priv)
837{
838 u32 data1, data2;
839 u32 address;
840
841 u32 val1 = 0x76543210;
842 u32 val2 = 0xFEDCBA98;
843
844 /* Domain 0 check - all values should be DOA_DEBUG */
845 for (address = IPW_REG_DOA_DEBUG_AREA_START;
James Ketrenosee8e3652005-09-14 09:47:29 -0500846 address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) {
James Ketrenos2c86c272005-03-23 17:32:29 -0600847 read_register(priv->net_dev, address, &data1);
848 if (data1 != IPW_DATA_DOA_DEBUG_VALUE)
849 return -EIO;
850 }
851
852 /* Domain 1 check - use arbitrary read/write compare */
853 for (address = 0; address < 5; address++) {
854 /* The memory area is not used now */
855 write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
856 val1);
857 write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
858 val2);
859 read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
860 &data1);
861 read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
862 &data2);
863 if (val1 == data1 && val2 == data2)
864 return 0;
865 }
866
867 return -EIO;
868}
869
870/*
871 *
872 * Loop until the CARD_DISABLED bit is the same value as the
873 * supplied parameter
874 *
875 * TODO: See if it would be more efficient to do a wait/wake
876 * cycle and have the completion event trigger the wakeup
877 *
878 */
879#define IPW_CARD_DISABLE_COMPLETE_WAIT 100 // 100 milli
880static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state)
881{
882 int i;
883 u32 card_state;
884 u32 len = sizeof(card_state);
885 int err;
886
887 for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) {
888 err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED,
889 &card_state, &len);
890 if (err) {
891 IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal "
892 "failed.\n");
893 return 0;
894 }
895
896 /* We'll break out if either the HW state says it is
897 * in the state we want, or if HOST_COMPLETE command
898 * finishes */
899 if ((card_state == state) ||
900 ((priv->status & STATUS_ENABLED) ?
901 IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) {
902 if (state == IPW_HW_STATE_ENABLED)
903 priv->status |= STATUS_ENABLED;
904 else
905 priv->status &= ~STATUS_ENABLED;
906
907 return 0;
908 }
909
910 udelay(50);
911 }
912
913 IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n",
914 state ? "DISABLED" : "ENABLED");
915 return -EIO;
916}
917
James Ketrenos2c86c272005-03-23 17:32:29 -0600918/*********************************************************************
919 Procedure : sw_reset_and_clock
920 Purpose : Asserts s/w reset, asserts clock initialization
921 and waits for clock stabilization
922 ********************************************************************/
923static int sw_reset_and_clock(struct ipw2100_priv *priv)
924{
925 int i;
926 u32 r;
927
928 // assert s/w reset
929 write_register(priv->net_dev, IPW_REG_RESET_REG,
930 IPW_AUX_HOST_RESET_REG_SW_RESET);
931
932 // wait for clock stabilization
933 for (i = 0; i < 1000; i++) {
934 udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY);
935
936 // check clock ready bit
937 read_register(priv->net_dev, IPW_REG_RESET_REG, &r);
938 if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET)
939 break;
940 }
941
942 if (i == 1000)
943 return -EIO; // TODO: better error value
944
945 /* set "initialization complete" bit to move adapter to
946 * D0 state */
947 write_register(priv->net_dev, IPW_REG_GP_CNTRL,
948 IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE);
949
950 /* wait for clock stabilization */
951 for (i = 0; i < 10000; i++) {
952 udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4);
953
954 /* check clock ready bit */
955 read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
956 if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY)
957 break;
958 }
959
960 if (i == 10000)
961 return -EIO; /* TODO: better error value */
962
James Ketrenos2c86c272005-03-23 17:32:29 -0600963 /* set D0 standby bit */
964 read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
965 write_register(priv->net_dev, IPW_REG_GP_CNTRL,
966 r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
James Ketrenos2c86c272005-03-23 17:32:29 -0600967
968 return 0;
969}
970
971/*********************************************************************
Pavel Machek8724a112005-06-20 14:28:43 -0700972 Procedure : ipw2100_download_firmware
James Ketrenos2c86c272005-03-23 17:32:29 -0600973 Purpose : Initiaze adapter after power on.
974 The sequence is:
975 1. assert s/w reset first!
976 2. awake clocks & wait for clock stabilization
977 3. hold ARC (don't ask me why...)
978 4. load Dino ucode and reset/clock init again
979 5. zero-out shared mem
980 6. download f/w
981 *******************************************************************/
982static int ipw2100_download_firmware(struct ipw2100_priv *priv)
983{
984 u32 address;
985 int err;
986
987#ifndef CONFIG_PM
988 /* Fetch the firmware and microcode */
989 struct ipw2100_fw ipw2100_firmware;
990#endif
991
992 if (priv->fatal_error) {
993 IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after "
James Ketrenosee8e3652005-09-14 09:47:29 -0500994 "fatal error %d. Interface must be brought down.\n",
995 priv->net_dev->name, priv->fatal_error);
James Ketrenos2c86c272005-03-23 17:32:29 -0600996 return -EINVAL;
997 }
James Ketrenos2c86c272005-03-23 17:32:29 -0600998#ifdef CONFIG_PM
999 if (!ipw2100_firmware.version) {
1000 err = ipw2100_get_firmware(priv, &ipw2100_firmware);
1001 if (err) {
1002 IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001003 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001004 priv->fatal_error = IPW2100_ERR_FW_LOAD;
1005 goto fail;
1006 }
1007 }
1008#else
1009 err = ipw2100_get_firmware(priv, &ipw2100_firmware);
1010 if (err) {
1011 IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001012 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001013 priv->fatal_error = IPW2100_ERR_FW_LOAD;
1014 goto fail;
1015 }
1016#endif
1017 priv->firmware_version = ipw2100_firmware.version;
1018
1019 /* s/w reset and clock stabilization */
1020 err = sw_reset_and_clock(priv);
1021 if (err) {
1022 IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001023 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001024 goto fail;
1025 }
1026
1027 err = ipw2100_verify(priv);
1028 if (err) {
1029 IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001030 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001031 goto fail;
1032 }
1033
1034 /* Hold ARC */
1035 write_nic_dword(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05001036 IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000);
James Ketrenos2c86c272005-03-23 17:32:29 -06001037
1038 /* allow ARC to run */
1039 write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
1040
1041 /* load microcode */
1042 err = ipw2100_ucode_download(priv, &ipw2100_firmware);
1043 if (err) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001044 printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001045 priv->net_dev->name, err);
1046 goto fail;
1047 }
1048
1049 /* release ARC */
1050 write_nic_dword(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05001051 IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000);
James Ketrenos2c86c272005-03-23 17:32:29 -06001052
1053 /* s/w reset and clock stabilization (again!!!) */
1054 err = sw_reset_and_clock(priv);
1055 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001056 printk(KERN_ERR DRV_NAME
1057 ": %s: sw_reset_and_clock failed: %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001058 priv->net_dev->name, err);
1059 goto fail;
1060 }
1061
1062 /* load f/w */
1063 err = ipw2100_fw_download(priv, &ipw2100_firmware);
1064 if (err) {
1065 IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001066 priv->net_dev->name, err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001067 goto fail;
1068 }
James Ketrenos2c86c272005-03-23 17:32:29 -06001069#ifndef CONFIG_PM
1070 /*
1071 * When the .resume method of the driver is called, the other
1072 * part of the system, i.e. the ide driver could still stay in
1073 * the suspend stage. This prevents us from loading the firmware
1074 * from the disk. --YZ
1075 */
1076
1077 /* free any storage allocated for firmware image */
1078 ipw2100_release_firmware(priv, &ipw2100_firmware);
1079#endif
1080
1081 /* zero out Domain 1 area indirectly (Si requirement) */
1082 for (address = IPW_HOST_FW_SHARED_AREA0;
1083 address < IPW_HOST_FW_SHARED_AREA0_END; address += 4)
1084 write_nic_dword(priv->net_dev, address, 0);
1085 for (address = IPW_HOST_FW_SHARED_AREA1;
1086 address < IPW_HOST_FW_SHARED_AREA1_END; address += 4)
1087 write_nic_dword(priv->net_dev, address, 0);
1088 for (address = IPW_HOST_FW_SHARED_AREA2;
1089 address < IPW_HOST_FW_SHARED_AREA2_END; address += 4)
1090 write_nic_dword(priv->net_dev, address, 0);
1091 for (address = IPW_HOST_FW_SHARED_AREA3;
1092 address < IPW_HOST_FW_SHARED_AREA3_END; address += 4)
1093 write_nic_dword(priv->net_dev, address, 0);
1094 for (address = IPW_HOST_FW_INTERRUPT_AREA;
1095 address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4)
1096 write_nic_dword(priv->net_dev, address, 0);
1097
1098 return 0;
1099
James Ketrenosee8e3652005-09-14 09:47:29 -05001100 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06001101 ipw2100_release_firmware(priv, &ipw2100_firmware);
1102 return err;
1103}
1104
1105static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv)
1106{
1107 if (priv->status & STATUS_INT_ENABLED)
1108 return;
1109 priv->status |= STATUS_INT_ENABLED;
1110 write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK);
1111}
1112
1113static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv)
1114{
1115 if (!(priv->status & STATUS_INT_ENABLED))
1116 return;
1117 priv->status &= ~STATUS_INT_ENABLED;
1118 write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0);
1119}
1120
James Ketrenos2c86c272005-03-23 17:32:29 -06001121static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv)
1122{
1123 struct ipw2100_ordinals *ord = &priv->ordinals;
1124
1125 IPW_DEBUG_INFO("enter\n");
1126
1127 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1,
1128 &ord->table1_addr);
1129
1130 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2,
1131 &ord->table2_addr);
1132
1133 read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size);
1134 read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size);
1135
1136 ord->table2_size &= 0x0000FFFF;
1137
1138 IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size);
1139 IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size);
1140 IPW_DEBUG_INFO("exit\n");
1141}
1142
1143static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv)
1144{
1145 u32 reg = 0;
1146 /*
1147 * Set GPIO 3 writable by FW; GPIO 1 writable
1148 * by driver and enable clock
1149 */
1150 reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE |
1151 IPW_BIT_GPIO_LED_OFF);
1152 write_register(priv->net_dev, IPW_REG_GPIO, reg);
1153}
1154
Arjan van de Ven858119e2006-01-14 13:20:43 -08001155static int rf_kill_active(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06001156{
1157#define MAX_RF_KILL_CHECKS 5
1158#define RF_KILL_CHECK_DELAY 40
James Ketrenos2c86c272005-03-23 17:32:29 -06001159
1160 unsigned short value = 0;
1161 u32 reg = 0;
1162 int i;
1163
1164 if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
Matthew Garrettc26409a2009-11-11 14:36:30 -05001165 wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
James Ketrenos2c86c272005-03-23 17:32:29 -06001166 priv->status &= ~STATUS_RF_KILL_HW;
1167 return 0;
1168 }
1169
1170 for (i = 0; i < MAX_RF_KILL_CHECKS; i++) {
1171 udelay(RF_KILL_CHECK_DELAY);
1172 read_register(priv->net_dev, IPW_REG_GPIO, &reg);
1173 value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1);
1174 }
1175
Matthew Garrettc26409a2009-11-11 14:36:30 -05001176 if (value == 0) {
1177 wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
James Ketrenos2c86c272005-03-23 17:32:29 -06001178 priv->status |= STATUS_RF_KILL_HW;
Matthew Garrettc26409a2009-11-11 14:36:30 -05001179 } else {
1180 wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
James Ketrenos2c86c272005-03-23 17:32:29 -06001181 priv->status &= ~STATUS_RF_KILL_HW;
Matthew Garrettc26409a2009-11-11 14:36:30 -05001182 }
James Ketrenos2c86c272005-03-23 17:32:29 -06001183
1184 return (value == 0);
1185}
1186
1187static int ipw2100_get_hw_features(struct ipw2100_priv *priv)
1188{
1189 u32 addr, len;
1190 u32 val;
1191
1192 /*
1193 * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1
1194 */
1195 len = sizeof(addr);
James Ketrenosee8e3652005-09-14 09:47:29 -05001196 if (ipw2100_get_ordinal
1197 (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06001198 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001199 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06001200 return -EIO;
1201 }
1202
1203 IPW_DEBUG_INFO("EEPROM address: %08X\n", addr);
1204
1205 /*
1206 * EEPROM version is the byte at offset 0xfd in firmware
1207 * We read 4 bytes, then shift out the byte we actually want */
1208 read_nic_dword(priv->net_dev, addr + 0xFC, &val);
1209 priv->eeprom_version = (val >> 24) & 0xFF;
1210 IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version);
1211
James Ketrenosee8e3652005-09-14 09:47:29 -05001212 /*
James Ketrenos2c86c272005-03-23 17:32:29 -06001213 * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware
1214 *
1215 * notice that the EEPROM bit is reverse polarity, i.e.
1216 * bit = 0 signifies HW RF kill switch is supported
1217 * bit = 1 signifies HW RF kill switch is NOT supported
1218 */
1219 read_nic_dword(priv->net_dev, addr + 0x20, &val);
1220 if (!((val >> 24) & 0x01))
1221 priv->hw_features |= HW_FEATURE_RFKILL;
1222
1223 IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001224 (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not ");
James Ketrenos2c86c272005-03-23 17:32:29 -06001225
1226 return 0;
1227}
1228
1229/*
1230 * Start firmware execution after power on and intialization
1231 * The sequence is:
1232 * 1. Release ARC
1233 * 2. Wait for f/w initialization completes;
1234 */
1235static int ipw2100_start_adapter(struct ipw2100_priv *priv)
1236{
James Ketrenos2c86c272005-03-23 17:32:29 -06001237 int i;
1238 u32 inta, inta_mask, gpio;
1239
1240 IPW_DEBUG_INFO("enter\n");
1241
1242 if (priv->status & STATUS_RUNNING)
1243 return 0;
1244
1245 /*
1246 * Initialize the hw - drive adapter to DO state by setting
1247 * init_done bit. Wait for clk_ready bit and Download
1248 * fw & dino ucode
1249 */
1250 if (ipw2100_download_firmware(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001251 printk(KERN_ERR DRV_NAME
1252 ": %s: Failed to power on the adapter.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001253 priv->net_dev->name);
1254 return -EIO;
1255 }
1256
1257 /* Clear the Tx, Rx and Msg queues and the r/w indexes
1258 * in the firmware RBD and TBD ring queue */
1259 ipw2100_queues_initialize(priv);
1260
1261 ipw2100_hw_set_gpio(priv);
1262
1263 /* TODO -- Look at disabling interrupts here to make sure none
1264 * get fired during FW initialization */
1265
1266 /* Release ARC - clear reset bit */
1267 write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
1268
1269 /* wait for f/w intialization complete */
1270 IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n");
1271 i = 5000;
1272 do {
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001273 schedule_timeout_uninterruptible(msecs_to_jiffies(40));
James Ketrenos2c86c272005-03-23 17:32:29 -06001274 /* Todo... wait for sync command ... */
1275
1276 read_register(priv->net_dev, IPW_REG_INTA, &inta);
1277
1278 /* check "init done" bit */
1279 if (inta & IPW2100_INTA_FW_INIT_DONE) {
1280 /* reset "init done" bit */
1281 write_register(priv->net_dev, IPW_REG_INTA,
1282 IPW2100_INTA_FW_INIT_DONE);
1283 break;
1284 }
1285
1286 /* check error conditions : we check these after the firmware
1287 * check so that if there is an error, the interrupt handler
1288 * will see it and the adapter will be reset */
1289 if (inta &
1290 (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) {
1291 /* clear error conditions */
1292 write_register(priv->net_dev, IPW_REG_INTA,
1293 IPW2100_INTA_FATAL_ERROR |
1294 IPW2100_INTA_PARITY_ERROR);
1295 }
Roel Kluina2a1c3e2007-11-05 23:55:02 +01001296 } while (--i);
James Ketrenos2c86c272005-03-23 17:32:29 -06001297
1298 /* Clear out any pending INTAs since we aren't supposed to have
1299 * interrupts enabled at this point... */
1300 read_register(priv->net_dev, IPW_REG_INTA, &inta);
1301 read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
1302 inta &= IPW_INTERRUPT_MASK;
1303 /* Clear out any pending interrupts */
1304 if (inta & inta_mask)
1305 write_register(priv->net_dev, IPW_REG_INTA, inta);
1306
1307 IPW_DEBUG_FW("f/w initialization complete: %s\n",
1308 i ? "SUCCESS" : "FAILED");
1309
1310 if (!i) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001311 printk(KERN_WARNING DRV_NAME
1312 ": %s: Firmware did not initialize.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001313 priv->net_dev->name);
1314 return -EIO;
1315 }
1316
1317 /* allow firmware to write to GPIO1 & GPIO3 */
1318 read_register(priv->net_dev, IPW_REG_GPIO, &gpio);
1319
1320 gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK);
1321
1322 write_register(priv->net_dev, IPW_REG_GPIO, gpio);
1323
1324 /* Ready to receive commands */
1325 priv->status |= STATUS_RUNNING;
1326
1327 /* The adapter has been reset; we are not associated */
1328 priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
1329
1330 IPW_DEBUG_INFO("exit\n");
1331
1332 return 0;
1333}
1334
1335static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv)
1336{
1337 if (!priv->fatal_error)
1338 return;
1339
1340 priv->fatal_errors[priv->fatal_index++] = priv->fatal_error;
1341 priv->fatal_index %= IPW2100_ERROR_QUEUE;
1342 priv->fatal_error = 0;
1343}
1344
James Ketrenos2c86c272005-03-23 17:32:29 -06001345/* NOTE: Our interrupt is disabled when this method is called */
1346static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
1347{
1348 u32 reg;
1349 int i;
1350
1351 IPW_DEBUG_INFO("Power cycling the hardware.\n");
1352
1353 ipw2100_hw_set_gpio(priv);
1354
1355 /* Step 1. Stop Master Assert */
1356 write_register(priv->net_dev, IPW_REG_RESET_REG,
1357 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
1358
1359 /* Step 2. Wait for stop Master Assert
Frederik Schwarzer025dfda2008-10-16 19:02:37 +02001360 * (not more than 50us, otherwise ret error */
James Ketrenos2c86c272005-03-23 17:32:29 -06001361 i = 5;
1362 do {
1363 udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
1364 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
1365
1366 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
1367 break;
Roel Kluina2a1c3e2007-11-05 23:55:02 +01001368 } while (--i);
James Ketrenos2c86c272005-03-23 17:32:29 -06001369
1370 priv->status &= ~STATUS_RESET_PENDING;
1371
1372 if (!i) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001373 IPW_DEBUG_INFO
1374 ("exit - waited too long for master assert stop\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06001375 return -EIO;
1376 }
1377
1378 write_register(priv->net_dev, IPW_REG_RESET_REG,
1379 IPW_AUX_HOST_RESET_REG_SW_RESET);
1380
James Ketrenos2c86c272005-03-23 17:32:29 -06001381 /* Reset any fatal_error conditions */
1382 ipw2100_reset_fatalerror(priv);
1383
1384 /* At this point, the adapter is now stopped and disabled */
1385 priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING |
1386 STATUS_ASSOCIATED | STATUS_ENABLED);
1387
1388 return 0;
1389}
1390
1391/*
Justin P. Mattock942a8492011-02-01 21:06:21 -08001392 * Send the CARD_DISABLE_PHY_OFF command to the card to disable it
James Ketrenos2c86c272005-03-23 17:32:29 -06001393 *
1394 * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent.
1395 *
1396 * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of
1397 * if STATUS_ASSN_LOST is sent.
1398 */
1399static int ipw2100_hw_phy_off(struct ipw2100_priv *priv)
1400{
1401
1402#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000)
1403
1404 struct host_command cmd = {
1405 .host_command = CARD_DISABLE_PHY_OFF,
1406 .host_command_sequence = 0,
1407 .host_command_length = 0,
1408 };
1409 int err, i;
1410 u32 val1, val2;
1411
1412 IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n");
1413
1414 /* Turn off the radio */
1415 err = ipw2100_hw_send_command(priv, &cmd);
1416 if (err)
1417 return err;
1418
1419 for (i = 0; i < 2500; i++) {
1420 read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1);
1421 read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2);
1422
1423 if ((val1 & IPW2100_CONTROL_PHY_OFF) &&
1424 (val2 & IPW2100_COMMAND_PHY_OFF))
1425 return 0;
1426
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001427 schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY);
James Ketrenos2c86c272005-03-23 17:32:29 -06001428 }
1429
1430 return -EIO;
1431}
1432
James Ketrenos2c86c272005-03-23 17:32:29 -06001433static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
1434{
1435 struct host_command cmd = {
1436 .host_command = HOST_COMPLETE,
1437 .host_command_sequence = 0,
1438 .host_command_length = 0
1439 };
1440 int err = 0;
1441
1442 IPW_DEBUG_HC("HOST_COMPLETE\n");
1443
1444 if (priv->status & STATUS_ENABLED)
1445 return 0;
1446
Ingo Molnar752e3772006-02-28 07:20:54 +08001447 mutex_lock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001448
1449 if (rf_kill_active(priv)) {
1450 IPW_DEBUG_HC("Command aborted due to RF kill active.\n");
1451 goto fail_up;
1452 }
1453
1454 err = ipw2100_hw_send_command(priv, &cmd);
1455 if (err) {
1456 IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n");
1457 goto fail_up;
1458 }
1459
1460 err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED);
1461 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001462 IPW_DEBUG_INFO("%s: card not responding to init command.\n",
1463 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001464 goto fail_up;
1465 }
1466
1467 if (priv->stop_hang_check) {
1468 priv->stop_hang_check = 0;
Tejun Heobcb6d912011-01-26 12:12:50 +01001469 schedule_delayed_work(&priv->hang_check, HZ / 2);
James Ketrenos2c86c272005-03-23 17:32:29 -06001470 }
1471
James Ketrenosee8e3652005-09-14 09:47:29 -05001472 fail_up:
Ingo Molnar752e3772006-02-28 07:20:54 +08001473 mutex_unlock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001474 return err;
1475}
1476
1477static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
1478{
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001479#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100))
James Ketrenos2c86c272005-03-23 17:32:29 -06001480
1481 struct host_command cmd = {
1482 .host_command = HOST_PRE_POWER_DOWN,
1483 .host_command_sequence = 0,
1484 .host_command_length = 0,
1485 };
1486 int err, i;
1487 u32 reg;
1488
1489 if (!(priv->status & STATUS_RUNNING))
1490 return 0;
1491
1492 priv->status |= STATUS_STOPPING;
1493
1494 /* We can only shut down the card if the firmware is operational. So,
1495 * if we haven't reset since a fatal_error, then we can not send the
1496 * shutdown commands. */
1497 if (!priv->fatal_error) {
1498 /* First, make sure the adapter is enabled so that the PHY_OFF
1499 * command can shut it down */
1500 ipw2100_enable_adapter(priv);
1501
1502 err = ipw2100_hw_phy_off(priv);
1503 if (err)
James Ketrenosee8e3652005-09-14 09:47:29 -05001504 printk(KERN_WARNING DRV_NAME
1505 ": Error disabling radio %d\n", err);
James Ketrenos2c86c272005-03-23 17:32:29 -06001506
1507 /*
1508 * If in D0-standby mode going directly to D3 may cause a
1509 * PCI bus violation. Therefore we must change out of the D0
1510 * state.
1511 *
1512 * Sending the PREPARE_FOR_POWER_DOWN will restrict the
1513 * hardware from going into standby mode and will transition
Andreas Mohrd6e05ed2006-06-26 18:35:02 +02001514 * out of D0-standby if it is already in that state.
James Ketrenos2c86c272005-03-23 17:32:29 -06001515 *
1516 * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the
1517 * driver upon completion. Once received, the driver can
1518 * proceed to the D3 state.
1519 *
1520 * Prepare for power down command to fw. This command would
1521 * take HW out of D0-standby and prepare it for D3 state.
1522 *
1523 * Currently FW does not support event notification for this
1524 * event. Therefore, skip waiting for it. Just wait a fixed
1525 * 100ms
1526 */
1527 IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n");
1528
1529 err = ipw2100_hw_send_command(priv, &cmd);
1530 if (err)
Jiri Benc797b4f72005-08-25 20:03:27 -04001531 printk(KERN_WARNING DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06001532 "%s: Power down command failed: Error %d\n",
1533 priv->net_dev->name, err);
Nishanth Aravamudan3173c892005-09-11 02:09:55 -07001534 else
1535 schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY);
James Ketrenos2c86c272005-03-23 17:32:29 -06001536 }
1537
1538 priv->status &= ~STATUS_ENABLED;
1539
1540 /*
1541 * Set GPIO 3 writable by FW; GPIO 1 writable
1542 * by driver and enable clock
1543 */
1544 ipw2100_hw_set_gpio(priv);
1545
1546 /*
1547 * Power down adapter. Sequence:
1548 * 1. Stop master assert (RESET_REG[9]=1)
1549 * 2. Wait for stop master (RESET_REG[8]==1)
1550 * 3. S/w reset assert (RESET_REG[7] = 1)
1551 */
1552
1553 /* Stop master assert */
1554 write_register(priv->net_dev, IPW_REG_RESET_REG,
1555 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
1556
1557 /* wait stop master not more than 50 usec.
1558 * Otherwise return error. */
1559 for (i = 5; i > 0; i--) {
1560 udelay(10);
1561
1562 /* Check master stop bit */
1563 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
1564
1565 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
1566 break;
1567 }
1568
1569 if (i == 0)
Jiri Benc797b4f72005-08-25 20:03:27 -04001570 printk(KERN_WARNING DRV_NAME
James Ketrenos2c86c272005-03-23 17:32:29 -06001571 ": %s: Could now power down adapter.\n",
1572 priv->net_dev->name);
1573
1574 /* assert s/w reset */
1575 write_register(priv->net_dev, IPW_REG_RESET_REG,
1576 IPW_AUX_HOST_RESET_REG_SW_RESET);
1577
1578 priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING);
1579
1580 return 0;
1581}
1582
James Ketrenos2c86c272005-03-23 17:32:29 -06001583static int ipw2100_disable_adapter(struct ipw2100_priv *priv)
1584{
1585 struct host_command cmd = {
1586 .host_command = CARD_DISABLE,
1587 .host_command_sequence = 0,
1588 .host_command_length = 0
1589 };
1590 int err = 0;
1591
1592 IPW_DEBUG_HC("CARD_DISABLE\n");
1593
1594 if (!(priv->status & STATUS_ENABLED))
1595 return 0;
1596
1597 /* Make sure we clear the associated state */
1598 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1599
1600 if (!priv->stop_hang_check) {
1601 priv->stop_hang_check = 1;
1602 cancel_delayed_work(&priv->hang_check);
1603 }
1604
Ingo Molnar752e3772006-02-28 07:20:54 +08001605 mutex_lock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001606
1607 err = ipw2100_hw_send_command(priv, &cmd);
1608 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001609 printk(KERN_WARNING DRV_NAME
1610 ": exit - failed to send CARD_DISABLE command\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06001611 goto fail_up;
1612 }
1613
1614 err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED);
1615 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001616 printk(KERN_WARNING DRV_NAME
1617 ": exit - card failed to change to DISABLED\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06001618 goto fail_up;
1619 }
1620
1621 IPW_DEBUG_INFO("TODO: implement scan state machine\n");
1622
James Ketrenosee8e3652005-09-14 09:47:29 -05001623 fail_up:
Ingo Molnar752e3772006-02-28 07:20:54 +08001624 mutex_unlock(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001625 return err;
1626}
1627
Jiri Bencc4aee8c2005-08-25 20:04:43 -04001628static int ipw2100_set_scan_options(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06001629{
1630 struct host_command cmd = {
1631 .host_command = SET_SCAN_OPTIONS,
1632 .host_command_sequence = 0,
1633 .host_command_length = 8
1634 };
1635 int err;
1636
1637 IPW_DEBUG_INFO("enter\n");
1638
1639 IPW_DEBUG_SCAN("setting scan options\n");
1640
1641 cmd.host_command_parameters[0] = 0;
1642
1643 if (!(priv->config & CFG_ASSOCIATE))
1644 cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE;
25b645b2005-07-12 15:45:30 -05001645 if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled)
James Ketrenos2c86c272005-03-23 17:32:29 -06001646 cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL;
1647 if (priv->config & CFG_PASSIVE_SCAN)
1648 cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE;
1649
1650 cmd.host_command_parameters[1] = priv->channel_mask;
1651
1652 err = ipw2100_hw_send_command(priv, &cmd);
1653
1654 IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n",
1655 cmd.host_command_parameters[0]);
1656
1657 return err;
1658}
1659
Jiri Bencc4aee8c2005-08-25 20:04:43 -04001660static int ipw2100_start_scan(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06001661{
1662 struct host_command cmd = {
1663 .host_command = BROADCAST_SCAN,
1664 .host_command_sequence = 0,
1665 .host_command_length = 4
1666 };
1667 int err;
1668
1669 IPW_DEBUG_HC("START_SCAN\n");
1670
1671 cmd.host_command_parameters[0] = 0;
1672
1673 /* No scanning if in monitor mode */
1674 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
1675 return 1;
1676
1677 if (priv->status & STATUS_SCANNING) {
1678 IPW_DEBUG_SCAN("Scan requested while already in scan...\n");
1679 return 0;
1680 }
1681
1682 IPW_DEBUG_INFO("enter\n");
1683
1684 /* Not clearing here; doing so makes iwlist always return nothing...
1685 *
1686 * We should modify the table logic to use aging tables vs. clearing
1687 * the table on each scan start.
1688 */
1689 IPW_DEBUG_SCAN("starting scan\n");
1690
1691 priv->status |= STATUS_SCANNING;
1692 err = ipw2100_hw_send_command(priv, &cmd);
1693 if (err)
1694 priv->status &= ~STATUS_SCANNING;
1695
1696 IPW_DEBUG_INFO("exit\n");
1697
1698 return err;
1699}
1700
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04001701static const struct libipw_geo ipw_geos[] = {
Zhu Yibe6b3b12006-01-24 13:49:08 +08001702 { /* Restricted */
1703 "---",
1704 .bg_channels = 14,
1705 .bg = {{2412, 1}, {2417, 2}, {2422, 3},
1706 {2427, 4}, {2432, 5}, {2437, 6},
1707 {2442, 7}, {2447, 8}, {2452, 9},
1708 {2457, 10}, {2462, 11}, {2467, 12},
1709 {2472, 13}, {2484, 14}},
1710 },
1711};
1712
James Ketrenos2c86c272005-03-23 17:32:29 -06001713static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
1714{
1715 unsigned long flags;
1716 int rc = 0;
1717 u32 lock;
1718 u32 ord_len = sizeof(lock);
1719
Dan Williamsc3d72b92009-02-11 13:26:06 -05001720 /* Age scan list entries found before suspend */
1721 if (priv->suspend_time) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04001722 libipw_networks_age(priv->ieee, priv->suspend_time);
Dan Williamsc3d72b92009-02-11 13:26:06 -05001723 priv->suspend_time = 0;
1724 }
1725
1726 /* Quiet if manually disabled. */
James Ketrenos2c86c272005-03-23 17:32:29 -06001727 if (priv->status & STATUS_RF_KILL_SW) {
1728 IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "
1729 "switch\n", priv->net_dev->name);
1730 return 0;
1731 }
1732
Arjan van de Ven5c875792006-09-30 23:27:17 -07001733 /* the ipw2100 hardware really doesn't want power management delays
1734 * longer than 175usec
1735 */
James Bottomley82f68252010-07-05 22:53:06 +02001736 pm_qos_update_request(&ipw2100_pm_qos_req, 175);
Arjan van de Ven5c875792006-09-30 23:27:17 -07001737
James Ketrenos2c86c272005-03-23 17:32:29 -06001738 /* If the interrupt is enabled, turn it off... */
1739 spin_lock_irqsave(&priv->low_lock, flags);
1740 ipw2100_disable_interrupts(priv);
1741
1742 /* Reset any fatal_error conditions */
1743 ipw2100_reset_fatalerror(priv);
1744 spin_unlock_irqrestore(&priv->low_lock, flags);
1745
1746 if (priv->status & STATUS_POWERED ||
1747 (priv->status & STATUS_RESET_PENDING)) {
1748 /* Power cycle the card ... */
1749 if (ipw2100_power_cycle_adapter(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001750 printk(KERN_WARNING DRV_NAME
1751 ": %s: Could not cycle adapter.\n",
1752 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001753 rc = 1;
1754 goto exit;
1755 }
1756 } else
1757 priv->status |= STATUS_POWERED;
1758
Pavel Machek8724a112005-06-20 14:28:43 -07001759 /* Load the firmware, start the clocks, etc. */
James Ketrenos2c86c272005-03-23 17:32:29 -06001760 if (ipw2100_start_adapter(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001761 printk(KERN_ERR DRV_NAME
1762 ": %s: Failed to start the firmware.\n",
1763 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001764 rc = 1;
1765 goto exit;
1766 }
1767
1768 ipw2100_initialize_ordinals(priv);
1769
1770 /* Determine capabilities of this particular HW configuration */
1771 if (ipw2100_get_hw_features(priv)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001772 printk(KERN_ERR DRV_NAME
1773 ": %s: Failed to determine HW features.\n",
1774 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001775 rc = 1;
1776 goto exit;
1777 }
1778
Zhu Yibe6b3b12006-01-24 13:49:08 +08001779 /* Initialize the geo */
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04001780 if (libipw_set_geo(priv->ieee, &ipw_geos[0])) {
Zhu Yibe6b3b12006-01-24 13:49:08 +08001781 printk(KERN_WARNING DRV_NAME "Could not set geo\n");
1782 return 0;
1783 }
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04001784 priv->ieee->freq_band = LIBIPW_24GHZ_BAND;
Zhu Yibe6b3b12006-01-24 13:49:08 +08001785
James Ketrenos2c86c272005-03-23 17:32:29 -06001786 lock = LOCK_NONE;
1787 if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05001788 printk(KERN_ERR DRV_NAME
1789 ": %s: Failed to clear ordinal lock.\n",
1790 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001791 rc = 1;
1792 goto exit;
1793 }
1794
1795 priv->status &= ~STATUS_SCANNING;
1796
1797 if (rf_kill_active(priv)) {
1798 printk(KERN_INFO "%s: Radio is disabled by RF switch.\n",
1799 priv->net_dev->name);
1800
1801 if (priv->stop_rf_kill) {
1802 priv->stop_rf_kill = 0;
Tejun Heobcb6d912011-01-26 12:12:50 +01001803 schedule_delayed_work(&priv->rf_kill,
1804 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06001805 }
1806
1807 deferred = 1;
1808 }
1809
1810 /* Turn on the interrupt so that commands can be processed */
1811 ipw2100_enable_interrupts(priv);
1812
1813 /* Send all of the commands that must be sent prior to
1814 * HOST_COMPLETE */
1815 if (ipw2100_adapter_setup(priv)) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001816 printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05001817 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001818 rc = 1;
1819 goto exit;
1820 }
1821
1822 if (!deferred) {
1823 /* Enable the adapter - sends HOST_COMPLETE */
1824 if (ipw2100_enable_adapter(priv)) {
Jiri Benc797b4f72005-08-25 20:03:27 -04001825 printk(KERN_ERR DRV_NAME ": "
James Ketrenosee8e3652005-09-14 09:47:29 -05001826 "%s: failed in call to enable adapter.\n",
1827 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001828 ipw2100_hw_stop_adapter(priv);
1829 rc = 1;
1830 goto exit;
1831 }
1832
James Ketrenos2c86c272005-03-23 17:32:29 -06001833 /* Start a scan . . . */
1834 ipw2100_set_scan_options(priv);
1835 ipw2100_start_scan(priv);
1836 }
1837
James Ketrenosee8e3652005-09-14 09:47:29 -05001838 exit:
James Ketrenos2c86c272005-03-23 17:32:29 -06001839 return rc;
1840}
1841
James Ketrenos2c86c272005-03-23 17:32:29 -06001842static void ipw2100_down(struct ipw2100_priv *priv)
1843{
1844 unsigned long flags;
1845 union iwreq_data wrqu = {
1846 .ap_addr = {
James Ketrenosee8e3652005-09-14 09:47:29 -05001847 .sa_family = ARPHRD_ETHER}
James Ketrenos2c86c272005-03-23 17:32:29 -06001848 };
1849 int associated = priv->status & STATUS_ASSOCIATED;
1850
1851 /* Kill the RF switch timer */
1852 if (!priv->stop_rf_kill) {
1853 priv->stop_rf_kill = 1;
1854 cancel_delayed_work(&priv->rf_kill);
1855 }
1856
Nick Andrew44072452009-01-03 18:52:40 +11001857 /* Kill the firmware hang check timer */
James Ketrenos2c86c272005-03-23 17:32:29 -06001858 if (!priv->stop_hang_check) {
1859 priv->stop_hang_check = 1;
1860 cancel_delayed_work(&priv->hang_check);
1861 }
1862
1863 /* Kill any pending resets */
1864 if (priv->status & STATUS_RESET_PENDING)
1865 cancel_delayed_work(&priv->reset_work);
1866
1867 /* Make sure the interrupt is on so that FW commands will be
1868 * processed correctly */
1869 spin_lock_irqsave(&priv->low_lock, flags);
1870 ipw2100_enable_interrupts(priv);
1871 spin_unlock_irqrestore(&priv->low_lock, flags);
1872
1873 if (ipw2100_hw_stop_adapter(priv))
Jiri Benc797b4f72005-08-25 20:03:27 -04001874 printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06001875 priv->net_dev->name);
1876
1877 /* Do not disable the interrupt until _after_ we disable
1878 * the adaptor. Otherwise the CARD_DISABLE command will never
1879 * be ack'd by the firmware */
1880 spin_lock_irqsave(&priv->low_lock, flags);
1881 ipw2100_disable_interrupts(priv);
1882 spin_unlock_irqrestore(&priv->low_lock, flags);
1883
James Bottomley82f68252010-07-05 22:53:06 +02001884 pm_qos_update_request(&ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
Arjan van de Ven5c875792006-09-30 23:27:17 -07001885
James Ketrenos2c86c272005-03-23 17:32:29 -06001886 /* We have to signal any supplicant if we are disassociating */
1887 if (associated)
1888 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
1889
1890 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1891 netif_carrier_off(priv->net_dev);
1892 netif_stop_queue(priv->net_dev);
1893}
1894
Matthew Garrettc26409a2009-11-11 14:36:30 -05001895/* Called by register_netdev() */
1896static int ipw2100_net_init(struct net_device *dev)
1897{
1898 struct ipw2100_priv *priv = libipw_priv(dev);
Stanislaw Gruszka7cabafc2011-09-14 16:47:50 +02001899
1900 return ipw2100_up(priv, 1);
1901}
1902
1903static int ipw2100_wdev_init(struct net_device *dev)
1904{
1905 struct ipw2100_priv *priv = libipw_priv(dev);
Matthew Garrettc26409a2009-11-11 14:36:30 -05001906 const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
1907 struct wireless_dev *wdev = &priv->ieee->wdev;
Matthew Garrettc26409a2009-11-11 14:36:30 -05001908 int i;
1909
Matthew Garrettc26409a2009-11-11 14:36:30 -05001910 memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
1911
1912 /* fill-out priv->ieee->bg_band */
1913 if (geo->bg_channels) {
1914 struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
1915
1916 bg_band->band = IEEE80211_BAND_2GHZ;
1917 bg_band->n_channels = geo->bg_channels;
Joe Perchesbaeb2ff2010-08-11 07:02:48 +00001918 bg_band->channels = kcalloc(geo->bg_channels,
1919 sizeof(struct ieee80211_channel),
1920 GFP_KERNEL);
Christoph Fritz93c05842010-08-03 12:54:20 +02001921 if (!bg_band->channels) {
1922 ipw2100_down(priv);
1923 return -ENOMEM;
1924 }
Matthew Garrettc26409a2009-11-11 14:36:30 -05001925 /* translate geo->bg to bg_band.channels */
1926 for (i = 0; i < geo->bg_channels; i++) {
1927 bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
1928 bg_band->channels[i].center_freq = geo->bg[i].freq;
1929 bg_band->channels[i].hw_value = geo->bg[i].channel;
1930 bg_band->channels[i].max_power = geo->bg[i].max_power;
1931 if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
1932 bg_band->channels[i].flags |=
1933 IEEE80211_CHAN_PASSIVE_SCAN;
1934 if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
1935 bg_band->channels[i].flags |=
1936 IEEE80211_CHAN_NO_IBSS;
1937 if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
1938 bg_band->channels[i].flags |=
1939 IEEE80211_CHAN_RADAR;
1940 /* No equivalent for LIBIPW_CH_80211H_RULES,
1941 LIBIPW_CH_UNIFORM_SPREADING, or
1942 LIBIPW_CH_B_ONLY... */
1943 }
1944 /* point at bitrate info */
1945 bg_band->bitrates = ipw2100_bg_rates;
1946 bg_band->n_bitrates = RATE_COUNT;
1947
1948 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band;
1949 }
1950
1951 set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
1952 if (wiphy_register(wdev->wiphy)) {
1953 ipw2100_down(priv);
1954 return -EIO;
1955 }
1956 return 0;
1957}
1958
David Howellsc4028952006-11-22 14:57:56 +00001959static void ipw2100_reset_adapter(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06001960{
David Howellsc4028952006-11-22 14:57:56 +00001961 struct ipw2100_priv *priv =
1962 container_of(work, struct ipw2100_priv, reset_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06001963 unsigned long flags;
1964 union iwreq_data wrqu = {
1965 .ap_addr = {
James Ketrenosee8e3652005-09-14 09:47:29 -05001966 .sa_family = ARPHRD_ETHER}
James Ketrenos2c86c272005-03-23 17:32:29 -06001967 };
1968 int associated = priv->status & STATUS_ASSOCIATED;
1969
1970 spin_lock_irqsave(&priv->low_lock, flags);
Zhu Yia1e695a2005-07-04 14:06:00 +08001971 IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06001972 priv->resets++;
1973 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
1974 priv->status |= STATUS_SECURITY_UPDATED;
1975
1976 /* Force a power cycle even if interface hasn't been opened
1977 * yet */
1978 cancel_delayed_work(&priv->reset_work);
1979 priv->status |= STATUS_RESET_PENDING;
1980 spin_unlock_irqrestore(&priv->low_lock, flags);
1981
Ingo Molnar752e3772006-02-28 07:20:54 +08001982 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001983 /* stop timed checks so that they don't interfere with reset */
1984 priv->stop_hang_check = 1;
1985 cancel_delayed_work(&priv->hang_check);
1986
1987 /* We have to signal any supplicant if we are disassociating */
1988 if (associated)
1989 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
1990
1991 ipw2100_up(priv, 0);
Ingo Molnar752e3772006-02-28 07:20:54 +08001992 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06001993
1994}
1995
James Ketrenos2c86c272005-03-23 17:32:29 -06001996static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
1997{
1998
1999#define MAC_ASSOCIATION_READ_DELAY (HZ)
Hannes Ederb9da9e92009-02-14 11:50:26 +00002000 int ret;
2001 unsigned int len, essid_len;
James Ketrenos2c86c272005-03-23 17:32:29 -06002002 char essid[IW_ESSID_MAX_SIZE];
2003 u32 txrate;
2004 u32 chan;
2005 char *txratename;
James Ketrenosee8e3652005-09-14 09:47:29 -05002006 u8 bssid[ETH_ALEN];
John W. Linville9387b7c2008-09-30 20:59:05 -04002007 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002008
2009 /*
2010 * TBD: BSSID is usually 00:00:00:00:00:00 here and not
2011 * an actual MAC of the AP. Seems like FW sets this
2012 * address too late. Read it later and expose through
2013 * /proc or schedule a later task to query and update
2014 */
2015
2016 essid_len = IW_ESSID_MAX_SIZE;
2017 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID,
2018 essid, &essid_len);
2019 if (ret) {
2020 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002021 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06002022 return;
2023 }
2024
2025 len = sizeof(u32);
James Ketrenosee8e3652005-09-14 09:47:29 -05002026 ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002027 if (ret) {
2028 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002029 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06002030 return;
2031 }
2032
2033 len = sizeof(u32);
2034 ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len);
2035 if (ret) {
2036 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002037 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06002038 return;
2039 }
2040 len = ETH_ALEN;
James Ketrenosee8e3652005-09-14 09:47:29 -05002041 ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002042 if (ret) {
2043 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002044 __LINE__);
James Ketrenos2c86c272005-03-23 17:32:29 -06002045 return;
2046 }
2047 memcpy(priv->ieee->bssid, bssid, ETH_ALEN);
2048
James Ketrenos2c86c272005-03-23 17:32:29 -06002049 switch (txrate) {
2050 case TX_RATE_1_MBIT:
2051 txratename = "1Mbps";
2052 break;
2053 case TX_RATE_2_MBIT:
2054 txratename = "2Mbsp";
2055 break;
2056 case TX_RATE_5_5_MBIT:
2057 txratename = "5.5Mbps";
2058 break;
2059 case TX_RATE_11_MBIT:
2060 txratename = "11Mbps";
2061 break;
2062 default:
2063 IPW_DEBUG_INFO("Unknown rate: %d\n", txrate);
2064 txratename = "unknown rate";
2065 break;
2066 }
2067
Johannes Berge1749612008-10-27 15:59:26 -07002068 IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04002069 priv->net_dev->name, print_ssid(ssid, essid, essid_len),
Johannes Berge1749612008-10-27 15:59:26 -07002070 txratename, chan, bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002071
2072 /* now we copy read ssid into dev */
2073 if (!(priv->config & CFG_STATIC_ESSID)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002074 priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002075 memcpy(priv->essid, essid, priv->essid_len);
2076 }
2077 priv->channel = chan;
2078 memcpy(priv->bssid, bssid, ETH_ALEN);
2079
2080 priv->status |= STATUS_ASSOCIATING;
2081 priv->connect_start = get_seconds();
2082
Tejun Heobcb6d912011-01-26 12:12:50 +01002083 schedule_delayed_work(&priv->wx_event_work, HZ / 10);
James Ketrenos2c86c272005-03-23 17:32:29 -06002084}
2085
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002086static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
2087 int length, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06002088{
2089 int ssid_len = min(length, IW_ESSID_MAX_SIZE);
2090 struct host_command cmd = {
2091 .host_command = SSID,
2092 .host_command_sequence = 0,
2093 .host_command_length = ssid_len
2094 };
2095 int err;
John W. Linville9387b7c2008-09-30 20:59:05 -04002096 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002097
John W. Linville9387b7c2008-09-30 20:59:05 -04002098 IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len));
James Ketrenos2c86c272005-03-23 17:32:29 -06002099
2100 if (ssid_len)
James Ketrenos82328352005-08-24 22:33:31 -05002101 memcpy(cmd.host_command_parameters, essid, ssid_len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002102
2103 if (!batch_mode) {
2104 err = ipw2100_disable_adapter(priv);
2105 if (err)
2106 return err;
2107 }
2108
2109 /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to
2110 * disable auto association -- so we cheat by setting a bogus SSID */
2111 if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) {
2112 int i;
James Ketrenosee8e3652005-09-14 09:47:29 -05002113 u8 *bogus = (u8 *) cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06002114 for (i = 0; i < IW_ESSID_MAX_SIZE; i++)
2115 bogus[i] = 0x18 + i;
2116 cmd.host_command_length = IW_ESSID_MAX_SIZE;
2117 }
2118
2119 /* NOTE: We always send the SSID command even if the provided ESSID is
2120 * the same as what we currently think is set. */
2121
2122 err = ipw2100_hw_send_command(priv, &cmd);
2123 if (!err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002124 memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002125 memcpy(priv->essid, essid, ssid_len);
2126 priv->essid_len = ssid_len;
2127 }
2128
2129 if (!batch_mode) {
2130 if (ipw2100_enable_adapter(priv))
2131 err = -EIO;
2132 }
2133
2134 return err;
2135}
2136
2137static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
2138{
John W. Linville9387b7c2008-09-30 20:59:05 -04002139 DECLARE_SSID_BUF(ssid);
2140
James Ketrenos2c86c272005-03-23 17:32:29 -06002141 IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
Frans Pop9fd1ea42010-03-24 19:46:31 +01002142 "disassociated: '%s' %pM\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04002143 print_ssid(ssid, priv->essid, priv->essid_len),
Johannes Berge1749612008-10-27 15:59:26 -07002144 priv->bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06002145
2146 priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
2147
2148 if (priv->status & STATUS_STOPPING) {
2149 IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n");
2150 return;
2151 }
2152
2153 memset(priv->bssid, 0, ETH_ALEN);
2154 memset(priv->ieee->bssid, 0, ETH_ALEN);
2155
2156 netif_carrier_off(priv->net_dev);
2157 netif_stop_queue(priv->net_dev);
2158
2159 if (!(priv->status & STATUS_RUNNING))
2160 return;
2161
2162 if (priv->status & STATUS_SECURITY_UPDATED)
Tejun Heobcb6d912011-01-26 12:12:50 +01002163 schedule_delayed_work(&priv->security_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06002164
Tejun Heobcb6d912011-01-26 12:12:50 +01002165 schedule_delayed_work(&priv->wx_event_work, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06002166}
2167
2168static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
2169{
2170 IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002171 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002172
2173 /* RF_KILL is now enabled (else we wouldn't be here) */
Matthew Garrettc26409a2009-11-11 14:36:30 -05002174 wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
James Ketrenos2c86c272005-03-23 17:32:29 -06002175 priv->status |= STATUS_RF_KILL_HW;
2176
James Ketrenos2c86c272005-03-23 17:32:29 -06002177 /* Make sure the RF Kill check timer is running */
2178 priv->stop_rf_kill = 0;
2179 cancel_delayed_work(&priv->rf_kill);
Tejun Heobcb6d912011-01-26 12:12:50 +01002180 schedule_delayed_work(&priv->rf_kill, round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06002181}
2182
Dan Williamsd20c6782007-10-10 12:28:07 -04002183static void send_scan_event(void *data)
2184{
2185 struct ipw2100_priv *priv = data;
2186 union iwreq_data wrqu;
2187
2188 wrqu.data.length = 0;
2189 wrqu.data.flags = 0;
2190 wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
2191}
2192
2193static void ipw2100_scan_event_later(struct work_struct *work)
2194{
2195 send_scan_event(container_of(work, struct ipw2100_priv,
2196 scan_event_later.work));
2197}
2198
2199static void ipw2100_scan_event_now(struct work_struct *work)
2200{
2201 send_scan_event(container_of(work, struct ipw2100_priv,
2202 scan_event_now));
2203}
2204
James Ketrenos2c86c272005-03-23 17:32:29 -06002205static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
2206{
2207 IPW_DEBUG_SCAN("scan complete\n");
2208 /* Age the scan results... */
2209 priv->ieee->scans++;
2210 priv->status &= ~STATUS_SCANNING;
Dan Williamsd20c6782007-10-10 12:28:07 -04002211
2212 /* Only userspace-requested scan completion events go out immediately */
2213 if (!priv->user_requested_scan) {
2214 if (!delayed_work_pending(&priv->scan_event_later))
Tejun Heobcb6d912011-01-26 12:12:50 +01002215 schedule_delayed_work(&priv->scan_event_later,
2216 round_jiffies_relative(msecs_to_jiffies(4000)));
Dan Williamsd20c6782007-10-10 12:28:07 -04002217 } else {
2218 priv->user_requested_scan = 0;
2219 cancel_delayed_work(&priv->scan_event_later);
Tejun Heobcb6d912011-01-26 12:12:50 +01002220 schedule_work(&priv->scan_event_now);
Dan Williamsd20c6782007-10-10 12:28:07 -04002221 }
James Ketrenos2c86c272005-03-23 17:32:29 -06002222}
2223
Brice Goglin0f52bf92005-12-01 01:41:46 -08002224#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002225#define IPW2100_HANDLER(v, f) { v, f, # v }
2226struct ipw2100_status_indicator {
2227 int status;
James Ketrenosee8e3652005-09-14 09:47:29 -05002228 void (*cb) (struct ipw2100_priv * priv, u32 status);
James Ketrenos2c86c272005-03-23 17:32:29 -06002229 char *name;
2230};
2231#else
2232#define IPW2100_HANDLER(v, f) { v, f }
2233struct ipw2100_status_indicator {
2234 int status;
James Ketrenosee8e3652005-09-14 09:47:29 -05002235 void (*cb) (struct ipw2100_priv * priv, u32 status);
James Ketrenos2c86c272005-03-23 17:32:29 -06002236};
Brice Goglin0f52bf92005-12-01 01:41:46 -08002237#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -06002238
2239static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
2240{
2241 IPW_DEBUG_SCAN("Scanning...\n");
2242 priv->status |= STATUS_SCANNING;
2243}
2244
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002245static const struct ipw2100_status_indicator status_handlers[] = {
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002246 IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL),
2247 IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002248 IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated),
2249 IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002250 IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002251 IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002252 IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL),
2253 IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002254 IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002255 IPW2100_HANDLER(IPW_STATE_DISABLED, NULL),
2256 IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL),
James Ketrenos2c86c272005-03-23 17:32:29 -06002257 IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning),
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01002258 IPW2100_HANDLER(-1, NULL)
James Ketrenos2c86c272005-03-23 17:32:29 -06002259};
2260
James Ketrenos2c86c272005-03-23 17:32:29 -06002261static void isr_status_change(struct ipw2100_priv *priv, int status)
2262{
2263 int i;
2264
2265 if (status == IPW_STATE_SCANNING &&
2266 priv->status & STATUS_ASSOCIATED &&
2267 !(priv->status & STATUS_SCANNING)) {
2268 IPW_DEBUG_INFO("Scan detected while associated, with "
2269 "no scan request. Restarting firmware.\n");
2270
2271 /* Wake up any sleeping jobs */
2272 schedule_reset(priv);
2273 }
2274
2275 for (i = 0; status_handlers[i].status != -1; i++) {
2276 if (status == status_handlers[i].status) {
2277 IPW_DEBUG_NOTIF("Status change: %s\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002278 status_handlers[i].name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002279 if (status_handlers[i].cb)
2280 status_handlers[i].cb(priv, status);
2281 priv->wstats.status = status;
2282 return;
2283 }
2284 }
2285
2286 IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);
2287}
2288
James Ketrenosee8e3652005-09-14 09:47:29 -05002289static void isr_rx_complete_command(struct ipw2100_priv *priv,
2290 struct ipw2100_cmd_header *cmd)
James Ketrenos2c86c272005-03-23 17:32:29 -06002291{
Brice Goglin0f52bf92005-12-01 01:41:46 -08002292#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002293 if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
2294 IPW_DEBUG_HC("Command completed '%s (%d)'\n",
2295 command_types[cmd->host_command_reg],
2296 cmd->host_command_reg);
2297 }
2298#endif
2299 if (cmd->host_command_reg == HOST_COMPLETE)
2300 priv->status |= STATUS_ENABLED;
2301
2302 if (cmd->host_command_reg == CARD_DISABLE)
2303 priv->status &= ~STATUS_ENABLED;
2304
2305 priv->status &= ~STATUS_CMD_ACTIVE;
2306
2307 wake_up_interruptible(&priv->wait_command_queue);
2308}
2309
Brice Goglin0f52bf92005-12-01 01:41:46 -08002310#ifdef CONFIG_IPW2100_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002311static const char *frame_types[] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06002312 "COMMAND_STATUS_VAL",
2313 "STATUS_CHANGE_VAL",
2314 "P80211_DATA_VAL",
2315 "P8023_DATA_VAL",
2316 "HOST_NOTIFICATION_VAL"
2317};
2318#endif
2319
Arjan van de Ven858119e2006-01-14 13:20:43 -08002320static int ipw2100_alloc_skb(struct ipw2100_priv *priv,
James Ketrenosee8e3652005-09-14 09:47:29 -05002321 struct ipw2100_rx_packet *packet)
James Ketrenos2c86c272005-03-23 17:32:29 -06002322{
2323 packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
2324 if (!packet->skb)
2325 return -ENOMEM;
2326
2327 packet->rxp = (struct ipw2100_rx *)packet->skb->data;
2328 packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data,
2329 sizeof(struct ipw2100_rx),
2330 PCI_DMA_FROMDEVICE);
2331 /* NOTE: pci_map_single does not return an error code, and 0 is a valid
2332 * dma_addr */
2333
2334 return 0;
2335}
2336
James Ketrenos2c86c272005-03-23 17:32:29 -06002337#define SEARCH_ERROR 0xffffffff
2338#define SEARCH_FAIL 0xfffffffe
2339#define SEARCH_SUCCESS 0xfffffff0
2340#define SEARCH_DISCARD 0
2341#define SEARCH_SNAPSHOT 1
2342
2343#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
Zhu Yi3c5eca52006-01-24 13:49:26 +08002344static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
2345{
2346 int i;
2347 if (!priv->snapshot[0])
2348 return;
2349 for (i = 0; i < 0x30; i++)
2350 kfree(priv->snapshot[i]);
2351 priv->snapshot[0] = NULL;
2352}
2353
Robert P. J. Dayae800312007-01-31 02:39:40 -05002354#ifdef IPW2100_DEBUG_C3
Arjan van de Ven858119e2006-01-14 13:20:43 -08002355static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002356{
2357 int i;
2358 if (priv->snapshot[0])
2359 return 1;
2360 for (i = 0; i < 0x30; i++) {
Robert P. J. Day5cbded52006-12-13 00:35:56 -08002361 priv->snapshot[i] = kmalloc(0x1000, GFP_ATOMIC);
James Ketrenos2c86c272005-03-23 17:32:29 -06002362 if (!priv->snapshot[i]) {
2363 IPW_DEBUG_INFO("%s: Error allocating snapshot "
James Ketrenosee8e3652005-09-14 09:47:29 -05002364 "buffer %d\n", priv->net_dev->name, i);
James Ketrenos2c86c272005-03-23 17:32:29 -06002365 while (i > 0)
2366 kfree(priv->snapshot[--i]);
2367 priv->snapshot[0] = NULL;
2368 return 0;
2369 }
2370 }
2371
2372 return 1;
2373}
2374
Arjan van de Ven858119e2006-01-14 13:20:43 -08002375static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
James Ketrenos2c86c272005-03-23 17:32:29 -06002376 size_t len, int mode)
2377{
2378 u32 i, j;
2379 u32 tmp;
2380 u8 *s, *d;
2381 u32 ret;
2382
2383 s = in_buf;
2384 if (mode == SEARCH_SNAPSHOT) {
2385 if (!ipw2100_snapshot_alloc(priv))
2386 mode = SEARCH_DISCARD;
2387 }
2388
2389 for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) {
2390 read_nic_dword(priv->net_dev, i, &tmp);
2391 if (mode == SEARCH_SNAPSHOT)
James Ketrenosee8e3652005-09-14 09:47:29 -05002392 *(u32 *) SNAPSHOT_ADDR(i) = tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06002393 if (ret == SEARCH_FAIL) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002394 d = (u8 *) & tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06002395 for (j = 0; j < 4; j++) {
2396 if (*s != *d) {
2397 s = in_buf;
2398 continue;
2399 }
2400
2401 s++;
2402 d++;
2403
2404 if ((s - in_buf) == len)
2405 ret = (i + j) - len + 1;
2406 }
2407 } else if (mode == SEARCH_DISCARD)
2408 return ret;
2409 }
2410
2411 return ret;
2412}
Zhu Yi3c5eca52006-01-24 13:49:26 +08002413#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06002414
2415/*
2416 *
2417 * 0) Disconnect the SKB from the firmware (just unmap)
2418 * 1) Pack the ETH header into the SKB
2419 * 2) Pass the SKB to the network stack
2420 *
2421 * When packet is provided by the firmware, it contains the following:
2422 *
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002423 * . libipw_hdr
2424 * . libipw_snap_hdr
James Ketrenos2c86c272005-03-23 17:32:29 -06002425 *
2426 * The size of the constructed ethernet
2427 *
2428 */
Robert P. J. Dayae800312007-01-31 02:39:40 -05002429#ifdef IPW2100_RX_DEBUG
Jiri Bencc4aee8c2005-08-25 20:04:43 -04002430static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
James Ketrenos2c86c272005-03-23 17:32:29 -06002431#endif
2432
Arjan van de Ven858119e2006-01-14 13:20:43 -08002433static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
James Ketrenos2c86c272005-03-23 17:32:29 -06002434{
Robert P. J. Dayae800312007-01-31 02:39:40 -05002435#ifdef IPW2100_DEBUG_C3
James Ketrenos2c86c272005-03-23 17:32:29 -06002436 struct ipw2100_status *status = &priv->status_queue.drv[i];
2437 u32 match, reg;
2438 int j;
2439#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06002440
Zhu Yia1e695a2005-07-04 14:06:00 +08002441 IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n",
2442 i * sizeof(struct ipw2100_status));
James Ketrenos2c86c272005-03-23 17:32:29 -06002443
Robert P. J. Dayae800312007-01-31 02:39:40 -05002444#ifdef IPW2100_DEBUG_C3
Nick Andrew877d0312009-01-26 11:06:57 +01002445 /* Halt the firmware so we can get a good image */
James Ketrenos2c86c272005-03-23 17:32:29 -06002446 write_register(priv->net_dev, IPW_REG_RESET_REG,
2447 IPW_AUX_HOST_RESET_REG_STOP_MASTER);
2448 j = 5;
2449 do {
2450 udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
2451 read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
2452
2453 if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
2454 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05002455 } while (j--);
James Ketrenos2c86c272005-03-23 17:32:29 -06002456
James Ketrenosee8e3652005-09-14 09:47:29 -05002457 match = ipw2100_match_buf(priv, (u8 *) status,
James Ketrenos2c86c272005-03-23 17:32:29 -06002458 sizeof(struct ipw2100_status),
2459 SEARCH_SNAPSHOT);
2460 if (match < SEARCH_SUCCESS)
2461 IPW_DEBUG_INFO("%s: DMA status match in Firmware at "
2462 "offset 0x%06X, length %d:\n",
2463 priv->net_dev->name, match,
2464 sizeof(struct ipw2100_status));
2465 else
2466 IPW_DEBUG_INFO("%s: No DMA status match in "
2467 "Firmware.\n", priv->net_dev->name);
2468
James Ketrenosee8e3652005-09-14 09:47:29 -05002469 printk_buf((u8 *) priv->status_queue.drv,
James Ketrenos2c86c272005-03-23 17:32:29 -06002470 sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);
2471#endif
2472
2473 priv->fatal_error = IPW2100_ERR_C3_CORRUPTION;
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002474 priv->net_dev->stats.rx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002475 schedule_reset(priv);
2476}
2477
Arjan van de Ven858119e2006-01-14 13:20:43 -08002478static void isr_rx(struct ipw2100_priv *priv, int i,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002479 struct libipw_rx_stats *stats)
James Ketrenos2c86c272005-03-23 17:32:29 -06002480{
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002481 struct net_device *dev = priv->net_dev;
James Ketrenos2c86c272005-03-23 17:32:29 -06002482 struct ipw2100_status *status = &priv->status_queue.drv[i];
2483 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
2484
2485 IPW_DEBUG_RX("Handler...\n");
2486
2487 if (unlikely(status->frame_size > skb_tailroom(packet->skb))) {
2488 IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
2489 " Dropping.\n",
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002490 dev->name,
James Ketrenos2c86c272005-03-23 17:32:29 -06002491 status->frame_size, skb_tailroom(packet->skb));
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002492 dev->stats.rx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002493 return;
2494 }
2495
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002496 if (unlikely(!netif_running(dev))) {
2497 dev->stats.rx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002498 priv->wstats.discard.misc++;
2499 IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
2500 return;
2501 }
James Ketrenos2c86c272005-03-23 17:32:29 -06002502
2503 if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
James Ketrenosee8e3652005-09-14 09:47:29 -05002504 !(priv->status & STATUS_ASSOCIATED))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002505 IPW_DEBUG_DROP("Dropping packet while not associated.\n");
2506 priv->wstats.discard.misc++;
2507 return;
2508 }
2509
James Ketrenos2c86c272005-03-23 17:32:29 -06002510 pci_unmap_single(priv->pci_dev,
2511 packet->dma_addr,
James Ketrenosee8e3652005-09-14 09:47:29 -05002512 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002513
2514 skb_put(packet->skb, status->frame_size);
2515
Robert P. J. Dayae800312007-01-31 02:39:40 -05002516#ifdef IPW2100_RX_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002517 /* Make a copy of the frame so we can dump it to the logs if
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002518 * libipw_rx fails */
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03002519 skb_copy_from_linear_data(packet->skb, packet_data,
2520 min_t(u32, status->frame_size,
2521 IPW_RX_NIC_BUFFER_LENGTH));
James Ketrenos2c86c272005-03-23 17:32:29 -06002522#endif
2523
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002524 if (!libipw_rx(priv->ieee, packet->skb, stats)) {
Robert P. J. Dayae800312007-01-31 02:39:40 -05002525#ifdef IPW2100_RX_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002526 IPW_DEBUG_DROP("%s: Non consumed packet:\n",
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002527 dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002528 printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
2529#endif
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002530 dev->stats.rx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06002531
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002532 /* libipw_rx failed, so it didn't free the SKB */
James Ketrenos2c86c272005-03-23 17:32:29 -06002533 dev_kfree_skb_any(packet->skb);
2534 packet->skb = NULL;
2535 }
2536
2537 /* We need to allocate a new SKB and attach it to the RDB. */
2538 if (unlikely(ipw2100_alloc_skb(priv, packet))) {
Jiri Benc797b4f72005-08-25 20:03:27 -04002539 printk(KERN_WARNING DRV_NAME ": "
James Ketrenosee8e3652005-09-14 09:47:29 -05002540 "%s: Unable to allocate SKB onto RBD ring - disabling "
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002541 "adapter.\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002542 /* TODO: schedule adapter shutdown */
2543 IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
2544 }
2545
2546 /* Update the RDB entry */
2547 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
2548}
2549
Stefan Rompf15745a72006-02-21 18:36:17 +08002550#ifdef CONFIG_IPW2100_MONITOR
2551
2552static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002553 struct libipw_rx_stats *stats)
Stefan Rompf15745a72006-02-21 18:36:17 +08002554{
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002555 struct net_device *dev = priv->net_dev;
Stefan Rompf15745a72006-02-21 18:36:17 +08002556 struct ipw2100_status *status = &priv->status_queue.drv[i];
2557 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
2558
Stefan Rompf15745a72006-02-21 18:36:17 +08002559 /* Magic struct that slots into the radiotap header -- no reason
2560 * to build this manually element by element, we can write it much
2561 * more efficiently than we can parse it. ORDER MATTERS HERE */
2562 struct ipw_rt_hdr {
2563 struct ieee80211_radiotap_header rt_hdr;
2564 s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
2565 } *ipw_rt;
2566
Zhu Yicae16292006-02-21 18:41:14 +08002567 IPW_DEBUG_RX("Handler...\n");
2568
2569 if (unlikely(status->frame_size > skb_tailroom(packet->skb) -
2570 sizeof(struct ipw_rt_hdr))) {
Stefan Rompf15745a72006-02-21 18:36:17 +08002571 IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
2572 " Dropping.\n",
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002573 dev->name,
Zhu Yicae16292006-02-21 18:41:14 +08002574 status->frame_size,
2575 skb_tailroom(packet->skb));
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002576 dev->stats.rx_errors++;
Stefan Rompf15745a72006-02-21 18:36:17 +08002577 return;
2578 }
2579
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002580 if (unlikely(!netif_running(dev))) {
2581 dev->stats.rx_errors++;
Stefan Rompf15745a72006-02-21 18:36:17 +08002582 priv->wstats.discard.misc++;
2583 IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
2584 return;
2585 }
2586
2587 if (unlikely(priv->config & CFG_CRC_CHECK &&
2588 status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
2589 IPW_DEBUG_RX("CRC error in packet. Dropping.\n");
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002590 dev->stats.rx_errors++;
Stefan Rompf15745a72006-02-21 18:36:17 +08002591 return;
2592 }
2593
Zhu Yicae16292006-02-21 18:41:14 +08002594 pci_unmap_single(priv->pci_dev, packet->dma_addr,
Stefan Rompf15745a72006-02-21 18:36:17 +08002595 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
2596 memmove(packet->skb->data + sizeof(struct ipw_rt_hdr),
2597 packet->skb->data, status->frame_size);
2598
2599 ipw_rt = (struct ipw_rt_hdr *) packet->skb->data;
2600
2601 ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
2602 ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
Al Viro1edd3a52007-12-21 00:15:18 -05002603 ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total hdr+data */
Stefan Rompf15745a72006-02-21 18:36:17 +08002604
Al Viro1edd3a52007-12-21 00:15:18 -05002605 ipw_rt->rt_hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
Stefan Rompf15745a72006-02-21 18:36:17 +08002606
2607 ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM;
2608
2609 skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr));
2610
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002611 if (!libipw_rx(priv->ieee, packet->skb, stats)) {
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002612 dev->stats.rx_errors++;
Stefan Rompf15745a72006-02-21 18:36:17 +08002613
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002614 /* libipw_rx failed, so it didn't free the SKB */
Stefan Rompf15745a72006-02-21 18:36:17 +08002615 dev_kfree_skb_any(packet->skb);
2616 packet->skb = NULL;
2617 }
2618
2619 /* We need to allocate a new SKB and attach it to the RDB. */
2620 if (unlikely(ipw2100_alloc_skb(priv, packet))) {
2621 IPW_DEBUG_WARNING(
2622 "%s: Unable to allocate SKB onto RBD ring - disabling "
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00002623 "adapter.\n", dev->name);
Stefan Rompf15745a72006-02-21 18:36:17 +08002624 /* TODO: schedule adapter shutdown */
2625 IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
2626 }
2627
2628 /* Update the RDB entry */
2629 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
2630}
2631
2632#endif
2633
Arjan van de Ven858119e2006-01-14 13:20:43 -08002634static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
James Ketrenos2c86c272005-03-23 17:32:29 -06002635{
2636 struct ipw2100_status *status = &priv->status_queue.drv[i];
2637 struct ipw2100_rx *u = priv->rx_buffers[i].rxp;
2638 u16 frame_type = status->status_fields & STATUS_TYPE_MASK;
2639
2640 switch (frame_type) {
2641 case COMMAND_STATUS_VAL:
2642 return (status->frame_size != sizeof(u->rx_data.command));
2643 case STATUS_CHANGE_VAL:
2644 return (status->frame_size != sizeof(u->rx_data.status));
2645 case HOST_NOTIFICATION_VAL:
2646 return (status->frame_size < sizeof(u->rx_data.notification));
2647 case P80211_DATA_VAL:
2648 case P8023_DATA_VAL:
2649#ifdef CONFIG_IPW2100_MONITOR
2650 return 0;
2651#else
Al Viro1edd3a52007-12-21 00:15:18 -05002652 switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002653 case IEEE80211_FTYPE_MGMT:
2654 case IEEE80211_FTYPE_CTL:
2655 return 0;
2656 case IEEE80211_FTYPE_DATA:
2657 return (status->frame_size >
2658 IPW_MAX_802_11_PAYLOAD_LENGTH);
2659 }
2660#endif
2661 }
2662
2663 return 1;
2664}
2665
2666/*
2667 * ipw2100 interrupts are disabled at this point, and the ISR
2668 * is the only code that calls this method. So, we do not need
2669 * to play with any locks.
2670 *
2671 * RX Queue works as follows:
2672 *
2673 * Read index - firmware places packet in entry identified by the
2674 * Read index and advances Read index. In this manner,
2675 * Read index will always point to the next packet to
2676 * be filled--but not yet valid.
2677 *
2678 * Write index - driver fills this entry with an unused RBD entry.
2679 * This entry has not filled by the firmware yet.
2680 *
2681 * In between the W and R indexes are the RBDs that have been received
2682 * but not yet processed.
2683 *
2684 * The process of handling packets will start at WRITE + 1 and advance
2685 * until it reaches the READ index.
2686 *
2687 * The WRITE index is cached in the variable 'priv->rx_queue.next'.
2688 *
2689 */
Arjan van de Ven858119e2006-01-14 13:20:43 -08002690static void __ipw2100_rx_process(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002691{
2692 struct ipw2100_bd_queue *rxq = &priv->rx_queue;
2693 struct ipw2100_status_queue *sq = &priv->status_queue;
2694 struct ipw2100_rx_packet *packet;
2695 u16 frame_type;
2696 u32 r, w, i, s;
2697 struct ipw2100_rx *u;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002698 struct libipw_rx_stats stats = {
James Ketrenos2c86c272005-03-23 17:32:29 -06002699 .mac_time = jiffies,
2700 };
2701
2702 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r);
2703 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w);
2704
2705 if (r >= rxq->entries) {
2706 IPW_DEBUG_RX("exit - bad read index\n");
2707 return;
2708 }
2709
2710 i = (rxq->next + 1) % rxq->entries;
2711 s = i;
2712 while (i != r) {
2713 /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n",
2714 r, rxq->next, i); */
2715
2716 packet = &priv->rx_buffers[i];
2717
James Ketrenos2c86c272005-03-23 17:32:29 -06002718 /* Sync the DMA for the RX buffer so CPU is sure to get
2719 * the correct values */
2720 pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr,
2721 sizeof(struct ipw2100_rx),
2722 PCI_DMA_FROMDEVICE);
2723
2724 if (unlikely(ipw2100_corruption_check(priv, i))) {
2725 ipw2100_corruption_detected(priv, i);
2726 goto increment;
2727 }
2728
2729 u = packet->rxp;
James Ketrenosee8e3652005-09-14 09:47:29 -05002730 frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK;
James Ketrenos2c86c272005-03-23 17:32:29 -06002731 stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM;
2732 stats.len = sq->drv[i].frame_size;
2733
2734 stats.mask = 0;
2735 if (stats.rssi != 0)
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002736 stats.mask |= LIBIPW_STATMASK_RSSI;
2737 stats.freq = LIBIPW_24GHZ_BAND;
James Ketrenos2c86c272005-03-23 17:32:29 -06002738
James Ketrenosee8e3652005-09-14 09:47:29 -05002739 IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n",
2740 priv->net_dev->name, frame_types[frame_type],
2741 stats.len);
James Ketrenos2c86c272005-03-23 17:32:29 -06002742
2743 switch (frame_type) {
2744 case COMMAND_STATUS_VAL:
2745 /* Reset Rx watchdog */
James Ketrenosee8e3652005-09-14 09:47:29 -05002746 isr_rx_complete_command(priv, &u->rx_data.command);
James Ketrenos2c86c272005-03-23 17:32:29 -06002747 break;
2748
2749 case STATUS_CHANGE_VAL:
2750 isr_status_change(priv, u->rx_data.status);
2751 break;
2752
2753 case P80211_DATA_VAL:
2754 case P8023_DATA_VAL:
2755#ifdef CONFIG_IPW2100_MONITOR
2756 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
Stefan Rompf15745a72006-02-21 18:36:17 +08002757 isr_rx_monitor(priv, i, &stats);
James Ketrenos2c86c272005-03-23 17:32:29 -06002758 break;
2759 }
2760#endif
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002761 if (stats.len < sizeof(struct libipw_hdr_3addr))
James Ketrenos2c86c272005-03-23 17:32:29 -06002762 break;
Al Viro1edd3a52007-12-21 00:15:18 -05002763 switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06002764 case IEEE80211_FTYPE_MGMT:
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002765 libipw_rx_mgt(priv->ieee,
James Ketrenosee8e3652005-09-14 09:47:29 -05002766 &u->rx_data.header, &stats);
James Ketrenos2c86c272005-03-23 17:32:29 -06002767 break;
2768
2769 case IEEE80211_FTYPE_CTL:
2770 break;
2771
2772 case IEEE80211_FTYPE_DATA:
2773 isr_rx(priv, i, &stats);
2774 break;
2775
2776 }
2777 break;
2778 }
2779
James Ketrenosee8e3652005-09-14 09:47:29 -05002780 increment:
James Ketrenos2c86c272005-03-23 17:32:29 -06002781 /* clear status field associated with this RBD */
2782 rxq->drv[i].status.info.field = 0;
2783
2784 i = (i + 1) % rxq->entries;
2785 }
2786
2787 if (i != s) {
2788 /* backtrack one entry, wrapping to end if at 0 */
2789 rxq->next = (i ? i : rxq->entries) - 1;
2790
2791 write_register(priv->net_dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05002792 IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next);
James Ketrenos2c86c272005-03-23 17:32:29 -06002793 }
2794}
2795
James Ketrenos2c86c272005-03-23 17:32:29 -06002796/*
2797 * __ipw2100_tx_process
2798 *
2799 * This routine will determine whether the next packet on
2800 * the fw_pend_list has been processed by the firmware yet.
2801 *
2802 * If not, then it does nothing and returns.
2803 *
2804 * If so, then it removes the item from the fw_pend_list, frees
2805 * any associated storage, and places the item back on the
2806 * free list of its source (either msg_free_list or tx_free_list)
2807 *
2808 * TX Queue works as follows:
2809 *
2810 * Read index - points to the next TBD that the firmware will
2811 * process. The firmware will read the data, and once
2812 * done processing, it will advance the Read index.
2813 *
2814 * Write index - driver fills this entry with an constructed TBD
2815 * entry. The Write index is not advanced until the
2816 * packet has been configured.
2817 *
2818 * In between the W and R indexes are the TBDs that have NOT been
2819 * processed. Lagging behind the R index are packets that have
2820 * been processed but have not been freed by the driver.
2821 *
2822 * In order to free old storage, an internal index will be maintained
2823 * that points to the next packet to be freed. When all used
2824 * packets have been freed, the oldest index will be the same as the
2825 * firmware's read index.
2826 *
2827 * The OLDEST index is cached in the variable 'priv->tx_queue.oldest'
2828 *
2829 * Because the TBD structure can not contain arbitrary data, the
2830 * driver must keep an internal queue of cached allocations such that
2831 * it can put that data back into the tx_free_list and msg_free_list
2832 * for use by future command and data packets.
2833 *
2834 */
Arjan van de Ven858119e2006-01-14 13:20:43 -08002835static int __ipw2100_tx_process(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06002836{
2837 struct ipw2100_bd_queue *txq = &priv->tx_queue;
James Ketrenosee8e3652005-09-14 09:47:29 -05002838 struct ipw2100_bd *tbd;
James Ketrenos2c86c272005-03-23 17:32:29 -06002839 struct list_head *element;
2840 struct ipw2100_tx_packet *packet;
2841 int descriptors_used;
2842 int e, i;
2843 u32 r, w, frag_num = 0;
2844
2845 if (list_empty(&priv->fw_pend_list))
2846 return 0;
2847
2848 element = priv->fw_pend_list.next;
2849
2850 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenosee8e3652005-09-14 09:47:29 -05002851 tbd = &txq->drv[packet->index];
James Ketrenos2c86c272005-03-23 17:32:29 -06002852
2853 /* Determine how many TBD entries must be finished... */
2854 switch (packet->type) {
2855 case COMMAND:
2856 /* COMMAND uses only one slot; don't advance */
2857 descriptors_used = 1;
2858 e = txq->oldest;
2859 break;
2860
2861 case DATA:
2862 /* DATA uses two slots; advance and loop position. */
2863 descriptors_used = tbd->num_fragments;
James Ketrenosee8e3652005-09-14 09:47:29 -05002864 frag_num = tbd->num_fragments - 1;
James Ketrenos2c86c272005-03-23 17:32:29 -06002865 e = txq->oldest + frag_num;
2866 e %= txq->entries;
2867 break;
2868
2869 default:
Jiri Benc797b4f72005-08-25 20:03:27 -04002870 printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05002871 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06002872 return 0;
2873 }
2874
2875 /* if the last TBD is not done by NIC yet, then packet is
2876 * not ready to be released.
2877 *
2878 */
2879 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
2880 &r);
2881 read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
2882 &w);
2883 if (w != txq->next)
Jiri Benc797b4f72005-08-25 20:03:27 -04002884 printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06002885 priv->net_dev->name);
2886
James Ketrenosee8e3652005-09-14 09:47:29 -05002887 /*
James Ketrenos2c86c272005-03-23 17:32:29 -06002888 * txq->next is the index of the last packet written txq->oldest is
2889 * the index of the r is the index of the next packet to be read by
2890 * firmware
2891 */
2892
James Ketrenos2c86c272005-03-23 17:32:29 -06002893 /*
2894 * Quick graphic to help you visualize the following
2895 * if / else statement
2896 *
2897 * ===>| s---->|===============
2898 * e>|
2899 * | a | b | c | d | e | f | g | h | i | j | k | l
2900 * r---->|
2901 * w
2902 *
2903 * w - updated by driver
2904 * r - updated by firmware
2905 * s - start of oldest BD entry (txq->oldest)
2906 * e - end of oldest BD entry
2907 *
2908 */
2909 if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) {
2910 IPW_DEBUG_TX("exit - no processed packets ready to release.\n");
2911 return 0;
2912 }
2913
2914 list_del(element);
2915 DEC_STAT(&priv->fw_pend_stat);
2916
Brice Goglin0f52bf92005-12-01 01:41:46 -08002917#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002918 {
Reinette Chatre21f8a732009-08-18 10:25:05 -07002919 i = txq->oldest;
James Ketrenosee8e3652005-09-14 09:47:29 -05002920 IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
2921 &txq->drv[i],
2922 (u32) (txq->nic + i * sizeof(struct ipw2100_bd)),
2923 txq->drv[i].host_addr, txq->drv[i].buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002924
2925 if (packet->type == DATA) {
2926 i = (i + 1) % txq->entries;
2927
James Ketrenosee8e3652005-09-14 09:47:29 -05002928 IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
2929 &txq->drv[i],
2930 (u32) (txq->nic + i *
2931 sizeof(struct ipw2100_bd)),
2932 (u32) txq->drv[i].host_addr,
2933 txq->drv[i].buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002934 }
2935 }
2936#endif
2937
2938 switch (packet->type) {
2939 case DATA:
2940 if (txq->drv[txq->oldest].status.info.fields.txType != 0)
Jiri Benc797b4f72005-08-25 20:03:27 -04002941 printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
James Ketrenos2c86c272005-03-23 17:32:29 -06002942 "Expecting DATA TBD but pulled "
2943 "something else: ids %d=%d.\n",
2944 priv->net_dev->name, txq->oldest, packet->index);
2945
2946 /* DATA packet; we have to unmap and free the SKB */
James Ketrenos2c86c272005-03-23 17:32:29 -06002947 for (i = 0; i < frag_num; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05002948 tbd = &txq->drv[(packet->index + 1 + i) % txq->entries];
James Ketrenos2c86c272005-03-23 17:32:29 -06002949
James Ketrenosee8e3652005-09-14 09:47:29 -05002950 IPW_DEBUG_TX("TX%d P=%08x L=%d\n",
2951 (packet->index + 1 + i) % txq->entries,
2952 tbd->host_addr, tbd->buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06002953
2954 pci_unmap_single(priv->pci_dev,
2955 tbd->host_addr,
James Ketrenosee8e3652005-09-14 09:47:29 -05002956 tbd->buf_length, PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06002957 }
2958
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04002959 libipw_txb_free(packet->info.d_struct.txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06002960 packet->info.d_struct.txb = NULL;
2961
2962 list_add_tail(element, &priv->tx_free_list);
2963 INC_STAT(&priv->tx_free_stat);
2964
2965 /* We have a free slot in the Tx queue, so wake up the
2966 * transmit layer if it is stopped. */
James Ketrenos82328352005-08-24 22:33:31 -05002967 if (priv->status & STATUS_ASSOCIATED)
James Ketrenos2c86c272005-03-23 17:32:29 -06002968 netif_wake_queue(priv->net_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06002969
2970 /* A packet was processed by the hardware, so update the
2971 * watchdog */
2972 priv->net_dev->trans_start = jiffies;
2973
2974 break;
2975
2976 case COMMAND:
2977 if (txq->drv[txq->oldest].status.info.fields.txType != 1)
Jiri Benc797b4f72005-08-25 20:03:27 -04002978 printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
James Ketrenos2c86c272005-03-23 17:32:29 -06002979 "Expecting COMMAND TBD but pulled "
2980 "something else: ids %d=%d.\n",
2981 priv->net_dev->name, txq->oldest, packet->index);
2982
Brice Goglin0f52bf92005-12-01 01:41:46 -08002983#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06002984 if (packet->info.c_struct.cmd->host_command_reg <
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02002985 ARRAY_SIZE(command_types))
James Ketrenosee8e3652005-09-14 09:47:29 -05002986 IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n",
2987 command_types[packet->info.c_struct.cmd->
2988 host_command_reg],
2989 packet->info.c_struct.cmd->
2990 host_command_reg,
2991 packet->info.c_struct.cmd->cmd_status_reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06002992#endif
2993
2994 list_add_tail(element, &priv->msg_free_list);
2995 INC_STAT(&priv->msg_free_stat);
2996 break;
2997 }
2998
2999 /* advance oldest used TBD pointer to start of next entry */
3000 txq->oldest = (e + 1) % txq->entries;
3001 /* increase available TBDs number */
3002 txq->available += descriptors_used;
3003 SET_STAT(&priv->txq_stat, txq->available);
3004
3005 IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003006 jiffies - packet->jiffy_start);
James Ketrenos2c86c272005-03-23 17:32:29 -06003007
3008 return (!list_empty(&priv->fw_pend_list));
3009}
3010
James Ketrenos2c86c272005-03-23 17:32:29 -06003011static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
3012{
3013 int i = 0;
3014
James Ketrenosee8e3652005-09-14 09:47:29 -05003015 while (__ipw2100_tx_process(priv) && i < 200)
3016 i++;
James Ketrenos2c86c272005-03-23 17:32:29 -06003017
3018 if (i == 200) {
Jiri Benc19f7f742005-08-25 20:02:10 -04003019 printk(KERN_WARNING DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06003020 "%s: Driver is running slow (%d iters).\n",
3021 priv->net_dev->name, i);
3022 }
3023}
3024
Jiri Benc19f7f742005-08-25 20:02:10 -04003025static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06003026{
3027 struct list_head *element;
3028 struct ipw2100_tx_packet *packet;
3029 struct ipw2100_bd_queue *txq = &priv->tx_queue;
3030 struct ipw2100_bd *tbd;
3031 int next = txq->next;
3032
3033 while (!list_empty(&priv->msg_pend_list)) {
3034 /* if there isn't enough space in TBD queue, then
3035 * don't stuff a new one in.
3036 * NOTE: 3 are needed as a command will take one,
3037 * and there is a minimum of 2 that must be
3038 * maintained between the r and w indexes
3039 */
3040 if (txq->available <= 3) {
3041 IPW_DEBUG_TX("no room in tx_queue\n");
3042 break;
3043 }
3044
3045 element = priv->msg_pend_list.next;
3046 list_del(element);
3047 DEC_STAT(&priv->msg_pend_stat);
3048
James Ketrenosee8e3652005-09-14 09:47:29 -05003049 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06003050
John W. Linvilleaa0d52c2010-08-10 13:08:11 -04003051 IPW_DEBUG_TX("using TBD at virt=%p, phys=%04X\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003052 &txq->drv[txq->next],
John W. Linvilleaa0d52c2010-08-10 13:08:11 -04003053 (u32) (txq->nic + txq->next *
James Ketrenosee8e3652005-09-14 09:47:29 -05003054 sizeof(struct ipw2100_bd)));
James Ketrenos2c86c272005-03-23 17:32:29 -06003055
3056 packet->index = txq->next;
3057
3058 tbd = &txq->drv[txq->next];
3059
3060 /* initialize TBD */
3061 tbd->host_addr = packet->info.c_struct.cmd_phys;
3062 tbd->buf_length = sizeof(struct ipw2100_cmd_header);
3063 /* not marking number of fragments causes problems
3064 * with f/w debug version */
3065 tbd->num_fragments = 1;
3066 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003067 IPW_BD_STATUS_TX_FRAME_COMMAND |
3068 IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06003069
3070 /* update TBD queue counters */
3071 txq->next++;
3072 txq->next %= txq->entries;
3073 txq->available--;
3074 DEC_STAT(&priv->txq_stat);
3075
3076 list_add_tail(element, &priv->fw_pend_list);
3077 INC_STAT(&priv->fw_pend_stat);
3078 }
3079
3080 if (txq->next != next) {
3081 /* kick off the DMA by notifying firmware the
3082 * write index has moved; make sure TBD stores are sync'd */
3083 wmb();
3084 write_register(priv->net_dev,
3085 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
3086 txq->next);
3087 }
3088}
3089
James Ketrenos2c86c272005-03-23 17:32:29 -06003090/*
Jiri Benc19f7f742005-08-25 20:02:10 -04003091 * ipw2100_tx_send_data
James Ketrenos2c86c272005-03-23 17:32:29 -06003092 *
3093 */
Jiri Benc19f7f742005-08-25 20:02:10 -04003094static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06003095{
3096 struct list_head *element;
3097 struct ipw2100_tx_packet *packet;
3098 struct ipw2100_bd_queue *txq = &priv->tx_queue;
3099 struct ipw2100_bd *tbd;
3100 int next = txq->next;
James Ketrenosee8e3652005-09-14 09:47:29 -05003101 int i = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06003102 struct ipw2100_data_header *ipw_hdr;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003103 struct libipw_hdr_3addr *hdr;
James Ketrenos2c86c272005-03-23 17:32:29 -06003104
3105 while (!list_empty(&priv->tx_pend_list)) {
3106 /* if there isn't enough space in TBD queue, then
3107 * don't stuff a new one in.
3108 * NOTE: 4 are needed as a data will take two,
3109 * and there is a minimum of 2 that must be
3110 * maintained between the r and w indexes
3111 */
3112 element = priv->tx_pend_list.next;
James Ketrenosee8e3652005-09-14 09:47:29 -05003113 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06003114
3115 if (unlikely(1 + packet->info.d_struct.txb->nr_frags >
3116 IPW_MAX_BDS)) {
3117 /* TODO: Support merging buffers if more than
3118 * IPW_MAX_BDS are used */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02003119 IPW_DEBUG_INFO("%s: Maximum BD threshold exceeded. "
James Ketrenosee8e3652005-09-14 09:47:29 -05003120 "Increase fragmentation level.\n",
3121 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003122 }
3123
James Ketrenosee8e3652005-09-14 09:47:29 -05003124 if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003125 IPW_DEBUG_TX("no room in tx_queue\n");
3126 break;
3127 }
3128
3129 list_del(element);
3130 DEC_STAT(&priv->tx_pend_stat);
3131
3132 tbd = &txq->drv[txq->next];
3133
3134 packet->index = txq->next;
3135
3136 ipw_hdr = packet->info.d_struct.data;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003137 hdr = (struct libipw_hdr_3addr *)packet->info.d_struct.txb->
James Ketrenosee8e3652005-09-14 09:47:29 -05003138 fragments[0]->data;
James Ketrenos2c86c272005-03-23 17:32:29 -06003139
3140 if (priv->ieee->iw_mode == IW_MODE_INFRA) {
3141 /* To DS: Addr1 = BSSID, Addr2 = SA,
3142 Addr3 = DA */
3143 memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
3144 memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN);
3145 } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
3146 /* not From/To DS: Addr1 = DA, Addr2 = SA,
3147 Addr3 = BSSID */
3148 memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
3149 memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN);
3150 }
3151
3152 ipw_hdr->host_command_reg = SEND;
3153 ipw_hdr->host_command_reg1 = 0;
3154
3155 /* For now we only support host based encryption */
3156 ipw_hdr->needs_encryption = 0;
3157 ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted;
3158 if (packet->info.d_struct.txb->nr_frags > 1)
3159 ipw_hdr->fragment_size =
James Ketrenosee8e3652005-09-14 09:47:29 -05003160 packet->info.d_struct.txb->frag_size -
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003161 LIBIPW_3ADDR_LEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06003162 else
3163 ipw_hdr->fragment_size = 0;
3164
3165 tbd->host_addr = packet->info.d_struct.data_phys;
3166 tbd->buf_length = sizeof(struct ipw2100_data_header);
3167 tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags;
3168 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003169 IPW_BD_STATUS_TX_FRAME_802_3 |
3170 IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
James Ketrenos2c86c272005-03-23 17:32:29 -06003171 txq->next++;
3172 txq->next %= txq->entries;
3173
James Ketrenosee8e3652005-09-14 09:47:29 -05003174 IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n",
3175 packet->index, tbd->host_addr, tbd->buf_length);
Brice Goglin0f52bf92005-12-01 01:41:46 -08003176#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06003177 if (packet->info.d_struct.txb->nr_frags > 1)
3178 IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
3179 packet->info.d_struct.txb->nr_frags);
3180#endif
3181
James Ketrenosee8e3652005-09-14 09:47:29 -05003182 for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
3183 tbd = &txq->drv[txq->next];
James Ketrenos2c86c272005-03-23 17:32:29 -06003184 if (i == packet->info.d_struct.txb->nr_frags - 1)
3185 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003186 IPW_BD_STATUS_TX_FRAME_802_3 |
3187 IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06003188 else
3189 tbd->status.info.field =
James Ketrenosee8e3652005-09-14 09:47:29 -05003190 IPW_BD_STATUS_TX_FRAME_802_3 |
3191 IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
James Ketrenos2c86c272005-03-23 17:32:29 -06003192
3193 tbd->buf_length = packet->info.d_struct.txb->
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003194 fragments[i]->len - LIBIPW_3ADDR_LEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06003195
James Ketrenosee8e3652005-09-14 09:47:29 -05003196 tbd->host_addr = pci_map_single(priv->pci_dev,
3197 packet->info.d_struct.
3198 txb->fragments[i]->
3199 data +
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003200 LIBIPW_3ADDR_LEN,
James Ketrenosee8e3652005-09-14 09:47:29 -05003201 tbd->buf_length,
3202 PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003203
James Ketrenosee8e3652005-09-14 09:47:29 -05003204 IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n",
3205 txq->next, tbd->host_addr,
3206 tbd->buf_length);
James Ketrenos2c86c272005-03-23 17:32:29 -06003207
James Ketrenosee8e3652005-09-14 09:47:29 -05003208 pci_dma_sync_single_for_device(priv->pci_dev,
3209 tbd->host_addr,
3210 tbd->buf_length,
3211 PCI_DMA_TODEVICE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003212
3213 txq->next++;
3214 txq->next %= txq->entries;
James Ketrenosee8e3652005-09-14 09:47:29 -05003215 }
James Ketrenos2c86c272005-03-23 17:32:29 -06003216
3217 txq->available -= 1 + packet->info.d_struct.txb->nr_frags;
3218 SET_STAT(&priv->txq_stat, txq->available);
3219
3220 list_add_tail(element, &priv->fw_pend_list);
3221 INC_STAT(&priv->fw_pend_stat);
3222 }
3223
3224 if (txq->next != next) {
3225 /* kick off the DMA by notifying firmware the
3226 * write index has moved; make sure TBD stores are sync'd */
3227 write_register(priv->net_dev,
3228 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
3229 txq->next);
3230 }
James Ketrenos2c86c272005-03-23 17:32:29 -06003231}
3232
3233static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
3234{
3235 struct net_device *dev = priv->net_dev;
3236 unsigned long flags;
3237 u32 inta, tmp;
3238
3239 spin_lock_irqsave(&priv->low_lock, flags);
3240 ipw2100_disable_interrupts(priv);
3241
3242 read_register(dev, IPW_REG_INTA, &inta);
3243
3244 IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n",
3245 (unsigned long)inta & IPW_INTERRUPT_MASK);
3246
3247 priv->in_isr++;
3248 priv->interrupts++;
3249
3250 /* We do not loop and keep polling for more interrupts as this
3251 * is frowned upon and doesn't play nicely with other potentially
3252 * chained IRQs */
3253 IPW_DEBUG_ISR("INTA: 0x%08lX\n",
3254 (unsigned long)inta & IPW_INTERRUPT_MASK);
3255
3256 if (inta & IPW2100_INTA_FATAL_ERROR) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003257 printk(KERN_WARNING DRV_NAME
James Ketrenosee8e3652005-09-14 09:47:29 -05003258 ": Fatal interrupt. Scheduling firmware restart.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003259 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003260 write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003261
3262 read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error);
3263 IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n",
3264 priv->net_dev->name, priv->fatal_error);
3265
3266 read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp);
3267 IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n",
3268 priv->net_dev->name, tmp);
3269
3270 /* Wake up any sleeping jobs */
3271 schedule_reset(priv);
3272 }
3273
3274 if (inta & IPW2100_INTA_PARITY_ERROR) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003275 printk(KERN_ERR DRV_NAME
Frans Pop9fd1ea42010-03-24 19:46:31 +01003276 ": ***** PARITY ERROR INTERRUPT !!!!\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003277 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003278 write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003279 }
3280
3281 if (inta & IPW2100_INTA_RX_TRANSFER) {
3282 IPW_DEBUG_ISR("RX interrupt\n");
3283
3284 priv->rx_interrupts++;
3285
James Ketrenosee8e3652005-09-14 09:47:29 -05003286 write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER);
James Ketrenos2c86c272005-03-23 17:32:29 -06003287
3288 __ipw2100_rx_process(priv);
3289 __ipw2100_tx_complete(priv);
3290 }
3291
3292 if (inta & IPW2100_INTA_TX_TRANSFER) {
3293 IPW_DEBUG_ISR("TX interrupt\n");
3294
3295 priv->tx_interrupts++;
3296
James Ketrenosee8e3652005-09-14 09:47:29 -05003297 write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER);
James Ketrenos2c86c272005-03-23 17:32:29 -06003298
3299 __ipw2100_tx_complete(priv);
Jiri Benc19f7f742005-08-25 20:02:10 -04003300 ipw2100_tx_send_commands(priv);
3301 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06003302 }
3303
3304 if (inta & IPW2100_INTA_TX_COMPLETE) {
3305 IPW_DEBUG_ISR("TX complete\n");
3306 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003307 write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003308
3309 __ipw2100_tx_complete(priv);
3310 }
3311
3312 if (inta & IPW2100_INTA_EVENT_INTERRUPT) {
3313 /* ipw2100_handle_event(dev); */
3314 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003315 write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT);
James Ketrenos2c86c272005-03-23 17:32:29 -06003316 }
3317
3318 if (inta & IPW2100_INTA_FW_INIT_DONE) {
3319 IPW_DEBUG_ISR("FW init done interrupt\n");
3320 priv->inta_other++;
3321
3322 read_register(dev, IPW_REG_INTA, &tmp);
3323 if (tmp & (IPW2100_INTA_FATAL_ERROR |
3324 IPW2100_INTA_PARITY_ERROR)) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003325 write_register(dev, IPW_REG_INTA,
3326 IPW2100_INTA_FATAL_ERROR |
3327 IPW2100_INTA_PARITY_ERROR);
James Ketrenos2c86c272005-03-23 17:32:29 -06003328 }
3329
James Ketrenosee8e3652005-09-14 09:47:29 -05003330 write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003331 }
3332
3333 if (inta & IPW2100_INTA_STATUS_CHANGE) {
3334 IPW_DEBUG_ISR("Status change interrupt\n");
3335 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003336 write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003337 }
3338
3339 if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) {
3340 IPW_DEBUG_ISR("slave host mode interrupt\n");
3341 priv->inta_other++;
James Ketrenosee8e3652005-09-14 09:47:29 -05003342 write_register(dev, IPW_REG_INTA,
3343 IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
James Ketrenos2c86c272005-03-23 17:32:29 -06003344 }
3345
3346 priv->in_isr--;
3347 ipw2100_enable_interrupts(priv);
3348
3349 spin_unlock_irqrestore(&priv->low_lock, flags);
3350
3351 IPW_DEBUG_ISR("exit\n");
3352}
3353
David Howells7d12e782006-10-05 14:55:46 +01003354static irqreturn_t ipw2100_interrupt(int irq, void *data)
James Ketrenos2c86c272005-03-23 17:32:29 -06003355{
3356 struct ipw2100_priv *priv = data;
3357 u32 inta, inta_mask;
3358
3359 if (!data)
3360 return IRQ_NONE;
3361
James Ketrenosee8e3652005-09-14 09:47:29 -05003362 spin_lock(&priv->low_lock);
James Ketrenos2c86c272005-03-23 17:32:29 -06003363
3364 /* We check to see if we should be ignoring interrupts before
3365 * we touch the hardware. During ucode load if we try and handle
3366 * an interrupt we can cause keyboard problems as well as cause
3367 * the ucode to fail to initialize */
3368 if (!(priv->status & STATUS_INT_ENABLED)) {
3369 /* Shared IRQ */
3370 goto none;
3371 }
3372
3373 read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
3374 read_register(priv->net_dev, IPW_REG_INTA, &inta);
3375
3376 if (inta == 0xFFFFFFFF) {
3377 /* Hardware disappeared */
Jiri Benc797b4f72005-08-25 20:03:27 -04003378 printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06003379 goto none;
3380 }
3381
3382 inta &= IPW_INTERRUPT_MASK;
3383
3384 if (!(inta & inta_mask)) {
3385 /* Shared interrupt */
3386 goto none;
3387 }
3388
3389 /* We disable the hardware interrupt here just to prevent unneeded
3390 * calls to be made. We disable this again within the actual
3391 * work tasklet, so if another part of the code re-enables the
3392 * interrupt, that is fine */
3393 ipw2100_disable_interrupts(priv);
3394
3395 tasklet_schedule(&priv->irq_tasklet);
James Ketrenosee8e3652005-09-14 09:47:29 -05003396 spin_unlock(&priv->low_lock);
James Ketrenos2c86c272005-03-23 17:32:29 -06003397
3398 return IRQ_HANDLED;
James Ketrenosee8e3652005-09-14 09:47:29 -05003399 none:
James Ketrenos2c86c272005-03-23 17:32:29 -06003400 spin_unlock(&priv->low_lock);
3401 return IRQ_NONE;
3402}
3403
Stephen Hemmingerd0cf9c02009-08-31 19:50:57 +00003404static netdev_tx_t ipw2100_tx(struct libipw_txb *txb,
3405 struct net_device *dev, int pri)
James Ketrenos2c86c272005-03-23 17:32:29 -06003406{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04003407 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06003408 struct list_head *element;
3409 struct ipw2100_tx_packet *packet;
3410 unsigned long flags;
3411
3412 spin_lock_irqsave(&priv->low_lock, flags);
3413
3414 if (!(priv->status & STATUS_ASSOCIATED)) {
3415 IPW_DEBUG_INFO("Can not transmit when not connected.\n");
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00003416 priv->net_dev->stats.tx_carrier_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06003417 netif_stop_queue(dev);
3418 goto fail_unlock;
3419 }
3420
3421 if (list_empty(&priv->tx_free_list))
3422 goto fail_unlock;
3423
3424 element = priv->tx_free_list.next;
3425 packet = list_entry(element, struct ipw2100_tx_packet, list);
3426
3427 packet->info.d_struct.txb = txb;
3428
James Ketrenosee8e3652005-09-14 09:47:29 -05003429 IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len);
3430 printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len);
James Ketrenos2c86c272005-03-23 17:32:29 -06003431
3432 packet->jiffy_start = jiffies;
3433
3434 list_del(element);
3435 DEC_STAT(&priv->tx_free_stat);
3436
3437 list_add_tail(element, &priv->tx_pend_list);
3438 INC_STAT(&priv->tx_pend_stat);
3439
Jiri Benc19f7f742005-08-25 20:02:10 -04003440 ipw2100_tx_send_data(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06003441
3442 spin_unlock_irqrestore(&priv->low_lock, flags);
Stephen Hemmingerd0cf9c02009-08-31 19:50:57 +00003443 return NETDEV_TX_OK;
James Ketrenos2c86c272005-03-23 17:32:29 -06003444
Stephen Hemmingerd0cf9c02009-08-31 19:50:57 +00003445fail_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -06003446 netif_stop_queue(dev);
3447 spin_unlock_irqrestore(&priv->low_lock, flags);
Stephen Hemmingerd0cf9c02009-08-31 19:50:57 +00003448 return NETDEV_TX_BUSY;
James Ketrenos2c86c272005-03-23 17:32:29 -06003449}
3450
James Ketrenos2c86c272005-03-23 17:32:29 -06003451static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
3452{
3453 int i, j, err = -EINVAL;
3454 void *v;
3455 dma_addr_t p;
3456
James Ketrenosee8e3652005-09-14 09:47:29 -05003457 priv->msg_buffers =
Joe Perchesefe4c452010-05-31 20:23:15 -07003458 kmalloc(IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet),
3459 GFP_KERNEL);
James Ketrenos2c86c272005-03-23 17:32:29 -06003460 if (!priv->msg_buffers) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003461 printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg "
James Ketrenos2c86c272005-03-23 17:32:29 -06003462 "buffers.\n", priv->net_dev->name);
3463 return -ENOMEM;
3464 }
3465
3466 for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003467 v = pci_alloc_consistent(priv->pci_dev,
3468 sizeof(struct ipw2100_cmd_header), &p);
James Ketrenos2c86c272005-03-23 17:32:29 -06003469 if (!v) {
Jiri Benc797b4f72005-08-25 20:03:27 -04003470 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06003471 "%s: PCI alloc failed for msg "
James Ketrenosee8e3652005-09-14 09:47:29 -05003472 "buffers.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003473 err = -ENOMEM;
3474 break;
3475 }
3476
3477 memset(v, 0, sizeof(struct ipw2100_cmd_header));
3478
3479 priv->msg_buffers[i].type = COMMAND;
3480 priv->msg_buffers[i].info.c_struct.cmd =
James Ketrenosee8e3652005-09-14 09:47:29 -05003481 (struct ipw2100_cmd_header *)v;
James Ketrenos2c86c272005-03-23 17:32:29 -06003482 priv->msg_buffers[i].info.c_struct.cmd_phys = p;
3483 }
3484
3485 if (i == IPW_COMMAND_POOL_SIZE)
3486 return 0;
3487
3488 for (j = 0; j < i; j++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05003489 pci_free_consistent(priv->pci_dev,
3490 sizeof(struct ipw2100_cmd_header),
3491 priv->msg_buffers[j].info.c_struct.cmd,
3492 priv->msg_buffers[j].info.c_struct.
3493 cmd_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06003494 }
3495
3496 kfree(priv->msg_buffers);
3497 priv->msg_buffers = NULL;
3498
3499 return err;
3500}
3501
3502static int ipw2100_msg_initialize(struct ipw2100_priv *priv)
3503{
3504 int i;
3505
3506 INIT_LIST_HEAD(&priv->msg_free_list);
3507 INIT_LIST_HEAD(&priv->msg_pend_list);
3508
3509 for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++)
3510 list_add_tail(&priv->msg_buffers[i].list, &priv->msg_free_list);
3511 SET_STAT(&priv->msg_free_stat, i);
3512
3513 return 0;
3514}
3515
3516static void ipw2100_msg_free(struct ipw2100_priv *priv)
3517{
3518 int i;
3519
3520 if (!priv->msg_buffers)
3521 return;
3522
3523 for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
3524 pci_free_consistent(priv->pci_dev,
3525 sizeof(struct ipw2100_cmd_header),
3526 priv->msg_buffers[i].info.c_struct.cmd,
James Ketrenosee8e3652005-09-14 09:47:29 -05003527 priv->msg_buffers[i].info.c_struct.
3528 cmd_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06003529 }
3530
3531 kfree(priv->msg_buffers);
3532 priv->msg_buffers = NULL;
3533}
3534
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003535static ssize_t show_pci(struct device *d, struct device_attribute *attr,
3536 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003537{
3538 struct pci_dev *pci_dev = container_of(d, struct pci_dev, dev);
3539 char *out = buf;
3540 int i, j;
3541 u32 val;
3542
3543 for (i = 0; i < 16; i++) {
3544 out += sprintf(out, "[%08X] ", i * 16);
3545 for (j = 0; j < 16; j += 4) {
3546 pci_read_config_dword(pci_dev, i * 16 + j, &val);
3547 out += sprintf(out, "%08X ", val);
3548 }
3549 out += sprintf(out, "\n");
3550 }
3551
3552 return out - buf;
3553}
James Ketrenosee8e3652005-09-14 09:47:29 -05003554
James Ketrenos2c86c272005-03-23 17:32:29 -06003555static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL);
3556
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003557static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
3558 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003559{
Greg Kroah-Hartman928841b2009-04-30 23:02:47 -07003560 struct ipw2100_priv *p = dev_get_drvdata(d);
James Ketrenos2c86c272005-03-23 17:32:29 -06003561 return sprintf(buf, "0x%08x\n", (int)p->config);
3562}
James Ketrenosee8e3652005-09-14 09:47:29 -05003563
James Ketrenos2c86c272005-03-23 17:32:29 -06003564static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
3565
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003566static ssize_t show_status(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003567 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003568{
Greg Kroah-Hartman928841b2009-04-30 23:02:47 -07003569 struct ipw2100_priv *p = dev_get_drvdata(d);
James Ketrenos2c86c272005-03-23 17:32:29 -06003570 return sprintf(buf, "0x%08x\n", (int)p->status);
3571}
James Ketrenosee8e3652005-09-14 09:47:29 -05003572
James Ketrenos2c86c272005-03-23 17:32:29 -06003573static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
3574
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003575static ssize_t show_capability(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003576 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003577{
Greg Kroah-Hartman928841b2009-04-30 23:02:47 -07003578 struct ipw2100_priv *p = dev_get_drvdata(d);
James Ketrenos2c86c272005-03-23 17:32:29 -06003579 return sprintf(buf, "0x%08x\n", (int)p->capability);
3580}
James Ketrenos2c86c272005-03-23 17:32:29 -06003581
James Ketrenosee8e3652005-09-14 09:47:29 -05003582static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL);
James Ketrenos2c86c272005-03-23 17:32:29 -06003583
3584#define IPW2100_REG(x) { IPW_ ##x, #x }
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003585static const struct {
James Ketrenos2c86c272005-03-23 17:32:29 -06003586 u32 addr;
3587 const char *name;
3588} hw_data[] = {
James Ketrenosee8e3652005-09-14 09:47:29 -05003589IPW2100_REG(REG_GP_CNTRL),
3590 IPW2100_REG(REG_GPIO),
3591 IPW2100_REG(REG_INTA),
3592 IPW2100_REG(REG_INTA_MASK), IPW2100_REG(REG_RESET_REG),};
James Ketrenos2c86c272005-03-23 17:32:29 -06003593#define IPW2100_NIC(x, s) { x, #x, s }
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003594static const struct {
James Ketrenos2c86c272005-03-23 17:32:29 -06003595 u32 addr;
3596 const char *name;
3597 size_t size;
3598} nic_data[] = {
James Ketrenosee8e3652005-09-14 09:47:29 -05003599IPW2100_NIC(IPW2100_CONTROL_REG, 2),
3600 IPW2100_NIC(0x210014, 1), IPW2100_NIC(0x210000, 1),};
James Ketrenos2c86c272005-03-23 17:32:29 -06003601#define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d }
Jiri Bencc4aee8c2005-08-25 20:04:43 -04003602static const struct {
James Ketrenos2c86c272005-03-23 17:32:29 -06003603 u8 index;
3604 const char *name;
3605 const char *desc;
3606} ord_data[] = {
James Ketrenosee8e3652005-09-14 09:47:29 -05003607IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
3608 IPW2100_ORD(STAT_TX_HOST_COMPLETE,
3609 "successful Host Tx's (MSDU)"),
3610 IPW2100_ORD(STAT_TX_DIR_DATA,
3611 "successful Directed Tx's (MSDU)"),
3612 IPW2100_ORD(STAT_TX_DIR_DATA1,
3613 "successful Directed Tx's (MSDU) @ 1MB"),
3614 IPW2100_ORD(STAT_TX_DIR_DATA2,
3615 "successful Directed Tx's (MSDU) @ 2MB"),
3616 IPW2100_ORD(STAT_TX_DIR_DATA5_5,
3617 "successful Directed Tx's (MSDU) @ 5_5MB"),
3618 IPW2100_ORD(STAT_TX_DIR_DATA11,
3619 "successful Directed Tx's (MSDU) @ 11MB"),
3620 IPW2100_ORD(STAT_TX_NODIR_DATA1,
3621 "successful Non_Directed Tx's (MSDU) @ 1MB"),
3622 IPW2100_ORD(STAT_TX_NODIR_DATA2,
3623 "successful Non_Directed Tx's (MSDU) @ 2MB"),
3624 IPW2100_ORD(STAT_TX_NODIR_DATA5_5,
3625 "successful Non_Directed Tx's (MSDU) @ 5.5MB"),
3626 IPW2100_ORD(STAT_TX_NODIR_DATA11,
3627 "successful Non_Directed Tx's (MSDU) @ 11MB"),
3628 IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"),
3629 IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"),
3630 IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"),
3631 IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"),
3632 IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"),
3633 IPW2100_ORD(STAT_TX_ASSN_RESP,
3634 "successful Association response Tx's"),
3635 IPW2100_ORD(STAT_TX_REASSN,
3636 "successful Reassociation Tx's"),
3637 IPW2100_ORD(STAT_TX_REASSN_RESP,
3638 "successful Reassociation response Tx's"),
3639 IPW2100_ORD(STAT_TX_PROBE,
3640 "probes successfully transmitted"),
3641 IPW2100_ORD(STAT_TX_PROBE_RESP,
3642 "probe responses successfully transmitted"),
3643 IPW2100_ORD(STAT_TX_BEACON, "tx beacon"),
3644 IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"),
3645 IPW2100_ORD(STAT_TX_DISASSN,
3646 "successful Disassociation TX"),
3647 IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"),
3648 IPW2100_ORD(STAT_TX_DEAUTH,
3649 "successful Deauthentication TX"),
3650 IPW2100_ORD(STAT_TX_TOTAL_BYTES,
3651 "Total successful Tx data bytes"),
3652 IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"),
3653 IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"),
3654 IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"),
3655 IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"),
3656 IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"),
3657 IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"),
3658 IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,
3659 "times max tries in a hop failed"),
3660 IPW2100_ORD(STAT_TX_DISASSN_FAIL,
3661 "times disassociation failed"),
3662 IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"),
3663 IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"),
3664 IPW2100_ORD(STAT_RX_HOST, "packets passed to host"),
3665 IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"),
3666 IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"),
3667 IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"),
3668 IPW2100_ORD(STAT_RX_DIR_DATA5_5,
3669 "directed packets at 5.5MB"),
3670 IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"),
3671 IPW2100_ORD(STAT_RX_NODIR_DATA, "nondirected packets"),
3672 IPW2100_ORD(STAT_RX_NODIR_DATA1,
3673 "nondirected packets at 1MB"),
3674 IPW2100_ORD(STAT_RX_NODIR_DATA2,
3675 "nondirected packets at 2MB"),
3676 IPW2100_ORD(STAT_RX_NODIR_DATA5_5,
3677 "nondirected packets at 5.5MB"),
3678 IPW2100_ORD(STAT_RX_NODIR_DATA11,
3679 "nondirected packets at 11MB"),
3680 IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"),
3681 IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), IPW2100_ORD(STAT_RX_CTS,
3682 "Rx CTS"),
3683 IPW2100_ORD(STAT_RX_ACK, "Rx ACK"),
3684 IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"),
3685 IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"),
3686 IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"),
3687 IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"),
3688 IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"),
3689 IPW2100_ORD(STAT_RX_REASSN_RESP,
3690 "Reassociation response Rx's"),
3691 IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"),
3692 IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"),
3693 IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"),
3694 IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"),
3695 IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"),
3696 IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"),
3697 IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"),
3698 IPW2100_ORD(STAT_RX_TOTAL_BYTES,
3699 "Total rx data bytes received"),
3700 IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"),
3701 IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"),
3702 IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"),
3703 IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"),
3704 IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"),
3705 IPW2100_ORD(STAT_RX_DUPLICATE1,
3706 "duplicate rx packets at 1MB"),
3707 IPW2100_ORD(STAT_RX_DUPLICATE2,
3708 "duplicate rx packets at 2MB"),
3709 IPW2100_ORD(STAT_RX_DUPLICATE5_5,
3710 "duplicate rx packets at 5.5MB"),
3711 IPW2100_ORD(STAT_RX_DUPLICATE11,
3712 "duplicate rx packets at 11MB"),
3713 IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
3714 IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"),
3715 IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"),
3716 IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"),
3717 IPW2100_ORD(STAT_RX_INVALID_PROTOCOL,
3718 "rx frames with invalid protocol"),
3719 IPW2100_ORD(SYS_BOOT_TIME, "Boot time"),
3720 IPW2100_ORD(STAT_RX_NO_BUFFER,
3721 "rx frames rejected due to no buffer"),
3722 IPW2100_ORD(STAT_RX_MISSING_FRAG,
3723 "rx frames dropped due to missing fragment"),
3724 IPW2100_ORD(STAT_RX_ORPHAN_FRAG,
3725 "rx frames dropped due to non-sequential fragment"),
3726 IPW2100_ORD(STAT_RX_ORPHAN_FRAME,
3727 "rx frames dropped due to unmatched 1st frame"),
3728 IPW2100_ORD(STAT_RX_FRAG_AGEOUT,
3729 "rx frames dropped due to uncompleted frame"),
3730 IPW2100_ORD(STAT_RX_ICV_ERRORS,
3731 "ICV errors during decryption"),
3732 IPW2100_ORD(STAT_PSP_SUSPENSION, "times adapter suspended"),
3733 IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"),
3734 IPW2100_ORD(STAT_PSP_POLL_TIMEOUT,
3735 "poll response timeouts"),
3736 IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT,
3737 "timeouts waiting for last {broad,multi}cast pkt"),
3738 IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"),
3739 IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"),
3740 IPW2100_ORD(STAT_PSP_STATION_ID, "PSP Station ID"),
3741 IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"),
3742 IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,
3743 "current calculation of % missed beacons"),
3744 IPW2100_ORD(STAT_PERCENT_RETRIES,
3745 "current calculation of % missed tx retries"),
3746 IPW2100_ORD(ASSOCIATED_AP_PTR,
3747 "0 if not associated, else pointer to AP table entry"),
3748 IPW2100_ORD(AVAILABLE_AP_CNT,
3749 "AP's decsribed in the AP table"),
3750 IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"),
3751 IPW2100_ORD(STAT_AP_ASSNS, "associations"),
3752 IPW2100_ORD(STAT_ASSN_FAIL, "association failures"),
3753 IPW2100_ORD(STAT_ASSN_RESP_FAIL,
3754 "failures due to response fail"),
3755 IPW2100_ORD(STAT_FULL_SCANS, "full scans"),
3756 IPW2100_ORD(CARD_DISABLED, "Card Disabled"),
3757 IPW2100_ORD(STAT_ROAM_INHIBIT,
3758 "times roaming was inhibited due to activity"),
3759 IPW2100_ORD(RSSI_AT_ASSN,
3760 "RSSI of associated AP at time of association"),
3761 IPW2100_ORD(STAT_ASSN_CAUSE1,
3762 "reassociation: no probe response or TX on hop"),
3763 IPW2100_ORD(STAT_ASSN_CAUSE2,
3764 "reassociation: poor tx/rx quality"),
3765 IPW2100_ORD(STAT_ASSN_CAUSE3,
3766 "reassociation: tx/rx quality (excessive AP load"),
3767 IPW2100_ORD(STAT_ASSN_CAUSE4,
3768 "reassociation: AP RSSI level"),
3769 IPW2100_ORD(STAT_ASSN_CAUSE5,
3770 "reassociations due to load leveling"),
3771 IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"),
3772 IPW2100_ORD(STAT_AUTH_RESP_FAIL,
3773 "times authentication response failed"),
3774 IPW2100_ORD(STATION_TABLE_CNT,
3775 "entries in association table"),
3776 IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"),
3777 IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"),
3778 IPW2100_ORD(COUNTRY_CODE,
3779 "IEEE country code as recv'd from beacon"),
3780 IPW2100_ORD(COUNTRY_CHANNELS,
3781 "channels suported by country"),
3782 IPW2100_ORD(RESET_CNT, "adapter resets (warm)"),
3783 IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"),
3784 IPW2100_ORD(ANTENNA_DIVERSITY,
3785 "TRUE if antenna diversity is disabled"),
3786 IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"),
3787 IPW2100_ORD(OUR_FREQ,
3788 "current radio freq lower digits - channel ID"),
3789 IPW2100_ORD(RTC_TIME, "current RTC time"),
3790 IPW2100_ORD(PORT_TYPE, "operating mode"),
3791 IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"),
3792 IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"),
3793 IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"),
3794 IPW2100_ORD(BASIC_RATES, "basic tx rates"),
3795 IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"),
3796 IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"),
3797 IPW2100_ORD(CAPABILITIES,
3798 "Management frame capability field"),
3799 IPW2100_ORD(AUTH_TYPE, "Type of authentication"),
3800 IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"),
3801 IPW2100_ORD(RTS_THRESHOLD,
3802 "Min packet length for RTS handshaking"),
3803 IPW2100_ORD(INT_MODE, "International mode"),
3804 IPW2100_ORD(FRAGMENTATION_THRESHOLD,
3805 "protocol frag threshold"),
3806 IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
3807 "EEPROM offset in SRAM"),
3808 IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE,
3809 "EEPROM size in SRAM"),
3810 IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"),
3811 IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS,
3812 "EEPROM IBSS 11b channel set"),
3813 IPW2100_ORD(MAC_VERSION, "MAC Version"),
3814 IPW2100_ORD(MAC_REVISION, "MAC Revision"),
3815 IPW2100_ORD(RADIO_VERSION, "Radio Version"),
3816 IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"),
3817 IPW2100_ORD(UCODE_VERSION, "Ucode Version"),};
James Ketrenos2c86c272005-03-23 17:32:29 -06003818
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003819static ssize_t show_registers(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003820 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003821{
3822 int i;
3823 struct ipw2100_priv *priv = dev_get_drvdata(d);
3824 struct net_device *dev = priv->net_dev;
James Ketrenosee8e3652005-09-14 09:47:29 -05003825 char *out = buf;
James Ketrenos2c86c272005-03-23 17:32:29 -06003826 u32 val = 0;
3827
3828 out += sprintf(out, "%30s [Address ] : Hex\n", "Register");
3829
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003830 for (i = 0; i < ARRAY_SIZE(hw_data); i++) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003831 read_register(dev, hw_data[i].addr, &val);
3832 out += sprintf(out, "%30s [%08X] : %08X\n",
3833 hw_data[i].name, hw_data[i].addr, val);
3834 }
3835
3836 return out - buf;
3837}
James Ketrenosee8e3652005-09-14 09:47:29 -05003838
James Ketrenos2c86c272005-03-23 17:32:29 -06003839static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
3840
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003841static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003842 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003843{
3844 struct ipw2100_priv *priv = dev_get_drvdata(d);
3845 struct net_device *dev = priv->net_dev;
James Ketrenosee8e3652005-09-14 09:47:29 -05003846 char *out = buf;
James Ketrenos2c86c272005-03-23 17:32:29 -06003847 int i;
3848
3849 out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry");
3850
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003851 for (i = 0; i < ARRAY_SIZE(nic_data); i++) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003852 u8 tmp8;
3853 u16 tmp16;
3854 u32 tmp32;
3855
3856 switch (nic_data[i].size) {
3857 case 1:
3858 read_nic_byte(dev, nic_data[i].addr, &tmp8);
3859 out += sprintf(out, "%30s [%08X] : %02X\n",
3860 nic_data[i].name, nic_data[i].addr,
3861 tmp8);
3862 break;
3863 case 2:
3864 read_nic_word(dev, nic_data[i].addr, &tmp16);
3865 out += sprintf(out, "%30s [%08X] : %04X\n",
3866 nic_data[i].name, nic_data[i].addr,
3867 tmp16);
3868 break;
3869 case 4:
3870 read_nic_dword(dev, nic_data[i].addr, &tmp32);
3871 out += sprintf(out, "%30s [%08X] : %08X\n",
3872 nic_data[i].name, nic_data[i].addr,
3873 tmp32);
3874 break;
3875 }
3876 }
3877 return out - buf;
3878}
James Ketrenosee8e3652005-09-14 09:47:29 -05003879
James Ketrenos2c86c272005-03-23 17:32:29 -06003880static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
3881
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003882static ssize_t show_memory(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003883 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003884{
3885 struct ipw2100_priv *priv = dev_get_drvdata(d);
3886 struct net_device *dev = priv->net_dev;
3887 static unsigned long loop = 0;
3888 int len = 0;
3889 u32 buffer[4];
3890 int i;
3891 char line[81];
3892
3893 if (loop >= 0x30000)
3894 loop = 0;
3895
3896 /* sysfs provides us PAGE_SIZE buffer */
3897 while (len < PAGE_SIZE - 128 && loop < 0x30000) {
3898
James Ketrenosee8e3652005-09-14 09:47:29 -05003899 if (priv->snapshot[0])
3900 for (i = 0; i < 4; i++)
3901 buffer[i] =
3902 *(u32 *) SNAPSHOT_ADDR(loop + i * 4);
3903 else
3904 for (i = 0; i < 4; i++)
3905 read_nic_dword(dev, loop + i * 4, &buffer[i]);
James Ketrenos2c86c272005-03-23 17:32:29 -06003906
3907 if (priv->dump_raw)
3908 len += sprintf(buf + len,
3909 "%c%c%c%c"
3910 "%c%c%c%c"
3911 "%c%c%c%c"
3912 "%c%c%c%c",
James Ketrenosee8e3652005-09-14 09:47:29 -05003913 ((u8 *) buffer)[0x0],
3914 ((u8 *) buffer)[0x1],
3915 ((u8 *) buffer)[0x2],
3916 ((u8 *) buffer)[0x3],
3917 ((u8 *) buffer)[0x4],
3918 ((u8 *) buffer)[0x5],
3919 ((u8 *) buffer)[0x6],
3920 ((u8 *) buffer)[0x7],
3921 ((u8 *) buffer)[0x8],
3922 ((u8 *) buffer)[0x9],
3923 ((u8 *) buffer)[0xa],
3924 ((u8 *) buffer)[0xb],
3925 ((u8 *) buffer)[0xc],
3926 ((u8 *) buffer)[0xd],
3927 ((u8 *) buffer)[0xe],
3928 ((u8 *) buffer)[0xf]);
James Ketrenos2c86c272005-03-23 17:32:29 -06003929 else
3930 len += sprintf(buf + len, "%s\n",
3931 snprint_line(line, sizeof(line),
James Ketrenosee8e3652005-09-14 09:47:29 -05003932 (u8 *) buffer, 16, loop));
James Ketrenos2c86c272005-03-23 17:32:29 -06003933 loop += 16;
3934 }
3935
3936 return len;
3937}
3938
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003939static ssize_t store_memory(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003940 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06003941{
3942 struct ipw2100_priv *priv = dev_get_drvdata(d);
3943 struct net_device *dev = priv->net_dev;
3944 const char *p = buf;
3945
Zhu Yi8ed55a42006-01-24 13:49:20 +08003946 (void)dev; /* kill unused-var warning for debug-only code */
Jeff Garzikc2a8fad2005-11-09 00:49:38 -05003947
James Ketrenos2c86c272005-03-23 17:32:29 -06003948 if (count < 1)
3949 return count;
3950
3951 if (p[0] == '1' ||
3952 (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) {
3953 IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003954 dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003955 priv->dump_raw = 1;
3956
3957 } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' &&
James Ketrenosee8e3652005-09-14 09:47:29 -05003958 tolower(p[1]) == 'f')) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003959 IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05003960 dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003961 priv->dump_raw = 0;
3962
3963 } else if (tolower(p[0]) == 'r') {
James Ketrenosee8e3652005-09-14 09:47:29 -05003964 IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003965 ipw2100_snapshot_free(priv);
3966
3967 } else
3968 IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, "
James Ketrenosee8e3652005-09-14 09:47:29 -05003969 "reset = clear memory snapshot\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06003970
3971 return count;
3972}
James Ketrenos2c86c272005-03-23 17:32:29 -06003973
James Ketrenosee8e3652005-09-14 09:47:29 -05003974static DEVICE_ATTR(memory, S_IWUSR | S_IRUGO, show_memory, store_memory);
James Ketrenos2c86c272005-03-23 17:32:29 -06003975
Andrew Mortonedfc43f2005-06-20 14:30:35 -07003976static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05003977 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06003978{
3979 struct ipw2100_priv *priv = dev_get_drvdata(d);
3980 u32 val = 0;
3981 int len = 0;
3982 u32 val_len;
3983 static int loop = 0;
3984
James Ketrenos82328352005-08-24 22:33:31 -05003985 if (priv->status & STATUS_RF_KILL_MASK)
3986 return 0;
3987
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003988 if (loop >= ARRAY_SIZE(ord_data))
James Ketrenos2c86c272005-03-23 17:32:29 -06003989 loop = 0;
3990
3991 /* sysfs provides us PAGE_SIZE buffer */
Ahmed S. Darwish22d57432007-02-05 18:56:22 +02003992 while (len < PAGE_SIZE - 128 && loop < ARRAY_SIZE(ord_data)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06003993 val_len = sizeof(u32);
3994
3995 if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val,
3996 &val_len))
3997 len += sprintf(buf + len, "[0x%02X] = ERROR %s\n",
3998 ord_data[loop].index,
3999 ord_data[loop].desc);
4000 else
4001 len += sprintf(buf + len, "[0x%02X] = 0x%08X %s\n",
4002 ord_data[loop].index, val,
4003 ord_data[loop].desc);
4004 loop++;
4005 }
4006
4007 return len;
4008}
James Ketrenosee8e3652005-09-14 09:47:29 -05004009
James Ketrenos2c86c272005-03-23 17:32:29 -06004010static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL);
4011
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004012static ssize_t show_stats(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004013 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004014{
4015 struct ipw2100_priv *priv = dev_get_drvdata(d);
James Ketrenosee8e3652005-09-14 09:47:29 -05004016 char *out = buf;
James Ketrenos2c86c272005-03-23 17:32:29 -06004017
4018 out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n",
4019 priv->interrupts, priv->tx_interrupts,
4020 priv->rx_interrupts, priv->inta_other);
4021 out += sprintf(out, "firmware resets: %d\n", priv->resets);
4022 out += sprintf(out, "firmware hangs: %d\n", priv->hangs);
Brice Goglin0f52bf92005-12-01 01:41:46 -08004023#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06004024 out += sprintf(out, "packet mismatch image: %s\n",
4025 priv->snapshot[0] ? "YES" : "NO");
4026#endif
4027
4028 return out - buf;
4029}
James Ketrenos2c86c272005-03-23 17:32:29 -06004030
James Ketrenosee8e3652005-09-14 09:47:29 -05004031static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL);
James Ketrenos2c86c272005-03-23 17:32:29 -06004032
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004033static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004034{
4035 int err;
4036
4037 if (mode == priv->ieee->iw_mode)
4038 return 0;
4039
4040 err = ipw2100_disable_adapter(priv);
4041 if (err) {
Jiri Benc797b4f72005-08-25 20:03:27 -04004042 printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06004043 priv->net_dev->name, err);
4044 return err;
4045 }
4046
4047 switch (mode) {
4048 case IW_MODE_INFRA:
4049 priv->net_dev->type = ARPHRD_ETHER;
4050 break;
4051 case IW_MODE_ADHOC:
4052 priv->net_dev->type = ARPHRD_ETHER;
4053 break;
4054#ifdef CONFIG_IPW2100_MONITOR
4055 case IW_MODE_MONITOR:
4056 priv->last_mode = priv->ieee->iw_mode;
Stefan Rompf15745a72006-02-21 18:36:17 +08004057 priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
James Ketrenos2c86c272005-03-23 17:32:29 -06004058 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05004059#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06004060 }
4061
4062 priv->ieee->iw_mode = mode;
4063
4064#ifdef CONFIG_PM
James Ketrenosee8e3652005-09-14 09:47:29 -05004065 /* Indicate ipw2100_download_firmware download firmware
James Ketrenos2c86c272005-03-23 17:32:29 -06004066 * from disk instead of memory. */
4067 ipw2100_firmware.version = 0;
4068#endif
4069
James Ketrenosee8e3652005-09-14 09:47:29 -05004070 printk(KERN_INFO "%s: Reseting on mode change.\n", priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004071 priv->reset_backoff = 0;
4072 schedule_reset(priv);
4073
4074 return 0;
4075}
4076
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004077static ssize_t show_internals(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004078 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004079{
4080 struct ipw2100_priv *priv = dev_get_drvdata(d);
4081 int len = 0;
4082
James Ketrenosee8e3652005-09-14 09:47:29 -05004083#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x)
James Ketrenos2c86c272005-03-23 17:32:29 -06004084
4085 if (priv->status & STATUS_ASSOCIATED)
4086 len += sprintf(buf + len, "connected: %lu\n",
4087 get_seconds() - priv->connect_start);
4088 else
4089 len += sprintf(buf + len, "not connected\n");
4090
John W. Linville274bfb82008-10-29 11:35:05 -04004091 DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p");
James Ketrenosee8e3652005-09-14 09:47:29 -05004092 DUMP_VAR(status, "08lx");
4093 DUMP_VAR(config, "08lx");
4094 DUMP_VAR(capability, "08lx");
James Ketrenos2c86c272005-03-23 17:32:29 -06004095
James Ketrenosee8e3652005-09-14 09:47:29 -05004096 len +=
4097 sprintf(buf + len, "last_rtc: %lu\n",
4098 (unsigned long)priv->last_rtc);
James Ketrenos2c86c272005-03-23 17:32:29 -06004099
James Ketrenosee8e3652005-09-14 09:47:29 -05004100 DUMP_VAR(fatal_error, "d");
4101 DUMP_VAR(stop_hang_check, "d");
4102 DUMP_VAR(stop_rf_kill, "d");
4103 DUMP_VAR(messages_sent, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004104
James Ketrenosee8e3652005-09-14 09:47:29 -05004105 DUMP_VAR(tx_pend_stat.value, "d");
4106 DUMP_VAR(tx_pend_stat.hi, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004107
James Ketrenosee8e3652005-09-14 09:47:29 -05004108 DUMP_VAR(tx_free_stat.value, "d");
4109 DUMP_VAR(tx_free_stat.lo, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004110
James Ketrenosee8e3652005-09-14 09:47:29 -05004111 DUMP_VAR(msg_free_stat.value, "d");
4112 DUMP_VAR(msg_free_stat.lo, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004113
James Ketrenosee8e3652005-09-14 09:47:29 -05004114 DUMP_VAR(msg_pend_stat.value, "d");
4115 DUMP_VAR(msg_pend_stat.hi, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004116
James Ketrenosee8e3652005-09-14 09:47:29 -05004117 DUMP_VAR(fw_pend_stat.value, "d");
4118 DUMP_VAR(fw_pend_stat.hi, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004119
James Ketrenosee8e3652005-09-14 09:47:29 -05004120 DUMP_VAR(txq_stat.value, "d");
4121 DUMP_VAR(txq_stat.lo, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004122
James Ketrenosee8e3652005-09-14 09:47:29 -05004123 DUMP_VAR(ieee->scans, "d");
4124 DUMP_VAR(reset_backoff, "d");
James Ketrenos2c86c272005-03-23 17:32:29 -06004125
4126 return len;
4127}
James Ketrenosee8e3652005-09-14 09:47:29 -05004128
James Ketrenos2c86c272005-03-23 17:32:29 -06004129static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL);
4130
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004131static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004132 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004133{
4134 struct ipw2100_priv *priv = dev_get_drvdata(d);
4135 char essid[IW_ESSID_MAX_SIZE + 1];
4136 u8 bssid[ETH_ALEN];
4137 u32 chan = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05004138 char *out = buf;
Hannes Ederb9da9e92009-02-14 11:50:26 +00004139 unsigned int length;
James Ketrenos2c86c272005-03-23 17:32:29 -06004140 int ret;
4141
James Ketrenos82328352005-08-24 22:33:31 -05004142 if (priv->status & STATUS_RF_KILL_MASK)
4143 return 0;
4144
James Ketrenos2c86c272005-03-23 17:32:29 -06004145 memset(essid, 0, sizeof(essid));
4146 memset(bssid, 0, sizeof(bssid));
4147
4148 length = IW_ESSID_MAX_SIZE;
4149 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &length);
4150 if (ret)
4151 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
4152 __LINE__);
4153
4154 length = sizeof(bssid);
4155 ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
4156 bssid, &length);
4157 if (ret)
4158 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
4159 __LINE__);
4160
4161 length = sizeof(u32);
4162 ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &length);
4163 if (ret)
4164 IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
4165 __LINE__);
4166
4167 out += sprintf(out, "ESSID: %s\n", essid);
Johannes Berge1749612008-10-27 15:59:26 -07004168 out += sprintf(out, "BSSID: %pM\n", bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06004169 out += sprintf(out, "Channel: %d\n", chan);
4170
4171 return out - buf;
4172}
James Ketrenos2c86c272005-03-23 17:32:29 -06004173
James Ketrenosee8e3652005-09-14 09:47:29 -05004174static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
James Ketrenos2c86c272005-03-23 17:32:29 -06004175
Brice Goglin0f52bf92005-12-01 01:41:46 -08004176#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06004177static ssize_t show_debug_level(struct device_driver *d, char *buf)
4178{
4179 return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
4180}
4181
James Ketrenos82328352005-08-24 22:33:31 -05004182static ssize_t store_debug_level(struct device_driver *d,
4183 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004184{
4185 char *p = (char *)buf;
4186 u32 val;
4187
4188 if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
4189 p++;
4190 if (p[0] == 'x' || p[0] == 'X')
4191 p++;
4192 val = simple_strtoul(p, &p, 16);
4193 } else
4194 val = simple_strtoul(p, &p, 10);
4195 if (p == buf)
Zhu Yia1e695a2005-07-04 14:06:00 +08004196 IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf);
James Ketrenos2c86c272005-03-23 17:32:29 -06004197 else
4198 ipw2100_debug_level = val;
4199
4200 return strnlen(buf, count);
4201}
James Ketrenosee8e3652005-09-14 09:47:29 -05004202
James Ketrenos2c86c272005-03-23 17:32:29 -06004203static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level,
4204 store_debug_level);
Brice Goglin0f52bf92005-12-01 01:41:46 -08004205#endif /* CONFIG_IPW2100_DEBUG */
James Ketrenos2c86c272005-03-23 17:32:29 -06004206
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004207static ssize_t show_fatal_error(struct device *d,
James Ketrenosee8e3652005-09-14 09:47:29 -05004208 struct device_attribute *attr, char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004209{
4210 struct ipw2100_priv *priv = dev_get_drvdata(d);
4211 char *out = buf;
4212 int i;
4213
4214 if (priv->fatal_error)
James Ketrenosee8e3652005-09-14 09:47:29 -05004215 out += sprintf(out, "0x%08X\n", priv->fatal_error);
James Ketrenos2c86c272005-03-23 17:32:29 -06004216 else
4217 out += sprintf(out, "0\n");
4218
4219 for (i = 1; i <= IPW2100_ERROR_QUEUE; i++) {
4220 if (!priv->fatal_errors[(priv->fatal_index - i) %
4221 IPW2100_ERROR_QUEUE])
4222 continue;
4223
4224 out += sprintf(out, "%d. 0x%08X\n", i,
4225 priv->fatal_errors[(priv->fatal_index - i) %
4226 IPW2100_ERROR_QUEUE]);
4227 }
4228
4229 return out - buf;
4230}
4231
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004232static ssize_t store_fatal_error(struct device *d,
James Ketrenosee8e3652005-09-14 09:47:29 -05004233 struct device_attribute *attr, const char *buf,
4234 size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004235{
4236 struct ipw2100_priv *priv = dev_get_drvdata(d);
4237 schedule_reset(priv);
4238 return count;
4239}
James Ketrenos2c86c272005-03-23 17:32:29 -06004240
James Ketrenosee8e3652005-09-14 09:47:29 -05004241static DEVICE_ATTR(fatal_error, S_IWUSR | S_IRUGO, show_fatal_error,
4242 store_fatal_error);
James Ketrenos2c86c272005-03-23 17:32:29 -06004243
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004244static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004245 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004246{
4247 struct ipw2100_priv *priv = dev_get_drvdata(d);
4248 return sprintf(buf, "%d\n", priv->ieee->scan_age);
4249}
4250
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004251static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004252 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004253{
4254 struct ipw2100_priv *priv = dev_get_drvdata(d);
4255 struct net_device *dev = priv->net_dev;
4256 char buffer[] = "00000000";
4257 unsigned long len =
4258 (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
4259 unsigned long val;
4260 char *p = buffer;
4261
Zhu Yi8ed55a42006-01-24 13:49:20 +08004262 (void)dev; /* kill unused-var warning for debug-only code */
Jeff Garzikc2a8fad2005-11-09 00:49:38 -05004263
James Ketrenos2c86c272005-03-23 17:32:29 -06004264 IPW_DEBUG_INFO("enter\n");
4265
4266 strncpy(buffer, buf, len);
4267 buffer[len] = 0;
4268
4269 if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
4270 p++;
4271 if (p[0] == 'x' || p[0] == 'X')
4272 p++;
4273 val = simple_strtoul(p, &p, 16);
4274 } else
4275 val = simple_strtoul(p, &p, 10);
4276 if (p == buffer) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004277 IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004278 } else {
4279 priv->ieee->scan_age = val;
4280 IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
4281 }
4282
4283 IPW_DEBUG_INFO("exit\n");
4284 return len;
4285}
James Ketrenosee8e3652005-09-14 09:47:29 -05004286
James Ketrenos2c86c272005-03-23 17:32:29 -06004287static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
4288
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004289static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004290 char *buf)
James Ketrenos2c86c272005-03-23 17:32:29 -06004291{
4292 /* 0 - RF kill not enabled
4293 1 - SW based RF kill active (sysfs)
4294 2 - HW based RF kill active
4295 3 - Both HW and SW baed RF kill active */
Greg Kroah-Hartman928841b2009-04-30 23:02:47 -07004296 struct ipw2100_priv *priv = dev_get_drvdata(d);
James Ketrenos2c86c272005-03-23 17:32:29 -06004297 int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
James Ketrenosee8e3652005-09-14 09:47:29 -05004298 (rf_kill_active(priv) ? 0x2 : 0x0);
James Ketrenos2c86c272005-03-23 17:32:29 -06004299 return sprintf(buf, "%i\n", val);
4300}
4301
4302static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
4303{
4304 if ((disable_radio ? 1 : 0) ==
4305 (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
James Ketrenosee8e3652005-09-14 09:47:29 -05004306 return 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06004307
4308 IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
4309 disable_radio ? "OFF" : "ON");
4310
Ingo Molnar752e3772006-02-28 07:20:54 +08004311 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06004312
4313 if (disable_radio) {
4314 priv->status |= STATUS_RF_KILL_SW;
4315 ipw2100_down(priv);
4316 } else {
4317 priv->status &= ~STATUS_RF_KILL_SW;
4318 if (rf_kill_active(priv)) {
4319 IPW_DEBUG_RF_KILL("Can not turn radio back on - "
4320 "disabled by HW switch\n");
4321 /* Make sure the RF_KILL check timer is running */
4322 priv->stop_rf_kill = 0;
4323 cancel_delayed_work(&priv->rf_kill);
Tejun Heobcb6d912011-01-26 12:12:50 +01004324 schedule_delayed_work(&priv->rf_kill,
4325 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06004326 } else
4327 schedule_reset(priv);
4328 }
4329
Ingo Molnar752e3772006-02-28 07:20:54 +08004330 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06004331 return 1;
4332}
4333
Andrew Mortonedfc43f2005-06-20 14:30:35 -07004334static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
James Ketrenosee8e3652005-09-14 09:47:29 -05004335 const char *buf, size_t count)
James Ketrenos2c86c272005-03-23 17:32:29 -06004336{
4337 struct ipw2100_priv *priv = dev_get_drvdata(d);
4338 ipw_radio_kill_sw(priv, buf[0] == '1');
4339 return count;
4340}
James Ketrenos2c86c272005-03-23 17:32:29 -06004341
James Ketrenosee8e3652005-09-14 09:47:29 -05004342static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
James Ketrenos2c86c272005-03-23 17:32:29 -06004343
4344static struct attribute *ipw2100_sysfs_entries[] = {
4345 &dev_attr_hardware.attr,
4346 &dev_attr_registers.attr,
4347 &dev_attr_ordinals.attr,
4348 &dev_attr_pci.attr,
4349 &dev_attr_stats.attr,
4350 &dev_attr_internals.attr,
4351 &dev_attr_bssinfo.attr,
4352 &dev_attr_memory.attr,
4353 &dev_attr_scan_age.attr,
4354 &dev_attr_fatal_error.attr,
4355 &dev_attr_rf_kill.attr,
4356 &dev_attr_cfg.attr,
4357 &dev_attr_status.attr,
4358 &dev_attr_capability.attr,
4359 NULL,
4360};
4361
4362static struct attribute_group ipw2100_attribute_group = {
4363 .attrs = ipw2100_sysfs_entries,
4364};
4365
James Ketrenos2c86c272005-03-23 17:32:29 -06004366static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
4367{
4368 struct ipw2100_status_queue *q = &priv->status_queue;
4369
4370 IPW_DEBUG_INFO("enter\n");
4371
4372 q->size = entries * sizeof(struct ipw2100_status);
James Ketrenosee8e3652005-09-14 09:47:29 -05004373 q->drv =
4374 (struct ipw2100_status *)pci_alloc_consistent(priv->pci_dev,
4375 q->size, &q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004376 if (!q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004377 IPW_DEBUG_WARNING("Can not allocate status queue.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06004378 return -ENOMEM;
4379 }
4380
4381 memset(q->drv, 0, q->size);
4382
4383 IPW_DEBUG_INFO("exit\n");
4384
4385 return 0;
4386}
4387
4388static void status_queue_free(struct ipw2100_priv *priv)
4389{
4390 IPW_DEBUG_INFO("enter\n");
4391
4392 if (priv->status_queue.drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004393 pci_free_consistent(priv->pci_dev, priv->status_queue.size,
4394 priv->status_queue.drv,
4395 priv->status_queue.nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004396 priv->status_queue.drv = NULL;
4397 }
4398
4399 IPW_DEBUG_INFO("exit\n");
4400}
4401
4402static int bd_queue_allocate(struct ipw2100_priv *priv,
4403 struct ipw2100_bd_queue *q, int entries)
4404{
4405 IPW_DEBUG_INFO("enter\n");
4406
4407 memset(q, 0, sizeof(struct ipw2100_bd_queue));
4408
4409 q->entries = entries;
4410 q->size = entries * sizeof(struct ipw2100_bd);
4411 q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic);
4412 if (!q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004413 IPW_DEBUG_INFO
4414 ("can't allocate shared memory for buffer descriptors\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06004415 return -ENOMEM;
4416 }
4417 memset(q->drv, 0, q->size);
4418
4419 IPW_DEBUG_INFO("exit\n");
4420
4421 return 0;
4422}
4423
James Ketrenosee8e3652005-09-14 09:47:29 -05004424static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q)
James Ketrenos2c86c272005-03-23 17:32:29 -06004425{
4426 IPW_DEBUG_INFO("enter\n");
4427
4428 if (!q)
4429 return;
4430
4431 if (q->drv) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004432 pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004433 q->drv = NULL;
4434 }
4435
4436 IPW_DEBUG_INFO("exit\n");
4437}
4438
James Ketrenosee8e3652005-09-14 09:47:29 -05004439static void bd_queue_initialize(struct ipw2100_priv *priv,
4440 struct ipw2100_bd_queue *q, u32 base, u32 size,
4441 u32 r, u32 w)
James Ketrenos2c86c272005-03-23 17:32:29 -06004442{
4443 IPW_DEBUG_INFO("enter\n");
4444
James Ketrenosee8e3652005-09-14 09:47:29 -05004445 IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv,
4446 (u32) q->nic);
James Ketrenos2c86c272005-03-23 17:32:29 -06004447
4448 write_register(priv->net_dev, base, q->nic);
4449 write_register(priv->net_dev, size, q->entries);
4450 write_register(priv->net_dev, r, q->oldest);
4451 write_register(priv->net_dev, w, q->next);
4452
4453 IPW_DEBUG_INFO("exit\n");
4454}
4455
Tejun Heobcb6d912011-01-26 12:12:50 +01004456static void ipw2100_kill_works(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06004457{
Tejun Heobcb6d912011-01-26 12:12:50 +01004458 priv->stop_rf_kill = 1;
4459 priv->stop_hang_check = 1;
4460 cancel_delayed_work_sync(&priv->reset_work);
4461 cancel_delayed_work_sync(&priv->security_work);
4462 cancel_delayed_work_sync(&priv->wx_event_work);
4463 cancel_delayed_work_sync(&priv->hang_check);
4464 cancel_delayed_work_sync(&priv->rf_kill);
4465 cancel_work_sync(&priv->scan_event_now);
4466 cancel_delayed_work_sync(&priv->scan_event_later);
James Ketrenos2c86c272005-03-23 17:32:29 -06004467}
4468
4469static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
4470{
4471 int i, j, err = -EINVAL;
4472 void *v;
4473 dma_addr_t p;
4474
4475 IPW_DEBUG_INFO("enter\n");
4476
4477 err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH);
4478 if (err) {
4479 IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05004480 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004481 return err;
4482 }
4483
James Ketrenosee8e3652005-09-14 09:47:29 -05004484 priv->tx_buffers =
Joe Perchesefe4c452010-05-31 20:23:15 -07004485 kmalloc(TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet),
4486 GFP_ATOMIC);
James Ketrenos2c86c272005-03-23 17:32:29 -06004487 if (!priv->tx_buffers) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004488 printk(KERN_ERR DRV_NAME
4489 ": %s: alloc failed form tx buffers.\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06004490 priv->net_dev->name);
4491 bd_queue_free(priv, &priv->tx_queue);
4492 return -ENOMEM;
4493 }
4494
4495 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004496 v = pci_alloc_consistent(priv->pci_dev,
4497 sizeof(struct ipw2100_data_header),
4498 &p);
James Ketrenos2c86c272005-03-23 17:32:29 -06004499 if (!v) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004500 printk(KERN_ERR DRV_NAME
4501 ": %s: PCI alloc failed for tx " "buffers.\n",
4502 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06004503 err = -ENOMEM;
4504 break;
4505 }
4506
4507 priv->tx_buffers[i].type = DATA;
James Ketrenosee8e3652005-09-14 09:47:29 -05004508 priv->tx_buffers[i].info.d_struct.data =
4509 (struct ipw2100_data_header *)v;
James Ketrenos2c86c272005-03-23 17:32:29 -06004510 priv->tx_buffers[i].info.d_struct.data_phys = p;
4511 priv->tx_buffers[i].info.d_struct.txb = NULL;
4512 }
4513
4514 if (i == TX_PENDED_QUEUE_LENGTH)
4515 return 0;
4516
4517 for (j = 0; j < i; j++) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004518 pci_free_consistent(priv->pci_dev,
4519 sizeof(struct ipw2100_data_header),
4520 priv->tx_buffers[j].info.d_struct.data,
4521 priv->tx_buffers[j].info.d_struct.
4522 data_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06004523 }
4524
4525 kfree(priv->tx_buffers);
4526 priv->tx_buffers = NULL;
4527
4528 return err;
4529}
4530
4531static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
4532{
4533 int i;
4534
4535 IPW_DEBUG_INFO("enter\n");
4536
4537 /*
4538 * reinitialize packet info lists
4539 */
4540 INIT_LIST_HEAD(&priv->fw_pend_list);
4541 INIT_STAT(&priv->fw_pend_stat);
4542
4543 /*
4544 * reinitialize lists
4545 */
4546 INIT_LIST_HEAD(&priv->tx_pend_list);
4547 INIT_LIST_HEAD(&priv->tx_free_list);
4548 INIT_STAT(&priv->tx_pend_stat);
4549 INIT_STAT(&priv->tx_free_stat);
4550
4551 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
4552 /* We simply drop any SKBs that have been queued for
4553 * transmit */
4554 if (priv->tx_buffers[i].info.d_struct.txb) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04004555 libipw_txb_free(priv->tx_buffers[i].info.d_struct.
James Ketrenosee8e3652005-09-14 09:47:29 -05004556 txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06004557 priv->tx_buffers[i].info.d_struct.txb = NULL;
4558 }
4559
4560 list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list);
4561 }
4562
4563 SET_STAT(&priv->tx_free_stat, i);
4564
4565 priv->tx_queue.oldest = 0;
4566 priv->tx_queue.available = priv->tx_queue.entries;
4567 priv->tx_queue.next = 0;
4568 INIT_STAT(&priv->txq_stat);
4569 SET_STAT(&priv->txq_stat, priv->tx_queue.available);
4570
4571 bd_queue_initialize(priv, &priv->tx_queue,
4572 IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE,
4573 IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE,
4574 IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
4575 IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX);
4576
4577 IPW_DEBUG_INFO("exit\n");
4578
4579}
4580
4581static void ipw2100_tx_free(struct ipw2100_priv *priv)
4582{
4583 int i;
4584
4585 IPW_DEBUG_INFO("enter\n");
4586
4587 bd_queue_free(priv, &priv->tx_queue);
4588
4589 if (!priv->tx_buffers)
4590 return;
4591
4592 for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
4593 if (priv->tx_buffers[i].info.d_struct.txb) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04004594 libipw_txb_free(priv->tx_buffers[i].info.d_struct.
James Ketrenosee8e3652005-09-14 09:47:29 -05004595 txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06004596 priv->tx_buffers[i].info.d_struct.txb = NULL;
4597 }
4598 if (priv->tx_buffers[i].info.d_struct.data)
James Ketrenosee8e3652005-09-14 09:47:29 -05004599 pci_free_consistent(priv->pci_dev,
4600 sizeof(struct ipw2100_data_header),
4601 priv->tx_buffers[i].info.d_struct.
4602 data,
4603 priv->tx_buffers[i].info.d_struct.
4604 data_phys);
James Ketrenos2c86c272005-03-23 17:32:29 -06004605 }
4606
4607 kfree(priv->tx_buffers);
4608 priv->tx_buffers = NULL;
4609
4610 IPW_DEBUG_INFO("exit\n");
4611}
4612
James Ketrenos2c86c272005-03-23 17:32:29 -06004613static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
4614{
4615 int i, j, err = -EINVAL;
4616
4617 IPW_DEBUG_INFO("enter\n");
4618
4619 err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH);
4620 if (err) {
4621 IPW_DEBUG_INFO("failed bd_queue_allocate\n");
4622 return err;
4623 }
4624
4625 err = status_queue_allocate(priv, RX_QUEUE_LENGTH);
4626 if (err) {
4627 IPW_DEBUG_INFO("failed status_queue_allocate\n");
4628 bd_queue_free(priv, &priv->rx_queue);
4629 return err;
4630 }
4631
4632 /*
4633 * allocate packets
4634 */
Joe Perchesefe4c452010-05-31 20:23:15 -07004635 priv->rx_buffers = kmalloc(RX_QUEUE_LENGTH *
4636 sizeof(struct ipw2100_rx_packet),
4637 GFP_KERNEL);
James Ketrenos2c86c272005-03-23 17:32:29 -06004638 if (!priv->rx_buffers) {
4639 IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
4640
4641 bd_queue_free(priv, &priv->rx_queue);
4642
4643 status_queue_free(priv);
4644
4645 return -ENOMEM;
4646 }
4647
4648 for (i = 0; i < RX_QUEUE_LENGTH; i++) {
4649 struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
4650
4651 err = ipw2100_alloc_skb(priv, packet);
4652 if (unlikely(err)) {
4653 err = -ENOMEM;
4654 break;
4655 }
4656
4657 /* The BD holds the cache aligned address */
4658 priv->rx_queue.drv[i].host_addr = packet->dma_addr;
4659 priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH;
4660 priv->status_queue.drv[i].status_fields = 0;
4661 }
4662
4663 if (i == RX_QUEUE_LENGTH)
4664 return 0;
4665
4666 for (j = 0; j < i; j++) {
4667 pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr,
4668 sizeof(struct ipw2100_rx_packet),
4669 PCI_DMA_FROMDEVICE);
4670 dev_kfree_skb(priv->rx_buffers[j].skb);
4671 }
4672
4673 kfree(priv->rx_buffers);
4674 priv->rx_buffers = NULL;
4675
4676 bd_queue_free(priv, &priv->rx_queue);
4677
4678 status_queue_free(priv);
4679
4680 return err;
4681}
4682
4683static void ipw2100_rx_initialize(struct ipw2100_priv *priv)
4684{
4685 IPW_DEBUG_INFO("enter\n");
4686
4687 priv->rx_queue.oldest = 0;
4688 priv->rx_queue.available = priv->rx_queue.entries - 1;
4689 priv->rx_queue.next = priv->rx_queue.entries - 1;
4690
4691 INIT_STAT(&priv->rxq_stat);
4692 SET_STAT(&priv->rxq_stat, priv->rx_queue.available);
4693
4694 bd_queue_initialize(priv, &priv->rx_queue,
4695 IPW_MEM_HOST_SHARED_RX_BD_BASE,
4696 IPW_MEM_HOST_SHARED_RX_BD_SIZE,
4697 IPW_MEM_HOST_SHARED_RX_READ_INDEX,
4698 IPW_MEM_HOST_SHARED_RX_WRITE_INDEX);
4699
4700 /* set up the status queue */
4701 write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE,
4702 priv->status_queue.nic);
4703
4704 IPW_DEBUG_INFO("exit\n");
4705}
4706
4707static void ipw2100_rx_free(struct ipw2100_priv *priv)
4708{
4709 int i;
4710
4711 IPW_DEBUG_INFO("enter\n");
4712
4713 bd_queue_free(priv, &priv->rx_queue);
4714 status_queue_free(priv);
4715
4716 if (!priv->rx_buffers)
4717 return;
4718
4719 for (i = 0; i < RX_QUEUE_LENGTH; i++) {
4720 if (priv->rx_buffers[i].rxp) {
4721 pci_unmap_single(priv->pci_dev,
4722 priv->rx_buffers[i].dma_addr,
4723 sizeof(struct ipw2100_rx),
4724 PCI_DMA_FROMDEVICE);
4725 dev_kfree_skb(priv->rx_buffers[i].skb);
4726 }
4727 }
4728
4729 kfree(priv->rx_buffers);
4730 priv->rx_buffers = NULL;
4731
4732 IPW_DEBUG_INFO("exit\n");
4733}
4734
4735static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
4736{
4737 u32 length = ETH_ALEN;
Joe Perches0795af52007-10-03 17:59:30 -07004738 u8 addr[ETH_ALEN];
James Ketrenos2c86c272005-03-23 17:32:29 -06004739
4740 int err;
4741
Joe Perches0795af52007-10-03 17:59:30 -07004742 err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
James Ketrenos2c86c272005-03-23 17:32:29 -06004743 if (err) {
4744 IPW_DEBUG_INFO("MAC address read failed\n");
4745 return -EIO;
4746 }
James Ketrenos2c86c272005-03-23 17:32:29 -06004747
Joe Perches0795af52007-10-03 17:59:30 -07004748 memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN);
Johannes Berge1749612008-10-27 15:59:26 -07004749 IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06004750
4751 return 0;
4752}
4753
4754/********************************************************************
4755 *
4756 * Firmware Commands
4757 *
4758 ********************************************************************/
4759
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004760static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004761{
4762 struct host_command cmd = {
4763 .host_command = ADAPTER_ADDRESS,
4764 .host_command_sequence = 0,
4765 .host_command_length = ETH_ALEN
4766 };
4767 int err;
4768
4769 IPW_DEBUG_HC("SET_MAC_ADDRESS\n");
4770
4771 IPW_DEBUG_INFO("enter\n");
4772
4773 if (priv->config & CFG_CUSTOM_MAC) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004774 memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06004775 memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
4776 } else
4777 memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr,
4778 ETH_ALEN);
4779
4780 err = ipw2100_hw_send_command(priv, &cmd);
4781
4782 IPW_DEBUG_INFO("exit\n");
4783 return err;
4784}
4785
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004786static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type,
James Ketrenos2c86c272005-03-23 17:32:29 -06004787 int batch_mode)
4788{
4789 struct host_command cmd = {
4790 .host_command = PORT_TYPE,
4791 .host_command_sequence = 0,
4792 .host_command_length = sizeof(u32)
4793 };
4794 int err;
4795
4796 switch (port_type) {
4797 case IW_MODE_INFRA:
4798 cmd.host_command_parameters[0] = IPW_BSS;
4799 break;
4800 case IW_MODE_ADHOC:
4801 cmd.host_command_parameters[0] = IPW_IBSS;
4802 break;
4803 }
4804
4805 IPW_DEBUG_HC("PORT_TYPE: %s\n",
4806 port_type == IPW_IBSS ? "Ad-Hoc" : "Managed");
4807
4808 if (!batch_mode) {
4809 err = ipw2100_disable_adapter(priv);
4810 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004811 printk(KERN_ERR DRV_NAME
4812 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06004813 priv->net_dev->name, err);
4814 return err;
4815 }
4816 }
4817
4818 /* send cmd to firmware */
4819 err = ipw2100_hw_send_command(priv, &cmd);
4820
4821 if (!batch_mode)
4822 ipw2100_enable_adapter(priv);
4823
4824 return err;
4825}
4826
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004827static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
4828 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004829{
4830 struct host_command cmd = {
4831 .host_command = CHANNEL,
4832 .host_command_sequence = 0,
4833 .host_command_length = sizeof(u32)
4834 };
4835 int err;
4836
4837 cmd.host_command_parameters[0] = channel;
4838
4839 IPW_DEBUG_HC("CHANNEL: %d\n", channel);
4840
4841 /* If BSS then we don't support channel selection */
4842 if (priv->ieee->iw_mode == IW_MODE_INFRA)
4843 return 0;
4844
4845 if ((channel != 0) &&
4846 ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL)))
4847 return -EINVAL;
4848
4849 if (!batch_mode) {
4850 err = ipw2100_disable_adapter(priv);
4851 if (err)
4852 return err;
4853 }
4854
4855 err = ipw2100_hw_send_command(priv, &cmd);
4856 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05004857 IPW_DEBUG_INFO("Failed to set channel to %d", channel);
James Ketrenos2c86c272005-03-23 17:32:29 -06004858 return err;
4859 }
4860
4861 if (channel)
4862 priv->config |= CFG_STATIC_CHANNEL;
4863 else
4864 priv->config &= ~CFG_STATIC_CHANNEL;
4865
4866 priv->channel = channel;
4867
4868 if (!batch_mode) {
4869 err = ipw2100_enable_adapter(priv);
4870 if (err)
4871 return err;
4872 }
4873
4874 return 0;
4875}
4876
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004877static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004878{
4879 struct host_command cmd = {
4880 .host_command = SYSTEM_CONFIG,
4881 .host_command_sequence = 0,
4882 .host_command_length = 12,
4883 };
4884 u32 ibss_mask, len = sizeof(u32);
4885 int err;
4886
4887 /* Set system configuration */
4888
4889 if (!batch_mode) {
4890 err = ipw2100_disable_adapter(priv);
4891 if (err)
4892 return err;
4893 }
4894
4895 if (priv->ieee->iw_mode == IW_MODE_ADHOC)
4896 cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START;
4897
4898 cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK |
James Ketrenosee8e3652005-09-14 09:47:29 -05004899 IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE;
James Ketrenos2c86c272005-03-23 17:32:29 -06004900
4901 if (!(priv->config & CFG_LONG_PREAMBLE))
4902 cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO;
4903
4904 err = ipw2100_get_ordinal(priv,
4905 IPW_ORD_EEPROM_IBSS_11B_CHANNELS,
James Ketrenosee8e3652005-09-14 09:47:29 -05004906 &ibss_mask, &len);
James Ketrenos2c86c272005-03-23 17:32:29 -06004907 if (err)
4908 ibss_mask = IPW_IBSS_11B_DEFAULT_MASK;
4909
4910 cmd.host_command_parameters[1] = REG_CHANNEL_MASK;
4911 cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask;
4912
4913 /* 11b only */
James Ketrenosee8e3652005-09-14 09:47:29 -05004914 /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */
James Ketrenos2c86c272005-03-23 17:32:29 -06004915
4916 err = ipw2100_hw_send_command(priv, &cmd);
4917 if (err)
4918 return err;
4919
4920/* If IPv6 is configured in the kernel then we don't want to filter out all
4921 * of the multicast packets as IPv6 needs some. */
4922#if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE)
4923 cmd.host_command = ADD_MULTICAST;
4924 cmd.host_command_sequence = 0;
4925 cmd.host_command_length = 0;
4926
4927 ipw2100_hw_send_command(priv, &cmd);
4928#endif
4929 if (!batch_mode) {
4930 err = ipw2100_enable_adapter(priv);
4931 if (err)
4932 return err;
4933 }
4934
4935 return 0;
4936}
4937
Jiri Bencc4aee8c2005-08-25 20:04:43 -04004938static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate,
4939 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06004940{
4941 struct host_command cmd = {
4942 .host_command = BASIC_TX_RATES,
4943 .host_command_sequence = 0,
4944 .host_command_length = 4
4945 };
4946 int err;
4947
4948 cmd.host_command_parameters[0] = rate & TX_RATE_MASK;
4949
4950 if (!batch_mode) {
4951 err = ipw2100_disable_adapter(priv);
4952 if (err)
4953 return err;
4954 }
4955
4956 /* Set BASIC TX Rate first */
4957 ipw2100_hw_send_command(priv, &cmd);
4958
4959 /* Set TX Rate */
4960 cmd.host_command = TX_RATES;
4961 ipw2100_hw_send_command(priv, &cmd);
4962
4963 /* Set MSDU TX Rate */
4964 cmd.host_command = MSDU_TX_RATES;
4965 ipw2100_hw_send_command(priv, &cmd);
4966
4967 if (!batch_mode) {
4968 err = ipw2100_enable_adapter(priv);
4969 if (err)
4970 return err;
4971 }
4972
4973 priv->tx_rates = rate;
4974
4975 return 0;
4976}
4977
James Ketrenosee8e3652005-09-14 09:47:29 -05004978static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
James Ketrenos2c86c272005-03-23 17:32:29 -06004979{
4980 struct host_command cmd = {
4981 .host_command = POWER_MODE,
4982 .host_command_sequence = 0,
4983 .host_command_length = 4
4984 };
4985 int err;
4986
4987 cmd.host_command_parameters[0] = power_level;
4988
4989 err = ipw2100_hw_send_command(priv, &cmd);
4990 if (err)
4991 return err;
4992
4993 if (power_level == IPW_POWER_MODE_CAM)
4994 priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
4995 else
4996 priv->power_mode = IPW_POWER_ENABLED | power_level;
4997
Robert P. J. Dayae800312007-01-31 02:39:40 -05004998#ifdef IPW2100_TX_POWER
James Ketrenosee8e3652005-09-14 09:47:29 -05004999 if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005000 /* Set beacon interval */
5001 cmd.host_command = TX_POWER_INDEX;
James Ketrenosee8e3652005-09-14 09:47:29 -05005002 cmd.host_command_parameters[0] = (u32) priv->adhoc_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06005003
5004 err = ipw2100_hw_send_command(priv, &cmd);
5005 if (err)
5006 return err;
5007 }
5008#endif
5009
5010 return 0;
5011}
5012
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005013static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold)
James Ketrenos2c86c272005-03-23 17:32:29 -06005014{
5015 struct host_command cmd = {
5016 .host_command = RTS_THRESHOLD,
5017 .host_command_sequence = 0,
5018 .host_command_length = 4
5019 };
5020 int err;
5021
5022 if (threshold & RTS_DISABLED)
5023 cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD;
5024 else
5025 cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED;
5026
5027 err = ipw2100_hw_send_command(priv, &cmd);
5028 if (err)
5029 return err;
5030
5031 priv->rts_threshold = threshold;
5032
5033 return 0;
5034}
5035
5036#if 0
5037int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv,
5038 u32 threshold, int batch_mode)
5039{
5040 struct host_command cmd = {
5041 .host_command = FRAG_THRESHOLD,
5042 .host_command_sequence = 0,
5043 .host_command_length = 4,
5044 .host_command_parameters[0] = 0,
5045 };
5046 int err;
5047
5048 if (!batch_mode) {
5049 err = ipw2100_disable_adapter(priv);
5050 if (err)
5051 return err;
5052 }
5053
5054 if (threshold == 0)
5055 threshold = DEFAULT_FRAG_THRESHOLD;
5056 else {
5057 threshold = max(threshold, MIN_FRAG_THRESHOLD);
5058 threshold = min(threshold, MAX_FRAG_THRESHOLD);
5059 }
5060
5061 cmd.host_command_parameters[0] = threshold;
5062
5063 IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold);
5064
5065 err = ipw2100_hw_send_command(priv, &cmd);
5066
5067 if (!batch_mode)
5068 ipw2100_enable_adapter(priv);
5069
5070 if (!err)
5071 priv->frag_threshold = threshold;
5072
5073 return err;
5074}
5075#endif
5076
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005077static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry)
James Ketrenos2c86c272005-03-23 17:32:29 -06005078{
5079 struct host_command cmd = {
5080 .host_command = SHORT_RETRY_LIMIT,
5081 .host_command_sequence = 0,
5082 .host_command_length = 4
5083 };
5084 int err;
5085
5086 cmd.host_command_parameters[0] = retry;
5087
5088 err = ipw2100_hw_send_command(priv, &cmd);
5089 if (err)
5090 return err;
5091
5092 priv->short_retry_limit = retry;
5093
5094 return 0;
5095}
5096
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005097static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry)
James Ketrenos2c86c272005-03-23 17:32:29 -06005098{
5099 struct host_command cmd = {
5100 .host_command = LONG_RETRY_LIMIT,
5101 .host_command_sequence = 0,
5102 .host_command_length = 4
5103 };
5104 int err;
5105
5106 cmd.host_command_parameters[0] = retry;
5107
5108 err = ipw2100_hw_send_command(priv, &cmd);
5109 if (err)
5110 return err;
5111
5112 priv->long_retry_limit = retry;
5113
5114 return 0;
5115}
5116
James Ketrenosee8e3652005-09-14 09:47:29 -05005117static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005118 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005119{
5120 struct host_command cmd = {
5121 .host_command = MANDATORY_BSSID,
5122 .host_command_sequence = 0,
5123 .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN
5124 };
5125 int err;
5126
Brice Goglin0f52bf92005-12-01 01:41:46 -08005127#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06005128 if (bssid != NULL)
Johannes Berge1749612008-10-27 15:59:26 -07005129 IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06005130 else
5131 IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
5132#endif
5133 /* if BSSID is empty then we disable mandatory bssid mode */
5134 if (bssid != NULL)
James Ketrenos82328352005-08-24 22:33:31 -05005135 memcpy(cmd.host_command_parameters, bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06005136
5137 if (!batch_mode) {
5138 err = ipw2100_disable_adapter(priv);
5139 if (err)
5140 return err;
5141 }
5142
5143 err = ipw2100_hw_send_command(priv, &cmd);
5144
5145 if (!batch_mode)
5146 ipw2100_enable_adapter(priv);
5147
5148 return err;
5149}
5150
James Ketrenos2c86c272005-03-23 17:32:29 -06005151static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
5152{
5153 struct host_command cmd = {
5154 .host_command = DISASSOCIATION_BSSID,
5155 .host_command_sequence = 0,
5156 .host_command_length = ETH_ALEN
5157 };
5158 int err;
5159 int len;
5160
5161 IPW_DEBUG_HC("DISASSOCIATION_BSSID\n");
5162
5163 len = ETH_ALEN;
5164 /* The Firmware currently ignores the BSSID and just disassociates from
5165 * the currently associated AP -- but in the off chance that a future
5166 * firmware does use the BSSID provided here, we go ahead and try and
5167 * set it to the currently associated AP's BSSID */
5168 memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN);
5169
5170 err = ipw2100_hw_send_command(priv, &cmd);
5171
5172 return err;
5173}
James Ketrenos2c86c272005-03-23 17:32:29 -06005174
5175static int ipw2100_set_wpa_ie(struct ipw2100_priv *,
5176 struct ipw2100_wpa_assoc_frame *, int)
James Ketrenosee8e3652005-09-14 09:47:29 -05005177 __attribute__ ((unused));
James Ketrenos2c86c272005-03-23 17:32:29 -06005178
5179static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv,
5180 struct ipw2100_wpa_assoc_frame *wpa_frame,
5181 int batch_mode)
5182{
5183 struct host_command cmd = {
5184 .host_command = SET_WPA_IE,
5185 .host_command_sequence = 0,
5186 .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame),
5187 };
5188 int err;
5189
5190 IPW_DEBUG_HC("SET_WPA_IE\n");
5191
5192 if (!batch_mode) {
5193 err = ipw2100_disable_adapter(priv);
5194 if (err)
5195 return err;
5196 }
5197
5198 memcpy(cmd.host_command_parameters, wpa_frame,
5199 sizeof(struct ipw2100_wpa_assoc_frame));
5200
5201 err = ipw2100_hw_send_command(priv, &cmd);
5202
5203 if (!batch_mode) {
5204 if (ipw2100_enable_adapter(priv))
5205 err = -EIO;
5206 }
5207
5208 return err;
5209}
5210
5211struct security_info_params {
5212 u32 allowed_ciphers;
5213 u16 version;
5214 u8 auth_mode;
5215 u8 replay_counters_number;
5216 u8 unicast_using_group;
Eric Dumazetba2d3582010-06-02 18:10:09 +00005217} __packed;
James Ketrenos2c86c272005-03-23 17:32:29 -06005218
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005219static int ipw2100_set_security_information(struct ipw2100_priv *priv,
5220 int auth_mode,
5221 int security_level,
5222 int unicast_using_group,
5223 int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005224{
5225 struct host_command cmd = {
5226 .host_command = SET_SECURITY_INFORMATION,
5227 .host_command_sequence = 0,
5228 .host_command_length = sizeof(struct security_info_params)
5229 };
5230 struct security_info_params *security =
James Ketrenosee8e3652005-09-14 09:47:29 -05005231 (struct security_info_params *)&cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06005232 int err;
5233 memset(security, 0, sizeof(*security));
5234
5235 /* If shared key AP authentication is turned on, then we need to
5236 * configure the firmware to try and use it.
5237 *
5238 * Actual data encryption/decryption is handled by the host. */
5239 security->auth_mode = auth_mode;
5240 security->unicast_using_group = unicast_using_group;
5241
5242 switch (security_level) {
5243 default:
5244 case SEC_LEVEL_0:
5245 security->allowed_ciphers = IPW_NONE_CIPHER;
5246 break;
5247 case SEC_LEVEL_1:
5248 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005249 IPW_WEP104_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005250 break;
5251 case SEC_LEVEL_2:
5252 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005253 IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005254 break;
5255 case SEC_LEVEL_2_CKIP:
5256 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005257 IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005258 break;
5259 case SEC_LEVEL_3:
5260 security->allowed_ciphers = IPW_WEP40_CIPHER |
James Ketrenosee8e3652005-09-14 09:47:29 -05005261 IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
James Ketrenos2c86c272005-03-23 17:32:29 -06005262 break;
5263 }
5264
James Ketrenosee8e3652005-09-14 09:47:29 -05005265 IPW_DEBUG_HC
5266 ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
5267 security->auth_mode, security->allowed_ciphers, security_level);
James Ketrenos2c86c272005-03-23 17:32:29 -06005268
5269 security->replay_counters_number = 0;
5270
5271 if (!batch_mode) {
5272 err = ipw2100_disable_adapter(priv);
5273 if (err)
5274 return err;
5275 }
5276
5277 err = ipw2100_hw_send_command(priv, &cmd);
5278
5279 if (!batch_mode)
5280 ipw2100_enable_adapter(priv);
5281
5282 return err;
5283}
5284
James Ketrenosee8e3652005-09-14 09:47:29 -05005285static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power)
James Ketrenos2c86c272005-03-23 17:32:29 -06005286{
5287 struct host_command cmd = {
5288 .host_command = TX_POWER_INDEX,
5289 .host_command_sequence = 0,
5290 .host_command_length = 4
5291 };
5292 int err = 0;
Zhu Yi3173ca02006-01-24 13:49:01 +08005293 u32 tmp = tx_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06005294
Liu Hongf75459e2005-07-13 12:29:21 -05005295 if (tx_power != IPW_TX_POWER_DEFAULT)
Zhu Yi3173ca02006-01-24 13:49:01 +08005296 tmp = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 /
5297 (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
Liu Hongf75459e2005-07-13 12:29:21 -05005298
Zhu Yi3173ca02006-01-24 13:49:01 +08005299 cmd.host_command_parameters[0] = tmp;
James Ketrenos2c86c272005-03-23 17:32:29 -06005300
5301 if (priv->ieee->iw_mode == IW_MODE_ADHOC)
5302 err = ipw2100_hw_send_command(priv, &cmd);
5303 if (!err)
5304 priv->tx_power = tx_power;
5305
5306 return 0;
5307}
5308
Jiri Bencc4aee8c2005-08-25 20:04:43 -04005309static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv,
5310 u32 interval, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005311{
5312 struct host_command cmd = {
5313 .host_command = BEACON_INTERVAL,
5314 .host_command_sequence = 0,
5315 .host_command_length = 4
5316 };
5317 int err;
5318
5319 cmd.host_command_parameters[0] = interval;
5320
5321 IPW_DEBUG_INFO("enter\n");
5322
5323 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
5324 if (!batch_mode) {
5325 err = ipw2100_disable_adapter(priv);
5326 if (err)
5327 return err;
5328 }
5329
5330 ipw2100_hw_send_command(priv, &cmd);
5331
5332 if (!batch_mode) {
5333 err = ipw2100_enable_adapter(priv);
5334 if (err)
5335 return err;
5336 }
5337 }
5338
5339 IPW_DEBUG_INFO("exit\n");
5340
5341 return 0;
5342}
5343
Hannes Edera3d1fd22008-12-26 00:14:41 -08005344static void ipw2100_queues_initialize(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005345{
5346 ipw2100_tx_initialize(priv);
5347 ipw2100_rx_initialize(priv);
5348 ipw2100_msg_initialize(priv);
5349}
5350
Hannes Edera3d1fd22008-12-26 00:14:41 -08005351static void ipw2100_queues_free(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005352{
5353 ipw2100_tx_free(priv);
5354 ipw2100_rx_free(priv);
5355 ipw2100_msg_free(priv);
5356}
5357
Hannes Edera3d1fd22008-12-26 00:14:41 -08005358static int ipw2100_queues_allocate(struct ipw2100_priv *priv)
James Ketrenos2c86c272005-03-23 17:32:29 -06005359{
5360 if (ipw2100_tx_allocate(priv) ||
James Ketrenosee8e3652005-09-14 09:47:29 -05005361 ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv))
James Ketrenos2c86c272005-03-23 17:32:29 -06005362 goto fail;
5363
5364 return 0;
5365
James Ketrenosee8e3652005-09-14 09:47:29 -05005366 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06005367 ipw2100_tx_free(priv);
5368 ipw2100_rx_free(priv);
5369 ipw2100_msg_free(priv);
5370 return -ENOMEM;
5371}
5372
5373#define IPW_PRIVACY_CAPABLE 0x0008
5374
5375static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags,
5376 int batch_mode)
5377{
5378 struct host_command cmd = {
5379 .host_command = WEP_FLAGS,
5380 .host_command_sequence = 0,
5381 .host_command_length = 4
5382 };
5383 int err;
5384
5385 cmd.host_command_parameters[0] = flags;
5386
5387 IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags);
5388
5389 if (!batch_mode) {
5390 err = ipw2100_disable_adapter(priv);
5391 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005392 printk(KERN_ERR DRV_NAME
5393 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005394 priv->net_dev->name, err);
5395 return err;
5396 }
5397 }
5398
5399 /* send cmd to firmware */
5400 err = ipw2100_hw_send_command(priv, &cmd);
5401
5402 if (!batch_mode)
5403 ipw2100_enable_adapter(priv);
5404
5405 return err;
5406}
5407
5408struct ipw2100_wep_key {
5409 u8 idx;
5410 u8 len;
5411 u8 key[13];
5412};
5413
5414/* Macros to ease up priting WEP keys */
5415#define WEP_FMT_64 "%02X%02X%02X%02X-%02X"
5416#define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X"
5417#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4]
5418#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]
5419
James Ketrenos2c86c272005-03-23 17:32:29 -06005420/**
5421 * Set a the wep key
5422 *
5423 * @priv: struct to work on
5424 * @idx: index of the key we want to set
5425 * @key: ptr to the key data to set
5426 * @len: length of the buffer at @key
5427 * @batch_mode: FIXME perform the operation in batch mode, not
5428 * disabling the device.
5429 *
5430 * @returns 0 if OK, < 0 errno code on error.
5431 *
5432 * Fill out a command structure with the new wep key, length an
5433 * index and send it down the wire.
5434 */
5435static int ipw2100_set_key(struct ipw2100_priv *priv,
5436 int idx, char *key, int len, int batch_mode)
5437{
5438 int keylen = len ? (len <= 5 ? 5 : 13) : 0;
5439 struct host_command cmd = {
5440 .host_command = WEP_KEY_INFO,
5441 .host_command_sequence = 0,
5442 .host_command_length = sizeof(struct ipw2100_wep_key),
5443 };
James Ketrenosee8e3652005-09-14 09:47:29 -05005444 struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters;
James Ketrenos2c86c272005-03-23 17:32:29 -06005445 int err;
5446
5447 IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005448 idx, keylen, len);
James Ketrenos2c86c272005-03-23 17:32:29 -06005449
5450 /* NOTE: We don't check cached values in case the firmware was reset
Adrian Bunk80f72282006-06-30 18:27:16 +02005451 * or some other problem is occurring. If the user is setting the key,
James Ketrenos2c86c272005-03-23 17:32:29 -06005452 * then we push the change */
5453
5454 wep_key->idx = idx;
5455 wep_key->len = keylen;
5456
5457 if (keylen) {
5458 memcpy(wep_key->key, key, len);
5459 memset(wep_key->key + len, 0, keylen - len);
5460 }
5461
5462 /* Will be optimized out on debug not being configured in */
5463 if (keylen == 0)
5464 IPW_DEBUG_WEP("%s: Clearing key %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005465 priv->net_dev->name, wep_key->idx);
James Ketrenos2c86c272005-03-23 17:32:29 -06005466 else if (keylen == 5)
5467 IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05005468 priv->net_dev->name, wep_key->idx, wep_key->len,
5469 WEP_STR_64(wep_key->key));
James Ketrenos2c86c272005-03-23 17:32:29 -06005470 else
5471 IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128
James Ketrenosee8e3652005-09-14 09:47:29 -05005472 "\n",
5473 priv->net_dev->name, wep_key->idx, wep_key->len,
5474 WEP_STR_128(wep_key->key));
James Ketrenos2c86c272005-03-23 17:32:29 -06005475
5476 if (!batch_mode) {
5477 err = ipw2100_disable_adapter(priv);
5478 /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */
5479 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005480 printk(KERN_ERR DRV_NAME
5481 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005482 priv->net_dev->name, err);
5483 return err;
5484 }
5485 }
5486
5487 /* send cmd to firmware */
5488 err = ipw2100_hw_send_command(priv, &cmd);
5489
5490 if (!batch_mode) {
5491 int err2 = ipw2100_enable_adapter(priv);
5492 if (err == 0)
5493 err = err2;
5494 }
5495 return err;
5496}
5497
5498static int ipw2100_set_key_index(struct ipw2100_priv *priv,
5499 int idx, int batch_mode)
5500{
5501 struct host_command cmd = {
5502 .host_command = WEP_KEY_INDEX,
5503 .host_command_sequence = 0,
5504 .host_command_length = 4,
James Ketrenosee8e3652005-09-14 09:47:29 -05005505 .host_command_parameters = {idx},
James Ketrenos2c86c272005-03-23 17:32:29 -06005506 };
5507 int err;
5508
5509 IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx);
5510
5511 if (idx < 0 || idx > 3)
5512 return -EINVAL;
5513
5514 if (!batch_mode) {
5515 err = ipw2100_disable_adapter(priv);
5516 if (err) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005517 printk(KERN_ERR DRV_NAME
5518 ": %s: Could not disable adapter %d\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06005519 priv->net_dev->name, err);
5520 return err;
5521 }
5522 }
5523
5524 /* send cmd to firmware */
5525 err = ipw2100_hw_send_command(priv, &cmd);
5526
5527 if (!batch_mode)
5528 ipw2100_enable_adapter(priv);
5529
5530 return err;
5531}
5532
James Ketrenosee8e3652005-09-14 09:47:29 -05005533static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06005534{
5535 int i, err, auth_mode, sec_level, use_group;
5536
5537 if (!(priv->status & STATUS_RUNNING))
5538 return 0;
5539
5540 if (!batch_mode) {
5541 err = ipw2100_disable_adapter(priv);
5542 if (err)
5543 return err;
5544 }
5545
25b645b2005-07-12 15:45:30 -05005546 if (!priv->ieee->sec.enabled) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005547 err =
5548 ipw2100_set_security_information(priv, IPW_AUTH_OPEN,
5549 SEC_LEVEL_0, 0, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005550 } else {
5551 auth_mode = IPW_AUTH_OPEN;
Zhu Yicbbdd032006-01-24 13:48:53 +08005552 if (priv->ieee->sec.flags & SEC_AUTH_MODE) {
5553 if (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)
5554 auth_mode = IPW_AUTH_SHARED;
5555 else if (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)
5556 auth_mode = IPW_AUTH_LEAP_CISCO_ID;
5557 }
James Ketrenos2c86c272005-03-23 17:32:29 -06005558
5559 sec_level = SEC_LEVEL_0;
25b645b2005-07-12 15:45:30 -05005560 if (priv->ieee->sec.flags & SEC_LEVEL)
5561 sec_level = priv->ieee->sec.level;
James Ketrenos2c86c272005-03-23 17:32:29 -06005562
5563 use_group = 0;
25b645b2005-07-12 15:45:30 -05005564 if (priv->ieee->sec.flags & SEC_UNICAST_GROUP)
5565 use_group = priv->ieee->sec.unicast_uses_group;
James Ketrenos2c86c272005-03-23 17:32:29 -06005566
James Ketrenosee8e3652005-09-14 09:47:29 -05005567 err =
5568 ipw2100_set_security_information(priv, auth_mode, sec_level,
5569 use_group, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005570 }
5571
5572 if (err)
5573 goto exit;
5574
25b645b2005-07-12 15:45:30 -05005575 if (priv->ieee->sec.enabled) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005576 for (i = 0; i < 4; i++) {
25b645b2005-07-12 15:45:30 -05005577 if (!(priv->ieee->sec.flags & (1 << i))) {
5578 memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN);
5579 priv->ieee->sec.key_sizes[i] = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005580 } else {
5581 err = ipw2100_set_key(priv, i,
25b645b2005-07-12 15:45:30 -05005582 priv->ieee->sec.keys[i],
5583 priv->ieee->sec.
5584 key_sizes[i], 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005585 if (err)
5586 goto exit;
5587 }
5588 }
5589
John W. Linville274bfb82008-10-29 11:35:05 -04005590 ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005591 }
5592
5593 /* Always enable privacy so the Host can filter WEP packets if
5594 * encrypted data is sent up */
James Ketrenosee8e3652005-09-14 09:47:29 -05005595 err =
5596 ipw2100_set_wep_flags(priv,
25b645b2005-07-12 15:45:30 -05005597 priv->ieee->sec.
5598 enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
James Ketrenos2c86c272005-03-23 17:32:29 -06005599 if (err)
5600 goto exit;
5601
5602 priv->status &= ~STATUS_SECURITY_UPDATED;
5603
James Ketrenosee8e3652005-09-14 09:47:29 -05005604 exit:
James Ketrenos2c86c272005-03-23 17:32:29 -06005605 if (!batch_mode)
5606 ipw2100_enable_adapter(priv);
5607
5608 return err;
5609}
5610
David Howellsc4028952006-11-22 14:57:56 +00005611static void ipw2100_security_work(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06005612{
David Howellsc4028952006-11-22 14:57:56 +00005613 struct ipw2100_priv *priv =
5614 container_of(work, struct ipw2100_priv, security_work.work);
5615
James Ketrenos2c86c272005-03-23 17:32:29 -06005616 /* If we happen to have reconnected before we get a chance to
5617 * process this, then update the security settings--which causes
5618 * a disassociation to occur */
5619 if (!(priv->status & STATUS_ASSOCIATED) &&
5620 priv->status & STATUS_SECURITY_UPDATED)
5621 ipw2100_configure_security(priv, 0);
5622}
5623
5624static void shim__set_security(struct net_device *dev,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005625 struct libipw_security *sec)
James Ketrenos2c86c272005-03-23 17:32:29 -06005626{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005627 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005628 int i, force_update = 0;
5629
Ingo Molnar752e3772006-02-28 07:20:54 +08005630 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005631 if (!(priv->status & STATUS_INITIALIZED))
5632 goto done;
5633
5634 for (i = 0; i < 4; i++) {
5635 if (sec->flags & (1 << i)) {
25b645b2005-07-12 15:45:30 -05005636 priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
James Ketrenos2c86c272005-03-23 17:32:29 -06005637 if (sec->key_sizes[i] == 0)
25b645b2005-07-12 15:45:30 -05005638 priv->ieee->sec.flags &= ~(1 << i);
James Ketrenos2c86c272005-03-23 17:32:29 -06005639 else
25b645b2005-07-12 15:45:30 -05005640 memcpy(priv->ieee->sec.keys[i], sec->keys[i],
James Ketrenos2c86c272005-03-23 17:32:29 -06005641 sec->key_sizes[i]);
Hong Liu054b08d2005-08-25 17:45:49 +08005642 if (sec->level == SEC_LEVEL_1) {
5643 priv->ieee->sec.flags |= (1 << i);
5644 priv->status |= STATUS_SECURITY_UPDATED;
5645 } else
5646 priv->ieee->sec.flags &= ~(1 << i);
James Ketrenos2c86c272005-03-23 17:32:29 -06005647 }
5648 }
5649
5650 if ((sec->flags & SEC_ACTIVE_KEY) &&
25b645b2005-07-12 15:45:30 -05005651 priv->ieee->sec.active_key != sec->active_key) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005652 if (sec->active_key <= 3) {
25b645b2005-07-12 15:45:30 -05005653 priv->ieee->sec.active_key = sec->active_key;
5654 priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
James Ketrenos2c86c272005-03-23 17:32:29 -06005655 } else
25b645b2005-07-12 15:45:30 -05005656 priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
James Ketrenos2c86c272005-03-23 17:32:29 -06005657
5658 priv->status |= STATUS_SECURITY_UPDATED;
5659 }
5660
5661 if ((sec->flags & SEC_AUTH_MODE) &&
25b645b2005-07-12 15:45:30 -05005662 (priv->ieee->sec.auth_mode != sec->auth_mode)) {
5663 priv->ieee->sec.auth_mode = sec->auth_mode;
5664 priv->ieee->sec.flags |= SEC_AUTH_MODE;
James Ketrenos2c86c272005-03-23 17:32:29 -06005665 priv->status |= STATUS_SECURITY_UPDATED;
5666 }
5667
25b645b2005-07-12 15:45:30 -05005668 if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
5669 priv->ieee->sec.flags |= SEC_ENABLED;
5670 priv->ieee->sec.enabled = sec->enabled;
James Ketrenos2c86c272005-03-23 17:32:29 -06005671 priv->status |= STATUS_SECURITY_UPDATED;
5672 force_update = 1;
5673 }
5674
25b645b2005-07-12 15:45:30 -05005675 if (sec->flags & SEC_ENCRYPT)
5676 priv->ieee->sec.encrypt = sec->encrypt;
5677
5678 if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
5679 priv->ieee->sec.level = sec->level;
5680 priv->ieee->sec.flags |= SEC_LEVEL;
James Ketrenos2c86c272005-03-23 17:32:29 -06005681 priv->status |= STATUS_SECURITY_UPDATED;
5682 }
5683
5684 IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n",
25b645b2005-07-12 15:45:30 -05005685 priv->ieee->sec.flags & (1 << 8) ? '1' : '0',
5686 priv->ieee->sec.flags & (1 << 7) ? '1' : '0',
5687 priv->ieee->sec.flags & (1 << 6) ? '1' : '0',
5688 priv->ieee->sec.flags & (1 << 5) ? '1' : '0',
5689 priv->ieee->sec.flags & (1 << 4) ? '1' : '0',
5690 priv->ieee->sec.flags & (1 << 3) ? '1' : '0',
5691 priv->ieee->sec.flags & (1 << 2) ? '1' : '0',
5692 priv->ieee->sec.flags & (1 << 1) ? '1' : '0',
5693 priv->ieee->sec.flags & (1 << 0) ? '1' : '0');
James Ketrenos2c86c272005-03-23 17:32:29 -06005694
5695/* As a temporary work around to enable WPA until we figure out why
5696 * wpa_supplicant toggles the security capability of the driver, which
5697 * forces a disassocation with force_update...
5698 *
5699 * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/
5700 if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
5701 ipw2100_configure_security(priv, 0);
James Ketrenosee8e3652005-09-14 09:47:29 -05005702 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08005703 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005704}
5705
5706static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
5707{
5708 int err;
5709 int batch_mode = 1;
5710 u8 *bssid;
5711
5712 IPW_DEBUG_INFO("enter\n");
5713
5714 err = ipw2100_disable_adapter(priv);
5715 if (err)
5716 return err;
5717#ifdef CONFIG_IPW2100_MONITOR
5718 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
5719 err = ipw2100_set_channel(priv, priv->channel, batch_mode);
5720 if (err)
5721 return err;
5722
5723 IPW_DEBUG_INFO("exit\n");
5724
5725 return 0;
5726 }
James Ketrenosee8e3652005-09-14 09:47:29 -05005727#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06005728
5729 err = ipw2100_read_mac_address(priv);
5730 if (err)
5731 return -EIO;
5732
5733 err = ipw2100_set_mac_address(priv, batch_mode);
5734 if (err)
5735 return err;
5736
5737 err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode);
5738 if (err)
5739 return err;
5740
5741 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
5742 err = ipw2100_set_channel(priv, priv->channel, batch_mode);
5743 if (err)
5744 return err;
5745 }
5746
James Ketrenosee8e3652005-09-14 09:47:29 -05005747 err = ipw2100_system_config(priv, batch_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06005748 if (err)
5749 return err;
5750
5751 err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode);
5752 if (err)
5753 return err;
5754
5755 /* Default to power mode OFF */
5756 err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
5757 if (err)
5758 return err;
5759
5760 err = ipw2100_set_rts_threshold(priv, priv->rts_threshold);
5761 if (err)
5762 return err;
5763
5764 if (priv->config & CFG_STATIC_BSSID)
5765 bssid = priv->bssid;
5766 else
5767 bssid = NULL;
5768 err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode);
5769 if (err)
5770 return err;
5771
5772 if (priv->config & CFG_STATIC_ESSID)
5773 err = ipw2100_set_essid(priv, priv->essid, priv->essid_len,
5774 batch_mode);
5775 else
5776 err = ipw2100_set_essid(priv, NULL, 0, batch_mode);
5777 if (err)
5778 return err;
5779
5780 err = ipw2100_configure_security(priv, batch_mode);
5781 if (err)
5782 return err;
5783
5784 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
James Ketrenosee8e3652005-09-14 09:47:29 -05005785 err =
5786 ipw2100_set_ibss_beacon_interval(priv,
5787 priv->beacon_interval,
5788 batch_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06005789 if (err)
5790 return err;
5791
5792 err = ipw2100_set_tx_power(priv, priv->tx_power);
5793 if (err)
5794 return err;
5795 }
5796
5797 /*
James Ketrenosee8e3652005-09-14 09:47:29 -05005798 err = ipw2100_set_fragmentation_threshold(
5799 priv, priv->frag_threshold, batch_mode);
5800 if (err)
5801 return err;
5802 */
James Ketrenos2c86c272005-03-23 17:32:29 -06005803
5804 IPW_DEBUG_INFO("exit\n");
5805
5806 return 0;
5807}
5808
James Ketrenos2c86c272005-03-23 17:32:29 -06005809/*************************************************************************
5810 *
5811 * EXTERNALLY CALLED METHODS
5812 *
5813 *************************************************************************/
5814
5815/* This method is called by the network layer -- not to be confused with
5816 * ipw2100_set_mac_address() declared above called by this driver (and this
5817 * method as well) to talk to the firmware */
5818static int ipw2100_set_address(struct net_device *dev, void *p)
5819{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005820 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005821 struct sockaddr *addr = p;
5822 int err = 0;
5823
5824 if (!is_valid_ether_addr(addr->sa_data))
5825 return -EADDRNOTAVAIL;
5826
Ingo Molnar752e3772006-02-28 07:20:54 +08005827 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005828
5829 priv->config |= CFG_CUSTOM_MAC;
5830 memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
5831
5832 err = ipw2100_set_mac_address(priv, 0);
5833 if (err)
5834 goto done;
5835
5836 priv->reset_backoff = 0;
Ingo Molnar752e3772006-02-28 07:20:54 +08005837 mutex_unlock(&priv->action_mutex);
David Howellsc4028952006-11-22 14:57:56 +00005838 ipw2100_reset_adapter(&priv->reset_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06005839 return 0;
5840
James Ketrenosee8e3652005-09-14 09:47:29 -05005841 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08005842 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06005843 return err;
5844}
5845
5846static int ipw2100_open(struct net_device *dev)
5847{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005848 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005849 unsigned long flags;
5850 IPW_DEBUG_INFO("dev->open\n");
5851
5852 spin_lock_irqsave(&priv->low_lock, flags);
Jiri Benc3ce329c2005-08-25 20:07:01 -04005853 if (priv->status & STATUS_ASSOCIATED) {
5854 netif_carrier_on(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005855 netif_start_queue(dev);
Jiri Benc3ce329c2005-08-25 20:07:01 -04005856 }
James Ketrenos2c86c272005-03-23 17:32:29 -06005857 spin_unlock_irqrestore(&priv->low_lock, flags);
5858
5859 return 0;
5860}
5861
5862static int ipw2100_close(struct net_device *dev)
5863{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005864 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005865 unsigned long flags;
5866 struct list_head *element;
5867 struct ipw2100_tx_packet *packet;
5868
5869 IPW_DEBUG_INFO("enter\n");
5870
5871 spin_lock_irqsave(&priv->low_lock, flags);
5872
5873 if (priv->status & STATUS_ASSOCIATED)
5874 netif_carrier_off(dev);
5875 netif_stop_queue(dev);
5876
5877 /* Flush the TX queue ... */
5878 while (!list_empty(&priv->tx_pend_list)) {
5879 element = priv->tx_pend_list.next;
James Ketrenosee8e3652005-09-14 09:47:29 -05005880 packet = list_entry(element, struct ipw2100_tx_packet, list);
James Ketrenos2c86c272005-03-23 17:32:29 -06005881
5882 list_del(element);
5883 DEC_STAT(&priv->tx_pend_stat);
5884
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005885 libipw_txb_free(packet->info.d_struct.txb);
James Ketrenos2c86c272005-03-23 17:32:29 -06005886 packet->info.d_struct.txb = NULL;
5887
5888 list_add_tail(element, &priv->tx_free_list);
5889 INC_STAT(&priv->tx_free_stat);
5890 }
5891 spin_unlock_irqrestore(&priv->low_lock, flags);
5892
5893 IPW_DEBUG_INFO("exit\n");
5894
5895 return 0;
5896}
5897
James Ketrenos2c86c272005-03-23 17:32:29 -06005898/*
5899 * TODO: Fix this function... its just wrong
5900 */
5901static void ipw2100_tx_timeout(struct net_device *dev)
5902{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005903 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005904
Stephen Hemmingerce55cba2009-03-20 19:36:38 +00005905 dev->stats.tx_errors++;
James Ketrenos2c86c272005-03-23 17:32:29 -06005906
5907#ifdef CONFIG_IPW2100_MONITOR
5908 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
5909 return;
5910#endif
5911
5912 IPW_DEBUG_INFO("%s: TX timed out. Scheduling firmware restart.\n",
5913 dev->name);
5914 schedule_reset(priv);
5915}
5916
James Ketrenosee8e3652005-09-14 09:47:29 -05005917static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value)
5918{
James Ketrenos82328352005-08-24 22:33:31 -05005919 /* This is called when wpa_supplicant loads and closes the driver
5920 * interface. */
5921 priv->ieee->wpa_enabled = value;
5922 return 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005923}
5924
James Ketrenosee8e3652005-09-14 09:47:29 -05005925static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value)
5926{
James Ketrenos2c86c272005-03-23 17:32:29 -06005927
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005928 struct libipw_device *ieee = priv->ieee;
5929 struct libipw_security sec = {
James Ketrenos2c86c272005-03-23 17:32:29 -06005930 .flags = SEC_AUTH_MODE,
5931 };
5932 int ret = 0;
5933
James Ketrenos82328352005-08-24 22:33:31 -05005934 if (value & IW_AUTH_ALG_SHARED_KEY) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005935 sec.auth_mode = WLAN_AUTH_SHARED_KEY;
5936 ieee->open_wep = 0;
James Ketrenos82328352005-08-24 22:33:31 -05005937 } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
James Ketrenos2c86c272005-03-23 17:32:29 -06005938 sec.auth_mode = WLAN_AUTH_OPEN;
5939 ieee->open_wep = 1;
Zhu Yicbbdd032006-01-24 13:48:53 +08005940 } else if (value & IW_AUTH_ALG_LEAP) {
5941 sec.auth_mode = WLAN_AUTH_LEAP;
5942 ieee->open_wep = 1;
James Ketrenos82328352005-08-24 22:33:31 -05005943 } else
5944 return -EINVAL;
James Ketrenos2c86c272005-03-23 17:32:29 -06005945
5946 if (ieee->set_security)
5947 ieee->set_security(ieee->dev, &sec);
5948 else
5949 ret = -EOPNOTSUPP;
5950
5951 return ret;
5952}
5953
Adrian Bunk3c398b82006-01-21 01:36:36 +01005954static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
5955 char *wpa_ie, int wpa_ie_len)
James Ketrenosee8e3652005-09-14 09:47:29 -05005956{
James Ketrenos2c86c272005-03-23 17:32:29 -06005957
5958 struct ipw2100_wpa_assoc_frame frame;
5959
5960 frame.fixed_ie_mask = 0;
5961
5962 /* copy WPA IE */
5963 memcpy(frame.var_ie, wpa_ie, wpa_ie_len);
5964 frame.var_ie_len = wpa_ie_len;
5965
5966 /* make sure WPA is enabled */
5967 ipw2100_wpa_enable(priv, 1);
5968 ipw2100_set_wpa_ie(priv, &frame, 0);
5969}
5970
James Ketrenos2c86c272005-03-23 17:32:29 -06005971static void ipw_ethtool_get_drvinfo(struct net_device *dev,
5972 struct ethtool_drvinfo *info)
5973{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005974 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06005975 char fw_ver[64], ucode_ver[64];
5976
Rick Jones1f80c232011-11-15 10:40:49 -08005977 strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
5978 strlcpy(info->version, DRV_VERSION, sizeof(info->version));
James Ketrenos2c86c272005-03-23 17:32:29 -06005979
5980 ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver));
5981 ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver));
5982
5983 snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s",
5984 fw_ver, priv->eeprom_version, ucode_ver);
5985
Rick Jones1f80c232011-11-15 10:40:49 -08005986 strlcpy(info->bus_info, pci_name(priv->pci_dev),
5987 sizeof(info->bus_info));
James Ketrenos2c86c272005-03-23 17:32:29 -06005988}
5989
5990static u32 ipw2100_ethtool_get_link(struct net_device *dev)
5991{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04005992 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05005993 return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06005994}
5995
Jeff Garzik7282d492006-09-13 14:30:00 -04005996static const struct ethtool_ops ipw2100_ethtool_ops = {
James Ketrenosee8e3652005-09-14 09:47:29 -05005997 .get_link = ipw2100_ethtool_get_link,
5998 .get_drvinfo = ipw_ethtool_get_drvinfo,
James Ketrenos2c86c272005-03-23 17:32:29 -06005999};
6000
David Howellsc4028952006-11-22 14:57:56 +00006001static void ipw2100_hang_check(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06006002{
David Howellsc4028952006-11-22 14:57:56 +00006003 struct ipw2100_priv *priv =
6004 container_of(work, struct ipw2100_priv, hang_check.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06006005 unsigned long flags;
6006 u32 rtc = 0xa5a5a5a5;
6007 u32 len = sizeof(rtc);
6008 int restart = 0;
6009
6010 spin_lock_irqsave(&priv->low_lock, flags);
6011
6012 if (priv->fatal_error != 0) {
6013 /* If fatal_error is set then we need to restart */
6014 IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n",
6015 priv->net_dev->name);
6016
6017 restart = 1;
6018 } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) ||
6019 (rtc == priv->last_rtc)) {
6020 /* Check if firmware is hung */
6021 IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n",
6022 priv->net_dev->name);
6023
6024 restart = 1;
6025 }
6026
6027 if (restart) {
6028 /* Kill timer */
6029 priv->stop_hang_check = 1;
6030 priv->hangs++;
6031
6032 /* Restart the NIC */
6033 schedule_reset(priv);
6034 }
6035
6036 priv->last_rtc = rtc;
6037
6038 if (!priv->stop_hang_check)
Tejun Heobcb6d912011-01-26 12:12:50 +01006039 schedule_delayed_work(&priv->hang_check, HZ / 2);
James Ketrenos2c86c272005-03-23 17:32:29 -06006040
6041 spin_unlock_irqrestore(&priv->low_lock, flags);
6042}
6043
David Howellsc4028952006-11-22 14:57:56 +00006044static void ipw2100_rf_kill(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06006045{
David Howellsc4028952006-11-22 14:57:56 +00006046 struct ipw2100_priv *priv =
6047 container_of(work, struct ipw2100_priv, rf_kill.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06006048 unsigned long flags;
6049
6050 spin_lock_irqsave(&priv->low_lock, flags);
6051
6052 if (rf_kill_active(priv)) {
6053 IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
6054 if (!priv->stop_rf_kill)
Tejun Heobcb6d912011-01-26 12:12:50 +01006055 schedule_delayed_work(&priv->rf_kill,
6056 round_jiffies_relative(HZ));
James Ketrenos2c86c272005-03-23 17:32:29 -06006057 goto exit_unlock;
6058 }
6059
6060 /* RF Kill is now disabled, so bring the device back up */
6061
6062 if (!(priv->status & STATUS_RF_KILL_MASK)) {
6063 IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
6064 "device\n");
6065 schedule_reset(priv);
6066 } else
6067 IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
6068 "enabled\n");
6069
James Ketrenosee8e3652005-09-14 09:47:29 -05006070 exit_unlock:
James Ketrenos2c86c272005-03-23 17:32:29 -06006071 spin_unlock_irqrestore(&priv->low_lock, flags);
6072}
6073
6074static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
6075
Stephen Hemminger3e47fce2009-03-20 19:36:40 +00006076static const struct net_device_ops ipw2100_netdev_ops = {
6077 .ndo_open = ipw2100_open,
6078 .ndo_stop = ipw2100_close,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006079 .ndo_start_xmit = libipw_xmit,
6080 .ndo_change_mtu = libipw_change_mtu,
Stephen Hemminger3e47fce2009-03-20 19:36:40 +00006081 .ndo_init = ipw2100_net_init,
6082 .ndo_tx_timeout = ipw2100_tx_timeout,
6083 .ndo_set_mac_address = ipw2100_set_address,
6084 .ndo_validate_addr = eth_validate_addr,
6085};
6086
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006087/* Look into using netdev destructor to shutdown libipw? */
James Ketrenos2c86c272005-03-23 17:32:29 -06006088
James Ketrenosee8e3652005-09-14 09:47:29 -05006089static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
6090 void __iomem * base_addr,
6091 unsigned long mem_start,
6092 unsigned long mem_len)
James Ketrenos2c86c272005-03-23 17:32:29 -06006093{
6094 struct ipw2100_priv *priv;
6095 struct net_device *dev;
6096
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006097 dev = alloc_libipw(sizeof(struct ipw2100_priv), 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006098 if (!dev)
6099 return NULL;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006100 priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006101 priv->ieee = netdev_priv(dev);
6102 priv->pci_dev = pci_dev;
6103 priv->net_dev = dev;
6104
6105 priv->ieee->hard_start_xmit = ipw2100_tx;
6106 priv->ieee->set_security = shim__set_security;
6107
James Ketrenos82328352005-08-24 22:33:31 -05006108 priv->ieee->perfect_rssi = -20;
6109 priv->ieee->worst_rssi = -85;
6110
Stephen Hemminger3e47fce2009-03-20 19:36:40 +00006111 dev->netdev_ops = &ipw2100_netdev_ops;
James Ketrenos2c86c272005-03-23 17:32:29 -06006112 dev->ethtool_ops = &ipw2100_ethtool_ops;
James Ketrenos2c86c272005-03-23 17:32:29 -06006113 dev->wireless_handlers = &ipw2100_wx_handler_def;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006114 priv->wireless_data.libipw = priv->ieee;
James Ketrenoseaf8f532005-11-12 12:50:12 -06006115 dev->wireless_data = &priv->wireless_data;
James Ketrenosee8e3652005-09-14 09:47:29 -05006116 dev->watchdog_timeo = 3 * HZ;
James Ketrenos2c86c272005-03-23 17:32:29 -06006117 dev->irq = 0;
6118
6119 dev->base_addr = (unsigned long)base_addr;
6120 dev->mem_start = mem_start;
6121 dev->mem_end = dev->mem_start + mem_len - 1;
6122
6123 /* NOTE: We don't use the wireless_handlers hook
6124 * in dev as the system will start throwing WX requests
6125 * to us before we're actually initialized and it just
6126 * ends up causing problems. So, we just handle
6127 * the WX extensions through the ipw2100_ioctl interface */
6128
Jean Delvarec03983a2007-10-19 23:22:55 +02006129 /* memset() puts everything to 0, so we only have explicitly set
James Ketrenos2c86c272005-03-23 17:32:29 -06006130 * those values that need to be something else */
6131
6132 /* If power management is turned on, default to AUTO mode */
6133 priv->power_mode = IPW_POWER_AUTO;
6134
James Ketrenos82328352005-08-24 22:33:31 -05006135#ifdef CONFIG_IPW2100_MONITOR
6136 priv->config |= CFG_CRC_CHECK;
6137#endif
James Ketrenos2c86c272005-03-23 17:32:29 -06006138 priv->ieee->wpa_enabled = 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06006139 priv->ieee->drop_unencrypted = 0;
6140 priv->ieee->privacy_invoked = 0;
6141 priv->ieee->ieee802_1x = 1;
James Ketrenos2c86c272005-03-23 17:32:29 -06006142
6143 /* Set module parameters */
Reinette Chatre21f8a732009-08-18 10:25:05 -07006144 switch (network_mode) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006145 case 1:
6146 priv->ieee->iw_mode = IW_MODE_ADHOC;
6147 break;
6148#ifdef CONFIG_IPW2100_MONITOR
6149 case 2:
6150 priv->ieee->iw_mode = IW_MODE_MONITOR;
6151 break;
6152#endif
6153 default:
6154 case 0:
6155 priv->ieee->iw_mode = IW_MODE_INFRA;
6156 break;
6157 }
6158
6159 if (disable == 1)
6160 priv->status |= STATUS_RF_KILL_SW;
6161
6162 if (channel != 0 &&
James Ketrenosee8e3652005-09-14 09:47:29 -05006163 ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006164 priv->config |= CFG_STATIC_CHANNEL;
6165 priv->channel = channel;
6166 }
6167
6168 if (associate)
6169 priv->config |= CFG_ASSOCIATE;
6170
6171 priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
6172 priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
6173 priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
6174 priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED;
6175 priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED;
6176 priv->tx_power = IPW_TX_POWER_DEFAULT;
6177 priv->tx_rates = DEFAULT_TX_RATES;
6178
6179 strcpy(priv->nick, "ipw2100");
6180
6181 spin_lock_init(&priv->low_lock);
Ingo Molnar752e3772006-02-28 07:20:54 +08006182 mutex_init(&priv->action_mutex);
6183 mutex_init(&priv->adapter_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006184
6185 init_waitqueue_head(&priv->wait_command_queue);
6186
6187 netif_carrier_off(dev);
6188
6189 INIT_LIST_HEAD(&priv->msg_free_list);
6190 INIT_LIST_HEAD(&priv->msg_pend_list);
6191 INIT_STAT(&priv->msg_free_stat);
6192 INIT_STAT(&priv->msg_pend_stat);
6193
6194 INIT_LIST_HEAD(&priv->tx_free_list);
6195 INIT_LIST_HEAD(&priv->tx_pend_list);
6196 INIT_STAT(&priv->tx_free_stat);
6197 INIT_STAT(&priv->tx_pend_stat);
6198
6199 INIT_LIST_HEAD(&priv->fw_pend_list);
6200 INIT_STAT(&priv->fw_pend_stat);
6201
David Howellsc4028952006-11-22 14:57:56 +00006202 INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter);
6203 INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work);
6204 INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
6205 INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
6206 INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
Dan Williamsd20c6782007-10-10 12:28:07 -04006207 INIT_WORK(&priv->scan_event_now, ipw2100_scan_event_now);
6208 INIT_DELAYED_WORK(&priv->scan_event_later, ipw2100_scan_event_later);
James Ketrenos2c86c272005-03-23 17:32:29 -06006209
6210 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
6211 ipw2100_irq_tasklet, (unsigned long)priv);
6212
6213 /* NOTE: We do not start the deferred work for status checks yet */
6214 priv->stop_rf_kill = 1;
6215 priv->stop_hang_check = 1;
6216
6217 return dev;
6218}
6219
James Ketrenos2c86c272005-03-23 17:32:29 -06006220static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
6221 const struct pci_device_id *ent)
6222{
6223 unsigned long mem_start, mem_len, mem_flags;
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01006224 void __iomem *base_addr = NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06006225 struct net_device *dev = NULL;
6226 struct ipw2100_priv *priv = NULL;
6227 int err = 0;
6228 int registered = 0;
6229 u32 val;
6230
6231 IPW_DEBUG_INFO("enter\n");
6232
6233 mem_start = pci_resource_start(pci_dev, 0);
6234 mem_len = pci_resource_len(pci_dev, 0);
6235 mem_flags = pci_resource_flags(pci_dev, 0);
6236
6237 if ((mem_flags & IORESOURCE_MEM) != IORESOURCE_MEM) {
6238 IPW_DEBUG_INFO("weird - resource type is not memory\n");
6239 err = -ENODEV;
6240 goto fail;
6241 }
6242
6243 base_addr = ioremap_nocache(mem_start, mem_len);
6244 if (!base_addr) {
6245 printk(KERN_WARNING DRV_NAME
6246 "Error calling ioremap_nocache.\n");
6247 err = -EIO;
6248 goto fail;
6249 }
6250
6251 /* allocate and initialize our net_device */
6252 dev = ipw2100_alloc_device(pci_dev, base_addr, mem_start, mem_len);
6253 if (!dev) {
6254 printk(KERN_WARNING DRV_NAME
6255 "Error calling ipw2100_alloc_device.\n");
6256 err = -ENOMEM;
6257 goto fail;
6258 }
6259
6260 /* set up PCI mappings for device */
6261 err = pci_enable_device(pci_dev);
6262 if (err) {
6263 printk(KERN_WARNING DRV_NAME
6264 "Error calling pci_enable_device.\n");
6265 return err;
6266 }
6267
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006268 priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006269
6270 pci_set_master(pci_dev);
6271 pci_set_drvdata(pci_dev, priv);
6272
Yang Hongyang284901a2009-04-06 19:01:15 -07006273 err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
James Ketrenos2c86c272005-03-23 17:32:29 -06006274 if (err) {
6275 printk(KERN_WARNING DRV_NAME
6276 "Error calling pci_set_dma_mask.\n");
6277 pci_disable_device(pci_dev);
6278 return err;
6279 }
6280
6281 err = pci_request_regions(pci_dev, DRV_NAME);
6282 if (err) {
6283 printk(KERN_WARNING DRV_NAME
6284 "Error calling pci_request_regions.\n");
6285 pci_disable_device(pci_dev);
6286 return err;
6287 }
6288
James Ketrenosee8e3652005-09-14 09:47:29 -05006289 /* We disable the RETRY_TIMEOUT register (0x41) to keep
James Ketrenos2c86c272005-03-23 17:32:29 -06006290 * PCI Tx retries from interfering with C3 CPU state */
6291 pci_read_config_dword(pci_dev, 0x40, &val);
6292 if ((val & 0x0000ff00) != 0)
6293 pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
6294
Pavel Machek8724a112005-06-20 14:28:43 -07006295 pci_set_power_state(pci_dev, PCI_D0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006296
6297 if (!ipw2100_hw_is_adapter_in_system(dev)) {
6298 printk(KERN_WARNING DRV_NAME
6299 "Device not found via register read.\n");
6300 err = -ENODEV;
6301 goto fail;
6302 }
6303
6304 SET_NETDEV_DEV(dev, &pci_dev->dev);
6305
6306 /* Force interrupts to be shut off on the device */
6307 priv->status |= STATUS_INT_ENABLED;
6308 ipw2100_disable_interrupts(priv);
6309
6310 /* Allocate and initialize the Tx/Rx queues and lists */
6311 if (ipw2100_queues_allocate(priv)) {
6312 printk(KERN_WARNING DRV_NAME
Zhu Yi90c009a2006-12-05 14:41:32 +08006313 "Error calling ipw2100_queues_allocate.\n");
James Ketrenos2c86c272005-03-23 17:32:29 -06006314 err = -ENOMEM;
6315 goto fail;
6316 }
6317 ipw2100_queues_initialize(priv);
6318
6319 err = request_irq(pci_dev->irq,
Thomas Gleixner1fb9df52006-07-01 19:29:39 -07006320 ipw2100_interrupt, IRQF_SHARED, dev->name, priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006321 if (err) {
6322 printk(KERN_WARNING DRV_NAME
James Ketrenosee8e3652005-09-14 09:47:29 -05006323 "Error calling request_irq: %d.\n", pci_dev->irq);
James Ketrenos2c86c272005-03-23 17:32:29 -06006324 goto fail;
6325 }
6326 dev->irq = pci_dev->irq;
6327
6328 IPW_DEBUG_INFO("Attempting to register device...\n");
6329
James Ketrenos2c86c272005-03-23 17:32:29 -06006330 printk(KERN_INFO DRV_NAME
6331 ": Detected Intel PRO/Wireless 2100 Network Connection\n");
6332
6333 /* Bring up the interface. Pre 0.46, after we registered the
6334 * network device we would call ipw2100_up. This introduced a race
6335 * condition with newer hotplug configurations (network was coming
6336 * up and making calls before the device was initialized).
6337 *
6338 * If we called ipw2100_up before we registered the device, then the
6339 * device name wasn't registered. So, we instead use the net_dev->init
6340 * member to call a function that then just turns and calls ipw2100_up.
6341 * net_dev->init is called after name allocation but before the
6342 * notifier chain is called */
James Ketrenos2c86c272005-03-23 17:32:29 -06006343 err = register_netdev(dev);
6344 if (err) {
6345 printk(KERN_WARNING DRV_NAME
6346 "Error calling register_netdev.\n");
Zhu Yiefbd8092006-08-21 11:38:52 +08006347 goto fail;
James Ketrenos2c86c272005-03-23 17:32:29 -06006348 }
Stanislaw Gruszka7cabafc2011-09-14 16:47:50 +02006349 registered = 1;
6350
6351 err = ipw2100_wdev_init(dev);
6352 if (err)
6353 goto fail;
Zhu Yiefbd8092006-08-21 11:38:52 +08006354
6355 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006356
6357 IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
6358
6359 /* perform this after register_netdev so that dev->name is set */
Jeff Garzikde897882006-10-01 07:31:09 -04006360 err = sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
6361 if (err)
6362 goto fail_unlock;
James Ketrenos2c86c272005-03-23 17:32:29 -06006363
6364 /* If the RF Kill switch is disabled, go ahead and complete the
6365 * startup sequence */
6366 if (!(priv->status & STATUS_RF_KILL_MASK)) {
6367 /* Enable the adapter - sends HOST_COMPLETE */
6368 if (ipw2100_enable_adapter(priv)) {
6369 printk(KERN_WARNING DRV_NAME
6370 ": %s: failed in call to enable adapter.\n",
6371 priv->net_dev->name);
6372 ipw2100_hw_stop_adapter(priv);
6373 err = -EIO;
6374 goto fail_unlock;
6375 }
6376
6377 /* Start a scan . . . */
6378 ipw2100_set_scan_options(priv);
6379 ipw2100_start_scan(priv);
6380 }
6381
6382 IPW_DEBUG_INFO("exit\n");
6383
6384 priv->status |= STATUS_INITIALIZED;
6385
Ingo Molnar752e3772006-02-28 07:20:54 +08006386 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006387
6388 return 0;
6389
James Ketrenosee8e3652005-09-14 09:47:29 -05006390 fail_unlock:
Ingo Molnar752e3772006-02-28 07:20:54 +08006391 mutex_unlock(&priv->action_mutex);
Stanislaw Gruszka7cabafc2011-09-14 16:47:50 +02006392 wiphy_unregister(priv->ieee->wdev.wiphy);
6393 kfree(priv->ieee->bg_band.channels);
James Ketrenosee8e3652005-09-14 09:47:29 -05006394 fail:
James Ketrenos2c86c272005-03-23 17:32:29 -06006395 if (dev) {
John W. Linville143d40f2009-11-06 12:58:20 -05006396 if (registered)
James Ketrenos2c86c272005-03-23 17:32:29 -06006397 unregister_netdev(dev);
6398
6399 ipw2100_hw_stop_adapter(priv);
6400
6401 ipw2100_disable_interrupts(priv);
6402
6403 if (dev->irq)
6404 free_irq(dev->irq, priv);
6405
Tejun Heobcb6d912011-01-26 12:12:50 +01006406 ipw2100_kill_works(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006407
6408 /* These are safe to call even if they weren't allocated */
6409 ipw2100_queues_free(priv);
James Ketrenosee8e3652005-09-14 09:47:29 -05006410 sysfs_remove_group(&pci_dev->dev.kobj,
6411 &ipw2100_attribute_group);
James Ketrenos2c86c272005-03-23 17:32:29 -06006412
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006413 free_libipw(dev, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006414 pci_set_drvdata(pci_dev, NULL);
6415 }
6416
6417 if (base_addr)
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01006418 iounmap(base_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06006419
6420 pci_release_regions(pci_dev);
6421 pci_disable_device(pci_dev);
6422
6423 return err;
6424}
6425
6426static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
6427{
6428 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6429 struct net_device *dev;
6430
6431 if (priv) {
Ingo Molnar752e3772006-02-28 07:20:54 +08006432 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006433
6434 priv->status &= ~STATUS_INITIALIZED;
6435
6436 dev = priv->net_dev;
James Ketrenosee8e3652005-09-14 09:47:29 -05006437 sysfs_remove_group(&pci_dev->dev.kobj,
6438 &ipw2100_attribute_group);
James Ketrenos2c86c272005-03-23 17:32:29 -06006439
6440#ifdef CONFIG_PM
6441 if (ipw2100_firmware.version)
6442 ipw2100_release_firmware(priv, &ipw2100_firmware);
6443#endif
6444 /* Take down the hardware */
6445 ipw2100_down(priv);
6446
Ingo Molnar752e3772006-02-28 07:20:54 +08006447 /* Release the mutex so that the network subsystem can
James Ketrenos2c86c272005-03-23 17:32:29 -06006448 * complete any needed calls into the driver... */
Ingo Molnar752e3772006-02-28 07:20:54 +08006449 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006450
6451 /* Unregister the device first - this results in close()
6452 * being called if the device is open. If we free storage
6453 * first, then close() will crash. */
6454 unregister_netdev(dev);
6455
Tejun Heobcb6d912011-01-26 12:12:50 +01006456 ipw2100_kill_works(priv);
James Ketrenos2c86c272005-03-23 17:32:29 -06006457
6458 ipw2100_queues_free(priv);
6459
6460 /* Free potential debugging firmware snapshot */
6461 ipw2100_snapshot_free(priv);
6462
6463 if (dev->irq)
6464 free_irq(dev->irq, priv);
6465
6466 if (dev->base_addr)
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01006467 iounmap((void __iomem *)dev->base_addr);
James Ketrenos2c86c272005-03-23 17:32:29 -06006468
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006469 /* wiphy_unregister needs to be here, before free_libipw */
Matthew Garrettc26409a2009-11-11 14:36:30 -05006470 wiphy_unregister(priv->ieee->wdev.wiphy);
6471 kfree(priv->ieee->bg_band.channels);
Pavel Roskin27ae60f2010-03-12 00:01:22 -05006472 free_libipw(dev, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006473 }
6474
6475 pci_release_regions(pci_dev);
6476 pci_disable_device(pci_dev);
6477
6478 IPW_DEBUG_INFO("exit\n");
6479}
6480
James Ketrenos2c86c272005-03-23 17:32:29 -06006481#ifdef CONFIG_PM
James Ketrenos2c86c272005-03-23 17:32:29 -06006482static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state)
James Ketrenos2c86c272005-03-23 17:32:29 -06006483{
6484 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6485 struct net_device *dev = priv->net_dev;
6486
James Ketrenosee8e3652005-09-14 09:47:29 -05006487 IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06006488
Ingo Molnar752e3772006-02-28 07:20:54 +08006489 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006490 if (priv->status & STATUS_INITIALIZED) {
6491 /* Take down the device; powers it off, etc. */
6492 ipw2100_down(priv);
6493 }
6494
6495 /* Remove the PRESENT state of the device */
6496 netif_device_detach(dev);
6497
James Ketrenos2c86c272005-03-23 17:32:29 -06006498 pci_save_state(pci_dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05006499 pci_disable_device(pci_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006500 pci_set_power_state(pci_dev, PCI_D3hot);
James Ketrenos2c86c272005-03-23 17:32:29 -06006501
Dan Williamsc3d72b92009-02-11 13:26:06 -05006502 priv->suspend_at = get_seconds();
6503
Ingo Molnar752e3772006-02-28 07:20:54 +08006504 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006505
6506 return 0;
6507}
6508
6509static int ipw2100_resume(struct pci_dev *pci_dev)
6510{
6511 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6512 struct net_device *dev = priv->net_dev;
John W. Linville02e0e5e2006-11-07 20:53:48 -05006513 int err;
James Ketrenos2c86c272005-03-23 17:32:29 -06006514 u32 val;
6515
6516 if (IPW2100_PM_DISABLED)
6517 return 0;
6518
Ingo Molnar752e3772006-02-28 07:20:54 +08006519 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006520
James Ketrenosee8e3652005-09-14 09:47:29 -05006521 IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06006522
James Ketrenos2c86c272005-03-23 17:32:29 -06006523 pci_set_power_state(pci_dev, PCI_D0);
John W. Linville02e0e5e2006-11-07 20:53:48 -05006524 err = pci_enable_device(pci_dev);
6525 if (err) {
6526 printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
6527 dev->name);
Julia Lawall80c42af2008-07-21 09:58:11 +02006528 mutex_unlock(&priv->action_mutex);
John W. Linville02e0e5e2006-11-07 20:53:48 -05006529 return err;
6530 }
James Ketrenos2c86c272005-03-23 17:32:29 -06006531 pci_restore_state(pci_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006532
6533 /*
6534 * Suspend/Resume resets the PCI configuration space, so we have to
6535 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
6536 * from interfering with C3 CPU state. pci_restore_state won't help
6537 * here since it only restores the first 64 bytes pci config header.
6538 */
6539 pci_read_config_dword(pci_dev, 0x40, &val);
6540 if ((val & 0x0000ff00) != 0)
6541 pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
6542
6543 /* Set the device back into the PRESENT state; this will also wake
6544 * the queue of needed */
6545 netif_device_attach(dev);
6546
Dan Williamsc3d72b92009-02-11 13:26:06 -05006547 priv->suspend_time = get_seconds() - priv->suspend_at;
6548
James Ketrenosee8e3652005-09-14 09:47:29 -05006549 /* Bring the device back up */
6550 if (!(priv->status & STATUS_RF_KILL_SW))
6551 ipw2100_up(priv, 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06006552
Ingo Molnar752e3772006-02-28 07:20:54 +08006553 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006554
6555 return 0;
6556}
6557#endif
6558
Zhu Yi52ce3e9a72009-12-02 14:24:37 +08006559static void ipw2100_shutdown(struct pci_dev *pci_dev)
6560{
6561 struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
6562
6563 /* Take down the device; powers it off, etc. */
6564 ipw2100_down(priv);
6565
6566 pci_disable_device(pci_dev);
6567}
6568
James Ketrenos2c86c272005-03-23 17:32:29 -06006569#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
6570
Alexey Dobriyana3aa1882010-01-07 11:58:11 +00006571static DEFINE_PCI_DEVICE_TABLE(ipw2100_pci_id_table) = {
James Ketrenosee8e3652005-09-14 09:47:29 -05006572 IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
6573 IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
6574 IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
6575 IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
6576 IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
6577 IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
6578 IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
6579 IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
6580 IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
6581 IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
6582 IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
6583 IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
6584 IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
James Ketrenos2c86c272005-03-23 17:32:29 -06006585
James Ketrenosee8e3652005-09-14 09:47:29 -05006586 IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
6587 IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
6588 IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
6589 IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
6590 IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006591
James Ketrenosee8e3652005-09-14 09:47:29 -05006592 IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
6593 IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
6594 IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
6595 IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
6596 IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
6597 IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
6598 IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
James Ketrenos2c86c272005-03-23 17:32:29 -06006599
James Ketrenosee8e3652005-09-14 09:47:29 -05006600 IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006601
James Ketrenosee8e3652005-09-14 09:47:29 -05006602 IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
6603 IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
6604 IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
6605 IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
6606 IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
6607 IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
6608 IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006609
James Ketrenosee8e3652005-09-14 09:47:29 -05006610 IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
6611 IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
6612 IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
6613 IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
6614 IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
6615 IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006616
James Ketrenosee8e3652005-09-14 09:47:29 -05006617 IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
James Ketrenos2c86c272005-03-23 17:32:29 -06006618 {0,},
6619};
6620
6621MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table);
6622
6623static struct pci_driver ipw2100_pci_driver = {
6624 .name = DRV_NAME,
6625 .id_table = ipw2100_pci_id_table,
6626 .probe = ipw2100_pci_init_one,
6627 .remove = __devexit_p(ipw2100_pci_remove_one),
6628#ifdef CONFIG_PM
6629 .suspend = ipw2100_suspend,
6630 .resume = ipw2100_resume,
6631#endif
Zhu Yi52ce3e9a72009-12-02 14:24:37 +08006632 .shutdown = ipw2100_shutdown,
James Ketrenos2c86c272005-03-23 17:32:29 -06006633};
6634
James Ketrenos2c86c272005-03-23 17:32:29 -06006635/**
6636 * Initialize the ipw2100 driver/module
6637 *
6638 * @returns 0 if ok, < 0 errno node con error.
6639 *
6640 * Note: we cannot init the /proc stuff until the PCI driver is there,
6641 * or we risk an unlikely race condition on someone accessing
6642 * uninitialized data in the PCI dev struct through /proc.
6643 */
6644static int __init ipw2100_init(void)
6645{
6646 int ret;
6647
6648 printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
6649 printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
6650
John W. Linville2f81b472010-08-11 16:11:00 -04006651 pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
6652 PM_QOS_DEFAULT_VALUE);
6653
Jeff Garzik29917622006-08-19 17:48:59 -04006654 ret = pci_register_driver(&ipw2100_pci_driver);
Jeff Garzikde897882006-10-01 07:31:09 -04006655 if (ret)
6656 goto out;
James Ketrenos2c86c272005-03-23 17:32:29 -06006657
Brice Goglin0f52bf92005-12-01 01:41:46 -08006658#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06006659 ipw2100_debug_level = debug;
Jeff Garzikde897882006-10-01 07:31:09 -04006660 ret = driver_create_file(&ipw2100_pci_driver.driver,
6661 &driver_attr_debug_level);
James Ketrenos2c86c272005-03-23 17:32:29 -06006662#endif
6663
Jeff Garzikde897882006-10-01 07:31:09 -04006664out:
James Ketrenos2c86c272005-03-23 17:32:29 -06006665 return ret;
6666}
6667
James Ketrenos2c86c272005-03-23 17:32:29 -06006668/**
6669 * Cleanup ipw2100 driver registration
6670 */
6671static void __exit ipw2100_exit(void)
6672{
6673 /* FIXME: IPG: check that we have no instances of the devices open */
Brice Goglin0f52bf92005-12-01 01:41:46 -08006674#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06006675 driver_remove_file(&ipw2100_pci_driver.driver,
6676 &driver_attr_debug_level);
6677#endif
6678 pci_unregister_driver(&ipw2100_pci_driver);
James Bottomley82f68252010-07-05 22:53:06 +02006679 pm_qos_remove_request(&ipw2100_pm_qos_req);
James Ketrenos2c86c272005-03-23 17:32:29 -06006680}
6681
6682module_init(ipw2100_init);
6683module_exit(ipw2100_exit);
6684
James Ketrenos2c86c272005-03-23 17:32:29 -06006685static int ipw2100_wx_get_name(struct net_device *dev,
6686 struct iw_request_info *info,
6687 union iwreq_data *wrqu, char *extra)
6688{
6689 /*
6690 * This can be called at any time. No action lock required
6691 */
6692
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006693 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006694 if (!(priv->status & STATUS_ASSOCIATED))
6695 strcpy(wrqu->name, "unassociated");
6696 else
6697 snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
6698
6699 IPW_DEBUG_WX("Name: %s\n", wrqu->name);
6700 return 0;
6701}
6702
James Ketrenos2c86c272005-03-23 17:32:29 -06006703static int ipw2100_wx_set_freq(struct net_device *dev,
6704 struct iw_request_info *info,
6705 union iwreq_data *wrqu, char *extra)
6706{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006707 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006708 struct iw_freq *fwrq = &wrqu->freq;
6709 int err = 0;
6710
6711 if (priv->ieee->iw_mode == IW_MODE_INFRA)
6712 return -EOPNOTSUPP;
6713
Ingo Molnar752e3772006-02-28 07:20:54 +08006714 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006715 if (!(priv->status & STATUS_INITIALIZED)) {
6716 err = -EIO;
6717 goto done;
6718 }
6719
6720 /* if setting by freq convert to channel */
6721 if (fwrq->e == 1) {
James Ketrenosee8e3652005-09-14 09:47:29 -05006722 if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06006723 int f = fwrq->m / 100000;
6724 int c = 0;
6725
6726 while ((c < REG_MAX_CHANNEL) &&
6727 (f != ipw2100_frequencies[c]))
6728 c++;
6729
6730 /* hack to fall through */
6731 fwrq->e = 0;
6732 fwrq->m = c + 1;
6733 }
6734 }
6735
James Ketrenos82328352005-08-24 22:33:31 -05006736 if (fwrq->e > 0 || fwrq->m > 1000) {
6737 err = -EOPNOTSUPP;
6738 goto done;
6739 } else { /* Set the channel */
Frans Pop9fd1ea42010-03-24 19:46:31 +01006740 IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
James Ketrenos2c86c272005-03-23 17:32:29 -06006741 err = ipw2100_set_channel(priv, fwrq->m, 0);
6742 }
6743
James Ketrenosee8e3652005-09-14 09:47:29 -05006744 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006745 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006746 return err;
6747}
6748
James Ketrenos2c86c272005-03-23 17:32:29 -06006749static int ipw2100_wx_get_freq(struct net_device *dev,
6750 struct iw_request_info *info,
6751 union iwreq_data *wrqu, char *extra)
6752{
6753 /*
6754 * This can be called at any time. No action lock required
6755 */
6756
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006757 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006758
6759 wrqu->freq.e = 0;
6760
6761 /* If we are associated, trying to associate, or have a statically
6762 * configured CHANNEL then return that; otherwise return ANY */
6763 if (priv->config & CFG_STATIC_CHANNEL ||
6764 priv->status & STATUS_ASSOCIATED)
6765 wrqu->freq.m = priv->channel;
6766 else
6767 wrqu->freq.m = 0;
6768
Frans Pop9fd1ea42010-03-24 19:46:31 +01006769 IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
James Ketrenos2c86c272005-03-23 17:32:29 -06006770 return 0;
6771
6772}
6773
6774static int ipw2100_wx_set_mode(struct net_device *dev,
6775 struct iw_request_info *info,
6776 union iwreq_data *wrqu, char *extra)
6777{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006778 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006779 int err = 0;
6780
Frans Pop9fd1ea42010-03-24 19:46:31 +01006781 IPW_DEBUG_WX("SET Mode -> %d\n", wrqu->mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06006782
6783 if (wrqu->mode == priv->ieee->iw_mode)
6784 return 0;
6785
Ingo Molnar752e3772006-02-28 07:20:54 +08006786 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006787 if (!(priv->status & STATUS_INITIALIZED)) {
6788 err = -EIO;
6789 goto done;
6790 }
6791
6792 switch (wrqu->mode) {
6793#ifdef CONFIG_IPW2100_MONITOR
6794 case IW_MODE_MONITOR:
6795 err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
6796 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05006797#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06006798 case IW_MODE_ADHOC:
6799 err = ipw2100_switch_mode(priv, IW_MODE_ADHOC);
6800 break;
6801 case IW_MODE_INFRA:
6802 case IW_MODE_AUTO:
6803 default:
6804 err = ipw2100_switch_mode(priv, IW_MODE_INFRA);
6805 break;
6806 }
6807
James Ketrenosee8e3652005-09-14 09:47:29 -05006808 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08006809 mutex_unlock(&priv->action_mutex);
James Ketrenosee8e3652005-09-14 09:47:29 -05006810 return err;
James Ketrenos2c86c272005-03-23 17:32:29 -06006811}
6812
6813static int ipw2100_wx_get_mode(struct net_device *dev,
6814 struct iw_request_info *info,
6815 union iwreq_data *wrqu, char *extra)
6816{
6817 /*
6818 * This can be called at any time. No action lock required
6819 */
6820
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006821 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006822
6823 wrqu->mode = priv->ieee->iw_mode;
6824 IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode);
6825
6826 return 0;
6827}
6828
James Ketrenos2c86c272005-03-23 17:32:29 -06006829#define POWER_MODES 5
6830
6831/* Values are in microsecond */
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006832static const s32 timeout_duration[POWER_MODES] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006833 350000,
6834 250000,
6835 75000,
6836 37000,
6837 25000,
6838};
6839
Jiri Bencc4aee8c2005-08-25 20:04:43 -04006840static const s32 period_duration[POWER_MODES] = {
James Ketrenos2c86c272005-03-23 17:32:29 -06006841 400000,
6842 700000,
6843 1000000,
6844 1000000,
6845 1000000
6846};
6847
6848static int ipw2100_wx_get_range(struct net_device *dev,
6849 struct iw_request_info *info,
6850 union iwreq_data *wrqu, char *extra)
6851{
6852 /*
6853 * This can be called at any time. No action lock required
6854 */
6855
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006856 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006857 struct iw_range *range = (struct iw_range *)extra;
6858 u16 val;
6859 int i, level;
6860
6861 wrqu->data.length = sizeof(*range);
6862 memset(range, 0, sizeof(*range));
6863
6864 /* Let's try to keep this struct in the same order as in
6865 * linux/include/wireless.h
6866 */
6867
6868 /* TODO: See what values we can set, and remove the ones we can't
6869 * set, or fill them with some default data.
6870 */
6871
6872 /* ~5 Mb/s real (802.11b) */
6873 range->throughput = 5 * 1000 * 1000;
6874
James Ketrenosee8e3652005-09-14 09:47:29 -05006875// range->sensitivity; /* signal level threshold range */
James Ketrenos2c86c272005-03-23 17:32:29 -06006876
6877 range->max_qual.qual = 100;
6878 /* TODO: Find real max RSSI and stick here */
6879 range->max_qual.level = 0;
6880 range->max_qual.noise = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05006881 range->max_qual.updated = 7; /* Updated all three */
James Ketrenos2c86c272005-03-23 17:32:29 -06006882
James Ketrenosee8e3652005-09-14 09:47:29 -05006883 range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02006884 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
James Ketrenos2c86c272005-03-23 17:32:29 -06006885 range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
6886 range->avg_qual.noise = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05006887 range->avg_qual.updated = 7; /* Updated all three */
James Ketrenos2c86c272005-03-23 17:32:29 -06006888
6889 range->num_bitrates = RATE_COUNT;
6890
6891 for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
Stanislav Yakovlev4d94c152012-02-09 20:23:52 -05006892 range->bitrate[i] = ipw2100_bg_rates[i].bitrate * 100 * 1000;
James Ketrenos2c86c272005-03-23 17:32:29 -06006893 }
6894
6895 range->min_rts = MIN_RTS_THRESHOLD;
6896 range->max_rts = MAX_RTS_THRESHOLD;
6897 range->min_frag = MIN_FRAG_THRESHOLD;
6898 range->max_frag = MAX_FRAG_THRESHOLD;
6899
6900 range->min_pmp = period_duration[0]; /* Minimal PM period */
James Ketrenosee8e3652005-09-14 09:47:29 -05006901 range->max_pmp = period_duration[POWER_MODES - 1]; /* Maximal PM period */
6902 range->min_pmt = timeout_duration[POWER_MODES - 1]; /* Minimal PM timeout */
6903 range->max_pmt = timeout_duration[0]; /* Maximal PM timeout */
James Ketrenos2c86c272005-03-23 17:32:29 -06006904
James Ketrenosee8e3652005-09-14 09:47:29 -05006905 /* How to decode max/min PM period */
James Ketrenos2c86c272005-03-23 17:32:29 -06006906 range->pmp_flags = IW_POWER_PERIOD;
James Ketrenosee8e3652005-09-14 09:47:29 -05006907 /* How to decode max/min PM period */
James Ketrenos2c86c272005-03-23 17:32:29 -06006908 range->pmt_flags = IW_POWER_TIMEOUT;
6909 /* What PM options are supported */
6910 range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD;
6911
6912 range->encoding_size[0] = 5;
James Ketrenosee8e3652005-09-14 09:47:29 -05006913 range->encoding_size[1] = 13; /* Different token sizes */
6914 range->num_encoding_sizes = 2; /* Number of entry in the list */
6915 range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */
6916// range->encoding_login_index; /* token index for login token */
James Ketrenos2c86c272005-03-23 17:32:29 -06006917
6918 if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
6919 range->txpower_capa = IW_TXPOW_DBM;
6920 range->num_txpower = IW_MAX_TXPOWER;
James Ketrenosee8e3652005-09-14 09:47:29 -05006921 for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16);
6922 i < IW_MAX_TXPOWER;
6923 i++, level -=
6924 ((IPW_TX_POWER_MAX_DBM -
6925 IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1))
James Ketrenos2c86c272005-03-23 17:32:29 -06006926 range->txpower[i] = level / 16;
6927 } else {
6928 range->txpower_capa = 0;
6929 range->num_txpower = 0;
6930 }
6931
James Ketrenos2c86c272005-03-23 17:32:29 -06006932 /* Set the Wireless Extension versions */
6933 range->we_version_compiled = WIRELESS_EXT;
Dan Williams166c3432006-01-09 11:04:31 -05006934 range->we_version_source = 18;
James Ketrenos2c86c272005-03-23 17:32:29 -06006935
James Ketrenosee8e3652005-09-14 09:47:29 -05006936// range->retry_capa; /* What retry options are supported */
6937// range->retry_flags; /* How to decode max/min retry limit */
6938// range->r_time_flags; /* How to decode max/min retry life */
6939// range->min_retry; /* Minimal number of retries */
6940// range->max_retry; /* Maximal number of retries */
6941// range->min_r_time; /* Minimal retry lifetime */
6942// range->max_r_time; /* Maximal retry lifetime */
James Ketrenos2c86c272005-03-23 17:32:29 -06006943
James Ketrenosee8e3652005-09-14 09:47:29 -05006944 range->num_channels = FREQ_COUNT;
James Ketrenos2c86c272005-03-23 17:32:29 -06006945
6946 val = 0;
6947 for (i = 0; i < FREQ_COUNT; i++) {
6948 // TODO: Include only legal frequencies for some countries
James Ketrenosee8e3652005-09-14 09:47:29 -05006949// if (local->channel_mask & (1 << i)) {
6950 range->freq[val].i = i + 1;
6951 range->freq[val].m = ipw2100_frequencies[i] * 100000;
6952 range->freq[val].e = 1;
6953 val++;
6954// }
James Ketrenos2c86c272005-03-23 17:32:29 -06006955 if (val == IW_MAX_FREQUENCIES)
James Ketrenosee8e3652005-09-14 09:47:29 -05006956 break;
James Ketrenos2c86c272005-03-23 17:32:29 -06006957 }
6958 range->num_frequency = val;
6959
James Ketrenoseaf8f532005-11-12 12:50:12 -06006960 /* Event capability (kernel + driver) */
6961 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
6962 IW_EVENT_CAPA_MASK(SIOCGIWAP));
6963 range->event_capa[1] = IW_EVENT_CAPA_K_1;
6964
Dan Williams166c3432006-01-09 11:04:31 -05006965 range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
6966 IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
6967
James Ketrenos2c86c272005-03-23 17:32:29 -06006968 IPW_DEBUG_WX("GET Range\n");
6969
6970 return 0;
6971}
6972
6973static int ipw2100_wx_set_wap(struct net_device *dev,
6974 struct iw_request_info *info,
6975 union iwreq_data *wrqu, char *extra)
6976{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04006977 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06006978 int err = 0;
6979
6980 static const unsigned char any[] = {
6981 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
6982 };
6983 static const unsigned char off[] = {
6984 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6985 };
6986
6987 // sanity checks
6988 if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
6989 return -EINVAL;
6990
Ingo Molnar752e3772006-02-28 07:20:54 +08006991 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06006992 if (!(priv->status & STATUS_INITIALIZED)) {
6993 err = -EIO;
6994 goto done;
6995 }
6996
6997 if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
6998 !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
6999 /* we disable mandatory BSSID association */
7000 IPW_DEBUG_WX("exit - disable mandatory BSSID\n");
7001 priv->config &= ~CFG_STATIC_BSSID;
7002 err = ipw2100_set_mandatory_bssid(priv, NULL, 0);
7003 goto done;
7004 }
7005
7006 priv->config |= CFG_STATIC_BSSID;
7007 memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN);
7008
7009 err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
7010
Johannes Berge1749612008-10-27 15:59:26 -07007011 IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data);
James Ketrenos2c86c272005-03-23 17:32:29 -06007012
James Ketrenosee8e3652005-09-14 09:47:29 -05007013 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007014 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007015 return err;
7016}
7017
7018static int ipw2100_wx_get_wap(struct net_device *dev,
7019 struct iw_request_info *info,
7020 union iwreq_data *wrqu, char *extra)
7021{
7022 /*
7023 * This can be called at any time. No action lock required
7024 */
7025
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007026 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007027
7028 /* If we are associated, trying to associate, or have a statically
7029 * configured BSSID then return that; otherwise return ANY */
James Ketrenosee8e3652005-09-14 09:47:29 -05007030 if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007031 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
James Ketrenos82328352005-08-24 22:33:31 -05007032 memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06007033 } else
7034 memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
7035
Johannes Berge1749612008-10-27 15:59:26 -07007036 IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data);
James Ketrenos2c86c272005-03-23 17:32:29 -06007037 return 0;
7038}
7039
7040static int ipw2100_wx_set_essid(struct net_device *dev,
7041 struct iw_request_info *info,
7042 union iwreq_data *wrqu, char *extra)
7043{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007044 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenosee8e3652005-09-14 09:47:29 -05007045 char *essid = ""; /* ANY */
James Ketrenos2c86c272005-03-23 17:32:29 -06007046 int length = 0;
7047 int err = 0;
John W. Linville9387b7c2008-09-30 20:59:05 -04007048 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06007049
Ingo Molnar752e3772006-02-28 07:20:54 +08007050 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007051 if (!(priv->status & STATUS_INITIALIZED)) {
7052 err = -EIO;
7053 goto done;
7054 }
7055
7056 if (wrqu->essid.flags && wrqu->essid.length) {
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007057 length = wrqu->essid.length;
James Ketrenos2c86c272005-03-23 17:32:29 -06007058 essid = extra;
7059 }
7060
7061 if (length == 0) {
7062 IPW_DEBUG_WX("Setting ESSID to ANY\n");
7063 priv->config &= ~CFG_STATIC_ESSID;
7064 err = ipw2100_set_essid(priv, NULL, 0, 0);
7065 goto done;
7066 }
7067
7068 length = min(length, IW_ESSID_MAX_SIZE);
7069
7070 priv->config |= CFG_STATIC_ESSID;
7071
7072 if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
7073 IPW_DEBUG_WX("ESSID set to current ESSID.\n");
7074 err = 0;
7075 goto done;
7076 }
7077
John W. Linville9387b7c2008-09-30 20:59:05 -04007078 IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
7079 print_ssid(ssid, essid, length), length);
James Ketrenos2c86c272005-03-23 17:32:29 -06007080
7081 priv->essid_len = length;
7082 memcpy(priv->essid, essid, priv->essid_len);
7083
7084 err = ipw2100_set_essid(priv, essid, length, 0);
7085
James Ketrenosee8e3652005-09-14 09:47:29 -05007086 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007087 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007088 return err;
7089}
7090
7091static int ipw2100_wx_get_essid(struct net_device *dev,
7092 struct iw_request_info *info,
7093 union iwreq_data *wrqu, char *extra)
7094{
7095 /*
7096 * This can be called at any time. No action lock required
7097 */
7098
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007099 struct ipw2100_priv *priv = libipw_priv(dev);
John W. Linville9387b7c2008-09-30 20:59:05 -04007100 DECLARE_SSID_BUF(ssid);
James Ketrenos2c86c272005-03-23 17:32:29 -06007101
7102 /* If we are associated, trying to associate, or have a statically
7103 * configured ESSID then return that; otherwise return ANY */
James Ketrenosee8e3652005-09-14 09:47:29 -05007104 if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007105 IPW_DEBUG_WX("Getting essid: '%s'\n",
John W. Linville9387b7c2008-09-30 20:59:05 -04007106 print_ssid(ssid, priv->essid, priv->essid_len));
James Ketrenos2c86c272005-03-23 17:32:29 -06007107 memcpy(extra, priv->essid, priv->essid_len);
7108 wrqu->essid.length = priv->essid_len;
James Ketrenosee8e3652005-09-14 09:47:29 -05007109 wrqu->essid.flags = 1; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007110 } else {
7111 IPW_DEBUG_WX("Getting essid: ANY\n");
7112 wrqu->essid.length = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05007113 wrqu->essid.flags = 0; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007114 }
7115
7116 return 0;
7117}
7118
7119static int ipw2100_wx_set_nick(struct net_device *dev,
7120 struct iw_request_info *info,
7121 union iwreq_data *wrqu, char *extra)
7122{
7123 /*
7124 * This can be called at any time. No action lock required
7125 */
7126
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007127 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007128
7129 if (wrqu->data.length > IW_ESSID_MAX_SIZE)
7130 return -E2BIG;
7131
James Ketrenosee8e3652005-09-14 09:47:29 -05007132 wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
James Ketrenos2c86c272005-03-23 17:32:29 -06007133 memset(priv->nick, 0, sizeof(priv->nick));
James Ketrenosee8e3652005-09-14 09:47:29 -05007134 memcpy(priv->nick, extra, wrqu->data.length);
James Ketrenos2c86c272005-03-23 17:32:29 -06007135
Frans Pop9fd1ea42010-03-24 19:46:31 +01007136 IPW_DEBUG_WX("SET Nickname -> %s\n", priv->nick);
James Ketrenos2c86c272005-03-23 17:32:29 -06007137
7138 return 0;
7139}
7140
7141static int ipw2100_wx_get_nick(struct net_device *dev,
7142 struct iw_request_info *info,
7143 union iwreq_data *wrqu, char *extra)
7144{
7145 /*
7146 * This can be called at any time. No action lock required
7147 */
7148
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007149 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007150
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007151 wrqu->data.length = strlen(priv->nick);
James Ketrenos2c86c272005-03-23 17:32:29 -06007152 memcpy(extra, priv->nick, wrqu->data.length);
James Ketrenosee8e3652005-09-14 09:47:29 -05007153 wrqu->data.flags = 1; /* active */
James Ketrenos2c86c272005-03-23 17:32:29 -06007154
Frans Pop9fd1ea42010-03-24 19:46:31 +01007155 IPW_DEBUG_WX("GET Nickname -> %s\n", extra);
James Ketrenos2c86c272005-03-23 17:32:29 -06007156
7157 return 0;
7158}
7159
7160static int ipw2100_wx_set_rate(struct net_device *dev,
7161 struct iw_request_info *info,
7162 union iwreq_data *wrqu, char *extra)
7163{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007164 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007165 u32 target_rate = wrqu->bitrate.value;
7166 u32 rate;
7167 int err = 0;
7168
Ingo Molnar752e3772006-02-28 07:20:54 +08007169 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007170 if (!(priv->status & STATUS_INITIALIZED)) {
7171 err = -EIO;
7172 goto done;
7173 }
7174
7175 rate = 0;
7176
7177 if (target_rate == 1000000 ||
7178 (!wrqu->bitrate.fixed && target_rate > 1000000))
7179 rate |= TX_RATE_1_MBIT;
7180 if (target_rate == 2000000 ||
7181 (!wrqu->bitrate.fixed && target_rate > 2000000))
7182 rate |= TX_RATE_2_MBIT;
7183 if (target_rate == 5500000 ||
7184 (!wrqu->bitrate.fixed && target_rate > 5500000))
7185 rate |= TX_RATE_5_5_MBIT;
7186 if (target_rate == 11000000 ||
7187 (!wrqu->bitrate.fixed && target_rate > 11000000))
7188 rate |= TX_RATE_11_MBIT;
7189 if (rate == 0)
7190 rate = DEFAULT_TX_RATES;
7191
7192 err = ipw2100_set_tx_rates(priv, rate, 0);
7193
Frans Pop9fd1ea42010-03-24 19:46:31 +01007194 IPW_DEBUG_WX("SET Rate -> %04X\n", rate);
James Ketrenosee8e3652005-09-14 09:47:29 -05007195 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007196 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007197 return err;
7198}
7199
James Ketrenos2c86c272005-03-23 17:32:29 -06007200static int ipw2100_wx_get_rate(struct net_device *dev,
7201 struct iw_request_info *info,
7202 union iwreq_data *wrqu, char *extra)
7203{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007204 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007205 int val;
Hannes Ederb9da9e92009-02-14 11:50:26 +00007206 unsigned int len = sizeof(val);
James Ketrenos2c86c272005-03-23 17:32:29 -06007207 int err = 0;
7208
7209 if (!(priv->status & STATUS_ENABLED) ||
7210 priv->status & STATUS_RF_KILL_MASK ||
7211 !(priv->status & STATUS_ASSOCIATED)) {
7212 wrqu->bitrate.value = 0;
7213 return 0;
7214 }
7215
Ingo Molnar752e3772006-02-28 07:20:54 +08007216 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007217 if (!(priv->status & STATUS_INITIALIZED)) {
7218 err = -EIO;
7219 goto done;
7220 }
7221
7222 err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len);
7223 if (err) {
7224 IPW_DEBUG_WX("failed querying ordinals.\n");
Julia Lawall80c42af2008-07-21 09:58:11 +02007225 goto done;
James Ketrenos2c86c272005-03-23 17:32:29 -06007226 }
7227
7228 switch (val & TX_RATE_MASK) {
7229 case TX_RATE_1_MBIT:
7230 wrqu->bitrate.value = 1000000;
7231 break;
7232 case TX_RATE_2_MBIT:
7233 wrqu->bitrate.value = 2000000;
7234 break;
7235 case TX_RATE_5_5_MBIT:
7236 wrqu->bitrate.value = 5500000;
7237 break;
7238 case TX_RATE_11_MBIT:
7239 wrqu->bitrate.value = 11000000;
7240 break;
7241 default:
7242 wrqu->bitrate.value = 0;
7243 }
7244
Frans Pop9fd1ea42010-03-24 19:46:31 +01007245 IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007246
James Ketrenosee8e3652005-09-14 09:47:29 -05007247 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007248 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007249 return err;
7250}
7251
7252static int ipw2100_wx_set_rts(struct net_device *dev,
7253 struct iw_request_info *info,
7254 union iwreq_data *wrqu, char *extra)
7255{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007256 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007257 int value, err;
7258
7259 /* Auto RTS not yet supported */
7260 if (wrqu->rts.fixed == 0)
7261 return -EINVAL;
7262
Ingo Molnar752e3772006-02-28 07:20:54 +08007263 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007264 if (!(priv->status & STATUS_INITIALIZED)) {
7265 err = -EIO;
7266 goto done;
7267 }
7268
7269 if (wrqu->rts.disabled)
7270 value = priv->rts_threshold | RTS_DISABLED;
7271 else {
James Ketrenosee8e3652005-09-14 09:47:29 -05007272 if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007273 err = -EINVAL;
7274 goto done;
7275 }
7276 value = wrqu->rts.value;
7277 }
7278
7279 err = ipw2100_set_rts_threshold(priv, value);
7280
Frans Pop9fd1ea42010-03-24 19:46:31 +01007281 IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X\n", value);
James Ketrenosee8e3652005-09-14 09:47:29 -05007282 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007283 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007284 return err;
7285}
7286
7287static int ipw2100_wx_get_rts(struct net_device *dev,
7288 struct iw_request_info *info,
7289 union iwreq_data *wrqu, char *extra)
7290{
7291 /*
7292 * This can be called at any time. No action lock required
7293 */
7294
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007295 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007296
7297 wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
James Ketrenosee8e3652005-09-14 09:47:29 -05007298 wrqu->rts.fixed = 1; /* no auto select */
James Ketrenos2c86c272005-03-23 17:32:29 -06007299
7300 /* If RTS is set to the default value, then it is disabled */
7301 wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
7302
Frans Pop9fd1ea42010-03-24 19:46:31 +01007303 IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X\n", wrqu->rts.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007304
7305 return 0;
7306}
7307
7308static int ipw2100_wx_set_txpow(struct net_device *dev,
7309 struct iw_request_info *info,
7310 union iwreq_data *wrqu, char *extra)
7311{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007312 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007313 int err = 0, value;
Zhu Yib6e4da72006-01-24 13:49:32 +08007314
7315 if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled))
7316 return -EINPROGRESS;
James Ketrenos2c86c272005-03-23 17:32:29 -06007317
7318 if (priv->ieee->iw_mode != IW_MODE_ADHOC)
Zhu Yib6e4da72006-01-24 13:49:32 +08007319 return 0;
7320
7321 if ((wrqu->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
James Ketrenos2c86c272005-03-23 17:32:29 -06007322 return -EINVAL;
7323
Zhu Yib6e4da72006-01-24 13:49:32 +08007324 if (wrqu->txpower.fixed == 0)
James Ketrenos2c86c272005-03-23 17:32:29 -06007325 value = IPW_TX_POWER_DEFAULT;
7326 else {
7327 if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM ||
7328 wrqu->txpower.value > IPW_TX_POWER_MAX_DBM)
7329 return -EINVAL;
7330
Liu Hongf75459e2005-07-13 12:29:21 -05007331 value = wrqu->txpower.value;
James Ketrenos2c86c272005-03-23 17:32:29 -06007332 }
7333
Ingo Molnar752e3772006-02-28 07:20:54 +08007334 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007335 if (!(priv->status & STATUS_INITIALIZED)) {
7336 err = -EIO;
7337 goto done;
7338 }
7339
7340 err = ipw2100_set_tx_power(priv, value);
7341
Frans Pop9fd1ea42010-03-24 19:46:31 +01007342 IPW_DEBUG_WX("SET TX Power -> %d\n", value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007343
James Ketrenosee8e3652005-09-14 09:47:29 -05007344 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007345 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007346 return err;
7347}
7348
7349static int ipw2100_wx_get_txpow(struct net_device *dev,
7350 struct iw_request_info *info,
7351 union iwreq_data *wrqu, char *extra)
7352{
7353 /*
7354 * This can be called at any time. No action lock required
7355 */
7356
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007357 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007358
Zhu Yib6e4da72006-01-24 13:49:32 +08007359 wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
James Ketrenos2c86c272005-03-23 17:32:29 -06007360
7361 if (priv->tx_power == IPW_TX_POWER_DEFAULT) {
Zhu Yib6e4da72006-01-24 13:49:32 +08007362 wrqu->txpower.fixed = 0;
7363 wrqu->txpower.value = IPW_TX_POWER_MAX_DBM;
James Ketrenos2c86c272005-03-23 17:32:29 -06007364 } else {
Zhu Yib6e4da72006-01-24 13:49:32 +08007365 wrqu->txpower.fixed = 1;
7366 wrqu->txpower.value = priv->tx_power;
James Ketrenos2c86c272005-03-23 17:32:29 -06007367 }
7368
Zhu Yib6e4da72006-01-24 13:49:32 +08007369 wrqu->txpower.flags = IW_TXPOW_DBM;
James Ketrenos2c86c272005-03-23 17:32:29 -06007370
Frans Pop9fd1ea42010-03-24 19:46:31 +01007371 IPW_DEBUG_WX("GET TX Power -> %d\n", wrqu->txpower.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007372
7373 return 0;
7374}
7375
7376static int ipw2100_wx_set_frag(struct net_device *dev,
7377 struct iw_request_info *info,
7378 union iwreq_data *wrqu, char *extra)
7379{
7380 /*
7381 * This can be called at any time. No action lock required
7382 */
7383
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007384 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007385
7386 if (!wrqu->frag.fixed)
7387 return -EINVAL;
7388
7389 if (wrqu->frag.disabled) {
7390 priv->frag_threshold |= FRAG_DISABLED;
7391 priv->ieee->fts = DEFAULT_FTS;
7392 } else {
7393 if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
7394 wrqu->frag.value > MAX_FRAG_THRESHOLD)
7395 return -EINVAL;
7396
7397 priv->ieee->fts = wrqu->frag.value & ~0x1;
7398 priv->frag_threshold = priv->ieee->fts;
7399 }
7400
Frans Pop9fd1ea42010-03-24 19:46:31 +01007401 IPW_DEBUG_WX("SET Frag Threshold -> %d\n", priv->ieee->fts);
James Ketrenos2c86c272005-03-23 17:32:29 -06007402
7403 return 0;
7404}
7405
7406static int ipw2100_wx_get_frag(struct net_device *dev,
7407 struct iw_request_info *info,
7408 union iwreq_data *wrqu, char *extra)
7409{
7410 /*
7411 * This can be called at any time. No action lock required
7412 */
7413
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007414 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007415 wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED;
7416 wrqu->frag.fixed = 0; /* no auto select */
7417 wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
7418
Frans Pop9fd1ea42010-03-24 19:46:31 +01007419 IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007420
7421 return 0;
7422}
7423
7424static int ipw2100_wx_set_retry(struct net_device *dev,
7425 struct iw_request_info *info,
7426 union iwreq_data *wrqu, char *extra)
7427{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007428 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007429 int err = 0;
7430
James Ketrenosee8e3652005-09-14 09:47:29 -05007431 if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
James Ketrenos2c86c272005-03-23 17:32:29 -06007432 return -EINVAL;
7433
7434 if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
7435 return 0;
7436
Ingo Molnar752e3772006-02-28 07:20:54 +08007437 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007438 if (!(priv->status & STATUS_INITIALIZED)) {
7439 err = -EIO;
7440 goto done;
7441 }
7442
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007443 if (wrqu->retry.flags & IW_RETRY_SHORT) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007444 err = ipw2100_set_short_retry(priv, wrqu->retry.value);
Frans Pop9fd1ea42010-03-24 19:46:31 +01007445 IPW_DEBUG_WX("SET Short Retry Limit -> %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05007446 wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007447 goto done;
7448 }
7449
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007450 if (wrqu->retry.flags & IW_RETRY_LONG) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007451 err = ipw2100_set_long_retry(priv, wrqu->retry.value);
Frans Pop9fd1ea42010-03-24 19:46:31 +01007452 IPW_DEBUG_WX("SET Long Retry Limit -> %d\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05007453 wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007454 goto done;
7455 }
7456
7457 err = ipw2100_set_short_retry(priv, wrqu->retry.value);
7458 if (!err)
7459 err = ipw2100_set_long_retry(priv, wrqu->retry.value);
7460
Frans Pop9fd1ea42010-03-24 19:46:31 +01007461 IPW_DEBUG_WX("SET Both Retry Limits -> %d\n", wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007462
James Ketrenosee8e3652005-09-14 09:47:29 -05007463 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007464 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007465 return err;
7466}
7467
7468static int ipw2100_wx_get_retry(struct net_device *dev,
7469 struct iw_request_info *info,
7470 union iwreq_data *wrqu, char *extra)
7471{
7472 /*
7473 * This can be called at any time. No action lock required
7474 */
7475
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007476 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007477
James Ketrenosee8e3652005-09-14 09:47:29 -05007478 wrqu->retry.disabled = 0; /* can't be disabled */
James Ketrenos2c86c272005-03-23 17:32:29 -06007479
James Ketrenosee8e3652005-09-14 09:47:29 -05007480 if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
James Ketrenos2c86c272005-03-23 17:32:29 -06007481 return -EINVAL;
7482
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007483 if (wrqu->retry.flags & IW_RETRY_LONG) {
7484 wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
James Ketrenos2c86c272005-03-23 17:32:29 -06007485 wrqu->retry.value = priv->long_retry_limit;
7486 } else {
7487 wrqu->retry.flags =
7488 (priv->short_retry_limit !=
7489 priv->long_retry_limit) ?
Jean Tourrilhes5b63bae2006-08-29 18:00:48 -07007490 IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT;
James Ketrenos2c86c272005-03-23 17:32:29 -06007491
7492 wrqu->retry.value = priv->short_retry_limit;
7493 }
7494
Frans Pop9fd1ea42010-03-24 19:46:31 +01007495 IPW_DEBUG_WX("GET Retry -> %d\n", wrqu->retry.value);
James Ketrenos2c86c272005-03-23 17:32:29 -06007496
7497 return 0;
7498}
7499
7500static int ipw2100_wx_set_scan(struct net_device *dev,
7501 struct iw_request_info *info,
7502 union iwreq_data *wrqu, char *extra)
7503{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007504 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007505 int err = 0;
7506
Ingo Molnar752e3772006-02-28 07:20:54 +08007507 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007508 if (!(priv->status & STATUS_INITIALIZED)) {
7509 err = -EIO;
7510 goto done;
7511 }
7512
7513 IPW_DEBUG_WX("Initiating scan...\n");
Dan Williamsd20c6782007-10-10 12:28:07 -04007514
7515 priv->user_requested_scan = 1;
James Ketrenosee8e3652005-09-14 09:47:29 -05007516 if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06007517 IPW_DEBUG_WX("Start scan failed.\n");
7518
7519 /* TODO: Mark a scan as pending so when hardware initialized
7520 * a scan starts */
7521 }
7522
James Ketrenosee8e3652005-09-14 09:47:29 -05007523 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007524 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007525 return err;
7526}
7527
7528static int ipw2100_wx_get_scan(struct net_device *dev,
7529 struct iw_request_info *info,
7530 union iwreq_data *wrqu, char *extra)
7531{
7532 /*
7533 * This can be called at any time. No action lock required
7534 */
7535
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007536 struct ipw2100_priv *priv = libipw_priv(dev);
7537 return libipw_wx_get_scan(priv->ieee, info, wrqu, extra);
James Ketrenos2c86c272005-03-23 17:32:29 -06007538}
7539
James Ketrenos2c86c272005-03-23 17:32:29 -06007540/*
7541 * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c
7542 */
7543static int ipw2100_wx_set_encode(struct net_device *dev,
7544 struct iw_request_info *info,
7545 union iwreq_data *wrqu, char *key)
7546{
7547 /*
7548 * No check of STATUS_INITIALIZED required
7549 */
7550
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007551 struct ipw2100_priv *priv = libipw_priv(dev);
7552 return libipw_wx_set_encode(priv->ieee, info, wrqu, key);
James Ketrenos2c86c272005-03-23 17:32:29 -06007553}
7554
7555static int ipw2100_wx_get_encode(struct net_device *dev,
7556 struct iw_request_info *info,
7557 union iwreq_data *wrqu, char *key)
7558{
7559 /*
7560 * This can be called at any time. No action lock required
7561 */
7562
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007563 struct ipw2100_priv *priv = libipw_priv(dev);
7564 return libipw_wx_get_encode(priv->ieee, info, wrqu, key);
James Ketrenos2c86c272005-03-23 17:32:29 -06007565}
7566
7567static int ipw2100_wx_set_power(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05007568 struct iw_request_info *info,
7569 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007570{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007571 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007572 int err = 0;
7573
Ingo Molnar752e3772006-02-28 07:20:54 +08007574 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007575 if (!(priv->status & STATUS_INITIALIZED)) {
7576 err = -EIO;
7577 goto done;
7578 }
7579
7580 if (wrqu->power.disabled) {
7581 priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
7582 err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
7583 IPW_DEBUG_WX("SET Power Management Mode -> off\n");
7584 goto done;
7585 }
7586
7587 switch (wrqu->power.flags & IW_POWER_MODE) {
James Ketrenosee8e3652005-09-14 09:47:29 -05007588 case IW_POWER_ON: /* If not specified */
7589 case IW_POWER_MODE: /* If set all mask */
Jean Delvarec03983a2007-10-19 23:22:55 +02007590 case IW_POWER_ALL_R: /* If explicitly state all */
James Ketrenos2c86c272005-03-23 17:32:29 -06007591 break;
James Ketrenosee8e3652005-09-14 09:47:29 -05007592 default: /* Otherwise we don't support it */
James Ketrenos2c86c272005-03-23 17:32:29 -06007593 IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
7594 wrqu->power.flags);
7595 err = -EOPNOTSUPP;
7596 goto done;
7597 }
7598
7599 /* If the user hasn't specified a power management mode yet, default
7600 * to BATTERY */
7601 priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
7602 err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
7603
James Ketrenosee8e3652005-09-14 09:47:29 -05007604 IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
James Ketrenos2c86c272005-03-23 17:32:29 -06007605
James Ketrenosee8e3652005-09-14 09:47:29 -05007606 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007607 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007608 return err;
7609
7610}
7611
7612static int ipw2100_wx_get_power(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05007613 struct iw_request_info *info,
7614 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06007615{
7616 /*
7617 * This can be called at any time. No action lock required
7618 */
7619
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007620 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007621
James Ketrenos82328352005-08-24 22:33:31 -05007622 if (!(priv->power_mode & IPW_POWER_ENABLED))
James Ketrenos2c86c272005-03-23 17:32:29 -06007623 wrqu->power.disabled = 1;
James Ketrenos82328352005-08-24 22:33:31 -05007624 else {
James Ketrenos2c86c272005-03-23 17:32:29 -06007625 wrqu->power.disabled = 0;
7626 wrqu->power.flags = 0;
7627 }
7628
7629 IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
7630
7631 return 0;
7632}
7633
James Ketrenos82328352005-08-24 22:33:31 -05007634/*
7635 * WE-18 WPA support
7636 */
7637
7638/* SIOCSIWGENIE */
7639static int ipw2100_wx_set_genie(struct net_device *dev,
7640 struct iw_request_info *info,
7641 union iwreq_data *wrqu, char *extra)
7642{
7643
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007644 struct ipw2100_priv *priv = libipw_priv(dev);
7645 struct libipw_device *ieee = priv->ieee;
James Ketrenos82328352005-08-24 22:33:31 -05007646 u8 *buf;
7647
7648 if (!ieee->wpa_enabled)
7649 return -EOPNOTSUPP;
7650
7651 if (wrqu->data.length > MAX_WPA_IE_LEN ||
7652 (wrqu->data.length && extra == NULL))
7653 return -EINVAL;
7654
7655 if (wrqu->data.length) {
Eric Sesterhennc3a93922006-10-23 22:20:15 +02007656 buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
James Ketrenos82328352005-08-24 22:33:31 -05007657 if (buf == NULL)
7658 return -ENOMEM;
7659
James Ketrenos82328352005-08-24 22:33:31 -05007660 kfree(ieee->wpa_ie);
7661 ieee->wpa_ie = buf;
7662 ieee->wpa_ie_len = wrqu->data.length;
7663 } else {
7664 kfree(ieee->wpa_ie);
7665 ieee->wpa_ie = NULL;
7666 ieee->wpa_ie_len = 0;
7667 }
7668
7669 ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
7670
7671 return 0;
7672}
7673
7674/* SIOCGIWGENIE */
7675static int ipw2100_wx_get_genie(struct net_device *dev,
7676 struct iw_request_info *info,
7677 union iwreq_data *wrqu, char *extra)
7678{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007679 struct ipw2100_priv *priv = libipw_priv(dev);
7680 struct libipw_device *ieee = priv->ieee;
James Ketrenos82328352005-08-24 22:33:31 -05007681
7682 if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
7683 wrqu->data.length = 0;
7684 return 0;
7685 }
7686
7687 if (wrqu->data.length < ieee->wpa_ie_len)
7688 return -E2BIG;
7689
7690 wrqu->data.length = ieee->wpa_ie_len;
7691 memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
7692
7693 return 0;
7694}
7695
7696/* SIOCSIWAUTH */
7697static int ipw2100_wx_set_auth(struct net_device *dev,
7698 struct iw_request_info *info,
7699 union iwreq_data *wrqu, char *extra)
7700{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007701 struct ipw2100_priv *priv = libipw_priv(dev);
7702 struct libipw_device *ieee = priv->ieee;
James Ketrenos82328352005-08-24 22:33:31 -05007703 struct iw_param *param = &wrqu->param;
John W. Linville274bfb82008-10-29 11:35:05 -04007704 struct lib80211_crypt_data *crypt;
James Ketrenos82328352005-08-24 22:33:31 -05007705 unsigned long flags;
7706 int ret = 0;
7707
7708 switch (param->flags & IW_AUTH_INDEX) {
7709 case IW_AUTH_WPA_VERSION:
7710 case IW_AUTH_CIPHER_PAIRWISE:
7711 case IW_AUTH_CIPHER_GROUP:
7712 case IW_AUTH_KEY_MGMT:
7713 /*
7714 * ipw2200 does not use these parameters
7715 */
7716 break;
7717
7718 case IW_AUTH_TKIP_COUNTERMEASURES:
John W. Linville274bfb82008-10-29 11:35:05 -04007719 crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
James Ketrenos991d1cc2005-10-13 09:26:48 +00007720 if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
James Ketrenos82328352005-08-24 22:33:31 -05007721 break;
James Ketrenos82328352005-08-24 22:33:31 -05007722
7723 flags = crypt->ops->get_flags(crypt->priv);
7724
7725 if (param->value)
7726 flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
7727 else
7728 flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
7729
7730 crypt->ops->set_flags(flags, crypt->priv);
7731
7732 break;
7733
7734 case IW_AUTH_DROP_UNENCRYPTED:{
7735 /* HACK:
7736 *
7737 * wpa_supplicant calls set_wpa_enabled when the driver
7738 * is loaded and unloaded, regardless of if WPA is being
7739 * used. No other calls are made which can be used to
7740 * determine if encryption will be used or not prior to
7741 * association being expected. If encryption is not being
7742 * used, drop_unencrypted is set to false, else true -- we
7743 * can use this to determine if the CAP_PRIVACY_ON bit should
7744 * be set.
7745 */
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007746 struct libipw_security sec = {
James Ketrenos82328352005-08-24 22:33:31 -05007747 .flags = SEC_ENABLED,
7748 .enabled = param->value,
7749 };
7750 priv->ieee->drop_unencrypted = param->value;
7751 /* We only change SEC_LEVEL for open mode. Others
7752 * are set by ipw_wpa_set_encryption.
7753 */
7754 if (!param->value) {
7755 sec.flags |= SEC_LEVEL;
7756 sec.level = SEC_LEVEL_0;
7757 } else {
7758 sec.flags |= SEC_LEVEL;
7759 sec.level = SEC_LEVEL_1;
7760 }
7761 if (priv->ieee->set_security)
7762 priv->ieee->set_security(priv->ieee->dev, &sec);
7763 break;
7764 }
7765
7766 case IW_AUTH_80211_AUTH_ALG:
7767 ret = ipw2100_wpa_set_auth_algs(priv, param->value);
7768 break;
7769
7770 case IW_AUTH_WPA_ENABLED:
7771 ret = ipw2100_wpa_enable(priv, param->value);
7772 break;
7773
7774 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
7775 ieee->ieee802_1x = param->value;
7776 break;
7777
7778 //case IW_AUTH_ROAMING_CONTROL:
7779 case IW_AUTH_PRIVACY_INVOKED:
7780 ieee->privacy_invoked = param->value;
7781 break;
7782
7783 default:
7784 return -EOPNOTSUPP;
7785 }
7786 return ret;
7787}
7788
7789/* SIOCGIWAUTH */
7790static int ipw2100_wx_get_auth(struct net_device *dev,
7791 struct iw_request_info *info,
7792 union iwreq_data *wrqu, char *extra)
7793{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007794 struct ipw2100_priv *priv = libipw_priv(dev);
7795 struct libipw_device *ieee = priv->ieee;
John W. Linville274bfb82008-10-29 11:35:05 -04007796 struct lib80211_crypt_data *crypt;
James Ketrenos82328352005-08-24 22:33:31 -05007797 struct iw_param *param = &wrqu->param;
7798 int ret = 0;
7799
7800 switch (param->flags & IW_AUTH_INDEX) {
7801 case IW_AUTH_WPA_VERSION:
7802 case IW_AUTH_CIPHER_PAIRWISE:
7803 case IW_AUTH_CIPHER_GROUP:
7804 case IW_AUTH_KEY_MGMT:
7805 /*
7806 * wpa_supplicant will control these internally
7807 */
7808 ret = -EOPNOTSUPP;
7809 break;
7810
7811 case IW_AUTH_TKIP_COUNTERMEASURES:
John W. Linville274bfb82008-10-29 11:35:05 -04007812 crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
James Ketrenos82328352005-08-24 22:33:31 -05007813 if (!crypt || !crypt->ops->get_flags) {
7814 IPW_DEBUG_WARNING("Can't get TKIP countermeasures: "
7815 "crypt not set!\n");
7816 break;
7817 }
7818
7819 param->value = (crypt->ops->get_flags(crypt->priv) &
7820 IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
7821
7822 break;
7823
7824 case IW_AUTH_DROP_UNENCRYPTED:
7825 param->value = ieee->drop_unencrypted;
7826 break;
7827
7828 case IW_AUTH_80211_AUTH_ALG:
25b645b2005-07-12 15:45:30 -05007829 param->value = priv->ieee->sec.auth_mode;
James Ketrenos82328352005-08-24 22:33:31 -05007830 break;
7831
7832 case IW_AUTH_WPA_ENABLED:
7833 param->value = ieee->wpa_enabled;
7834 break;
7835
7836 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
7837 param->value = ieee->ieee802_1x;
7838 break;
7839
7840 case IW_AUTH_ROAMING_CONTROL:
7841 case IW_AUTH_PRIVACY_INVOKED:
7842 param->value = ieee->privacy_invoked;
7843 break;
7844
7845 default:
7846 return -EOPNOTSUPP;
7847 }
7848 return 0;
7849}
7850
7851/* SIOCSIWENCODEEXT */
7852static int ipw2100_wx_set_encodeext(struct net_device *dev,
7853 struct iw_request_info *info,
7854 union iwreq_data *wrqu, char *extra)
7855{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007856 struct ipw2100_priv *priv = libipw_priv(dev);
7857 return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra);
James Ketrenos82328352005-08-24 22:33:31 -05007858}
7859
7860/* SIOCGIWENCODEEXT */
7861static int ipw2100_wx_get_encodeext(struct net_device *dev,
7862 struct iw_request_info *info,
7863 union iwreq_data *wrqu, char *extra)
7864{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007865 struct ipw2100_priv *priv = libipw_priv(dev);
7866 return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra);
James Ketrenos82328352005-08-24 22:33:31 -05007867}
7868
7869/* SIOCSIWMLME */
7870static int ipw2100_wx_set_mlme(struct net_device *dev,
7871 struct iw_request_info *info,
7872 union iwreq_data *wrqu, char *extra)
7873{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007874 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos82328352005-08-24 22:33:31 -05007875 struct iw_mlme *mlme = (struct iw_mlme *)extra;
Al Viro1edd3a52007-12-21 00:15:18 -05007876 __le16 reason;
James Ketrenos82328352005-08-24 22:33:31 -05007877
7878 reason = cpu_to_le16(mlme->reason_code);
7879
7880 switch (mlme->cmd) {
7881 case IW_MLME_DEAUTH:
7882 // silently ignore
7883 break;
7884
7885 case IW_MLME_DISASSOC:
7886 ipw2100_disassociate_bssid(priv);
7887 break;
7888
7889 default:
7890 return -EOPNOTSUPP;
7891 }
7892 return 0;
7893}
James Ketrenos2c86c272005-03-23 17:32:29 -06007894
7895/*
7896 *
7897 * IWPRIV handlers
7898 *
7899 */
7900#ifdef CONFIG_IPW2100_MONITOR
7901static int ipw2100_wx_set_promisc(struct net_device *dev,
7902 struct iw_request_info *info,
7903 union iwreq_data *wrqu, char *extra)
7904{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007905 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007906 int *parms = (int *)extra;
7907 int enable = (parms[0] > 0);
7908 int err = 0;
7909
Ingo Molnar752e3772006-02-28 07:20:54 +08007910 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007911 if (!(priv->status & STATUS_INITIALIZED)) {
7912 err = -EIO;
7913 goto done;
7914 }
7915
7916 if (enable) {
7917 if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
7918 err = ipw2100_set_channel(priv, parms[1], 0);
7919 goto done;
7920 }
7921 priv->channel = parms[1];
7922 err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
7923 } else {
7924 if (priv->ieee->iw_mode == IW_MODE_MONITOR)
7925 err = ipw2100_switch_mode(priv, priv->last_mode);
7926 }
James Ketrenosee8e3652005-09-14 09:47:29 -05007927 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007928 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007929 return err;
7930}
7931
7932static int ipw2100_wx_reset(struct net_device *dev,
7933 struct iw_request_info *info,
7934 union iwreq_data *wrqu, char *extra)
7935{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007936 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007937 if (priv->status & STATUS_INITIALIZED)
7938 schedule_reset(priv);
7939 return 0;
7940}
7941
7942#endif
7943
7944static int ipw2100_wx_set_powermode(struct net_device *dev,
7945 struct iw_request_info *info,
7946 union iwreq_data *wrqu, char *extra)
7947{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007948 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007949 int err = 0, mode = *(int *)extra;
7950
Ingo Molnar752e3772006-02-28 07:20:54 +08007951 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007952 if (!(priv->status & STATUS_INITIALIZED)) {
7953 err = -EIO;
7954 goto done;
7955 }
7956
Zhu Yi9f3b2412007-07-12 16:09:24 +08007957 if ((mode < 0) || (mode > POWER_MODES))
James Ketrenos2c86c272005-03-23 17:32:29 -06007958 mode = IPW_POWER_AUTO;
7959
Zhu Yi9f3b2412007-07-12 16:09:24 +08007960 if (IPW_POWER_LEVEL(priv->power_mode) != mode)
James Ketrenos2c86c272005-03-23 17:32:29 -06007961 err = ipw2100_set_power_mode(priv, mode);
James Ketrenosee8e3652005-09-14 09:47:29 -05007962 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08007963 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06007964 return err;
7965}
7966
7967#define MAX_POWER_STRING 80
7968static int ipw2100_wx_get_powermode(struct net_device *dev,
7969 struct iw_request_info *info,
7970 union iwreq_data *wrqu, char *extra)
7971{
7972 /*
7973 * This can be called at any time. No action lock required
7974 */
7975
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04007976 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06007977 int level = IPW_POWER_LEVEL(priv->power_mode);
7978 s32 timeout, period;
7979
7980 if (!(priv->power_mode & IPW_POWER_ENABLED)) {
7981 snprintf(extra, MAX_POWER_STRING,
7982 "Power save level: %d (Off)", level);
7983 } else {
7984 switch (level) {
7985 case IPW_POWER_MODE_CAM:
7986 snprintf(extra, MAX_POWER_STRING,
7987 "Power save level: %d (None)", level);
7988 break;
7989 case IPW_POWER_AUTO:
James Ketrenosee8e3652005-09-14 09:47:29 -05007990 snprintf(extra, MAX_POWER_STRING,
Zhu Yi9f3b2412007-07-12 16:09:24 +08007991 "Power save level: %d (Auto)", level);
James Ketrenos2c86c272005-03-23 17:32:29 -06007992 break;
7993 default:
7994 timeout = timeout_duration[level - 1] / 1000;
7995 period = period_duration[level - 1] / 1000;
7996 snprintf(extra, MAX_POWER_STRING,
7997 "Power save level: %d "
7998 "(Timeout %dms, Period %dms)",
7999 level, timeout, period);
8000 }
8001 }
8002
8003 wrqu->data.length = strlen(extra) + 1;
8004
8005 return 0;
8006}
8007
James Ketrenos2c86c272005-03-23 17:32:29 -06008008static int ipw2100_wx_set_preamble(struct net_device *dev,
8009 struct iw_request_info *info,
8010 union iwreq_data *wrqu, char *extra)
8011{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008012 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008013 int err, mode = *(int *)extra;
8014
Ingo Molnar752e3772006-02-28 07:20:54 +08008015 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008016 if (!(priv->status & STATUS_INITIALIZED)) {
8017 err = -EIO;
8018 goto done;
8019 }
8020
8021 if (mode == 1)
8022 priv->config |= CFG_LONG_PREAMBLE;
8023 else if (mode == 0)
8024 priv->config &= ~CFG_LONG_PREAMBLE;
8025 else {
8026 err = -EINVAL;
8027 goto done;
8028 }
8029
8030 err = ipw2100_system_config(priv, 0);
8031
James Ketrenosee8e3652005-09-14 09:47:29 -05008032 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08008033 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008034 return err;
8035}
8036
8037static int ipw2100_wx_get_preamble(struct net_device *dev,
James Ketrenosee8e3652005-09-14 09:47:29 -05008038 struct iw_request_info *info,
8039 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06008040{
8041 /*
8042 * This can be called at any time. No action lock required
8043 */
8044
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008045 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008046
8047 if (priv->config & CFG_LONG_PREAMBLE)
8048 snprintf(wrqu->name, IFNAMSIZ, "long (1)");
8049 else
8050 snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
8051
8052 return 0;
8053}
8054
James Ketrenos82328352005-08-24 22:33:31 -05008055#ifdef CONFIG_IPW2100_MONITOR
8056static int ipw2100_wx_set_crc_check(struct net_device *dev,
8057 struct iw_request_info *info,
8058 union iwreq_data *wrqu, char *extra)
James Ketrenos2c86c272005-03-23 17:32:29 -06008059{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008060 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos82328352005-08-24 22:33:31 -05008061 int err, mode = *(int *)extra;
8062
Ingo Molnar752e3772006-02-28 07:20:54 +08008063 mutex_lock(&priv->action_mutex);
James Ketrenos82328352005-08-24 22:33:31 -05008064 if (!(priv->status & STATUS_INITIALIZED)) {
8065 err = -EIO;
8066 goto done;
8067 }
8068
8069 if (mode == 1)
8070 priv->config |= CFG_CRC_CHECK;
8071 else if (mode == 0)
8072 priv->config &= ~CFG_CRC_CHECK;
8073 else {
8074 err = -EINVAL;
8075 goto done;
8076 }
8077 err = 0;
8078
8079 done:
Ingo Molnar752e3772006-02-28 07:20:54 +08008080 mutex_unlock(&priv->action_mutex);
James Ketrenos82328352005-08-24 22:33:31 -05008081 return err;
8082}
8083
8084static int ipw2100_wx_get_crc_check(struct net_device *dev,
8085 struct iw_request_info *info,
8086 union iwreq_data *wrqu, char *extra)
8087{
8088 /*
8089 * This can be called at any time. No action lock required
8090 */
8091
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008092 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos82328352005-08-24 22:33:31 -05008093
8094 if (priv->config & CFG_CRC_CHECK)
8095 snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)");
8096 else
8097 snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)");
8098
8099 return 0;
8100}
8101#endif /* CONFIG_IPW2100_MONITOR */
8102
James Ketrenosee8e3652005-09-14 09:47:29 -05008103static iw_handler ipw2100_wx_handlers[] = {
Stanislav Yakovlev06d9b6a2012-02-23 17:31:24 -05008104 IW_HANDLER(SIOCGIWNAME, ipw2100_wx_get_name),
8105 IW_HANDLER(SIOCSIWFREQ, ipw2100_wx_set_freq),
8106 IW_HANDLER(SIOCGIWFREQ, ipw2100_wx_get_freq),
8107 IW_HANDLER(SIOCSIWMODE, ipw2100_wx_set_mode),
8108 IW_HANDLER(SIOCGIWMODE, ipw2100_wx_get_mode),
8109 IW_HANDLER(SIOCGIWRANGE, ipw2100_wx_get_range),
8110 IW_HANDLER(SIOCSIWAP, ipw2100_wx_set_wap),
8111 IW_HANDLER(SIOCGIWAP, ipw2100_wx_get_wap),
8112 IW_HANDLER(SIOCSIWMLME, ipw2100_wx_set_mlme),
8113 IW_HANDLER(SIOCSIWSCAN, ipw2100_wx_set_scan),
8114 IW_HANDLER(SIOCGIWSCAN, ipw2100_wx_get_scan),
8115 IW_HANDLER(SIOCSIWESSID, ipw2100_wx_set_essid),
8116 IW_HANDLER(SIOCGIWESSID, ipw2100_wx_get_essid),
8117 IW_HANDLER(SIOCSIWNICKN, ipw2100_wx_set_nick),
8118 IW_HANDLER(SIOCGIWNICKN, ipw2100_wx_get_nick),
8119 IW_HANDLER(SIOCSIWRATE, ipw2100_wx_set_rate),
8120 IW_HANDLER(SIOCGIWRATE, ipw2100_wx_get_rate),
8121 IW_HANDLER(SIOCSIWRTS, ipw2100_wx_set_rts),
8122 IW_HANDLER(SIOCGIWRTS, ipw2100_wx_get_rts),
8123 IW_HANDLER(SIOCSIWFRAG, ipw2100_wx_set_frag),
8124 IW_HANDLER(SIOCGIWFRAG, ipw2100_wx_get_frag),
8125 IW_HANDLER(SIOCSIWTXPOW, ipw2100_wx_set_txpow),
8126 IW_HANDLER(SIOCGIWTXPOW, ipw2100_wx_get_txpow),
8127 IW_HANDLER(SIOCSIWRETRY, ipw2100_wx_set_retry),
8128 IW_HANDLER(SIOCGIWRETRY, ipw2100_wx_get_retry),
8129 IW_HANDLER(SIOCSIWENCODE, ipw2100_wx_set_encode),
8130 IW_HANDLER(SIOCGIWENCODE, ipw2100_wx_get_encode),
8131 IW_HANDLER(SIOCSIWPOWER, ipw2100_wx_set_power),
8132 IW_HANDLER(SIOCGIWPOWER, ipw2100_wx_get_power),
8133 IW_HANDLER(SIOCSIWGENIE, ipw2100_wx_set_genie),
8134 IW_HANDLER(SIOCGIWGENIE, ipw2100_wx_get_genie),
8135 IW_HANDLER(SIOCSIWAUTH, ipw2100_wx_set_auth),
8136 IW_HANDLER(SIOCGIWAUTH, ipw2100_wx_get_auth),
8137 IW_HANDLER(SIOCSIWENCODEEXT, ipw2100_wx_set_encodeext),
8138 IW_HANDLER(SIOCGIWENCODEEXT, ipw2100_wx_get_encodeext),
James Ketrenos2c86c272005-03-23 17:32:29 -06008139};
8140
8141#define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV
8142#define IPW2100_PRIV_RESET SIOCIWFIRSTPRIV+1
8143#define IPW2100_PRIV_SET_POWER SIOCIWFIRSTPRIV+2
8144#define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3
8145#define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4
8146#define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5
James Ketrenos82328352005-08-24 22:33:31 -05008147#define IPW2100_PRIV_SET_CRC_CHECK SIOCIWFIRSTPRIV+6
8148#define IPW2100_PRIV_GET_CRC_CHECK SIOCIWFIRSTPRIV+7
James Ketrenos2c86c272005-03-23 17:32:29 -06008149
8150static const struct iw_priv_args ipw2100_private_args[] = {
8151
8152#ifdef CONFIG_IPW2100_MONITOR
8153 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008154 IPW2100_PRIV_SET_MONITOR,
8155 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008156 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008157 IPW2100_PRIV_RESET,
8158 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
8159#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008160
8161 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008162 IPW2100_PRIV_SET_POWER,
8163 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008164 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008165 IPW2100_PRIV_GET_POWER,
8166 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING,
8167 "get_power"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008168 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008169 IPW2100_PRIV_SET_LONGPREAMBLE,
8170 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"},
James Ketrenos2c86c272005-03-23 17:32:29 -06008171 {
James Ketrenosee8e3652005-09-14 09:47:29 -05008172 IPW2100_PRIV_GET_LONGPREAMBLE,
8173 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"},
James Ketrenos82328352005-08-24 22:33:31 -05008174#ifdef CONFIG_IPW2100_MONITOR
8175 {
8176 IPW2100_PRIV_SET_CRC_CHECK,
8177 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"},
8178 {
8179 IPW2100_PRIV_GET_CRC_CHECK,
8180 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"},
8181#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008182};
8183
8184static iw_handler ipw2100_private_handler[] = {
8185#ifdef CONFIG_IPW2100_MONITOR
8186 ipw2100_wx_set_promisc,
8187 ipw2100_wx_reset,
James Ketrenosee8e3652005-09-14 09:47:29 -05008188#else /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008189 NULL,
8190 NULL,
James Ketrenosee8e3652005-09-14 09:47:29 -05008191#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008192 ipw2100_wx_set_powermode,
8193 ipw2100_wx_get_powermode,
8194 ipw2100_wx_set_preamble,
8195 ipw2100_wx_get_preamble,
James Ketrenos82328352005-08-24 22:33:31 -05008196#ifdef CONFIG_IPW2100_MONITOR
8197 ipw2100_wx_set_crc_check,
8198 ipw2100_wx_get_crc_check,
8199#else /* CONFIG_IPW2100_MONITOR */
8200 NULL,
8201 NULL,
8202#endif /* CONFIG_IPW2100_MONITOR */
James Ketrenos2c86c272005-03-23 17:32:29 -06008203};
8204
James Ketrenos2c86c272005-03-23 17:32:29 -06008205/*
8206 * Get wireless statistics.
8207 * Called by /proc/net/wireless
8208 * Also called by SIOCGIWSTATS
8209 */
James Ketrenosee8e3652005-09-14 09:47:29 -05008210static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
James Ketrenos2c86c272005-03-23 17:32:29 -06008211{
8212 enum {
8213 POOR = 30,
8214 FAIR = 60,
8215 GOOD = 80,
8216 VERY_GOOD = 90,
8217 EXCELLENT = 95,
8218 PERFECT = 100
8219 };
8220 int rssi_qual;
8221 int tx_qual;
8222 int beacon_qual;
Reinette Chatre21f8a732009-08-18 10:25:05 -07008223 int quality;
James Ketrenos2c86c272005-03-23 17:32:29 -06008224
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -04008225 struct ipw2100_priv *priv = libipw_priv(dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008226 struct iw_statistics *wstats;
Reinette Chatre21f8a732009-08-18 10:25:05 -07008227 u32 rssi, tx_retries, missed_beacons, tx_failures;
James Ketrenos2c86c272005-03-23 17:32:29 -06008228 u32 ord_len = sizeof(u32);
8229
8230 if (!priv)
James Ketrenosee8e3652005-09-14 09:47:29 -05008231 return (struct iw_statistics *)NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06008232
8233 wstats = &priv->wstats;
8234
8235 /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
8236 * ipw2100_wx_wireless_stats seems to be called before fw is
8237 * initialized. STATUS_ASSOCIATED will only be set if the hw is up
8238 * and associated; if not associcated, the values are all meaningless
8239 * anyway, so set them all to NULL and INVALID */
8240 if (!(priv->status & STATUS_ASSOCIATED)) {
8241 wstats->miss.beacon = 0;
8242 wstats->discard.retries = 0;
8243 wstats->qual.qual = 0;
8244 wstats->qual.level = 0;
8245 wstats->qual.noise = 0;
8246 wstats->qual.updated = 7;
8247 wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
James Ketrenosee8e3652005-09-14 09:47:29 -05008248 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
James Ketrenos2c86c272005-03-23 17:32:29 -06008249 return wstats;
8250 }
8251
8252 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS,
8253 &missed_beacons, &ord_len))
8254 goto fail_get_ordinal;
8255
James Ketrenosee8e3652005-09-14 09:47:29 -05008256 /* If we don't have a connection the quality and level is 0 */
James Ketrenos2c86c272005-03-23 17:32:29 -06008257 if (!(priv->status & STATUS_ASSOCIATED)) {
8258 wstats->qual.qual = 0;
8259 wstats->qual.level = 0;
8260 } else {
8261 if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR,
8262 &rssi, &ord_len))
8263 goto fail_get_ordinal;
8264 wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
8265 if (rssi < 10)
8266 rssi_qual = rssi * POOR / 10;
8267 else if (rssi < 15)
8268 rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR;
8269 else if (rssi < 20)
8270 rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR;
8271 else if (rssi < 30)
8272 rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008273 10 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008274 else
8275 rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008276 10 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008277
8278 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES,
8279 &tx_retries, &ord_len))
8280 goto fail_get_ordinal;
8281
8282 if (tx_retries > 75)
8283 tx_qual = (90 - tx_retries) * POOR / 15;
8284 else if (tx_retries > 70)
8285 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
8286 else if (tx_retries > 65)
8287 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
8288 else if (tx_retries > 50)
8289 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008290 15 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008291 else
8292 tx_qual = (50 - tx_retries) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008293 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008294
8295 if (missed_beacons > 50)
8296 beacon_qual = (60 - missed_beacons) * POOR / 10;
8297 else if (missed_beacons > 40)
8298 beacon_qual = (50 - missed_beacons) * (FAIR - POOR) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008299 10 + POOR;
James Ketrenos2c86c272005-03-23 17:32:29 -06008300 else if (missed_beacons > 32)
8301 beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) /
James Ketrenosee8e3652005-09-14 09:47:29 -05008302 18 + FAIR;
James Ketrenos2c86c272005-03-23 17:32:29 -06008303 else if (missed_beacons > 20)
8304 beacon_qual = (32 - missed_beacons) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008305 (VERY_GOOD - GOOD) / 20 + GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008306 else
8307 beacon_qual = (20 - missed_beacons) *
James Ketrenosee8e3652005-09-14 09:47:29 -05008308 (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
James Ketrenos2c86c272005-03-23 17:32:29 -06008309
Reinette Chatre21f8a732009-08-18 10:25:05 -07008310 quality = min(tx_qual, rssi_qual);
8311 quality = min(beacon_qual, quality);
James Ketrenos2c86c272005-03-23 17:32:29 -06008312
Brice Goglin0f52bf92005-12-01 01:41:46 -08008313#ifdef CONFIG_IPW2100_DEBUG
James Ketrenos2c86c272005-03-23 17:32:29 -06008314 if (beacon_qual == quality)
8315 IPW_DEBUG_WX("Quality clamped by Missed Beacons\n");
8316 else if (tx_qual == quality)
8317 IPW_DEBUG_WX("Quality clamped by Tx Retries\n");
8318 else if (quality != 100)
8319 IPW_DEBUG_WX("Quality clamped by Signal Strength\n");
8320 else
8321 IPW_DEBUG_WX("Quality not clamped.\n");
8322#endif
8323
8324 wstats->qual.qual = quality;
8325 wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
8326 }
8327
8328 wstats->qual.noise = 0;
8329 wstats->qual.updated = 7;
8330 wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
8331
James Ketrenosee8e3652005-09-14 09:47:29 -05008332 /* FIXME: this is percent and not a # */
James Ketrenos2c86c272005-03-23 17:32:29 -06008333 wstats->miss.beacon = missed_beacons;
8334
8335 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES,
8336 &tx_failures, &ord_len))
8337 goto fail_get_ordinal;
8338 wstats->discard.retries = tx_failures;
8339
8340 return wstats;
8341
James Ketrenosee8e3652005-09-14 09:47:29 -05008342 fail_get_ordinal:
James Ketrenos2c86c272005-03-23 17:32:29 -06008343 IPW_DEBUG_WX("failed querying ordinals.\n");
8344
James Ketrenosee8e3652005-09-14 09:47:29 -05008345 return (struct iw_statistics *)NULL;
James Ketrenos2c86c272005-03-23 17:32:29 -06008346}
8347
James Ketrenoseaf8f532005-11-12 12:50:12 -06008348static struct iw_handler_def ipw2100_wx_handler_def = {
8349 .standard = ipw2100_wx_handlers,
Denis Chengff8ac602007-09-02 18:30:18 +08008350 .num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
8351 .num_private = ARRAY_SIZE(ipw2100_private_handler),
8352 .num_private_args = ARRAY_SIZE(ipw2100_private_args),
James Ketrenoseaf8f532005-11-12 12:50:12 -06008353 .private = (iw_handler *) ipw2100_private_handler,
8354 .private_args = (struct iw_priv_args *)ipw2100_private_args,
8355 .get_wireless_stats = ipw2100_wx_wireless_stats,
8356};
8357
David Howellsc4028952006-11-22 14:57:56 +00008358static void ipw2100_wx_event_work(struct work_struct *work)
James Ketrenos2c86c272005-03-23 17:32:29 -06008359{
David Howellsc4028952006-11-22 14:57:56 +00008360 struct ipw2100_priv *priv =
8361 container_of(work, struct ipw2100_priv, wx_event_work.work);
James Ketrenos2c86c272005-03-23 17:32:29 -06008362 union iwreq_data wrqu;
Hannes Ederb9da9e92009-02-14 11:50:26 +00008363 unsigned int len = ETH_ALEN;
James Ketrenos2c86c272005-03-23 17:32:29 -06008364
8365 if (priv->status & STATUS_STOPPING)
8366 return;
8367
Ingo Molnar752e3772006-02-28 07:20:54 +08008368 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008369
8370 IPW_DEBUG_WX("enter\n");
8371
Ingo Molnar752e3772006-02-28 07:20:54 +08008372 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008373
8374 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
8375
8376 /* Fetch BSSID from the hardware */
8377 if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) ||
8378 priv->status & STATUS_RF_KILL_MASK ||
8379 ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
James Ketrenosee8e3652005-09-14 09:47:29 -05008380 &priv->bssid, &len)) {
James Ketrenos2c86c272005-03-23 17:32:29 -06008381 memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
8382 } else {
8383 /* We now have the BSSID, so can finish setting to the full
8384 * associated state */
8385 memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
James Ketrenos82328352005-08-24 22:33:31 -05008386 memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN);
James Ketrenos2c86c272005-03-23 17:32:29 -06008387 priv->status &= ~STATUS_ASSOCIATING;
8388 priv->status |= STATUS_ASSOCIATED;
8389 netif_carrier_on(priv->net_dev);
James Ketrenos82328352005-08-24 22:33:31 -05008390 netif_wake_queue(priv->net_dev);
James Ketrenos2c86c272005-03-23 17:32:29 -06008391 }
8392
8393 if (!(priv->status & STATUS_ASSOCIATED)) {
8394 IPW_DEBUG_WX("Configuring ESSID\n");
Ingo Molnar752e3772006-02-28 07:20:54 +08008395 mutex_lock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008396 /* This is a disassociation event, so kick the firmware to
8397 * look for another AP */
8398 if (priv->config & CFG_STATIC_ESSID)
James Ketrenosee8e3652005-09-14 09:47:29 -05008399 ipw2100_set_essid(priv, priv->essid, priv->essid_len,
8400 0);
James Ketrenos2c86c272005-03-23 17:32:29 -06008401 else
8402 ipw2100_set_essid(priv, NULL, 0, 0);
Ingo Molnar752e3772006-02-28 07:20:54 +08008403 mutex_unlock(&priv->action_mutex);
James Ketrenos2c86c272005-03-23 17:32:29 -06008404 }
8405
8406 wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
8407}
8408
8409#define IPW2100_FW_MAJOR_VERSION 1
8410#define IPW2100_FW_MINOR_VERSION 3
8411
8412#define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8)
8413#define IPW2100_FW_MAJOR(x) (x & 0xff)
8414
8415#define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \
8416 IPW2100_FW_MAJOR_VERSION)
8417
8418#define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \
8419"." __stringify(IPW2100_FW_MINOR_VERSION)
8420
8421#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw"
8422
James Ketrenos2c86c272005-03-23 17:32:29 -06008423/*
8424
8425BINARY FIRMWARE HEADER FORMAT
8426
8427offset length desc
84280 2 version
84292 2 mode == 0:BSS,1:IBSS,2:MONITOR
84304 4 fw_len
84318 4 uc_len
8432C fw_len firmware data
843312 + fw_len uc_len microcode data
8434
8435*/
8436
8437struct ipw2100_fw_header {
8438 short version;
8439 short mode;
8440 unsigned int fw_size;
8441 unsigned int uc_size;
Eric Dumazetba2d3582010-06-02 18:10:09 +00008442} __packed;
James Ketrenos2c86c272005-03-23 17:32:29 -06008443
James Ketrenos2c86c272005-03-23 17:32:29 -06008444static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
8445{
8446 struct ipw2100_fw_header *h =
James Ketrenosee8e3652005-09-14 09:47:29 -05008447 (struct ipw2100_fw_header *)fw->fw_entry->data;
James Ketrenos2c86c272005-03-23 17:32:29 -06008448
8449 if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008450 printk(KERN_WARNING DRV_NAME ": Firmware image not compatible "
James Ketrenos2c86c272005-03-23 17:32:29 -06008451 "(detected version id of %u). "
8452 "See Documentation/networking/README.ipw2100\n",
8453 h->version);
8454 return 1;
8455 }
8456
8457 fw->version = h->version;
8458 fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header);
8459 fw->fw.size = h->fw_size;
8460 fw->uc.data = fw->fw.data + h->fw_size;
8461 fw->uc.size = h->uc_size;
8462
8463 return 0;
8464}
8465
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008466static int ipw2100_get_firmware(struct ipw2100_priv *priv,
8467 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008468{
8469 char *fw_name;
8470 int rc;
8471
8472 IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n",
James Ketrenosee8e3652005-09-14 09:47:29 -05008473 priv->net_dev->name);
James Ketrenos2c86c272005-03-23 17:32:29 -06008474
8475 switch (priv->ieee->iw_mode) {
8476 case IW_MODE_ADHOC:
8477 fw_name = IPW2100_FW_NAME("-i");
8478 break;
8479#ifdef CONFIG_IPW2100_MONITOR
8480 case IW_MODE_MONITOR:
8481 fw_name = IPW2100_FW_NAME("-p");
8482 break;
8483#endif
8484 case IW_MODE_INFRA:
8485 default:
8486 fw_name = IPW2100_FW_NAME("");
8487 break;
8488 }
8489
8490 rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev);
8491
8492 if (rc < 0) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008493 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06008494 "%s: Firmware '%s' not available or load failed.\n",
8495 priv->net_dev->name, fw_name);
8496 return rc;
8497 }
Jiri Bencaaa4d302005-06-07 14:58:41 +02008498 IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data,
James Ketrenosee8e3652005-09-14 09:47:29 -05008499 fw->fw_entry->size);
James Ketrenos2c86c272005-03-23 17:32:29 -06008500
8501 ipw2100_mod_firmware_load(fw);
8502
8503 return 0;
8504}
8505
Ben Hutchingsa278ea32009-11-07 21:58:47 +00008506MODULE_FIRMWARE(IPW2100_FW_NAME("-i"));
8507#ifdef CONFIG_IPW2100_MONITOR
8508MODULE_FIRMWARE(IPW2100_FW_NAME("-p"));
8509#endif
8510MODULE_FIRMWARE(IPW2100_FW_NAME(""));
8511
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008512static void ipw2100_release_firmware(struct ipw2100_priv *priv,
8513 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008514{
8515 fw->version = 0;
8516 if (fw->fw_entry)
8517 release_firmware(fw->fw_entry);
8518 fw->fw_entry = NULL;
8519}
8520
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008521static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
8522 size_t max)
James Ketrenos2c86c272005-03-23 17:32:29 -06008523{
8524 char ver[MAX_FW_VERSION_LEN];
8525 u32 len = MAX_FW_VERSION_LEN;
8526 u32 tmp;
8527 int i;
8528 /* firmware version is an ascii string (max len of 14) */
James Ketrenosee8e3652005-09-14 09:47:29 -05008529 if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len))
James Ketrenos2c86c272005-03-23 17:32:29 -06008530 return -EIO;
8531 tmp = max;
8532 if (len >= max)
8533 len = max - 1;
8534 for (i = 0; i < len; i++)
8535 buf[i] = ver[i];
8536 buf[i] = '\0';
8537 return tmp;
8538}
8539
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008540static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
8541 size_t max)
James Ketrenos2c86c272005-03-23 17:32:29 -06008542{
8543 u32 ver;
8544 u32 len = sizeof(ver);
8545 /* microcode version is a 32 bit integer */
James Ketrenosee8e3652005-09-14 09:47:29 -05008546 if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len))
James Ketrenos2c86c272005-03-23 17:32:29 -06008547 return -EIO;
8548 return snprintf(buf, max, "%08X", ver);
8549}
8550
8551/*
8552 * On exit, the firmware will have been freed from the fw list
8553 */
James Ketrenosee8e3652005-09-14 09:47:29 -05008554static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008555{
8556 /* firmware is constructed of N contiguous entries, each entry is
8557 * structured as:
8558 *
8559 * offset sie desc
8560 * 0 4 address to write to
8561 * 4 2 length of data run
James Ketrenosee8e3652005-09-14 09:47:29 -05008562 * 6 length data
James Ketrenos2c86c272005-03-23 17:32:29 -06008563 */
8564 unsigned int addr;
8565 unsigned short len;
8566
8567 const unsigned char *firmware_data = fw->fw.data;
8568 unsigned int firmware_data_left = fw->fw.size;
8569
8570 while (firmware_data_left > 0) {
James Ketrenosee8e3652005-09-14 09:47:29 -05008571 addr = *(u32 *) (firmware_data);
8572 firmware_data += 4;
James Ketrenos2c86c272005-03-23 17:32:29 -06008573 firmware_data_left -= 4;
8574
James Ketrenosee8e3652005-09-14 09:47:29 -05008575 len = *(u16 *) (firmware_data);
8576 firmware_data += 2;
James Ketrenos2c86c272005-03-23 17:32:29 -06008577 firmware_data_left -= 2;
8578
8579 if (len > 32) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008580 printk(KERN_ERR DRV_NAME ": "
James Ketrenos2c86c272005-03-23 17:32:29 -06008581 "Invalid firmware run-length of %d bytes\n",
8582 len);
8583 return -EINVAL;
8584 }
8585
8586 write_nic_memory(priv->net_dev, addr, len, firmware_data);
James Ketrenosee8e3652005-09-14 09:47:29 -05008587 firmware_data += len;
James Ketrenos2c86c272005-03-23 17:32:29 -06008588 firmware_data_left -= len;
8589 }
8590
8591 return 0;
8592}
8593
8594struct symbol_alive_response {
8595 u8 cmd_id;
8596 u8 seq_num;
8597 u8 ucode_rev;
8598 u8 eeprom_valid;
8599 u16 valid_flags;
8600 u8 IEEE_addr[6];
8601 u16 flags;
8602 u16 pcb_rev;
8603 u16 clock_settle_time; // 1us LSB
8604 u16 powerup_settle_time; // 1us LSB
8605 u16 hop_settle_time; // 1us LSB
8606 u8 date[3]; // month, day, year
8607 u8 time[2]; // hours, minutes
8608 u8 ucode_valid;
8609};
8610
Jiri Bencc4aee8c2005-08-25 20:04:43 -04008611static int ipw2100_ucode_download(struct ipw2100_priv *priv,
8612 struct ipw2100_fw *fw)
James Ketrenos2c86c272005-03-23 17:32:29 -06008613{
8614 struct net_device *dev = priv->net_dev;
8615 const unsigned char *microcode_data = fw->uc.data;
8616 unsigned int microcode_data_left = fw->uc.size;
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008617 void __iomem *reg = (void __iomem *)dev->base_addr;
James Ketrenos2c86c272005-03-23 17:32:29 -06008618
8619 struct symbol_alive_response response;
8620 int i, j;
8621 u8 data;
8622
8623 /* Symbol control */
8624 write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008625 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008626 write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008627 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008628
8629 /* HW config */
8630 write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008631 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008632 write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008633 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008634
8635 /* EN_CS_ACCESS bit to reset control store pointer */
8636 write_nic_byte(dev, 0x210000, 0x40);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008637 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008638 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008639 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008640 write_nic_byte(dev, 0x210000, 0x40);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008641 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008642
8643 /* copy microcode from buffer into Symbol */
8644
8645 while (microcode_data_left > 0) {
8646 write_nic_byte(dev, 0x210010, *microcode_data++);
8647 write_nic_byte(dev, 0x210010, *microcode_data++);
8648 microcode_data_left -= 2;
8649 }
8650
8651 /* EN_CS_ACCESS bit to reset the control store pointer */
8652 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008653 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008654
8655 /* Enable System (Reg 0)
8656 * first enable causes garbage in RX FIFO */
8657 write_nic_byte(dev, 0x210000, 0x0);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008658 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008659 write_nic_byte(dev, 0x210000, 0x80);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008660 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008661
8662 /* Reset External Baseband Reg */
8663 write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008664 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008665 write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008666 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008667
8668 /* HW Config (Reg 5) */
8669 write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008670 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008671 write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008672 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008673
8674 /* Enable System (Reg 0)
8675 * second enable should be OK */
8676 write_nic_byte(dev, 0x210000, 0x00); // clear enable system
viro@ftp.linux.org.uk2be041a2005-09-05 03:26:08 +01008677 readl(reg);
James Ketrenos2c86c272005-03-23 17:32:29 -06008678 write_nic_byte(dev, 0x210000, 0x80); // set enable system
8679
8680 /* check Symbol is enabled - upped this from 5 as it wasn't always
8681 * catching the update */
8682 for (i = 0; i < 10; i++) {
8683 udelay(10);
8684
8685 /* check Dino is enabled bit */
8686 read_nic_byte(dev, 0x210000, &data);
8687 if (data & 0x1)
8688 break;
8689 }
8690
8691 if (i == 10) {
Jiri Benc797b4f72005-08-25 20:03:27 -04008692 printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06008693 dev->name);
8694 return -EIO;
8695 }
8696
8697 /* Get Symbol alive response */
8698 for (i = 0; i < 30; i++) {
8699 /* Read alive response structure */
8700 for (j = 0;
James Ketrenosee8e3652005-09-14 09:47:29 -05008701 j < (sizeof(struct symbol_alive_response) >> 1); j++)
8702 read_nic_word(dev, 0x210004, ((u16 *) & response) + j);
James Ketrenos2c86c272005-03-23 17:32:29 -06008703
James Ketrenosee8e3652005-09-14 09:47:29 -05008704 if ((response.cmd_id == 1) && (response.ucode_valid == 0x1))
James Ketrenos2c86c272005-03-23 17:32:29 -06008705 break;
8706 udelay(10);
8707 }
8708
8709 if (i == 30) {
James Ketrenosee8e3652005-09-14 09:47:29 -05008710 printk(KERN_ERR DRV_NAME
8711 ": %s: No response from Symbol - hw not alive\n",
James Ketrenos2c86c272005-03-23 17:32:29 -06008712 dev->name);
James Ketrenosee8e3652005-09-14 09:47:29 -05008713 printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response));
James Ketrenos2c86c272005-03-23 17:32:29 -06008714 return -EIO;
8715 }
8716
8717 return 0;
8718}