iwl3945-base.c 246 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/******************************************************************************
 *
 * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
 *
 * Portions of this file are derived from the ipw3945 project, as well
 * as portions of the ieee80211 subsystem header files.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 *
 * The full GNU General Public License is included in this distribution in the
 * file called LICENSE.
 *
 * Contact Information:
 * James P. Ketrenos <ipw2100-admin@linux.intel.com>
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *
 *****************************************************************************/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <linux/firmware.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>

#include <net/ieee80211_radiotap.h>
#include <net/mac80211.h>

#include <asm/div64.h>

#include "iwl-3945.h"
#include "iwl-helpers.h"

52
#ifdef CONFIG_IWL3945_DEBUG
Christoph Hellwig's avatar
Christoph Hellwig committed
53
u32 iwl3945_debug_level;
54
55
#endif

Christoph Hellwig's avatar
Christoph Hellwig committed
56
57
static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv,
				  struct iwl3945_tx_queue *txq);
58

59
60
61
62
63
64
65
/******************************************************************************
 *
 * module boiler plate
 *
 ******************************************************************************/

/* module parameters */
66
67
68
static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */
static int iwl3945_param_debug;    /* def: 0 = minimal debug log messages */
static int iwl3945_param_disable;  /* def: 0 = enable radio */
69
static int iwl3945_param_antenna;  /* def: 0 = both antennas (use diversity) */
70
71
72
int iwl3945_param_hwcrypto;        /* def: 0 = use software encryption */
static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */
int iwl3945_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 8 Tx queues */
73
74
75
76
77
78
79
80
81

/*
 * module name, copyright, version, etc.
 * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk
 */

#define DRV_DESCRIPTION	\
"Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux"

82
#ifdef CONFIG_IWL3945_DEBUG
83
84
85
86
87
#define VD "d"
#else
#define VD
#endif

88
#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
89
90
91
92
93
#define VS "s"
#else
#define VS
#endif

94
#define IWLWIFI_VERSION "1.2.23k" VD VS
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#define DRV_COPYRIGHT	"Copyright(c) 2003-2007 Intel Corporation"
#define DRV_VERSION     IWLWIFI_VERSION

/* Change firmware file name, using "-" and incrementing number,
 *   *only* when uCode interface or architecture changes so that it
 *   is not compatible with earlier drivers.
 * This number will also appear in << 8 position of 1st dword of uCode file */
#define IWL3945_UCODE_API "-1"

MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");

