iwl-agn.c 125 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
 *
 * 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/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/mac80211.h>

#include <asm/div64.h>

47
#include "iwl-eeprom.h"
48
#include "iwl-dev.h"
49
#include "iwl-core.h"
50
#include "iwl-io.h"
51
#include "iwl-helpers.h"
52
#include "iwl-sta.h"
53
#include "iwl-calib.h"
54

55

56
57
58
59
60
61
62
63
64
65
66
/******************************************************************************
 *
 * module boiler plate
 *
 ******************************************************************************/

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

67
#define DRV_DESCRIPTION	"Intel(R) Wireless WiFi Link AGN driver for Linux"
68

69
#ifdef CONFIG_IWLWIFI_DEBUG
70
71
72
73
74
#define VD "d"
#else
#define VD
#endif

Tomas Winkler's avatar
Tomas Winkler committed
75
#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
76
77
78
79
80
#define VS "s"
#else
#define VS
#endif

Tomas Winkler's avatar
Tomas Winkler committed
81
#define DRV_VERSION     IWLWIFI_VERSION VD VS
82
83
84
85
86
87


MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
Tomas Winkler's avatar
Tomas Winkler committed
88
MODULE_ALIAS("iwl4965");
89
90

/*************** STATION TABLE MANAGEMENT ****
91
 * mac80211 should be examined to determine if sta_info is duplicating
92
93
94
95
96
97
98
 * the functionality provided here
 */

/**************************************************************/



99
100
static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
{
Gregory Greenman's avatar
Gregory Greenman committed
101
	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
102
103
104
105
106
107
108
109

	if (hw_decrypt)
		rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
	else
		rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;

}

110
/**
Christoph Hellwig's avatar
Christoph Hellwig committed
111
 * iwl4965_check_rxon_cmd - validate RXON structure is valid
112
113
114
115
116
 *
 * 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
 */
Gregory Greenman's avatar
Gregory Greenman committed
117
static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
{
	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 (error)
		IWL_WARNING("Tuning to channel %d\n",
			    le16_to_cpu(rxon->channel));

	if (error) {
Christoph Hellwig's avatar
Christoph Hellwig committed
177
		IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n");
178
179
180
181
182
183
		return -1;
	}
	return 0;
}

/**
184
 * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
185
 * @priv: staging_rxon is compared to active_rxon
186
 *
187
188
189
 * 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.
190
 */
