iwl3945-base.c 234 KB
Newer Older
1
2
/******************************************************************************
 *
3
 * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
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
 *
 * 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>

Tomas Winkler's avatar
Tomas Winkler committed
49
#include "iwl-3945-core.h"
50
51
52
#include "iwl-3945.h"
#include "iwl-helpers.h"

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

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

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

/* module parameters */
67
68
69
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 */
70
static int iwl3945_param_antenna;  /* def: 0 = both antennas (use diversity) */
71
72
int iwl3945_param_hwcrypto;        /* def: 0 = use software encryption */
static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */
73
int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */
74
75
76
77
78
79
80
81
82

/*
 * 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"

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

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

95
#define IWLWIFI_VERSION "1.2.26k" VD VS
96
#define DRV_COPYRIGHT	"Copyright(c) 2003-2008 Intel Corporation"
97
98
99
100
101
102
103
104
#define DRV_VERSION     IWLWIFI_VERSION


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

105
106
static const struct ieee80211_supported_band *iwl3945_get_band(
		struct iwl3945_priv *priv, enum ieee80211_band band)
107
{
108
	return priv->hw->wiphy->bands[band];
109
110
}

Christoph Hellwig's avatar
Christoph Hellwig committed
111
static int iwl3945_is_empty_essid(const char *essid, int essid_len)
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
{
	/* 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
127
static const char *iwl3945_escape_essid(const char *essid, u8 essid_len)
128
129
130
131
132
{
	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
	const char *s = essid;
	char *d = escaped;

Christoph Hellwig's avatar
Christoph Hellwig committed
133
	if (iwl3945_is_empty_essid(essid, essid_len)) {
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
		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;
}

/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
 * DMA services
 *
 * Theory of operation
 *
156
157
158
159
160
161
162
163
164
 * 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.
165
166
167
168
169
170
 *
 * 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.
 *
171
172
173
 * 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.
174
175
 ***************************************************/

176
int iwl3945_queue_space(const struct iwl3945_queue *q)
177
{
178
	int s = q->read_ptr - q->write_ptr;
179

180
	if (q->read_ptr > q->write_ptr)
181
182
183
184
185
186
187
188
189
190
191
		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;
}

192
int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i)
193
{
194
195
196
	return q->write_ptr > q->read_ptr ?
		(i >= q->read_ptr && i < q->write_ptr) :
		!(i < q->read_ptr && i >= q->write_ptr);
197
198
}

199

Christoph Hellwig's avatar
Christoph Hellwig committed
200
static inline u8 get_cmd_index(struct iwl3945_queue *q, u32 index, int is_huge)
201
{
202
	/* This is for scan command, the big buffer at end of command array */
203
	if (is_huge)
204
		return q->n_window;	/* must be power of 2 */
205

206
	/* Otherwise, use normal size buffers */
207
208
209
	return index & (q->n_window - 1);
}

210
211
212
/**
 * iwl3945_queue_init - Initialize queue's high/low-water and read/write indexes
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
213
static int iwl3945_queue_init(struct iwl3945_priv *priv, struct iwl3945_queue *q,
214
215
216
217
218
219
			  int count, int slots_num, u32 id)
{
	q->n_bd = count;
	q->n_window = slots_num;
	q->id = id;

220
221
	/* count must be power-of-two size, otherwise iwl_queue_inc_wrap
	 * and iwl_queue_dec_wrap are broken. */
222
223
224
225
226
227
228
229
230
231
232
233
234
235
	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;

236
	q->write_ptr = q->read_ptr = 0;
237
238
239
240

	return 0;
}

241
242
243
/**
 * iwl3945_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
244
245
static int iwl3945_tx_queue_alloc(struct iwl3945_priv *priv,
			      struct iwl3945_tx_queue *txq, u32 id)
246
247
248
{
	struct pci_dev *dev = priv->pci_dev;

249
250
	/* Driver private data, only for Tx (not command) queues,
	 * not shared with device. */
251
252
253
254
	if (id != IWL_CMD_QUEUE_NUM) {
		txq->txb = kmalloc(sizeof(txq->txb[0]) *
				   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
		if (!txq->txb) {
255
			IWL_ERROR("kmalloc for auxiliary BD "
256
257
258
259
260
261
				  "structures failed\n");
			goto error;
		}
	} else
		txq->txb = NULL;

262
263
	/* Circular buffer of transmit frame descriptors (TFDs),
	 * shared with device */
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
	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;
}