109
static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
110
111
112
113
114
115
116
117
118
{
	u16 fc = le16_to_cpu(hdr->frame_control);
	int hdr_len = ieee80211_get_hdrlen(fc);

	if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
		return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
	return NULL;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
119
120
static const struct ieee80211_hw_mode *iwl3945_get_hw_mode(
		struct iwl3945_priv *priv, int mode)
121
122
123
124
125
126
127
128
129
130
{
	int i;

	for (i = 0; i < 3; i++)
		if (priv->modes[i].mode == mode)
			return &priv->modes[i];

	return NULL;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
131
static int iwl3945_is_empty_essid(const char *essid, int essid_len)
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
{
	/* Single white space is for Linksys APs */
	if (essid_len == 1 && essid[0] == ' ')
		return 1;

	/* Otherwise, if the entire essid is 0, we assume it is hidden */
	while (essid_len) {
		essid_len--;
		if (essid[essid_len] != '\0')
			return 0;
	}

	return 1;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
147
static const char *iwl3945_escape_essid(const char *essid, u8 essid_len)
148
149
150
151
152
{
	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
	const char *s = essid;
	char *d = escaped;

Christoph Hellwig's avatar
Christoph Hellwig committed
153
	if (iwl3945_is_empty_essid(essid, essid_len)) {
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
		memcpy(escaped, "<hidden>", sizeof("<hidden>"));
		return escaped;
	}

	essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
	while (essid_len--) {
		if (*s == '\0') {
			*d++ = '\\';
			*d++ = '0';
			s++;
		} else
			*d++ = *s++;
	}
	*d = '\0';
	return escaped;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
171
static void iwl3945_print_hex_dump(int level, void *p, u32 len)
172
{
173
#ifdef CONFIG_IWL3945_DEBUG
Christoph Hellwig's avatar
Christoph Hellwig committed
174
	if (!(iwl3945_debug_level & level))
175
176
177
178
179
180
181
182
183
184
185
186
		return;

	print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
			p, len, 1);
#endif
}

/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
 * DMA services
 *
 * Theory of operation
 *
187
188
189
190
191
192
193
194
195
 * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
 * of buffer descriptors, each of which points to one or more data buffers for
 * the device to read from or fill.  Driver and device exchange status of each
 * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
 * entries in each circular buffer, to protect against confusing empty and full
 * queue states.
 *
 * The device reads or writes the data in the queues via the device's several
 * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
196
197
198
199
200
201
 *
 * For Tx queue, there are low mark and high mark limits. If, after queuing
 * the packet for Tx, free space become < low mark, Tx queue stopped. When
 * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
 * Tx queue resumed.
 *
202
203
204
 * The 3945 operates with six queues:  One receive queue, one transmit queue
 * (#4) for sending commands to the device firmware, and four transmit queues
 * (#0-3) for data tx via EDCA.  An additional 2 HCCA queues are unused.
205
206
 ***************************************************/

Christoph Hellwig's avatar
Christoph Hellwig committed
207
static int iwl3945_queue_space(const struct iwl3945_queue *q)
208
{
209
	int s = q->read_ptr - q->write_ptr;
210

211
	if (q->read_ptr > q->write_ptr)
212
213
214
215
216
217
218
219
220
221
222
		s -= q->n_bd;

	if (s <= 0)
		s += q->n_window;
	/* keep some reserve to not confuse empty and full situations */
	s -= 2;
	if (s < 0)
		s = 0;
	return s;
}

223
224
225
226
227
/**
 * iwl3945_queue_inc_wrap - increment queue index, wrap back to beginning
 * @index -- current index
 * @n_bd -- total number of entries in queue (must be power of 2)
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
228
static inline int iwl3945_queue_inc_wrap(int index, int n_bd)
229
230
231
232
{
	return ++index & (n_bd - 1);
}

233
234
235
236
237
/**
 * iwl3945_queue_dec_wrap - increment queue index, wrap back to end
 * @index -- current index
 * @n_bd -- total number of entries in queue (must be power of 2)
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
238
static inline int iwl3945_queue_dec_wrap(int index, int n_bd)
239
240
241
242
{
	return --index & (n_bd - 1);
}

Christoph Hellwig's avatar
Christoph Hellwig committed
243
static inline int x2_queue_used(const struct iwl3945_queue *q, int i)
244
{
245
246
247
	return q->write_ptr > q->read_ptr ?
		(i >= q->read_ptr && i < q->write_ptr) :
		!(i < q->read_ptr && i >= q->write_ptr);
248
249
}

Christoph Hellwig's avatar
Christoph Hellwig committed
250
static inline u8 get_cmd_index(struct iwl3945_queue *q, u32 index, int is_huge)
251
{
252
	/* This is for scan command, the big buffer at end of command array */
253
	if (is_huge)
254
		return q->n_window;	/* must be power of 2 */
255

256
	/* Otherwise, use normal size buffers */
257
258
259
	return index & (q->n_window - 1);
}

260
261
262
/**
 * iwl3945_queue_init - Initialize queue's high/low-water and read/write indexes
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
263
static int iwl3945_queue_init(struct iwl3945_priv *priv, struct iwl3945_queue *q,
264
265
266
267
268
269
			  int count, int slots_num, u32 id)
{
	q->n_bd = count;
	q->n_window = slots_num;
	q->id = id;

Christoph Hellwig's avatar
Christoph Hellwig committed
270
271
	/* count must be power-of-two size, otherwise iwl3945_queue_inc_wrap
	 * and iwl3945_queue_dec_wrap are broken. */
272
273
274
275
276
277
278
279
280
281
282
283
284
285
	BUG_ON(!is_power_of_2(count));

	/* slots_num must be power-of-two size, otherwise
	 * get_cmd_index is broken. */
	BUG_ON(!is_power_of_2(slots_num));

	q->low_mark = q->n_window / 4;
	if (q->low_mark < 4)
		q->low_mark = 4;

	q->high_mark = q->n_window / 8;
	if (q->high_mark < 2)
		q->high_mark = 2;

286
	q->write_ptr = q->read_ptr = 0;
287
288
289
290

	return 0;
}

291
292
293
/**
 * iwl3945_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
294
295
static int iwl3945_tx_queue_alloc(struct iwl3945_priv *priv,
			      struct iwl3945_tx_queue *txq, u32 id)
296
297
298
{
	struct pci_dev *dev = priv->pci_dev;

299
300
	/* Driver private data, only for Tx (not command) queues,
	 * not shared with device. */
301
302
303
304
	if (id != IWL_CMD_QUEUE_NUM) {
		txq->txb = kmalloc(sizeof(txq->txb[0]) *
				   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
		if (!txq->txb) {
305
			IWL_ERROR("kmalloc for auxiliary BD "
306
307
308
309
310
311
				  "structures failed\n");
			goto error;
		}
	} else
		txq->txb = NULL;

312
313
	/* Circular buffer of transmit frame descriptors (TFDs),
	 * shared with device */
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
	txq->bd = pci_alloc_consistent(dev,
			sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
			&txq->q.dma_addr);

	if (!txq->bd) {
		IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
			  sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
		goto error;
	}
	txq->q.id = id;

	return 0;

 error:
	if (txq->txb) {
		kfree(txq->txb);
		txq->txb = NULL;
	}

	return -ENOMEM;
}

336
337
338
/**
 * iwl3945_tx_queue_init - Allocate and initialize one tx/cmd queue
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
339
340
int iwl3945_tx_queue_init(struct iwl3945_priv *priv,
		      struct iwl3945_tx_queue *txq, int slots_num, u32 txq_id)
341
342
343
344
345
{
	struct pci_dev *dev = priv->pci_dev;
	int len;
	int rc = 0;

346
347
348
349
350
351
352
353
	/*
	 * Alloc buffer array for commands (Tx or other types of commands).
	 * For the command queue (#4), allocate command space + one big
	 * command for scan, since scan command is very huge; the system will
	 * not have two scans at the same time, so only one is needed.
	 * For data Tx queues (all other queues), no super-size command
	 * space is needed.
	 */
Christoph Hellwig's avatar
Christoph Hellwig committed
354
	len = sizeof(struct iwl3945_cmd) * slots_num;
355
356
357
358
359
360
	if (txq_id == IWL_CMD_QUEUE_NUM)
		len +=  IWL_MAX_SCAN_SIZE;
	txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
	if (!txq->cmd)
		return -ENOMEM;

361
	/* Alloc driver data array and TFD circular buffer */
Christoph Hellwig's avatar
Christoph Hellwig committed
362
	rc = iwl3945_tx_queue_alloc(priv, txq, txq_id);
363
364
365
366
367
368
369
370
	if (rc) {
		pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);

		return -ENOMEM;
	}
	txq->need_update = 0;

	/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
Christoph Hellwig's avatar
Christoph Hellwig committed
371
	 * iwl3945_queue_inc_wrap and iwl3945_queue_dec_wrap are broken. */
372
	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
373
374

	/* Initialize queue high/low-water, head/tail indexes */
Christoph Hellwig's avatar
Christoph Hellwig committed
375
	iwl3945_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
376

377
	/* Tell device where to find queue, enable DMA channel. */
Christoph Hellwig's avatar
Christoph Hellwig committed
378
	iwl3945_hw_tx_queue_init(priv, txq);
379
380
381
382
383

	return 0;
}

/**
Christoph Hellwig's avatar
Christoph Hellwig committed
384
 * iwl3945_tx_queue_free - Deallocate DMA queue.
385
386
387
 * @txq: Transmit queue to deallocate.
 *
 * Empty queue by removing and destroying all BD's.
388
389
 * Free all buffers.
 * 0-fill, but do not free "txq" descriptor structure.
390
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
391
void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq)
392
{
Christoph Hellwig's avatar
Christoph Hellwig committed
393
	struct iwl3945_queue *q = &txq->q;
394
395
396
397
398
399
400
	struct pci_dev *dev = priv->pci_dev;
	int len;

	if (q->n_bd == 0)
		return;

	/* first, empty all BD's */
401
	for (; q->write_ptr != q->read_ptr;
Christoph Hellwig's avatar
Christoph Hellwig committed
402
403
	     q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd))
		iwl3945_hw_txq_free_tfd(priv, txq);
404