191
static int iwl_full_rxon_required(struct iwl_priv *priv)
192
193
194
{

	/* These items are only settable from the full RXON command */
195
	if (!(iwl_is_associated(priv)) ||
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
	    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.ofdm_ht_single_stream_basic_rates !=
	     priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
	    (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
	     priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
	    (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
231
 * iwl4965_commit_rxon - commit staging_rxon to hardware
232
 *
233
 * The RXON command in staging_rxon is committed to the hardware and
234
235
236
237
 * 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.
 */
238
static int iwl4965_commit_rxon(struct iwl_priv *priv)
239
240
{
	/* cast away the const for active_rxon in this function */
Gregory Greenman's avatar
Gregory Greenman committed
241
	struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
242
	DECLARE_MAC_BUF(mac);
243
244
245
	int ret;
	bool new_assoc =
		!!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
246

247
	if (!iwl_is_alive(priv))
248
		return -EBUSY;
249
250
251

	/* always get timestamp with Rx frame */
	priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
252
253
254
	/* allow CTS-to-self if possible. this is relevant only for
	 * 5000, but will not damage 4965 */
	priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
255

256
257
	ret = iwl4965_check_rxon_cmd(&priv->staging_rxon);
	if (ret) {
258
259
260
261
262
		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
263
	 * iwl4965_rxon_assoc_cmd which is used to reconfigure filter
264
	 * and other flags for the current radio configuration. */
265
	if (!iwl_full_rxon_required(priv)) {
266
267
268
269
		ret = iwl_send_rxon_assoc(priv);
		if (ret) {
			IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret);
			return ret;
270
271
272
273
274
275
276
277
278
279
280
281
282
		}

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

	/* station table will be cleared */
	priv->assoc_station_added = 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 */
283
	if (iwl_is_associated(priv) && new_assoc) {
284
285
286
		IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;

287
		ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
Gregory Greenman's avatar
Gregory Greenman committed
288
				      sizeof(struct iwl_rxon_cmd),
289
290
291
292
				      &priv->active_rxon);

		/* If the mask clearing failed then we set
		 * active_rxon back to what it was previously */
293
		if (ret) {
294
			active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
295
296
			IWL_ERROR("Error clearing ASSOC_MSK (%d)\n", ret);
			return ret;
297
298
299
300
301
302
		}
	}

	IWL_DEBUG_INFO("Sending RXON\n"
		       "* with%s RXON_FILTER_ASSOC_MSK\n"
		       "* channel = %d\n"
303
		       "* bssid = %s\n",
304
		       (new_assoc ? "" : "out"),
305
		       le16_to_cpu(priv->staging_rxon.channel),
306
		       print_mac(mac, priv->staging_rxon.bssid_addr));
307

308
	iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
309
310
311
312
313
314
315
316

	/* Apply the new configuration
	 * RXON unassoc clears the station table in uCode, send it before
	 * we add the bcast station. If assoc bit is set, we will send RXON
	 * after having added the bcast and bssid station.
	 */
	if (!new_assoc) {
		ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
Gregory Greenman's avatar
Gregory Greenman committed
317
			      sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
318
319
320
321
322
		if (ret) {
			IWL_ERROR("Error setting new RXON (%d)\n", ret);
			return ret;
		}
		memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
323
324
	}

325
	iwl_clear_stations_table(priv);
326

327
328
329
330
	if (!priv->error_recovering)
		priv->start_calib = 0;

	/* Add the broadcast address so we can send broadcast frames */
331
	if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) ==
332
						IWL_INVALID_STATION) {
333
334
335
336
337
338
		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 */
339
	if (new_assoc) {
340
		if (priv->iw_mode == NL80211_IFTYPE_STATION) {
341
342
343
344
345
346
347
348
349
350
			ret = iwl_rxon_add_station(priv,
					   priv->active_rxon.bssid_addr, 1);
			if (ret == IWL_INVALID_STATION) {
				IWL_ERROR("Error adding AP address for TX.\n");
				return -EIO;
			}
			priv->assoc_station_added = 1;
			if (priv->default_wep_key &&
			    iwl_send_static_wepkey_cmd(priv, 0))
				IWL_ERROR("Could not send WEP static key.\n");
351
		}
352
353
354
355
356
357
358
359
360
361
362

		/* Apply the new configuration
		 * RXON assoc doesn't clear the station table in uCode,
		 */
		ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
			      sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
		if (ret) {
			IWL_ERROR("Error setting new RXON (%d)\n", ret);
			return ret;
		}
		memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
363
364
	}

365
366
367
368
369
370
371
372
373
374
	iwl_init_sensitivity(priv);

	/* 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 */
	ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
	if (ret) {
		IWL_ERROR("Error sending TX power (%d)\n", ret);
		return ret;
	}

375
376
377
	return 0;
}

378
379
380
void iwl4965_update_chain_flags(struct iwl_priv *priv)
{

381
	iwl_set_rxon_chain(priv);
382
383
384
	iwl4965_commit_rxon(priv);
}

385
static int iwl4965_send_bt_config(struct iwl_priv *priv)
386
{
Christoph Hellwig's avatar
Christoph Hellwig committed
387
	struct iwl4965_bt_cmd bt_cmd = {
388
389
390
391
392
393
394
		.flags = 3,
		.lead_time = 0xAA,
		.max_kill = 1,
		.kill_ack_mask = 0,
		.kill_cts_mask = 0,
	};

395
	return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
Christoph Hellwig's avatar
Christoph Hellwig committed
396
				sizeof(struct iwl4965_bt_cmd), &bt_cmd);
397
398
}

399
static void iwl_clear_free_frames(struct iwl_priv *priv)
400
401
402
403
404
405
406
407
408
{
	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);
409
		kfree(list_entry(element, struct iwl_frame, list));
410
411
412
413
414
415
416
417
418
419
		priv->frames_count--;
	}

	if (priv->frames_count) {
		IWL_WARNING("%d frames still in use.  Did we lose one?\n",
			    priv->frames_count);
		priv->frames_count = 0;
	}
}

420
static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
421
{
422
	struct iwl_frame *frame;
423
424
425
426
427
428
429
430
431
432
433
434
435
436
	struct list_head *element;
	if (list_empty(&priv->free_frames)) {
		frame = kzalloc(sizeof(*frame), GFP_KERNEL);
		if (!frame) {
			IWL_ERROR("Could not allocate frame!\n");
			return NULL;
		}

		priv->frames_count++;
		return frame;
	}

	element = priv->free_frames.next;
	list_del(element);
437
	return list_entry(element, struct iwl_frame, list);
438
439
}