286
287
288
/**
 * iwl3945_tx_queue_init - Allocate and initialize one tx/cmd queue
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
289
290
int iwl3945_tx_queue_init(struct iwl3945_priv *priv,
		      struct iwl3945_tx_queue *txq, int slots_num, u32 txq_id)
291
292
293
294
295
{
	struct pci_dev *dev = priv->pci_dev;
	int len;
	int rc = 0;

296
297
298
299
300
301
302
303
	/*
	 * 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
304
	len = sizeof(struct iwl3945_cmd) * slots_num;
305
306
307
308
309
310
	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;

311
	/* Alloc driver data array and TFD circular buffer */
Christoph Hellwig's avatar
Christoph Hellwig committed
312
	rc = iwl3945_tx_queue_alloc(priv, txq, txq_id);
313
314
315
316
317
318
319
320
	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
321
	 * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
322
	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
323
324

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

327
	/* Tell device where to find queue, enable DMA channel. */
Christoph Hellwig's avatar
Christoph Hellwig committed
328
	iwl3945_hw_tx_queue_init(priv, txq);
329
330
331
332
333

	return 0;
}

/**
Christoph Hellwig's avatar
Christoph Hellwig committed
334
 * iwl3945_tx_queue_free - Deallocate DMA queue.
335
336
337
 * @txq: Transmit queue to deallocate.
 *
 * Empty queue by removing and destroying all BD's.
338
339
 * Free all buffers.
 * 0-fill, but do not free "txq" descriptor structure.
340
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
341
void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq)
342
{
Christoph Hellwig's avatar
Christoph Hellwig committed
343
	struct iwl3945_queue *q = &txq->q;
344
345
346
347
348
349
350
	struct pci_dev *dev = priv->pci_dev;
	int len;

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

	/* first, empty all BD's */
351
	for (; q->write_ptr != q->read_ptr;
352
	     q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
Christoph Hellwig's avatar
Christoph Hellwig committed
353
		iwl3945_hw_txq_free_tfd(priv, txq);
354

Christoph Hellwig's avatar
Christoph Hellwig committed
355
	len = sizeof(struct iwl3945_cmd) * q->n_window;
356
357
358
	if (q->id == IWL_CMD_QUEUE_NUM)
		len += IWL_MAX_SCAN_SIZE;

359
	/* De-alloc array of command/tx buffers */
360
361
	pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);

362
	/* De-alloc circular buffer of TFDs */
363
	if (txq->q.n_bd)
Christoph Hellwig's avatar
Christoph Hellwig committed
364
		pci_free_consistent(dev, sizeof(struct iwl3945_tfd_frame) *
365
366
				    txq->q.n_bd, txq->bd, txq->q.dma_addr);

367
	/* De-alloc array of per-TFD driver data */
368
369
370
371
372
	if (txq->txb) {
		kfree(txq->txb);
		txq->txb = NULL;
	}

373
	/* 0-fill queue descriptor structure */
374
375
376
	memset(txq, 0, sizeof(*txq));
}

Christoph Hellwig's avatar
Christoph Hellwig committed
377
const u8 iwl3945_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
378
379

/*************** STATION TABLE MANAGEMENT ****
380
 * mac80211 should be examined to determine if sta_info is duplicating
381
382
383
384
 * the functionality provided here
 */

/**************************************************************/
385
#if 0 /* temporary disable till we add real remove station */
386
387
388
389
390
/**
 * 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
391
static u8 iwl3945_remove_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap)
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
{
	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;
}
426
#endif
427
428
429
430
431
432

/**
 * 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
433
static void iwl3945_clear_stations_table(struct iwl3945_priv *priv)
434
435
436
437
438
439
440
441
442
443
444
{
	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);
}

445
446
447
/**
 * iwl3945_add_station - Add station to station tables in driver and device
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
448
u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 flags)
449
450
451
{
	int i;
	int index = IWL_INVALID_STATION;
Christoph Hellwig's avatar
Christoph Hellwig committed
452
	struct iwl3945_station_entry *station;
453
	unsigned long flags_spin;
454
	DECLARE_MAC_BUF(mac);
455
	u8 rate;
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474

	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;
		}

475
	/* These two conditions has the same outcome but keep them separate
476
477
478
479
480
481
482
483
484
485
486
487
	  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;
	}

488
	IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
489
490
491
492
	station = &priv->stations[index];
	station->used = 1;
	priv->num_stations++;

493
	/* Set up the REPLY_ADD_STA command to send to device */