Christoph Hellwig's avatar
Christoph Hellwig committed
405
	len = sizeof(struct iwl3945_cmd) * q->n_window;
406
407
408
	if (q->id == IWL_CMD_QUEUE_NUM)
		len += IWL_MAX_SCAN_SIZE;

409
	/* De-alloc array of command/tx buffers */
410
411
	pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);

412
	/* De-alloc circular buffer of TFDs */
413
	if (txq->q.n_bd)
Christoph Hellwig's avatar
Christoph Hellwig committed
414
		pci_free_consistent(dev, sizeof(struct iwl3945_tfd_frame) *
415
416
				    txq->q.n_bd, txq->bd, txq->q.dma_addr);

417
	/* De-alloc array of per-TFD driver data */
418
419
420
421
422
	if (txq->txb) {
		kfree(txq->txb);
		txq->txb = NULL;
	}

423
	/* 0-fill queue descriptor structure */
424
425
426
	memset(txq, 0, sizeof(*txq));
}

Christoph Hellwig's avatar
Christoph Hellwig committed
427
const u8 iwl3945_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
428
429

/*************** STATION TABLE MANAGEMENT ****
430
 * mac80211 should be examined to determine if sta_info is duplicating
431
432
433
434
 * the functionality provided here
 */

/**************************************************************/
435
#if 0 /* temporary disable till we add real remove station */
436
437
438
439
440
/**
 * iwl3945_remove_station - Remove driver's knowledge of station.
 *
 * NOTE:  This does not remove station from device's station table.
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
441
static u8 iwl3945_remove_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap)
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
{
	int index = IWL_INVALID_STATION;
	int i;
	unsigned long flags;

	spin_lock_irqsave(&priv->sta_lock, flags);

	if (is_ap)
		index = IWL_AP_ID;
	else if (is_broadcast_ether_addr(addr))
		index = priv->hw_setting.bcast_sta_id;
	else
		for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
			if (priv->stations[i].used &&
			    !compare_ether_addr(priv->stations[i].sta.sta.addr,
						addr)) {
				index = i;
				break;
			}

	if (unlikely(index == IWL_INVALID_STATION))
		goto out;

	if (priv->stations[index].used) {
		priv->stations[index].used = 0;
		priv->num_stations--;
	}

	BUG_ON(priv->num_stations < 0);

out:
	spin_unlock_irqrestore(&priv->sta_lock, flags);
	return 0;
}
476
#endif
477
478
479
480
481
482

/**
 * iwl3945_clear_stations_table - Clear the driver's station table
 *
 * NOTE:  This does not clear or otherwise alter the device's station table.
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
483
static void iwl3945_clear_stations_table(struct iwl3945_priv *priv)
484
485
486
487
488
489
490
491
492
493
494
{
	unsigned long flags;

	spin_lock_irqsave(&priv->sta_lock, flags);

	priv->num_stations = 0;
	memset(priv->stations, 0, sizeof(priv->stations));

	spin_unlock_irqrestore(&priv->sta_lock, flags);
}

495
496
497
/**
 * iwl3945_add_station - Add station to station tables in driver and device
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
498
u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 flags)
499
500
501
{
	int i;
	int index = IWL_INVALID_STATION;
Christoph Hellwig's avatar
Christoph Hellwig committed
502
	struct iwl3945_station_entry *station;
503
	unsigned long flags_spin;
504
	DECLARE_MAC_BUF(mac);
505
	u8 rate;
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524

	spin_lock_irqsave(&priv->sta_lock, flags_spin);
	if (is_ap)
		index = IWL_AP_ID;
	else if (is_broadcast_ether_addr(addr))
		index = priv->hw_setting.bcast_sta_id;
	else
		for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) {
			if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
						addr)) {
				index = i;
				break;
			}

			if (!priv->stations[i].used &&
			    index == IWL_INVALID_STATION)
				index = i;
		}

525
	/* These two conditions has the same outcome but keep them separate
526
527
528
529
530
531
532
533
534
535
536
537
	  since they have different meaning */
	if (unlikely(index == IWL_INVALID_STATION)) {
		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
		return index;
	}

	if (priv->stations[index].used &&
	   !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
		return index;
	}

538
	IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
539
540
541
542
	station = &priv->stations[index];
	station->used = 1;
	priv->num_stations++;

543
	/* Set up the REPLY_ADD_STA command to send to device */
Christoph Hellwig's avatar
Christoph Hellwig committed
544
	memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd));
545
546
547
548
549
	memcpy(station->sta.sta.addr, addr, ETH_ALEN);
	station->sta.mode = 0;
	station->sta.sta.sta_id = index;
	station->sta.station_flags = 0;

550
551
552
553
	if (priv->phymode == MODE_IEEE80211A)
		rate = IWL_RATE_6M_PLCP;
	else
		rate =	IWL_RATE_1M_PLCP;
554
555
556

	/* Turn on both antennas for the station... */
	station->sta.rate_n_flags =
Christoph Hellwig's avatar
Christoph Hellwig committed
557
			iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK);
558
559
560
	station->current_rate.rate_n_flags =
			le16_to_cpu(station->sta.rate_n_flags);

561
	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
562
563

	/* Add station to device's station table */
Christoph Hellwig's avatar
Christoph Hellwig committed
564
	iwl3945_send_add_station(priv, &station->sta, flags);
565
566
567
568
569
570
	return index;

}

/*************** DRIVER STATUS FUNCTIONS   *****/

Christoph Hellwig's avatar
Christoph Hellwig committed
571
static inline int iwl3945_is_ready(struct iwl3945_priv *priv)
572
573
574
575
576
577
578
579
{
	/* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
	 * set but EXIT_PENDING is not */
	return test_bit(STATUS_READY, &priv->status) &&
	       test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
	       !test_bit(STATUS_EXIT_PENDING, &priv->status);
}

Christoph Hellwig's avatar
Christoph Hellwig committed
580
static inline int iwl3945_is_alive(struct iwl3945_priv *priv)
581
582
583
584
{
	return test_bit(STATUS_ALIVE, &priv->status);
}

Christoph Hellwig's avatar
Christoph Hellwig committed
585
static inline int iwl3945_is_init(struct iwl3945_priv *priv)
586
587
588
589
{
	return test_bit(STATUS_INIT, &priv->status);
}