440
static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
441
442
443
444
445
{
	memset(frame, 0, sizeof(*frame));
	list_add(&frame->list, &priv->free_frames);
}

446
447
448
static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
					  struct ieee80211_hdr *hdr,
					  const u8 *dest, int left)
449
{
450
	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
451
452
	    ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
	     (priv->iw_mode != NL80211_IFTYPE_AP)))
453
454
455
456
457
458
459
460
461
462
		return 0;

	if (priv->ibss_beacon->len > left)
		return 0;

	memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);

	return priv->ibss_beacon->len;
}

Guy Cohen's avatar
Guy Cohen committed
463
static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv)
464
{
Guy Cohen's avatar
Guy Cohen committed
465
466
467
468
469
470
471
472
	int i;
	int rate_mask;

	/* Set rate mask*/
	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
		rate_mask = priv->active_rate_basic & 0xF;
	else
		rate_mask = priv->active_rate_basic & 0xFF0;
473

Guy Cohen's avatar
Guy Cohen committed
474
	/* Find lowest valid rate */
475
	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
476
					i = iwl_rates[i].next_ieee) {
477
		if (rate_mask & (1 << i))
478
			return iwl_rates[i].plcp;
479
480
	}

Guy Cohen's avatar
Guy Cohen committed
481
482
483
484
485
	/* No valid rate was found. Assign the lowest one */
	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
		return IWL_RATE_1M_PLCP;
	else
		return IWL_RATE_6M_PLCP;
486
487
}

488
static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
				       struct iwl_frame *frame, u8 rate)
{
	struct iwl_tx_beacon_cmd *tx_beacon_cmd;
	unsigned int frame_size;

	tx_beacon_cmd = &frame->u.beacon;
	memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));

	tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;

	frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
				iwl_bcast_addr,
				sizeof(frame->u) - sizeof(*tx_beacon_cmd));

	BUG_ON(frame_size > MAX_MPDU_SIZE);
	tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);

	if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
		tx_beacon_cmd->tx.rate_n_flags =
			iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK);
	else
		tx_beacon_cmd->tx.rate_n_flags =
			iwl_hw_set_rate_n_flags(rate, 0);

	tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
				     TX_CMD_FLG_TSF_MSK |
				     TX_CMD_FLG_STA_RATE_MSK;

	return sizeof(*tx_beacon_cmd) + frame_size;
}
520
static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
521
{
522
	struct iwl_frame *frame;
523
524
525
526
	unsigned int frame_size;
	int rc;
	u8 rate;

527
	frame = iwl_get_free_frame(priv);
528
529
530
531
532
533
534

	if (!frame) {
		IWL_ERROR("Could not obtain free frame buffer for beacon "
			  "command.\n");
		return -ENOMEM;
	}

Guy Cohen's avatar
Guy Cohen committed
535
	rate = iwl4965_rate_get_lowest_plcp(priv);
536

Christoph Hellwig's avatar
Christoph Hellwig committed
537
	frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate);
538

539
	rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
540
541
			      &frame->u.cmd[0]);

542
	iwl_free_frame(priv, frame);
543
544
545
546
547
548
549
550
551
552

	return rc;
}

/******************************************************************************
 *
 * Misc. internal state and helper functions
 *
 ******************************************************************************/

553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
static void iwl4965_ht_conf(struct iwl_priv *priv,
			    struct ieee80211_bss_conf *bss_conf)
{
	struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf;
	struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf;
	struct iwl_ht_info *iwl_conf = &priv->current_ht_config;

	IWL_DEBUG_MAC80211("enter: \n");

	iwl_conf->is_ht = bss_conf->assoc_ht;

	if (!iwl_conf->is_ht)
		return;

	if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
568
		iwl_conf->sgf |= HT_SHORT_GI_20MHZ;
569
	if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
570
		iwl_conf->sgf |= HT_SHORT_GI_40MHZ;
571
572
573
574
575
576
577
578
579
580

	iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
	iwl_conf->max_amsdu_size =
		!!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);

	iwl_conf->supported_chan_width =
		!!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
	iwl_conf->extension_chan_offset =
		ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
	/* If no above or below channel supplied disable FAT channel */
581
582
583
	if (iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_ABOVE &&
	    iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_BELOW) {
		iwl_conf->extension_chan_offset = IEEE80211_HT_IE_CHA_SEC_NONE;
584
		iwl_conf->supported_chan_width = 0;
585
	}
586