Christoph Hellwig's avatar
Christoph Hellwig committed
494
	memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd));
495
496
497
498
499
	memcpy(station->sta.sta.addr, addr, ETH_ALEN);
	station->sta.mode = 0;
	station->sta.sta.sta_id = index;
	station->sta.station_flags = 0;

500
	if (priv->band == IEEE80211_BAND_5GHZ)
501
502
503
		rate = IWL_RATE_6M_PLCP;
	else
		rate =	IWL_RATE_1M_PLCP;
504
505
506

	/* Turn on both antennas for the station... */
	station->sta.rate_n_flags =
Christoph Hellwig's avatar
Christoph Hellwig committed
507
			iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK);
508
509
510
	station->current_rate.rate_n_flags =
			le16_to_cpu(station->sta.rate_n_flags);

511
	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
512
513

	/* Add station to device's station table */
Christoph Hellwig's avatar
Christoph Hellwig committed
514
	iwl3945_send_add_station(priv, &station->sta, flags);
515
516
517
518
519
520
	return index;

}

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

Christoph Hellwig's avatar
Christoph Hellwig committed
521
static inline int iwl3945_is_ready(struct iwl3945_priv *priv)
522
523
524
525
526
527
528
529
{
	/* 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
530
static inline int iwl3945_is_alive(struct iwl3945_priv *priv)
531
532
533
534
{
	return test_bit(STATUS_ALIVE, &priv->status);
}

Christoph Hellwig's avatar
Christoph Hellwig committed
535
static inline int iwl3945_is_init(struct iwl3945_priv *priv)
536
537
538
539
{
	return test_bit(STATUS_INIT, &priv->status);
}

Christoph Hellwig's avatar
Christoph Hellwig committed
540
static inline int iwl3945_is_rfkill(struct iwl3945_priv *priv)
541
542
543
544
545
{
	return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
	       test_bit(STATUS_RF_KILL_SW, &priv->status);
}

Christoph Hellwig's avatar
Christoph Hellwig committed
546
static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv)
547
548
{

Christoph Hellwig's avatar
Christoph Hellwig committed
549
	if (iwl3945_is_rfkill(priv))
550
551
		return 0;

Christoph Hellwig's avatar
Christoph Hellwig committed
552
	return iwl3945_is_ready(priv);
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
}

/*************** 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
611
 * iwl3945_enqueue_hcmd - enqueue a uCode command
612
613
614
615
616
617
618
 * @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
619
static int iwl3945_enqueue_hcmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
620
{
Christoph Hellwig's avatar
Christoph Hellwig committed
621
622
623
	struct iwl3945_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
	struct iwl3945_queue *q = &txq->q;
	struct iwl3945_tfd_frame *tfd;
624
	u32 *control_flags;
Christoph Hellwig's avatar
Christoph Hellwig committed
625
	struct iwl3945_cmd *out_cmd;
626
627
628
629
630
631
632
633
634
635
636
637
638
639
	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));

640
641
642
643
644
645

	if (iwl3945_is_rfkill(priv)) {
		IWL_DEBUG_INFO("Not sending command - RF KILL");
		return -EIO;
	}

Christoph Hellwig's avatar
Christoph Hellwig committed
646
	if (iwl3945_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
647
648
649
650
651
652
		IWL_ERROR("No space for Tx\n");
		return -ENOSPC;
	}

	spin_lock_irqsave(&priv->hcmd_lock, flags);

653
	tfd = &txq->bd[q->write_ptr];
654
655
656
657
	memset(tfd, 0, sizeof(*tfd));

	control_flags = (u32 *) tfd;

658
	idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
659
660
661
662
663
664
665
666
667
668
669
	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) |
670
			INDEX_TO_SEQ(q->write_ptr));
671
672
673
674
	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
675
676
			offsetof(struct iwl3945_cmd, hdr);
	iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
677
678
679
680
681
682
683
684
685

	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),
686
		     fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
687
688

	txq->need_update = 1;
689
690

	/* Increment and update queue's write index */
691
	q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
Christoph Hellwig's avatar
Christoph Hellwig committed
692
	ret = iwl3945_tx_queue_update_write_ptr(priv, txq);
693
694
695
696
697

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

Christoph Hellwig's avatar
Christoph Hellwig committed
698
static int iwl3945_send_cmd_async(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
699
700
701
702
703
704
705
706
707
708
709
710
711
712
{
	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
713
	ret = iwl3945_enqueue_hcmd(priv, cmd);
714
	if (ret < 0) {
Christoph Hellwig's avatar
Christoph Hellwig committed
715
		IWL_ERROR("Error sending %s: iwl3945_enqueue_hcmd failed: %d\n",
716
717
718
719
720
721
			  get_cmd_string(cmd->id), ret);
		return ret;
	}
	return 0;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
722
static int iwl3945_send_cmd_sync(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
723
724
725
726
727
728
729
730
731
{
	int cmd_idx;
	int ret;

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

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

732
	if (test_and_set_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)) {
733
734
		IWL_ERROR("Error sending %s: Already sending a host command\n",
			  get_cmd_string(cmd->id));
735
736
		ret = -EBUSY;
		goto out;
737
738
739
740
741
742
743
	}

	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
744
	cmd_idx = iwl3945_enqueue_hcmd(priv, cmd);
745
746
	if (cmd_idx < 0) {
		ret = cmd_idx;
Christoph Hellwig's avatar
Christoph Hellwig committed
747
		IWL_ERROR("Error sending %s: iwl3945_enqueue_hcmd failed: %d\n",
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
			  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
791
		struct iwl3945_cmd *qcmd;
792
793
794
795
796
797
798
799
800
801
802
803
804
805

		/* 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:
806
	clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
807
808
809
	return ret;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
810
int iwl3945_send_cmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
811
812
{
	if (cmd->meta.flags & CMD_ASYNC)
Christoph Hellwig's avatar
Christoph Hellwig committed
813
		return iwl3945_send_cmd_async(priv, cmd);
814

Christoph Hellwig's avatar
Christoph Hellwig committed
815
	return iwl3945_send_cmd_sync(priv, cmd);
816
817
}

Christoph Hellwig's avatar
Christoph Hellwig committed
818
int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len, const void *data)
819
{
Christoph Hellwig's avatar
Christoph Hellwig committed
820
	struct iwl3945_host_cmd cmd = {
821
822
823
824
825
		.id = id,
		.len = len,
		.data = data,
	};

Christoph Hellwig's avatar
Christoph Hellwig committed
826
	return iwl3945_send_cmd_sync(priv, &cmd);
827
828
}

Christoph Hellwig's avatar
Christoph Hellwig committed
829
static int __must_check iwl3945_send_cmd_u32(struct iwl3945_priv *priv, u8 id, u32 val)
830
{
Christoph Hellwig's avatar
Christoph Hellwig committed
831
	struct iwl3945_host_cmd cmd = {
832
833
834
835
836
		.id = id,
		.len = sizeof(val),
		.data = &val,
	};

Christoph Hellwig's avatar
Christoph Hellwig committed
837
	return iwl3945_send_cmd_sync(priv, &cmd);
838
839
}

Christoph Hellwig's avatar
Christoph Hellwig committed
840
int iwl3945_send_statistics_request(struct iwl3945_priv *priv)
841
{
Christoph Hellwig's avatar
Christoph Hellwig committed
842
	return iwl3945_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
843
844
845
}

/**
Christoph Hellwig's avatar
Christoph Hellwig committed
846
 * iwl3945_set_rxon_channel - Set the phymode and channel values in staging RXON
847
848
 * @band: 2.4 or 5 GHz band
 * @channel: Any channel valid for the requested band
849

850
 * In addition to setting the staging RXON, priv->band is also set.
851
852
 *
 * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
853
 * in the staging RXON flag structure based on the band
854
 */
855
856
857
static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv,
				    enum ieee80211_band band,
				    u16 channel)
858
{
859
	if (!iwl3945_get_channel_info(priv, band, channel)) {
860
		IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
861
			       channel, band);
862
863
864
865
		return -EINVAL;
	}

	if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
866
	    (priv->band == band))
867
868
869
		return 0;

	priv->staging_rxon.channel = cpu_to_le16(channel);
870
	if (band == IEEE80211_BAND_5GHZ)
871
872
873
874
		priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
	else
		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;

875
	priv->band = band;
876

877
	IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, band);
878
879
880
881
882

	return 0;
}

/**
Christoph Hellwig's avatar
Christoph Hellwig committed
883
 * iwl3945_check_rxon_cmd - validate RXON structure is valid
884
885
886
887
888
 *
 * 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
889
static int iwl3945_check_rxon_cmd(struct iwl3945_rxon_cmd *rxon)
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
{
	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
955
		IWL_ERROR("Not a valid iwl3945_rxon_assoc_cmd field values\n");
956
957
958
959
960
961
		return -1;
	}
	return 0;
}

/**
962
 * iwl3945_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
963
 * @priv: staging_rxon is compared to active_rxon
964
 *
965
966
967
 * 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.
968
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
969
static int iwl3945_full_rxon_required(struct iwl3945_priv *priv)
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
997
998
999
1000
1001
1002
1003
{

	/* 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
1004
static int iwl3945_send_rxon_assoc(struct iwl3945_priv *priv)
1005
1006
{
	int rc = 0;
Christoph Hellwig's avatar
Christoph Hellwig committed
1007
1008
1009
	struct iwl3945_rx_packet *res = NULL;
	struct iwl3945_rxon_assoc_cmd rxon_assoc;
	struct iwl3945_host_cmd cmd = {
1010
1011
1012
1013
1014
		.id = REPLY_RXON_ASSOC,
		.len = sizeof(rxon_assoc),
		.meta.flags = CMD_WANT_SKB,
		.data = &rxon_assoc,
	};
Christoph Hellwig's avatar
Christoph Hellwig committed
1015
1016
	const struct iwl3945_rxon_cmd *rxon1 = &priv->staging_rxon;
	const struct iwl3945_rxon_cmd *rxon2 = &priv->active_rxon;
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031

	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
1032
	rc = iwl3945_send_cmd_sync(priv, &cmd);
1033
1034
1035
	if (rc)
		return rc;

Christoph Hellwig's avatar
Christoph Hellwig committed
1036
	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
	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
1049
 * iwl3945_commit_rxon - commit staging_rxon to hardware
1050
 *
1051
 * The RXON command in staging_rxon is committed to the hardware and
1052
1053
1054
1055
 * 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
1056
static int iwl3945_commit_rxon(struct iwl3945_priv *priv)
1057
1058
{
	/* cast away the const for active_rxon in this function */
Christoph Hellwig's avatar
Christoph Hellwig committed
1059
	struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
1060
	int rc = 0;
1061
	DECLARE_MAC_BUF(mac);
1062

Christoph Hellwig's avatar
Christoph Hellwig committed
1063
	if (!iwl3945_is_alive(priv))
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
		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
1074
	rc = iwl3945_check_rxon_cmd(&priv->staging_rxon);
1075
1076
1077
1078
1079
1080
	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
1081
	 * iwl3945_rxon_assoc_cmd which is used to reconfigure filter
1082
	 * and other flags for the current radio configuration. */
Christoph Hellwig's avatar
Christoph Hellwig committed
1083
1084
	if (!iwl3945_full_rxon_required(priv)) {
		rc = iwl3945_send_rxon_assoc(priv);
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
		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
1100
	if (iwl3945_is_associated(priv) &&
1101
1102
1103
1104
	    (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
1105
1106
		rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON,
				      sizeof(struct iwl3945_rxon_cmd),
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
				      &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"
1122
		       "* bssid = %s\n",
1123
1124
1125
		       ((priv->staging_rxon.filter_flags &
			 RXON_FILTER_ASSOC_MSK) ? "" : "out"),
		       le16_to_cpu(priv->staging_rxon.channel),
1126
		       print_mac(mac, priv->staging_rxon.bssid_addr));
1127
1128

	/* Apply the new configuration */
Christoph Hellwig's avatar
Christoph Hellwig committed
1129
1130
	rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON,
			      sizeof(struct iwl3945_rxon_cmd), &priv->staging_rxon);
1131
1132
1133
1134
1135
1136
1137
	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
1138
	iwl3945_clear_stations_table(priv);
1139

1140
1141
	/* 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
1142
	rc = iwl3945_hw_reg_send_txpower(priv);
1143
1144
1145
1146
1147
1148
	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
1149
	if (iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0) ==
1150
1151
1152
1153
1154
1155
1156
	    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
1157
	if (iwl3945_is_associated(priv) &&
1158
	    (priv->iw_mode == IEEE80211_IF_TYPE_STA))
Christoph Hellwig's avatar
Christoph Hellwig committed
1159
		if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0)
1160
1161
1162
1163
1164
		    == IWL_INVALID_STATION) {
			IWL_ERROR("Error adding AP address for transmit.\n");
			return -EIO;
		}

1165
	/* Init the hardware's rate fallback order based on the band */
1166
1167
1168
1169
1170
1171
1172
1173
1174
	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
1175
static int iwl3945_send_bt_config(struct iwl3945_priv *priv)
1176
{
Christoph Hellwig's avatar
Christoph Hellwig committed
1177
	struct iwl3945_bt_cmd bt_cmd = {
1178
1179
1180
1181
1182
1183
1184
		.flags = 3,
		.lead_time = 0xAA,
		.max_kill = 1,
		.kill_ack_mask = 0,
		.kill_cts_mask = 0,
	};

Christoph Hellwig's avatar
Christoph Hellwig committed
1185
1186
	return iwl3945_send_cmd_pdu(priv, REPLY_BT_CONFIG,
				sizeof(struct iwl3945_bt_cmd), &bt_cmd);
1187
1188
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1189
static int iwl3945_send_scan_abort(struct iwl3945_priv *priv)
1190
1191
{
	int rc = 0;
Christoph Hellwig's avatar
Christoph Hellwig committed
1192
1193
	struct iwl3945_rx_packet *res;
	struct iwl3945_host_cmd cmd = {
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
		.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
1206
	rc = iwl3945_send_cmd_sync(priv, &cmd);
1207
1208
1209
1210
1211
	if (rc) {
		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
		return rc;
	}

Christoph Hellwig's avatar
Christoph Hellwig committed
1212
	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
	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
1230
1231
static int iwl3945_card_state_sync_callback(struct iwl3945_priv *priv,
					struct iwl3945_cmd *cmd,
1232
1233
1234
1235
1236
1237
1238
1239
					struct sk_buff *skb)
{
	return 1;
}

/*
 * CARD_STATE_CMD
 *
1240
 * Use: Sets the device's internal card state to enable, disable, or halt
1241
1242
1243
1244
1245
1246
 *
 * 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
1247
static int iwl3945_send_card_state(struct iwl3945_priv *priv, u32 flags, u8 meta_flag)
1248
{
Christoph Hellwig's avatar
Christoph Hellwig committed
1249
	struct iwl3945_host_cmd cmd = {
1250
1251
1252
1253
1254
1255
1256
		.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
1257
		cmd.meta.u.callback = iwl3945_card_state_sync_callback;
1258

Christoph Hellwig's avatar
Christoph Hellwig committed
1259
	return iwl3945_send_cmd(priv, &cmd);
1260
1261
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1262
1263
static int iwl3945_add_sta_sync_callback(struct iwl3945_priv *priv,
				     struct iwl3945_cmd *cmd, struct sk_buff *skb)
1264
{
Christoph Hellwig's avatar
Christoph Hellwig committed
1265
	struct iwl3945_rx_packet *res = NULL;
1266
1267
1268
1269
1270
1271

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

Christoph Hellwig's avatar
Christoph Hellwig committed
1272
	res = (struct iwl3945_rx_packet *)skb->data;
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
	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
1290
1291
int iwl3945_send_add_station(struct iwl3945_priv *priv,
			 struct iwl3945_addsta_cmd *sta, u8 flags)
1292
{
Christoph Hellwig's avatar
Christoph Hellwig committed
1293
	struct iwl3945_rx_packet *res = NULL;
1294
	int rc = 0;
Christoph Hellwig's avatar
Christoph Hellwig committed
1295
	struct iwl3945_host_cmd cmd = {
1296
		.id = REPLY_ADD_STA,
Christoph Hellwig's avatar
Christoph Hellwig committed
1297
		.len = sizeof(struct iwl3945_addsta_cmd),
1298
1299
1300
1301
1302
		.meta.flags = flags,
		.data = sta,
	};

	if (flags & CMD_ASYNC)
Christoph Hellwig's avatar
Christoph Hellwig committed
1303
		cmd.meta.u.callback = iwl3945_add_sta_sync_callback;
1304
1305
1306
	else
		cmd.meta.flags |= CMD_WANT_SKB;

Christoph Hellwig's avatar
Christoph Hellwig committed
1307
	rc = iwl3945_send_cmd(priv, &cmd);
1308
1309
1310
1311

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

Christoph Hellwig's avatar
Christoph Hellwig committed
1312
	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
	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
1337
static int iwl3945_update_sta_key_info(struct iwl3945_priv *priv,
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
				   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
1371
	iwl3945_send_add_station(priv, &priv->stations[sta_id].sta, 0);
1372
1373
1374
	return 0;
}

Christoph Hellwig's avatar
Christoph Hellwig committed