Christoph Hellwig's avatar
Christoph Hellwig committed
590
static inline int iwl3945_is_rfkill(struct iwl3945_priv *priv)
591
592
593
594
595
{
	return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
	       test_bit(STATUS_RF_KILL_SW, &priv->status);
}

Christoph Hellwig's avatar
Christoph Hellwig committed
596
static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv)
597
598
{

Christoph Hellwig's avatar
Christoph Hellwig committed
599
	if (iwl3945_is_rfkill(priv))
600
601
		return 0;

Christoph Hellwig's avatar
Christoph Hellwig committed
602
	return iwl3945_is_ready(priv);
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
}

/*************** HOST COMMAND QUEUE FUNCTIONS   *****/

#define IWL_CMD(x) case x : return #x

static const char *get_cmd_string(u8 cmd)
{
	switch (cmd) {
		IWL_CMD(REPLY_ALIVE);
		IWL_CMD(REPLY_ERROR);
		IWL_CMD(REPLY_RXON);
		IWL_CMD(REPLY_RXON_ASSOC);
		IWL_CMD(REPLY_QOS_PARAM);
		IWL_CMD(REPLY_RXON_TIMING);
		IWL_CMD(REPLY_ADD_STA);
		IWL_CMD(REPLY_REMOVE_STA);
		IWL_CMD(REPLY_REMOVE_ALL_STA);
		IWL_CMD(REPLY_3945_RX);
		IWL_CMD(REPLY_TX);
		IWL_CMD(REPLY_RATE_SCALE);
		IWL_CMD(REPLY_LEDS_CMD);
		IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
		IWL_CMD(RADAR_NOTIFICATION);
		IWL_CMD(REPLY_QUIET_CMD);
		IWL_CMD(REPLY_CHANNEL_SWITCH);
		IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
		IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
		IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
		IWL_CMD(POWER_TABLE_CMD);
		IWL_CMD(PM_SLEEP_NOTIFICATION);
		IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
		IWL_CMD(REPLY_SCAN_CMD);
		IWL_CMD(REPLY_SCAN_ABORT_CMD);
		IWL_CMD(SCAN_START_NOTIFICATION);
		IWL_CMD(SCAN_RESULTS_NOTIFICATION);
		IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
		IWL_CMD(BEACON_NOTIFICATION);
		IWL_CMD(REPLY_TX_BEACON);
		IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
		IWL_CMD(QUIET_NOTIFICATION);
		IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
		IWL_CMD(MEASURE_ABORT_NOTIFICATION);
		IWL_CMD(REPLY_BT_CONFIG);
		IWL_CMD(REPLY_STATISTICS_CMD);
		IWL_CMD(STATISTICS_NOTIFICATION);
		IWL_CMD(REPLY_CARD_STATE_CMD);
		IWL_CMD(CARD_STATE_NOTIFICATION);
		IWL_CMD(MISSED_BEACONS_NOTIFICATION);
	default:
		return "UNKNOWN";

	}
}

#define HOST_COMPLETE_TIMEOUT (HZ / 2)

/**
Christoph Hellwig's avatar
Christoph Hellwig committed
661
 * iwl3945_enqueue_hcmd - enqueue a uCode command
662
663
664
665
666
667
668
 * @priv: device private data point
 * @cmd: a point to the ucode command structure
 *
 * The function returns < 0 values to indicate the operation is
 * failed. On success, it turns the index (> 0) of command in the
 * command queue.
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
669
static int iwl3945_enqueue_hcmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
670
{
Christoph Hellwig's avatar
Christoph Hellwig committed
671
672
673
	struct iwl3945_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
	struct iwl3945_queue *q = &txq->q;
	struct iwl3945_tfd_frame *tfd;
674
	u32 *control_flags;
Christoph Hellwig's avatar
Christoph Hellwig committed
675
	struct iwl3945_cmd *out_cmd;
676
677
678
679
680
681
682
683
684
685
686
687
688
689
	u32 idx;
	u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
	dma_addr_t phys_addr;
	int pad;
	u16 count;
	int ret;
	unsigned long flags;

	/* If any of the command structures end up being larger than
	 * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
	 * we will need to increase the size of the TFD entries */
	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
	       !(cmd->meta.flags & CMD_SIZE_HUGE));

Christoph Hellwig's avatar
Christoph Hellwig committed
690
	if (iwl3945_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
691
692
693
694
695
696
		IWL_ERROR("No space for Tx\n");
		return -ENOSPC;
	}

	spin_lock_irqsave(&priv->hcmd_lock, flags);

697
	tfd = &txq->bd[q->write_ptr];
698
699
700
701
	memset(tfd, 0, sizeof(*tfd));

	control_flags = (u32 *) tfd;

702
	idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
703
704
705
706
707
708
709
710
711
712
713
	out_cmd = &txq->cmd[idx];

	out_cmd->hdr.cmd = cmd->id;
	memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
	memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);

	/* At this point, the out_cmd now has all of the incoming cmd
	 * information */

	out_cmd->hdr.flags = 0;
	out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
714
			INDEX_TO_SEQ(q->write_ptr));
715
716
717
718
	if (out_cmd->meta.flags & CMD_SIZE_HUGE)
		out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);

	phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
Christoph Hellwig's avatar
Christoph Hellwig committed
719
720
			offsetof(struct iwl3945_cmd, hdr);
	iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
721
722
723
724
725
726
727
728
729

	pad = U32_PAD(cmd->len);
	count = TFD_CTL_COUNT_GET(*control_flags);
	*control_flags = TFD_CTL_COUNT_SET(count) | TFD_CTL_PAD_SET(pad);

	IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
		     "%d bytes at %d[%d]:%d\n",
		     get_cmd_string(out_cmd->hdr.cmd),
		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
730
		     fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
731
732

	txq->need_update = 1;
733
734

	/* Increment and update queue's write index */
Christoph Hellwig's avatar
Christoph Hellwig committed
735
736
	q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd);
	ret = iwl3945_tx_queue_update_write_ptr(priv, txq);
737
738
739
740
741

	spin_unlock_irqrestore(&priv->hcmd_lock, flags);
	return ret ? ret : idx;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