587
588
	iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);

589
590
591
592
593
594
595
596
597
598
599
600
601
602
	memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);

	iwl_conf->control_channel = ht_bss_conf->primary_channel;
	iwl_conf->tx_chan_width =
		!!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
	iwl_conf->ht_protection =
		ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
	iwl_conf->non_GF_STA_present =
		!!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);

	IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel);
	IWL_DEBUG_MAC80211("leave\n");
}

603
604
605
/*
 * QoS  support
*/
606
static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
{
	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
		return;

	if (!priv->qos_data.qos_enable)
		return;

	priv->qos_data.def_qos_parm.qos_flags = 0;

	if (priv->qos_data.qos_cap.q_AP.queue_request &&
	    !priv->qos_data.qos_cap.q_AP.txop_request)
		priv->qos_data.def_qos_parm.qos_flags |=
			QOS_PARAM_FLG_TXOP_TYPE_MSK;
	if (priv->qos_data.qos_active)
		priv->qos_data.def_qos_parm.qos_flags |=
			QOS_PARAM_FLG_UPDATE_EDCA_MSK;

624
	if (priv->current_ht_config.is_ht)
625
626
		priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;

627
	if (force || iwl_is_associated(priv)) {
628
629
630
		IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n",
				priv->qos_data.qos_active,
				priv->qos_data.def_qos_parm.qos_flags);
631

632
633
634
		iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
				       sizeof(struct iwl_qosparam_cmd),
				       &priv->qos_data.def_qos_parm, NULL);
635
636
637
638
639
	}
}

#define MAX_UCODE_BEACON_INTERVAL	4096

Christoph Hellwig's avatar
Christoph Hellwig committed
640
static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val)
641
642
643
644
645
646
647
648
649
650
651
652
{
	u16 new_val = 0;
	u16 beacon_factor = 0;

	beacon_factor =
	    (beacon_val + MAX_UCODE_BEACON_INTERVAL)
		/ MAX_UCODE_BEACON_INTERVAL;
	new_val = beacon_val / beacon_factor;

	return cpu_to_le16(new_val);
}

653
static void iwl4965_setup_rxon_timing(struct iwl_priv *priv)
654
655
656
657
658
659
660
661
662
663
{
	u64 interval_tm_unit;
	u64 tsf, result;
	unsigned long flags;
	struct ieee80211_conf *conf = NULL;
	u16 beacon_int = 0;

	conf = ieee80211_get_hw_conf(priv->hw);

	spin_lock_irqsave(&priv->lock, flags);
664
665
666
	priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp >> 32);
	priv->rxon_timing.timestamp.dw[0] =
				cpu_to_le32(priv->timestamp & 0xFFFFFFFF);
667

668
	priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
669

670
	tsf = priv->timestamp;
671
672
673
674

	beacon_int = priv->beacon_int;
	spin_unlock_irqrestore(&priv->lock, flags);

675
	if (priv->iw_mode == NL80211_IFTYPE_STATION) {
676
677
678
679
680
681
682
		if (beacon_int == 0) {
			priv->rxon_timing.beacon_interval = cpu_to_le16(100);
			priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
		} else {
			priv->rxon_timing.beacon_interval =
				cpu_to_le16(beacon_int);
			priv->rxon_timing.beacon_interval =
Christoph Hellwig's avatar
Christoph Hellwig committed
683
			    iwl4965_adjust_beacon_interval(
684
685
686
687
688
689
				le16_to_cpu(priv->rxon_timing.beacon_interval));
		}

		priv->rxon_timing.atim_window = 0;
	} else {
		priv->rxon_timing.beacon_interval =
Christoph Hellwig's avatar
Christoph Hellwig committed
690
			iwl4965_adjust_beacon_interval(conf->beacon_int);
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
		/* TODO: we need to get atim_window from upper stack
		 * for now we set to 0 */
		priv->rxon_timing.atim_window = 0;
	}

	interval_tm_unit =
		(le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
	result = do_div(tsf, interval_tm_unit);
	priv->rxon_timing.beacon_init_val =
	    cpu_to_le32((u32) ((u64) interval_tm_unit - result));

	IWL_DEBUG_ASSOC
	    ("beacon interval %d beacon timer %d beacon tim %d\n",
		le16_to_cpu(priv->rxon_timing.beacon_interval),
		le32_to_cpu(priv->rxon_timing.beacon_init_val),
		le16_to_cpu(priv->rxon_timing.atim_window));
}