742
static int iwl3945_send_cmd_async(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
743
744
745
746
747
748
749
750
751
752
753
754
755
756
{
	int ret;

	BUG_ON(!(cmd->meta.flags & CMD_ASYNC));

	/* An asynchronous command can not expect an SKB to be set. */
	BUG_ON(cmd->meta.flags & CMD_WANT_SKB);

	/* An asynchronous command MUST have a callback. */
	BUG_ON(!cmd->meta.u.callback);

	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
		return -EBUSY;

Christoph Hellwig's avatar
Christoph Hellwig committed
757
	ret = iwl3945_enqueue_hcmd(priv, cmd);
758
	if (ret < 0) {
Christoph Hellwig's avatar
Christoph Hellwig committed
759
		IWL_ERROR("Error sending %s: iwl3945_enqueue_hcmd failed: %d\n",
760
761
762
763
764
765
			  get_cmd_string(cmd->id), ret);
		return ret;
	}
	return 0;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
766
static int iwl3945_send_cmd_sync(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
{
	int cmd_idx;
	int ret;
	static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */

	BUG_ON(cmd->meta.flags & CMD_ASYNC);

	 /* A synchronous command can not have a callback set. */
	BUG_ON(cmd->meta.u.callback != NULL);

	if (atomic_xchg(&entry, 1)) {
		IWL_ERROR("Error sending %s: Already sending a host command\n",
			  get_cmd_string(cmd->id));
		return -EBUSY;
	}

	set_bit(STATUS_HCMD_ACTIVE, &priv->status);

	if (cmd->meta.flags & CMD_WANT_SKB)
		cmd->meta.source = &cmd->meta;

Christoph Hellwig's avatar
Christoph Hellwig committed
788
	cmd_idx = iwl3945_enqueue_hcmd(priv, cmd);
789
790
	if (cmd_idx < 0) {
		ret = cmd_idx;
Christoph Hellwig's avatar
Christoph Hellwig committed
791
		IWL_ERROR("Error sending %s: iwl3945_enqueue_hcmd failed: %d\n",
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
			  get_cmd_string(cmd->id), ret);
		goto out;
	}

	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
			!test_bit(STATUS_HCMD_ACTIVE, &priv->status),
			HOST_COMPLETE_TIMEOUT);
	if (!ret) {
		if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
			IWL_ERROR("Error sending %s: time out after %dms.\n",
				  get_cmd_string(cmd->id),
				  jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));

			clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
			ret = -ETIMEDOUT;
			goto cancel;
		}
	}

	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
		IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n",
			       get_cmd_string(cmd->id));
		ret = -ECANCELED;
		goto fail;
	}
	if (test_bit(STATUS_FW_ERROR, &priv->status)) {
		IWL_DEBUG_INFO("Command %s failed: FW Error\n",
			       get_cmd_string(cmd->id));
		ret = -EIO;
		goto fail;
	}
	if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
		IWL_ERROR("Error: Response NULL in '%s'\n",
			  get_cmd_string(cmd->id));
		ret = -EIO;
		goto out;
	}

	ret = 0;
	goto out;

cancel:
	if (cmd->meta.flags & CMD_WANT_SKB) {
Christoph Hellwig's avatar
Christoph Hellwig committed
835
		struct iwl3945_cmd *qcmd;
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853

		/* Cancel the CMD_WANT_SKB flag for the cmd in the
		 * TX cmd queue. Otherwise in case the cmd comes
		 * in later, it will possibly set an invalid
		 * address (cmd->meta.source). */
		qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
		qcmd->meta.flags &= ~CMD_WANT_SKB;
	}
fail:
	if (cmd->meta.u.skb) {
		dev_kfree_skb_any(cmd->meta.u.skb);
		cmd->meta.u.skb = NULL;
	}
out:
	atomic_set(&entry, 0);
	return ret;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
854
int iwl3945_send_cmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
855
856
{
	if (cmd->meta.flags & CMD_ASYNC)
Christoph Hellwig's avatar
Christoph Hellwig committed
857
		return iwl3945_send_cmd_async(priv, cmd);
858

Christoph Hellwig's avatar
Christoph Hellwig committed
859
	return iwl3945_send_cmd_sync(priv, cmd);
860
861
}

Christoph Hellwig's avatar
Christoph Hellwig committed
862
int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len, const void *data)
863
{
Christoph Hellwig's avatar
Christoph Hellwig committed
864
	struct iwl3945_host_cmd cmd = {
865
866
867
868
869
		.id = id,
		.len = len,
		.data = data,
	};

Christoph Hellwig's avatar
Christoph Hellwig committed
870
	return iwl3945_send_cmd_sync(priv, &cmd);
871
872
}

Christoph Hellwig's avatar
Christoph Hellwig committed
873
static int __must_check iwl3945_send_cmd_u32(struct iwl3945_priv *priv, u8 id, u32 val)
874
{
Christoph Hellwig's avatar
Christoph Hellwig committed
875
	struct iwl3945_host_cmd cmd = {
876
877
878
879
880
		.id = id,
		.len = sizeof(val),
		.data = &val,
	};

Christoph Hellwig's avatar
Christoph Hellwig committed
881
	return iwl3945_send_cmd_sync(priv, &cmd);
882
883
}

Christoph Hellwig's avatar
Christoph Hellwig committed
884
int iwl3945_send_statistics_request(struct iwl3945_priv *priv)
885
{
Christoph Hellwig's avatar
Christoph Hellwig committed
886
	return iwl3945_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
887
888
889
}