709
710
static void iwl_set_flags_for_band(struct iwl_priv *priv,
				   enum ieee80211_band band)
711
{
712
	if (band == IEEE80211_BAND_5GHZ) {
713
714
715
716
717
		priv->staging_rxon.flags &=
		    ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
		      | RXON_FLG_CCK_MSK);
		priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
	} else {
718
		/* Copied from iwl4965_post_associate() */
719
720
721
722
723
		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
		else
			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;

724
		if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
725
726
727
728
729
730
731
732
733
			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;

		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
		priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
		priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
	}
}

/*
734
 * initialize rxon structure with default values from eeprom
735
 */
736
static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
737
{
738
	const struct iwl_channel_info *ch_info;
739
740
741
742

	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));

	switch (priv->iw_mode) {
743
	case NL80211_IFTYPE_AP:
744
745
746
		priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
		break;

747
	case NL80211_IFTYPE_STATION:
748
749
750
751
		priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
		priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
		break;

752
	case NL80211_IFTYPE_ADHOC:
753
754
755
756
757
758
		priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
		priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
		priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
						  RXON_FILTER_ACCEPT_GRP_MSK;
		break;

759
	case NL80211_IFTYPE_MONITOR:
760
761
762
763
		priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
		priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
		break;
764
765
766
	default:
		IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode);
		break;
767
768
769
770
771
772
773
774
775
776
777
	}

#if 0
	/* TODO:  Figure out when short_preamble would be set and cache from
	 * that */
	if (!hw_to_local(priv->hw)->short_preamble)
		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
	else
		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
#endif

778
	ch_info = iwl_get_channel_info(priv, priv->band,
779
				       le16_to_cpu(priv->active_rxon.channel));
780
781
782
783
784
785
786
787

	if (!ch_info)
		ch_info = &priv->channel_info[0];

	/*
	 * in some case A channels are all non IBSS
	 * in this case force B/G channel
	 */
788
	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
789
790
791
792
	    !(is_channel_ibss(ch_info)))
		ch_info = &priv->channel_info[0];

	priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
793
	priv->band = ch_info->band;
794

795
	iwl_set_flags_for_band(priv, priv->band);
796
797
798
799
800
801
802
803
804
805
806
807

	priv->staging_rxon.ofdm_basic_rates =
	    (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
	priv->staging_rxon.cck_basic_rates =
	    (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;

	priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
					RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
	memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
	priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
	priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
808
	iwl_set_rxon_chain(priv);
809
810
}

811
static int iwl4965_set_mode(struct iwl_priv *priv, int mode)
812
813
814
{
	priv->iw_mode = mode;

Christoph Hellwig's avatar
Christoph Hellwig committed
815
	iwl4965_connection_init_rx_config(priv);
816
817
	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);

818
	iwl_clear_stations_table(priv);
819

820
	/* dont commit rxon if rf-kill is on*/
821
	if (!iwl_is_ready_rf(priv))
822
823
824
		return -EAGAIN;

	cancel_delayed_work(&priv->scan_check);
825
	if (iwl_scan_cancel_timeout(priv, 100)) {
826
827
828
829
830
		IWL_WARNING("Aborted scan still in progress after 100ms\n");
		IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
		return -EAGAIN;
	}

Christoph Hellwig's avatar
Christoph Hellwig committed
831
	iwl4965_commit_rxon(priv);
832
833
834
835

	return 0;
}