/**
Christoph Hellwig's avatar
Christoph Hellwig committed
890
 * iwl3945_set_rxon_channel - Set the phymode and channel values in staging RXON
891
892
893
894
895
896
897
898
 * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
 * @channel: Any channel valid for the requested phymode

 * In addition to setting the staging RXON, priv->phymode is also set.
 *
 * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
 * in the staging RXON flag structure based on the phymode
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
899
static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv, u8 phymode, u16 channel)
900
{
Christoph Hellwig's avatar
Christoph Hellwig committed
901
	if (!iwl3945_get_channel_info(priv, phymode, channel)) {
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
		IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
			       channel, phymode);
		return -EINVAL;
	}

	if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
	    (priv->phymode == phymode))
		return 0;

	priv->staging_rxon.channel = cpu_to_le16(channel);
	if (phymode == MODE_IEEE80211A)
		priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
	else
		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;

	priv->phymode = phymode;

	IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);

	return 0;
}

/**
Christoph Hellwig's avatar
Christoph Hellwig committed
925
 * iwl3945_check_rxon_cmd - validate RXON structure is valid
926
927
928
929
930
 *
 * NOTE:  This is really only useful during development and can eventually
 * be #ifdef'd out once the driver is stable and folks aren't actively
 * making changes
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
931
static int iwl3945_check_rxon_cmd(struct iwl3945_rxon_cmd *rxon)
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
{
	int error = 0;
	int counter = 1;

	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
		error |= le32_to_cpu(rxon->flags &
				(RXON_FLG_TGJ_NARROW_BAND_MSK |
				 RXON_FLG_RADAR_DETECT_MSK));
		if (error)
			IWL_WARNING("check 24G fields %d | %d\n",
				    counter++, error);
	} else {
		error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
				0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
		if (error)
			IWL_WARNING("check 52 fields %d | %d\n",
				    counter++, error);
		error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
		if (error)
			IWL_WARNING("check 52 CCK %d | %d\n",
				    counter++, error);
	}
	error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
	if (error)
		IWL_WARNING("check mac addr %d | %d\n", counter++, error);

	/* make sure basic rates 6Mbps and 1Mbps are supported */
	error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
		  ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
	if (error)
		IWL_WARNING("check basic rate %d | %d\n", counter++, error);

	error |= (le16_to_cpu(rxon->assoc_id) > 2007);
	if (error)
		IWL_WARNING("check assoc id %d | %d\n", counter++, error);

	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
			== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
	if (error)
		IWL_WARNING("check CCK and short slot %d | %d\n",
			    counter++, error);

	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
			== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
	if (error)
		IWL_WARNING("check CCK & auto detect %d | %d\n",
			    counter++, error);

	error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
			RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
	if (error)
		IWL_WARNING("check TGG and auto detect %d | %d\n",
			    counter++, error);

	if ((rxon->flags & RXON_FLG_DIS_DIV_MSK))
		error |= ((rxon->flags & (RXON_FLG_ANT_B_MSK |
				RXON_FLG_ANT_A_MSK)) == 0);
	if (error)
		IWL_WARNING("check antenna %d %d\n", counter++, error);

	if (error)
		IWL_WARNING("Tuning to channel %d\n",
			    le16_to_cpu(rxon->channel));

	if (error) {
Christoph Hellwig's avatar
Christoph Hellwig committed
997
		IWL_ERROR("Not a valid iwl3945_rxon_assoc_cmd field values\n");
998
999
1000
1001
1002
1003
		return -1;
	}
	return 0;
}

/**
1004
 * iwl3945_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
1005
 * @priv: staging_rxon is compared to active_rxon
1006
 *
1007
1008
1009
 * If the RXON structure is changing enough to require a new tune,
 * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
 * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
1010
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
1011
static int iwl3945_full_rxon_required(struct iwl3945_priv *priv)
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
{

	/* These items are only settable from the full RXON command */
	if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ||
	    compare_ether_addr(priv->staging_rxon.bssid_addr,
			       priv->active_rxon.bssid_addr) ||
	    compare_ether_addr(priv->staging_rxon.node_addr,
			       priv->active_rxon.node_addr) ||
	    compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
			       priv->active_rxon.wlap_bssid_addr) ||
	    (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
	    (priv->staging_rxon.channel != priv->active_rxon.channel) ||
	    (priv->staging_rxon.air_propagation !=
	     priv->active_rxon.air_propagation) ||
	    (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
		return 1;

	/* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
	 * be updated with the RXON_ASSOC command -- however only some
	 * flag transitions are allowed using RXON_ASSOC */

	/* Check if we are not switching bands */
	if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) !=
	    (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK))
		return 1;

	/* Check if we are switching association toggle */
	if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) !=
		(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK))
		return 1;

	return 0;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1046
static int iwl3945_send_rxon_assoc(struct iwl3945_priv *priv)
1047
1048
{
	int rc = 0;
Christoph Hellwig's avatar
Christoph Hellwig committed
1049
1050
1051
	struct iwl3945_rx_packet *res = NULL;
	struct iwl3945_rxon_assoc_cmd rxon_assoc;
	struct iwl3945_host_cmd cmd = {
1052
1053
1054
1055
1056
		.id = REPLY_RXON_ASSOC,
		.len = sizeof(rxon_assoc),
		.meta.flags = CMD_WANT_SKB,
		.data = &rxon_assoc,
	};
Christoph Hellwig's avatar
Christoph Hellwig committed
1057
1058
	const struct iwl3945_rxon_cmd *rxon1 = &priv->staging_rxon;
	const struct iwl3945_rxon_cmd *rxon2 = &priv->active_rxon;
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073

	if ((rxon1->flags == rxon2->flags) &&
	    (rxon1->filter_flags == rxon2->filter_flags) &&
	    (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
	    (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
		IWL_DEBUG_INFO("Using current RXON_ASSOC.  Not resending.\n");
		return 0;
	}

	rxon_assoc.flags = priv->staging_rxon.flags;
	rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
	rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
	rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
	rxon_assoc.reserved = 0;

Christoph Hellwig's avatar
Christoph Hellwig committed
1074
	rc = iwl3945_send_cmd_sync(priv, &cmd);
1075
1076
1077
	if (rc)
		return rc;

Christoph Hellwig's avatar
Christoph Hellwig committed
1078
	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
		IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n");
		rc = -EIO;
	}

	priv->alloc_rxb_skb--;
	dev_kfree_skb_any(cmd.meta.u.skb);

	return rc;
}

/**
Christoph Hellwig's avatar
Christoph Hellwig committed
1091
 * iwl3945_commit_rxon - commit staging_rxon to hardware
1092
 *
1093
 * The RXON command in staging_rxon is committed to the hardware and
1094
1095
1096
1097
 * the active_rxon structure is updated with the new data.  This
 * function correctly transitions out of the RXON_ASSOC_MSK state if
 * a HW tune is required based on the RXON structure changes.
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
1098
static int iwl3945_commit_rxon(struct iwl3945_priv *priv)
1099
1100
{
	/* cast away the const for active_rxon in this function */
Christoph Hellwig's avatar
Christoph Hellwig committed
1101
	struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
1102
	int rc = 0;
1103
	DECLARE_MAC_BUF(mac);
1104

Christoph Hellwig's avatar
Christoph Hellwig committed
1105
	if (!iwl3945_is_alive(priv))
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
		return -1;

	/* always get timestamp with Rx frame */
	priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;

	/* select antenna */
	priv->staging_rxon.flags &=
	    ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
	priv->staging_rxon.flags |= iwl3945_get_antenna_flags(priv);

Christoph Hellwig's avatar
Christoph Hellwig committed
1116
	rc = iwl3945_check_rxon_cmd(&priv->staging_rxon);
1117
1118
1119
1120
1121
1122
	if (rc) {
		IWL_ERROR("Invalid RXON configuration.  Not committing.\n");
		return -EINVAL;
	}

	/* If we don't need to send a full RXON, we can use
Christoph Hellwig's avatar
Christoph Hellwig committed
1123
	 * iwl3945_rxon_assoc_cmd which is used to reconfigure filter
1124
	 * and other flags for the current radio configuration. */
Christoph Hellwig's avatar
Christoph Hellwig committed
1125
1126
	if (!iwl3945_full_rxon_required(priv)) {
		rc = iwl3945_send_rxon_assoc(priv);
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
		if (rc) {
			IWL_ERROR("Error setting RXON_ASSOC "
				  "configuration (%d).\n", rc);
			return rc;
		}

		memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));

		return 0;
	}

	/* If we are currently associated and the new config requires
	 * an RXON_ASSOC and the new config wants the associated mask enabled,
	 * we must clear the associated from the active configuration
	 * before we apply the new config */