836
static void iwl4965_set_rate(struct iwl_priv *priv)
837
{
838
	const struct ieee80211_supported_band *hw = NULL;
839
840
841
	struct ieee80211_rate *rate;
	int i;

842
	hw = iwl_get_hw_mode(priv, priv->band);
843
844
845
846
	if (!hw) {
		IWL_ERROR("Failed to set rate: unable to get hw mode\n");
		return;
	}
847
848
849
850

	priv->active_rate = 0;
	priv->active_rate_basic = 0;

851
852
853
854
	for (i = 0; i < hw->n_bitrates; i++) {
		rate = &(hw->bitrates[i]);
		if (rate->hw_value < IWL_RATE_COUNT)
			priv->active_rate |= (1 << rate->hw_value);
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
	}

	IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
		       priv->active_rate, priv->active_rate_basic);

	/*
	 * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
	 * otherwise set it to the default of all CCK rates and 6, 12, 24 for
	 * OFDM
	 */
	if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
		priv->staging_rxon.cck_basic_rates =
		    ((priv->active_rate_basic &
		      IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
	else
		priv->staging_rxon.cck_basic_rates =
		    (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;

	if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
		priv->staging_rxon.ofdm_basic_rates =
		    ((priv->active_rate_basic &
		      (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
		      IWL_FIRST_OFDM_RATE) & 0xFF;
	else
		priv->staging_rxon.ofdm_basic_rates =
		   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
}

Tomas Winkler's avatar
Tomas Winkler committed
883
#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
884
885
886
887
888
889
890
891
892
893
894
895
896
897

#include "iwl-spectrum.h"

#define BEACON_TIME_MASK_LOW	0x00FFFFFF
#define BEACON_TIME_MASK_HIGH	0xFF000000
#define TIME_UNIT		1024

/*
 * extended beacon time format
 * time in usec will be changed into a 32-bit value in 8:24 format
 * the high 1 byte is the beacon counts
 * the lower 3 bytes is the time in usec within one beacon interval
 */

Christoph Hellwig's avatar
Christoph Hellwig committed
898
static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval)
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
{
	u32 quot;
	u32 rem;
	u32 interval = beacon_interval * 1024;

	if (!interval || !usec)
		return 0;

	quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
	rem = (usec % interval) & BEACON_TIME_MASK_LOW;

	return (quot << 24) + rem;
}

/* base is usually what we get from ucode with each received frame,
 * the same as HW timer counter counting down
 */

Christoph Hellwig's avatar
Christoph Hellwig committed
917
static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
{
	u32 base_low = base & BEACON_TIME_MASK_LOW;
	u32 addon_low = addon & BEACON_TIME_MASK_LOW;
	u32 interval = beacon_interval * TIME_UNIT;
	u32 res = (base & BEACON_TIME_MASK_HIGH) +
	    (addon & BEACON_TIME_MASK_HIGH);

	if (base_low > addon_low)
		res += base_low - addon_low;
	else if (base_low < addon_low) {
		res += interval + base_low - addon_low;
		res += (1 << 24);
	} else
		res += (1 << 24);

	return cpu_to_le32(res);
}

936
static int iwl4965_get_measurement(struct iwl_priv *priv,
937
938
939
			       struct ieee80211_measurement_params *params,
			       u8 type)
{
Christoph Hellwig's avatar
Christoph Hellwig committed
940
	struct iwl4965_spectrum_cmd spectrum;
941
	struct iwl_rx_packet *res;
942
	struct iwl_host_cmd cmd = {
943
944
945
946
947
948
949
950
951
		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
		.data = (void *)&spectrum,
		.meta.flags = CMD_WANT_SKB,
	};
	u32 add_time = le64_to_cpu(params->start_time);
	int rc;
	int spectrum_resp_status;
	int duration = le16_to_cpu(params->duration);

952
	if (iwl_is_associated(priv))
953
		add_time =
Christoph Hellwig's avatar
Christoph Hellwig committed
954
		    iwl4965_usecs_to_beacons(
955
956
957
958
959
960
961
962
963
964
965
966
			le64_to_cpu(params->start_time) - priv->last_tsf,
			le16_to_cpu(priv->rxon_timing.beacon_interval));

	memset(&spectrum, 0, sizeof(spectrum));

	spectrum.channel_count = cpu_to_le16(1);
	spectrum.flags =
	    RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
	spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
	cmd.len = sizeof(spectrum);
	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));

967
	if (iwl_is_associated(priv))
968
		spectrum.start_time =
Christoph Hellwig's avatar
Christoph Hellwig committed
969
		    iwl4965_add_beacon_time(priv->last_beacon_time,
970
971
972
973
974
975
976
977
978
979
980
981
				add_time,
				le16_to_cpu(priv->rxon_timing.beacon_interval));
	else
		spectrum.start_time = 0;

	spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
	spectrum.channels[0].channel = params->channel;
	spectrum.channels[0].type = type;
	if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
		spectrum.flags |= RXON_FLG_BAND_24G_MSK |
		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;

982
	rc = iwl_send_cmd_sync(priv, &cmd);
983
984
985
	if (rc)
		return rc;

986
	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
		IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
		rc = -EIO;
	}

	spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
	switch (spectrum_resp_status) {
	case 0:		/* Command will be handled */
		if (res->u.spectrum.id != 0xff) {
			IWL_DEBUG_INFO
			    ("Replaced existing measurement: %d\n",
			     res->u.spectrum.id);
			priv->measurement_status &= ~MEASUREMENT_READY;
		}
For faster browsing, not all history is shown. View entire blame