Christoph Hellwig's avatar
Christoph Hellwig committed
1142
	if (iwl3945_is_associated(priv) &&
1143
1144
1145
1146
	    (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
		IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;

Christoph Hellwig's avatar
Christoph Hellwig committed
1147
1148
		rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON,
				      sizeof(struct iwl3945_rxon_cmd),
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
				      &priv->active_rxon);

		/* If the mask clearing failed then we set
		 * active_rxon back to what it was previously */
		if (rc) {
			active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
			IWL_ERROR("Error clearing ASSOC_MSK on current "
				  "configuration (%d).\n", rc);
			return rc;
		}
	}

	IWL_DEBUG_INFO("Sending RXON\n"
		       "* with%s RXON_FILTER_ASSOC_MSK\n"
		       "* channel = %d\n"
1164
		       "* bssid = %s\n",
1165
1166
1167
		       ((priv->staging_rxon.filter_flags &
			 RXON_FILTER_ASSOC_MSK) ? "" : "out"),
		       le16_to_cpu(priv->staging_rxon.channel),
1168
		       print_mac(mac, priv->staging_rxon.bssid_addr));
1169
1170

	/* Apply the new configuration */
Christoph Hellwig's avatar
Christoph Hellwig committed
1171
1172
	rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON,
			      sizeof(struct iwl3945_rxon_cmd), &priv->staging_rxon);
1173
1174
1175
1176
1177
1178
1179
	if (rc) {
		IWL_ERROR("Error setting new configuration (%d).\n", rc);
		return rc;
	}

	memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));

Christoph Hellwig's avatar
Christoph Hellwig committed
1180
	iwl3945_clear_stations_table(priv);
1181

1182
1183
	/* If we issue a new RXON command which required a tune then we must
	 * send a new TXPOWER command or we won't be able to Tx any frames */
Christoph Hellwig's avatar
Christoph Hellwig committed
1184
	rc = iwl3945_hw_reg_send_txpower(priv);
1185
1186
1187
1188
1189
1190
	if (rc) {
		IWL_ERROR("Error setting Tx power (%d).\n", rc);
		return rc;
	}

	/* Add the broadcast address so we can send broadcast frames */
Christoph Hellwig's avatar
Christoph Hellwig committed
1191
	if (iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0) ==
1192
1193
1194
1195
1196
1197
1198
	    IWL_INVALID_STATION) {
		IWL_ERROR("Error adding BROADCAST address for transmit.\n");
		return -EIO;
	}

	/* If we have set the ASSOC_MSK and we are in BSS mode then
	 * add the IWL_AP_ID to the station rate table */
Christoph Hellwig's avatar
Christoph Hellwig committed
1199
	if (iwl3945_is_associated(priv) &&
1200
	    (priv->iw_mode == IEEE80211_IF_TYPE_STA))
Christoph Hellwig's avatar
Christoph Hellwig committed
1201
		if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0)
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
		    == IWL_INVALID_STATION) {
			IWL_ERROR("Error adding AP address for transmit.\n");
			return -EIO;
		}

	/* Init the hardware's rate fallback order based on the
	 * phymode */
	rc = iwl3945_init_hw_rate_table(priv);
	if (rc) {
		IWL_ERROR("Error setting HW rate table: %02X\n", rc);
		return -EIO;
	}

	return 0;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1218
static int iwl3945_send_bt_config(struct iwl3945_priv *priv)
1219
{
Christoph Hellwig's avatar
Christoph Hellwig committed
1220
	struct iwl3945_bt_cmd bt_cmd = {
1221
1222
1223
1224
1225
1226
1227
		.flags = 3,
		.lead_time = 0xAA,
		.max_kill = 1,
		.kill_ack_mask = 0,
		.kill_cts_mask = 0,
	};

Christoph Hellwig's avatar
Christoph Hellwig committed
1228
1229
	return iwl3945_send_cmd_pdu(priv, REPLY_BT_CONFIG,
				sizeof(struct iwl3945_bt_cmd), &bt_cmd);
1230
1231
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1232
static int iwl3945_send_scan_abort(struct iwl3945_priv *priv)
1233
1234
{
	int rc = 0;
Christoph Hellwig's avatar
Christoph Hellwig committed
1235
1236
	struct iwl3945_rx_packet *res;
	struct iwl3945_host_cmd cmd = {
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
		.id = REPLY_SCAN_ABORT_CMD,
		.meta.flags = CMD_WANT_SKB,
	};

	/* If there isn't a scan actively going on in the hardware
	 * then we are in between scan bands and not actually
	 * actively scanning, so don't send the abort command */
	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
		return 0;
	}

Christoph Hellwig's avatar
Christoph Hellwig committed
1249
	rc = iwl3945_send_cmd_sync(priv, &cmd);
1250
1251
1252
1253
1254
	if (rc) {
		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
		return rc;
	}

Christoph Hellwig's avatar
Christoph Hellwig committed
1255
	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
	if (res->u.status != CAN_ABORT_STATUS) {
		/* The scan abort will return 1 for success or
		 * 2 for "failure".  A failure condition can be
		 * due to simply not being in an active scan which
		 * can occur if we send the scan abort before we
		 * the microcode has notified us that a scan is
		 * completed. */
		IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status);
		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
		clear_bit(STATUS_SCAN_HW, &priv->status);
	}

	dev_kfree_skb_any(cmd.meta.u.skb);

	return rc;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1273
1274
static int iwl3945_card_state_sync_callback(struct iwl3945_priv *priv,
					struct iwl3945_cmd *cmd,
1275
1276
1277
1278
1279
1280
1281
1282
					struct sk_buff *skb)
{
	return 1;
}

/*
 * CARD_STATE_CMD
 *
1283
 * Use: Sets the device's internal card state to enable, disable, or halt
1284
1285
1286
1287
1288
1289
 *
 * When in the 'enable' state the card operates as normal.
 * When in the 'disable' state, the card enters into a low power mode.
 * When in the 'halt' state, the card is shut down and must be fully
 * restarted to come back on.
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
1290
static int iwl3945_send_card_state(struct iwl3945_priv *priv, u32 flags, u8 meta_flag)
1291
{
Christoph Hellwig's avatar
Christoph Hellwig committed
1292
	struct iwl3945_host_cmd cmd = {
1293
1294
1295
1296
1297
1298
1299
		.id = REPLY_CARD_STATE_CMD,
		.len = sizeof(u32),
		.data = &flags,
		.meta.flags = meta_flag,
	};

	if (meta_flag & CMD_ASYNC)
Christoph Hellwig's avatar
Christoph Hellwig committed
1300
		cmd.meta.u.callback = iwl3945_card_state_sync_callback;
1301

Christoph Hellwig's avatar
Christoph Hellwig committed
1302
	return iwl3945_send_cmd(priv, &cmd);
1303
1304
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1305
1306
static int iwl3945_add_sta_sync_callback(struct iwl3945_priv *priv,
				     struct iwl3945_cmd *cmd, struct sk_buff *skb)
1307
{
Christoph Hellwig's avatar
Christoph Hellwig committed
1308
	struct iwl3945_rx_packet *res = NULL;
1309
1310
1311
1312
1313
1314

	if (!skb) {
		IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
		return 1;
	}

Christoph Hellwig's avatar
Christoph Hellwig committed
1315
	res = (struct iwl3945_rx_packet *)skb->data;
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
			  res->hdr.flags);
		return 1;
	}

	switch (res->u.add_sta.status) {
	case ADD_STA_SUCCESS_MSK:
		break;
	default:
		break;
	}

	/* We didn't cache the SKB; let the caller free it */
	return 1;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1333
1334
int iwl3945_send_add_station(struct iwl3945_priv *priv,
			 struct iwl3945_addsta_cmd *sta, u8 flags)
1335
{
Christoph Hellwig's avatar
Christoph Hellwig committed
1336
	struct iwl3945_rx_packet *res = NULL;
1337
	int rc = 0;
Christoph Hellwig's avatar
Christoph Hellwig committed
1338
	struct iwl3945_host_cmd cmd = {
1339
		.id = REPLY_ADD_STA,
Christoph Hellwig's avatar
Christoph Hellwig committed
1340
		.len = sizeof(struct iwl3945_addsta_cmd),
1341
1342
1343
1344
1345
		.meta.flags = flags,
		.data = sta,
	};

	if (flags & CMD_ASYNC)
Christoph Hellwig's avatar
Christoph Hellwig committed
1346
		cmd.meta.u.callback = iwl3945_add_sta_sync_callback;
1347
1348
1349
	else
		cmd.meta.flags |= CMD_WANT_SKB;

Christoph Hellwig's avatar
Christoph Hellwig committed
1350
	rc = iwl3945_send_cmd(priv, &cmd);
1351
1352
1353
1354

	if (rc || (flags & CMD_ASYNC))
		return rc;

Christoph Hellwig's avatar
Christoph Hellwig committed
1355
	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
			  res->hdr.flags);
		rc = -EIO;
	}

	if (rc == 0) {
		switch (res->u.add_sta.status) {
		case ADD_STA_SUCCESS_MSK:
			IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
			break;
		default:
			rc = -EIO;
			IWL_WARNING("REPLY_ADD_STA failed\n");
			break;
		}
	}

	priv->alloc_rxb_skb--;
	dev_kfree_skb_any(cmd.meta.u.skb);

	return rc;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1380
static int iwl3945_update_sta_key_info(struct iwl3945_priv *priv,
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
				   struct ieee80211_key_conf *keyconf,
				   u8 sta_id)
{
	unsigned long flags;
	__le16 key_flags = 0;

	switch (keyconf->alg) {
	case ALG_CCMP:
		key_flags |= STA_KEY_FLG_CCMP;
		key_flags |= cpu_to_le16(
				keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
		key_flags &= ~STA_KEY_FLG_INVALID;
		break;
	case ALG_TKIP:
	case ALG_WEP:
	default:
		return -EINVAL;
	}
	spin_lock_irqsave(&priv->sta_lock, flags);
	priv->stations[sta_id].keyinfo.alg = keyconf->alg;
	priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
	memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
	       keyconf->keylen);

	memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
	       keyconf->keylen);
	priv->stations[sta_id].sta.key.key_flags = key_flags;
	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;

	spin_unlock_irqrestore(&priv->sta_lock, flags);

	IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
Christoph Hellwig's avatar
Christoph Hellwig committed
1414
	iwl3945_send_add_station(priv, &priv->stations[sta_id].sta, 0);
1415
1416
1417
	return 0;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1418
static int iwl3945_clear_sta_key_info(struct iwl3945_priv *priv, u8 sta_id)
1419
1420
1421
1422
{
	unsigned long flags;

	spin_lock_irqsave(&priv->sta_lock, flags);
Christoph Hellwig's avatar
Christoph Hellwig committed
1423
1424
	memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl3945_hw_key));
	memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl3945_keyinfo));
1425
1426
1427
1428
1429
1430
	priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
	spin_unlock_irqrestore(&priv->sta_lock, flags);

	IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
Christoph Hellwig's avatar
Christoph Hellwig committed
1431
	iwl3945_send_add_station(priv, &priv->stations[sta_id].sta, 0);
1432
1433
1434
	return 0;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1435
static void iwl3945_clear_free_frames(struct iwl3945_priv *priv)
1436
1437
1438
1439
1440
1441
1442
1443
1444
{
	struct list_head *element;

	IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n",
		       priv->frames_count);

	while (!list_empty(&priv->free_frames)) {
		element = priv->free_frames.next;
		list_del(element);