iwl-core.c 67.7 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
/******************************************************************************
 *
 * GPL LICENSE SUMMARY
 *
 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
 *
 * 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.GPL.
 *
 * Contact Information:
 *  Intel Linux Wireless <ilw@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/etherdevice.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <net/mac80211.h>

#include "iwl-eeprom.h"
#include "iwl-dev.h"
#include "iwl-debug.h"
#include "iwl-core.h"
#include "iwl-io.h"
#include "iwl-power.h"
#include "iwl-sta.h"
#include "iwl-helpers.h"


MODULE_DESCRIPTION("iwl-legacy: common functions for 3945 and 4965");
MODULE_VERSION(IWLWIFI_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");

/*
 * set bt_coex_active to true, uCode will do kill/defer
 * every time the priority line is asserted (BT is sending signals on the
 * priority line in the PCIx).
 * set bt_coex_active to false, uCode will ignore the BT activity and
 * perform the normal operation
 *
 * User might experience transmit issue on some platform due to WiFi/BT
 * co-exist problem. The possible behaviors are:
 *   Able to scan and finding all the available AP
 *   Not able to associate with any AP
 * On those platforms, WiFi communication can be restored by set
 * "bt_coex_active" module parameter to "false"
 *
 * default: bt_coex_active = true (BT_COEX_ENABLE)
 */
67
static bool bt_coex_active = true;
68 69 70
module_param(bt_coex_active, bool, S_IRUGO);
MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist");

71 72
u32 il_debug_level;
EXPORT_SYMBOL(il_debug_level);
73

74 75
const u8 il_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
EXPORT_SYMBOL(il_bcast_addr);
76 77


S
Stanislaw Gruszka 已提交
78
/* This function both allocates and initializes hw and il. */
S
Stanislaw Gruszka 已提交
79
struct ieee80211_hw *il_alloc_all(struct il_cfg *cfg)
80
{
S
Stanislaw Gruszka 已提交
81
	struct il_priv *il;
82
	/* mac80211 allocates memory for this device instance, including
S
Stanislaw Gruszka 已提交
83
	 *   space for this driver's ilate structure */
84 85
	struct ieee80211_hw *hw;

S
Stanislaw Gruszka 已提交
86
	hw = ieee80211_alloc_hw(sizeof(struct il_priv),
87 88 89 90 91 92 93
				cfg->ops->ieee80211_ops);
	if (hw == NULL) {
		pr_err("%s: Can not allocate network device\n",
		       cfg->name);
		goto out;
	}

S
Stanislaw Gruszka 已提交
94 95
	il = hw->priv;
	il->hw = hw;
96 97 98 99

out:
	return hw;
}
S
Stanislaw Gruszka 已提交
100
EXPORT_SYMBOL(il_alloc_all);
101 102 103

#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
S
Stanislaw Gruszka 已提交
104
static void il_init_ht_hw_capab(const struct il_priv *il,
105 106 107 108
			      struct ieee80211_sta_ht_cap *ht_info,
			      enum ieee80211_band band)
{
	u16 max_bit_rate = 0;
S
Stanislaw Gruszka 已提交
109 110
	u8 rx_chains_num = il->hw_params.rx_chains_num;
	u8 tx_chains_num = il->hw_params.tx_chains_num;
111 112 113 114 115 116 117 118

	ht_info->cap = 0;
	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));

	ht_info->ht_supported = true;

	ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
	max_bit_rate = MAX_BIT_RATE_20_MHZ;
S
Stanislaw Gruszka 已提交
119
	if (il->hw_params.ht40_channel & BIT(band)) {
120 121 122 123 124 125
		ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
		ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
		ht_info->mcs.rx_mask[4] = 0x01;
		max_bit_rate = MAX_BIT_RATE_40_MHZ;
	}

S
Stanislaw Gruszka 已提交
126
	if (il->cfg->mod_params->amsdu_size_8K)
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
		ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;

	ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
	ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;

	ht_info->mcs.rx_mask[0] = 0xFF;
	if (rx_chains_num >= 2)
		ht_info->mcs.rx_mask[1] = 0xFF;
	if (rx_chains_num >= 3)
		ht_info->mcs.rx_mask[2] = 0xFF;

	/* Highest supported Rx data rate */
	max_bit_rate *= rx_chains_num;
	WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK);
	ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate);

	/* Tx MCS capabilities */
	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
	if (tx_chains_num != rx_chains_num) {
		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
		ht_info->mcs.tx_params |= ((tx_chains_num - 1) <<
				IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
	}
}

/**
S
Stanislaw Gruszka 已提交
153
 * il_init_geos - Initialize mac80211's geo/channel info based from eeprom
154
 */
S
Stanislaw Gruszka 已提交
155
int il_init_geos(struct il_priv *il)
156
{
S
Stanislaw Gruszka 已提交
157
	struct il_channel_info *ch;
158 159 160 161 162
	struct ieee80211_supported_band *sband;
	struct ieee80211_channel *channels;
	struct ieee80211_channel *geo_ch;
	struct ieee80211_rate *rates;
	int i = 0;
163
	s8 max_tx_power = 0;
164

S
Stanislaw Gruszka 已提交
165 166
	if (il->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
	    il->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
167
		D_INFO("Geography modes already initialized.\n");
S
Stanislaw Gruszka 已提交
168
		set_bit(STATUS_GEO_CONFIGURED, &il->status);
169 170 171 172
		return 0;
	}

	channels = kzalloc(sizeof(struct ieee80211_channel) *
S
Stanislaw Gruszka 已提交
173
			   il->channel_count, GFP_KERNEL);
174 175 176
	if (!channels)
		return -ENOMEM;

S
Stanislaw Gruszka 已提交
177
	rates = kzalloc((sizeof(struct ieee80211_rate) * IL_RATE_COUNT_LEGACY),
178 179 180 181 182 183 184
			GFP_KERNEL);
	if (!rates) {
		kfree(channels);
		return -ENOMEM;
	}

	/* 5.2GHz channels start after the 2.4GHz channels */
S
Stanislaw Gruszka 已提交
185
	sband = &il->bands[IEEE80211_BAND_5GHZ];
186
	sband->channels = &channels[ARRAY_SIZE(il_eeprom_band_1)];
187
	/* just OFDM */
S
Stanislaw Gruszka 已提交
188 189
	sband->bitrates = &rates[IL_FIRST_OFDM_RATE];
	sband->n_bitrates = IL_RATE_COUNT_LEGACY - IL_FIRST_OFDM_RATE;
190

S
Stanislaw Gruszka 已提交
191 192
	if (il->cfg->sku & IL_SKU_N)
		il_init_ht_hw_capab(il, &sband->ht_cap,
193 194
					 IEEE80211_BAND_5GHZ);

S
Stanislaw Gruszka 已提交
195
	sband = &il->bands[IEEE80211_BAND_2GHZ];
196 197 198
	sband->channels = channels;
	/* OFDM & CCK */
	sband->bitrates = rates;
S
Stanislaw Gruszka 已提交
199
	sband->n_bitrates = IL_RATE_COUNT_LEGACY;
200

S
Stanislaw Gruszka 已提交
201 202
	if (il->cfg->sku & IL_SKU_N)
		il_init_ht_hw_capab(il, &sband->ht_cap,
203 204
					 IEEE80211_BAND_2GHZ);

S
Stanislaw Gruszka 已提交
205 206
	il->ieee_channels = channels;
	il->ieee_rates = rates;
207

S
Stanislaw Gruszka 已提交
208 209
	for (i = 0;  i < il->channel_count; i++) {
		ch = &il->channel_info[i];
210

S
Stanislaw Gruszka 已提交
211
		if (!il_is_channel_valid(ch))
212 213
			continue;

S
Stanislaw Gruszka 已提交
214
		sband = &il->bands[ch->band];
215 216 217 218 219 220 221 222 223

		geo_ch = &sband->channels[sband->n_channels++];

		geo_ch->center_freq =
			ieee80211_channel_to_frequency(ch->channel, ch->band);
		geo_ch->max_power = ch->max_power_avg;
		geo_ch->max_antenna_gain = 0xff;
		geo_ch->hw_value = ch->channel;

S
Stanislaw Gruszka 已提交
224
		if (il_is_channel_valid(ch)) {
225 226 227 228 229 230 231 232 233 234 235
			if (!(ch->flags & EEPROM_CHANNEL_IBSS))
				geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;

			if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
				geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;

			if (ch->flags & EEPROM_CHANNEL_RADAR)
				geo_ch->flags |= IEEE80211_CHAN_RADAR;

			geo_ch->flags |= ch->ht40_extension_channel;

236 237
			if (ch->max_power_avg > max_tx_power)
				max_tx_power = ch->max_power_avg;
238 239 240 241
		} else {
			geo_ch->flags |= IEEE80211_CHAN_DISABLED;
		}

242
		D_INFO("Channel %d Freq=%d[%sGHz] %s flag=0x%X\n",
243
				ch->channel, geo_ch->center_freq,
S
Stanislaw Gruszka 已提交
244
				il_is_channel_a_band(ch) ?  "5.2" : "2.4",
245 246 247 248 249
				geo_ch->flags & IEEE80211_CHAN_DISABLED ?
				"restricted" : "valid",
				 geo_ch->flags);
	}

S
Stanislaw Gruszka 已提交
250 251 252
	il->tx_power_device_lmt = max_tx_power;
	il->tx_power_user_lmt = max_tx_power;
	il->tx_power_next = max_tx_power;
253

S
Stanislaw Gruszka 已提交
254 255
	if ((il->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
	     il->cfg->sku & IL_SKU_A) {
256
		IL_INFO("Incorrectly detected BG card as ABG. "
257
			"Please send your PCI ID 0x%04X:0x%04X to maintainer.\n",
S
Stanislaw Gruszka 已提交
258 259 260
			   il->pci_dev->device,
			   il->pci_dev->subsystem_device);
		il->cfg->sku &= ~IL_SKU_A;
261 262
	}

263
	IL_INFO("Tunable channels: %d 802.11bg, %d 802.11a channels\n",
S
Stanislaw Gruszka 已提交
264 265
		   il->bands[IEEE80211_BAND_2GHZ].n_channels,
		   il->bands[IEEE80211_BAND_5GHZ].n_channels);
266

S
Stanislaw Gruszka 已提交
267
	set_bit(STATUS_GEO_CONFIGURED, &il->status);
268 269 270

	return 0;
}
S
Stanislaw Gruszka 已提交
271
EXPORT_SYMBOL(il_init_geos);
272 273

/*
S
Stanislaw Gruszka 已提交
274
 * il_free_geos - undo allocations in il_init_geos
275
 */
S
Stanislaw Gruszka 已提交
276
void il_free_geos(struct il_priv *il)
277
{
S
Stanislaw Gruszka 已提交
278 279 280
	kfree(il->ieee_channels);
	kfree(il->ieee_rates);
	clear_bit(STATUS_GEO_CONFIGURED, &il->status);
281
}
S
Stanislaw Gruszka 已提交
282
EXPORT_SYMBOL(il_free_geos);
283

S
Stanislaw Gruszka 已提交
284
static bool il_is_channel_extension(struct il_priv *il,
285 286 287
				     enum ieee80211_band band,
				     u16 channel, u8 extension_chan_offset)
{
S
Stanislaw Gruszka 已提交
288
	const struct il_channel_info *ch_info;
289

S
Stanislaw Gruszka 已提交
290
	ch_info = il_get_channel_info(il, band, channel);
S
Stanislaw Gruszka 已提交
291
	if (!il_is_channel_valid(ch_info))
292 293 294 295 296 297 298 299 300 301 302 303
		return false;

	if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
		return !(ch_info->ht40_extension_channel &
					IEEE80211_CHAN_NO_HT40PLUS);
	else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
		return !(ch_info->ht40_extension_channel &
					IEEE80211_CHAN_NO_HT40MINUS);

	return false;
}

S
Stanislaw Gruszka 已提交
304
bool il_is_ht40_tx_allowed(struct il_priv *il,
S
Stanislaw Gruszka 已提交
305
			    struct il_rxon_context *ctx,
306 307 308 309 310 311 312 313 314 315 316 317 318
			    struct ieee80211_sta_ht_cap *ht_cap)
{
	if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
		return false;

	/*
	 * We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
	 * the bit will not set if it is pure 40MHz case
	 */
	if (ht_cap && !ht_cap->ht_supported)
		return false;

#ifdef CONFIG_IWLWIFI_LEGACY_DEBUGFS
S
Stanislaw Gruszka 已提交
319
	if (il->disable_ht40)
320 321 322
		return false;
#endif

S
Stanislaw Gruszka 已提交
323
	return il_is_channel_extension(il, il->band,
324 325 326
			le16_to_cpu(ctx->staging.channel),
			ctx->ht.extension_chan_offset);
}
S
Stanislaw Gruszka 已提交
327
EXPORT_SYMBOL(il_is_ht40_tx_allowed);
328

S
Stanislaw Gruszka 已提交
329
static u16 il_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
{
	u16 new_val;
	u16 beacon_factor;

	/*
	 * If mac80211 hasn't given us a beacon interval, program
	 * the default into the device.
	 */
	if (!beacon_val)
		return DEFAULT_BEACON_INTERVAL;

	/*
	 * If the beacon interval we obtained from the peer
	 * is too large, we'll have to wake up more often
	 * (and in IBSS case, we'll beacon too much)
	 *
	 * For example, if max_beacon_val is 4096, and the
	 * requested beacon interval is 7000, we'll have to
	 * use 3500 to be able to wake up on the beacons.
	 *
	 * This could badly influence beacon detection stats.
	 */

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

	if (!new_val)
		new_val = max_beacon_val;

	return new_val;
}

int
S
Stanislaw Gruszka 已提交
363
il_send_rxon_timing(struct il_priv *il, struct il_rxon_context *ctx)
364 365 366 367 368 369 370
{
	u64 tsf;
	s32 interval_tm, rem;
	struct ieee80211_conf *conf = NULL;
	u16 beacon_int;
	struct ieee80211_vif *vif = ctx->vif;

S
Stanislaw Gruszka 已提交
371
	conf = il_ieee80211_get_hw_conf(il->hw);
372

S
Stanislaw Gruszka 已提交
373
	lockdep_assert_held(&il->mutex);
374

S
Stanislaw Gruszka 已提交
375
	memset(&ctx->timing, 0, sizeof(struct il_rxon_time_cmd));
376

S
Stanislaw Gruszka 已提交
377
	ctx->timing.timestamp = cpu_to_le64(il->timestamp);
378 379 380 381 382 383 384 385 386 387
	ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval);

	beacon_int = vif ? vif->bss_conf.beacon_int : 0;

	/*
	 * TODO: For IBSS we need to get atim_window from mac80211,
	 *	 for now just always use 0
	 */
	ctx->timing.atim_window = 0;

S
Stanislaw Gruszka 已提交
388
	beacon_int = il_adjust_beacon_interval(beacon_int,
S
Stanislaw Gruszka 已提交
389
			il->hw_params.max_beacon_itrvl * TIME_UNIT);
390 391
	ctx->timing.beacon_interval = cpu_to_le16(beacon_int);

S
Stanislaw Gruszka 已提交
392
	tsf = il->timestamp; /* tsf is modifed by do_div: copy it */
393 394 395 396 397 398
	interval_tm = beacon_int * TIME_UNIT;
	rem = do_div(tsf, interval_tm);
	ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem);

	ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1;

399
	D_ASSOC(
400 401 402 403 404
			"beacon interval %d beacon timer %d beacon tim %d\n",
			le16_to_cpu(ctx->timing.beacon_interval),
			le32_to_cpu(ctx->timing.beacon_init_val),
			le16_to_cpu(ctx->timing.atim_window));

S
Stanislaw Gruszka 已提交
405
	return il_send_cmd_pdu(il, ctx->rxon_timing_cmd,
406 407
				sizeof(ctx->timing), &ctx->timing);
}
S
Stanislaw Gruszka 已提交
408
EXPORT_SYMBOL(il_send_rxon_timing);
409 410

void
S
Stanislaw Gruszka 已提交
411
il_set_rxon_hwcrypto(struct il_priv *il,
S
Stanislaw Gruszka 已提交
412
				struct il_rxon_context *ctx,
413 414
				int hw_decrypt)
{
S
Stanislaw Gruszka 已提交
415
	struct il_rxon_cmd *rxon = &ctx->staging;
416 417 418 419 420 421 422

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

}
S
Stanislaw Gruszka 已提交
423
EXPORT_SYMBOL(il_set_rxon_hwcrypto);
424 425 426

/* validate RXON structure is valid */
int
S
Stanislaw Gruszka 已提交
427
il_check_rxon_cmd(struct il_priv *il, struct il_rxon_context *ctx)
428
{
S
Stanislaw Gruszka 已提交
429
	struct il_rxon_cmd *rxon = &ctx->staging;
430 431 432 433
	bool error = false;

	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
		if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) {
434
			IL_WARN("check 2.4G: wrong narrow\n");
435 436 437
			error = true;
		}
		if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) {
438
			IL_WARN("check 2.4G: wrong radar\n");
439 440 441 442
			error = true;
		}
	} else {
		if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) {
443
			IL_WARN("check 5.2G: not short slot!\n");
444 445 446
			error = true;
		}
		if (rxon->flags & RXON_FLG_CCK_MSK) {
447
			IL_WARN("check 5.2G: CCK!\n");
448 449 450 451
			error = true;
		}
	}
	if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) {
452
		IL_WARN("mac/bssid mcast!\n");
453 454 455 456
		error = true;
	}

	/* make sure basic rates 6Mbps and 1Mbps are supported */
S
Stanislaw Gruszka 已提交
457 458
	if ((rxon->ofdm_basic_rates & IL_RATE_6M_MASK) == 0 &&
	    (rxon->cck_basic_rates & IL_RATE_1M_MASK) == 0) {
459
		IL_WARN("neither 1 nor 6 are basic\n");
460 461 462 463
		error = true;
	}

	if (le16_to_cpu(rxon->assoc_id) > 2007) {
464
		IL_WARN("aid > 2007\n");
465 466 467 468 469
		error = true;
	}

	if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
			== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) {
470
		IL_WARN("CCK and short slot\n");
471 472 473 474 475
		error = true;
	}

	if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
			== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) {
476
		IL_WARN("CCK and auto detect");
477 478 479 480 481 482
		error = true;
	}

	if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
			    RXON_FLG_TGG_PROTECT_MSK)) ==
			    RXON_FLG_TGG_PROTECT_MSK) {
483
		IL_WARN("TGg but no auto-detect\n");
484 485 486 487
		error = true;
	}

	if (error)
488
		IL_WARN("Tuning to channel %d\n",
489 490 491
			    le16_to_cpu(rxon->channel));

	if (error) {
492
		IL_ERR("Invalid RXON\n");
493 494 495 496
		return -EINVAL;
	}
	return 0;
}
S
Stanislaw Gruszka 已提交
497
EXPORT_SYMBOL(il_check_rxon_cmd);
498 499

/**
S
Stanislaw Gruszka 已提交
500
 * il_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
S
Stanislaw Gruszka 已提交
501
 * @il: staging_rxon is compared to active_rxon
502 503 504 505 506
 *
 * 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.
 */
S
Stanislaw Gruszka 已提交
507
int il_full_rxon_required(struct il_priv *il,
S
Stanislaw Gruszka 已提交
508
			   struct il_rxon_context *ctx)
509
{
S
Stanislaw Gruszka 已提交
510 511
	const struct il_rxon_cmd *staging = &ctx->staging;
	const struct il_rxon_cmd *active = &ctx->active;
512 513 514

#define CHK(cond)							\
	if ((cond)) {							\
515
		D_INFO("need full RXON - " #cond "\n");	\
516 517 518 519 520
		return 1;						\
	}

#define CHK_NEQ(c1, c2)						\
	if ((c1) != (c2)) {					\
521
		D_INFO("need full RXON - "	\
522 523 524 525 526 527
			       #c1 " != " #c2 " - %d != %d\n",	\
			       (c1), (c2));			\
		return 1;					\
	}

	/* These items are only settable from the full RXON command */
S
Stanislaw Gruszka 已提交
528
	CHK(!il_is_associated_ctx(ctx));
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
	CHK(compare_ether_addr(staging->bssid_addr, active->bssid_addr));
	CHK(compare_ether_addr(staging->node_addr, active->node_addr));
	CHK(compare_ether_addr(staging->wlap_bssid_addr,
				active->wlap_bssid_addr));
	CHK_NEQ(staging->dev_type, active->dev_type);
	CHK_NEQ(staging->channel, active->channel);
	CHK_NEQ(staging->air_propagation, active->air_propagation);
	CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates,
		active->ofdm_ht_single_stream_basic_rates);
	CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates,
		active->ofdm_ht_dual_stream_basic_rates);
	CHK_NEQ(staging->assoc_id, active->assoc_id);

	/* 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 */
	CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK,
		active->flags & RXON_FLG_BAND_24G_MSK);

	/* Check if we are switching association toggle */
	CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK,
		active->filter_flags & RXON_FILTER_ASSOC_MSK);

#undef CHK
#undef CHK_NEQ

	return 0;
}
S
Stanislaw Gruszka 已提交
559
EXPORT_SYMBOL(il_full_rxon_required);
560

S
Stanislaw Gruszka 已提交
561
u8 il_get_lowest_plcp(struct il_priv *il,
S
Stanislaw Gruszka 已提交
562
			    struct il_rxon_context *ctx)
563 564 565 566 567 568
{
	/*
	 * Assign the lowest rate -- should really get this from
	 * the beacon skb from mac80211.
	 */
	if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK)
S
Stanislaw Gruszka 已提交
569
		return IL_RATE_1M_PLCP;
570
	else
S
Stanislaw Gruszka 已提交
571
		return IL_RATE_6M_PLCP;
572
}
S
Stanislaw Gruszka 已提交
573
EXPORT_SYMBOL(il_get_lowest_plcp);
574

S
Stanislaw Gruszka 已提交
575
static void _il_set_rxon_ht(struct il_priv *il,
S
Stanislaw Gruszka 已提交
576 577
			     struct il_ht_config *ht_conf,
			     struct il_rxon_context *ctx)
578
{
S
Stanislaw Gruszka 已提交
579
	struct il_rxon_cmd *rxon = &ctx->staging;
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596

	if (!ctx->ht.enabled) {
		rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
			RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
			RXON_FLG_HT40_PROT_MSK |
			RXON_FLG_HT_PROT_MSK);
		return;
	}

	rxon->flags |= cpu_to_le32(ctx->ht.protection <<
					RXON_FLG_HT_OPERATING_MODE_POS);

	/* Set up channel bandwidth:
	 * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
	/* clear the HT channel mode before set the mode */
	rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
			 RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
S
Stanislaw Gruszka 已提交
597
	if (il_is_ht40_tx_allowed(il, ctx, NULL)) {
598 599 600 601 602 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
		/* pure ht40 */
		if (ctx->ht.protection ==
				IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
			rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
			/* Note: control channel is opposite of extension channel */
			switch (ctx->ht.extension_chan_offset) {
			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
				rxon->flags &=
					~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
				break;
			case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
				rxon->flags |=
					RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
				break;
			}
		} else {
			/* Note: control channel is opposite of extension channel */
			switch (ctx->ht.extension_chan_offset) {
			case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
				rxon->flags &=
					~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
				rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
				break;
			case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
				rxon->flags |=
					RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
				rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
				break;
			case IEEE80211_HT_PARAM_CHA_SEC_NONE:
			default:
				/* channel location only valid if in Mixed mode */
629
				IL_ERR(
630 631 632 633 634 635 636 637
					"invalid extension channel offset\n");
				break;
			}
		}
	} else {
		rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
	}

S
Stanislaw Gruszka 已提交
638 639
	if (il->cfg->ops->hcmd->set_rxon_chain)
		il->cfg->ops->hcmd->set_rxon_chain(il, ctx);
640

641
	D_ASSOC("rxon flags 0x%X operation mode :0x%X "
642 643 644 645 646
			"extension channel offset 0x%x\n",
			le32_to_cpu(rxon->flags), ctx->ht.protection,
			ctx->ht.extension_chan_offset);
}

S
Stanislaw Gruszka 已提交
647
void il_set_rxon_ht(struct il_priv *il, struct il_ht_config *ht_conf)
648
{
S
Stanislaw Gruszka 已提交
649
	struct il_rxon_context *ctx;
650

S
Stanislaw Gruszka 已提交
651 652
	for_each_context(il, ctx)
		_il_set_rxon_ht(il, ht_conf, ctx);
653
}
S
Stanislaw Gruszka 已提交
654
EXPORT_SYMBOL(il_set_rxon_ht);
655 656

/* Return valid, unused, channel for a passive scan to reset the RF */
S
Stanislaw Gruszka 已提交
657
u8 il_get_single_channel_number(struct il_priv *il,
658 659
				 enum ieee80211_band band)
{
S
Stanislaw Gruszka 已提交
660
	const struct il_channel_info *ch_info;
661 662 663
	int i;
	u8 channel = 0;
	u8 min, max;
S
Stanislaw Gruszka 已提交
664
	struct il_rxon_context *ctx;
665 666 667

	if (band == IEEE80211_BAND_5GHZ) {
		min = 14;
S
Stanislaw Gruszka 已提交
668
		max = il->channel_count;
669 670 671 672 673 674 675 676
	} else {
		min = 0;
		max = 14;
	}

	for (i = min; i < max; i++) {
		bool busy = false;

S
Stanislaw Gruszka 已提交
677 678
		for_each_context(il, ctx) {
			busy = il->channel_info[i].channel ==
679 680 681 682 683 684 685 686
				le16_to_cpu(ctx->staging.channel);
			if (busy)
				break;
		}

		if (busy)
			continue;

S
Stanislaw Gruszka 已提交
687 688
		channel = il->channel_info[i].channel;
		ch_info = il_get_channel_info(il, band, channel);
S
Stanislaw Gruszka 已提交
689
		if (il_is_channel_valid(ch_info))
690 691 692 693 694
			break;
	}

	return channel;
}
S
Stanislaw Gruszka 已提交
695
EXPORT_SYMBOL(il_get_single_channel_number);
696 697

/**
S
Stanislaw Gruszka 已提交
698
 * il_set_rxon_channel - Set the band and channel values in staging RXON
699 700 701 702 703 704
 * @ch: requested channel as a pointer to struct ieee80211_channel

 * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
 * in the staging RXON flag structure based on the ch->band
 */
int
S
Stanislaw Gruszka 已提交
705
il_set_rxon_channel(struct il_priv *il, struct ieee80211_channel *ch,
S
Stanislaw Gruszka 已提交
706
			 struct il_rxon_context *ctx)
707 708 709 710 711
{
	enum ieee80211_band band = ch->band;
	u16 channel = ch->hw_value;

	if ((le16_to_cpu(ctx->staging.channel) == channel) &&
S
Stanislaw Gruszka 已提交
712
	    (il->band == band))
713 714 715 716 717 718 719 720
		return 0;

	ctx->staging.channel = cpu_to_le16(channel);
	if (band == IEEE80211_BAND_5GHZ)
		ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK;
	else
		ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;

S
Stanislaw Gruszka 已提交
721
	il->band = band;
722

723
	D_INFO("Staging channel set to %d [%d]\n", channel, band);
724 725 726

	return 0;
}
S
Stanislaw Gruszka 已提交
727
EXPORT_SYMBOL(il_set_rxon_channel);
728

S
Stanislaw Gruszka 已提交
729
void il_set_flags_for_band(struct il_priv *il,
S
Stanislaw Gruszka 已提交
730
			    struct il_rxon_context *ctx,
731 732 733 734 735 736 737 738 739
			    enum ieee80211_band band,
			    struct ieee80211_vif *vif)
{
	if (band == IEEE80211_BAND_5GHZ) {
		ctx->staging.flags &=
		    ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
		      | RXON_FLG_CCK_MSK);
		ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
	} else {
S
Stanislaw Gruszka 已提交
740
		/* Copied from il_post_associate() */
741 742 743 744 745 746 747 748 749 750
		if (vif && vif->bss_conf.use_short_slot)
			ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
		else
			ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;

		ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
		ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK;
		ctx->staging.flags &= ~RXON_FLG_CCK_MSK;
	}
}
S
Stanislaw Gruszka 已提交
751
EXPORT_SYMBOL(il_set_flags_for_band);
752 753 754 755

/*
 * initialize rxon structure with default values from eeprom
 */
S
Stanislaw Gruszka 已提交
756
void il_connection_init_rx_config(struct il_priv *il,
S
Stanislaw Gruszka 已提交
757
				   struct il_rxon_context *ctx)
758
{
S
Stanislaw Gruszka 已提交
759
	const struct il_channel_info *ch_info;
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780

	memset(&ctx->staging, 0, sizeof(ctx->staging));

	if (!ctx->vif) {
		ctx->staging.dev_type = ctx->unused_devtype;
	} else
	switch (ctx->vif->type) {

	case NL80211_IFTYPE_STATION:
		ctx->staging.dev_type = ctx->station_devtype;
		ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
		break;

	case NL80211_IFTYPE_ADHOC:
		ctx->staging.dev_type = ctx->ibss_devtype;
		ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
		ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
						  RXON_FILTER_ACCEPT_GRP_MSK;
		break;

	default:
781
		IL_ERR("Unsupported interface type %d\n",
782 783 784 785 786 787 788
			ctx->vif->type);
		break;
	}

#if 0
	/* TODO:  Figure out when short_preamble would be set and cache from
	 * that */
S
Stanislaw Gruszka 已提交
789
	if (!hw_to_local(il->hw)->short_preamble)
790 791 792 793 794
		ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
	else
		ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
#endif

S
Stanislaw Gruszka 已提交
795
	ch_info = il_get_channel_info(il, il->band,
796 797 798
				       le16_to_cpu(ctx->active.channel));

	if (!ch_info)
S
Stanislaw Gruszka 已提交
799
		ch_info = &il->channel_info[0];
800 801

	ctx->staging.channel = cpu_to_le16(ch_info->channel);
S
Stanislaw Gruszka 已提交
802
	il->band = ch_info->band;
803

S
Stanislaw Gruszka 已提交
804
	il_set_flags_for_band(il, ctx, il->band, ctx->vif);
805 806

	ctx->staging.ofdm_basic_rates =
S
Stanislaw Gruszka 已提交
807
	    (IL_OFDM_RATES_MASK >> IL_FIRST_OFDM_RATE) & 0xFF;
808
	ctx->staging.cck_basic_rates =
S
Stanislaw Gruszka 已提交
809
	    (IL_CCK_RATES_MASK >> IL_FIRST_CCK_RATE) & 0xF;
810 811 812 813 814 815 816 817 818 819

	/* clear both MIX and PURE40 mode flag */
	ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
					RXON_FLG_CHANNEL_MODE_PURE_40);
	if (ctx->vif)
		memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN);

	ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff;
	ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff;
}
S
Stanislaw Gruszka 已提交
820
EXPORT_SYMBOL(il_connection_init_rx_config);
821

S
Stanislaw Gruszka 已提交
822
void il_set_rate(struct il_priv *il)
823 824 825
{
	const struct ieee80211_supported_band *hw = NULL;
	struct ieee80211_rate *rate;
S
Stanislaw Gruszka 已提交
826
	struct il_rxon_context *ctx;
827 828
	int i;

S
Stanislaw Gruszka 已提交
829
	hw = il_get_hw_mode(il, il->band);
830
	if (!hw) {
831
		IL_ERR("Failed to set rate: unable to get hw mode\n");
832 833 834
		return;
	}

S
Stanislaw Gruszka 已提交
835
	il->active_rate = 0;
836 837 838

	for (i = 0; i < hw->n_bitrates; i++) {
		rate = &(hw->bitrates[i]);
S
Stanislaw Gruszka 已提交
839
		if (rate->hw_value < IL_RATE_COUNT_LEGACY)
S
Stanislaw Gruszka 已提交
840
			il->active_rate |= (1 << rate->hw_value);
841 842
	}

843
	D_RATE("Set active_rate = %0x\n", il->active_rate);
844

S
Stanislaw Gruszka 已提交
845
	for_each_context(il, ctx) {
846
		ctx->staging.cck_basic_rates =
S
Stanislaw Gruszka 已提交
847
		    (IL_CCK_BASIC_RATES_MASK >> IL_FIRST_CCK_RATE) & 0xF;
848 849

		ctx->staging.ofdm_basic_rates =
S
Stanislaw Gruszka 已提交
850
		   (IL_OFDM_BASIC_RATES_MASK >> IL_FIRST_OFDM_RATE) & 0xFF;
851 852
	}
}
S
Stanislaw Gruszka 已提交
853
EXPORT_SYMBOL(il_set_rate);
854

S
Stanislaw Gruszka 已提交
855
void il_chswitch_done(struct il_priv *il, bool is_success)
856
{
S
Stanislaw Gruszka 已提交
857
	struct il_rxon_context *ctx = &il->contexts[IL_RXON_CTX_BSS];
858

S
Stanislaw Gruszka 已提交
859
	if (test_bit(STATUS_EXIT_PENDING, &il->status))
860 861
		return;

S
Stanislaw Gruszka 已提交
862
	if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &il->status))
863 864
		ieee80211_chswitch_done(ctx->vif, is_success);
}
S
Stanislaw Gruszka 已提交
865
EXPORT_SYMBOL(il_chswitch_done);
866

S
Stanislaw Gruszka 已提交
867
void il_rx_csa(struct il_priv *il, struct il_rx_mem_buffer *rxb)
868
{
S
Stanislaw Gruszka 已提交
869 870
	struct il_rx_packet *pkt = rxb_addr(rxb);
	struct il_csa_notification *csa = &(pkt->u.csa_notif);
871

S
Stanislaw Gruszka 已提交
872
	struct il_rxon_context *ctx = &il->contexts[IL_RXON_CTX_BSS];
S
Stanislaw Gruszka 已提交
873
	struct il_rxon_cmd *rxon = (void *)&ctx->active;
874

S
Stanislaw Gruszka 已提交
875
	if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &il->status))
876 877
		return;

S
Stanislaw Gruszka 已提交
878
	if (!le32_to_cpu(csa->status) && csa->channel == il->switch_channel) {
879 880
		rxon->channel = csa->channel;
		ctx->staging.channel = csa->channel;
881
		D_11H("CSA notif: channel %d\n",
882
			      le16_to_cpu(csa->channel));
S
Stanislaw Gruszka 已提交
883
		il_chswitch_done(il, true);
884
	} else {
885
		IL_ERR("CSA notif (fail) : channel %d\n",
886
			le16_to_cpu(csa->channel));
S
Stanislaw Gruszka 已提交
887
		il_chswitch_done(il, false);
888 889
	}
}
S
Stanislaw Gruszka 已提交
890
EXPORT_SYMBOL(il_rx_csa);
891 892

#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
S
Stanislaw Gruszka 已提交
893
void il_print_rx_config_cmd(struct il_priv *il,
S
Stanislaw Gruszka 已提交
894
			     struct il_rxon_context *ctx)
895
{
S
Stanislaw Gruszka 已提交
896
	struct il_rxon_cmd *rxon = &ctx->staging;
897

898
	D_RADIO("RX CONFIG:\n");
S
Stanislaw Gruszka 已提交
899
	il_print_hex_dump(il, IL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
900
	D_RADIO("u16 channel: 0x%x\n",
901
				le16_to_cpu(rxon->channel));
902 903
	D_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
	D_RADIO("u32 filter_flags: 0x%08x\n",
904
				le32_to_cpu(rxon->filter_flags));
905 906
	D_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type);
	D_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
907
			rxon->ofdm_basic_rates);
908
	D_RADIO("u8 cck_basic_rates: 0x%02x\n",
909
				rxon->cck_basic_rates);
910 911 912
	D_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr);
	D_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
	D_RADIO("u16 assoc_id: 0x%x\n",
913 914
				le16_to_cpu(rxon->assoc_id));
}
S
Stanislaw Gruszka 已提交
915
EXPORT_SYMBOL(il_print_rx_config_cmd);
916 917
#endif
/**
S
Stanislaw Gruszka 已提交
918
 * il_irq_handle_error - called for HW or SW error interrupt from card
919
 */
S
Stanislaw Gruszka 已提交
920
void il_irq_handle_error(struct il_priv *il)
921
{
S
Stanislaw Gruszka 已提交
922
	/* Set the FW error flag -- cleared on il_down */
S
Stanislaw Gruszka 已提交
923
	set_bit(STATUS_FW_ERROR, &il->status);
924 925

	/* Cancel currently queued command. */
S
Stanislaw Gruszka 已提交
926
	clear_bit(STATUS_HCMD_ACTIVE, &il->status);
927

928
	IL_ERR("Loaded firmware version: %s\n",
S
Stanislaw Gruszka 已提交
929
		il->hw->wiphy->fw_version);
930

S
Stanislaw Gruszka 已提交
931 932 933
	il->cfg->ops->lib->dump_nic_error_log(il);
	if (il->cfg->ops->lib->dump_fh)
		il->cfg->ops->lib->dump_fh(il, NULL, false);
934
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
S
Stanislaw Gruszka 已提交
935 936 937
	if (il_get_debug_level(il) & IL_DL_FW_ERRORS)
		il_print_rx_config_cmd(il,
					&il->contexts[IL_RXON_CTX_BSS]);
938 939
#endif

S
Stanislaw Gruszka 已提交
940
	wake_up(&il->wait_command_queue);
941 942 943

	/* Keep the restart process from trying to send host
	 * commands by clearing the INIT status bit */
S
Stanislaw Gruszka 已提交
944
	clear_bit(STATUS_READY, &il->status);
945

S
Stanislaw Gruszka 已提交
946
	if (!test_bit(STATUS_EXIT_PENDING, &il->status)) {
947
		IL_DBG(IL_DL_FW_ERRORS,
948 949
			  "Restarting adapter due to uCode error.\n");

S
Stanislaw Gruszka 已提交
950 951
		if (il->cfg->mod_params->restart_fw)
			queue_work(il->workqueue, &il->restart);
952 953
	}
}
S
Stanislaw Gruszka 已提交
954
EXPORT_SYMBOL(il_irq_handle_error);
955

S
Stanislaw Gruszka 已提交
956
static int il_apm_stop_master(struct il_priv *il)
957 958 959 960
{
	int ret = 0;

	/* stop device's busmaster DMA activity */
S
Stanislaw Gruszka 已提交
961
	il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
962

963
	ret = _il_poll_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED,
964 965
			CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
	if (ret)
966
		IL_WARN("Master Disable Timed Out, 100 usec\n");
967

968
	D_INFO("stop master\n");
969 970 971 972

	return ret;
}

S
Stanislaw Gruszka 已提交
973
void il_apm_stop(struct il_priv *il)
974
{
975
	D_INFO("Stop card, put in low power state\n");
976 977

	/* Stop device's DMA activity */
S
Stanislaw Gruszka 已提交
978
	il_apm_stop_master(il);
979 980

	/* Reset the entire device */
S
Stanislaw Gruszka 已提交
981
	il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
982 983 984 985 986 987 988

	udelay(10);

	/*
	 * Clear "initialization complete" bit to move adapter from
	 * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
	 */
S
Stanislaw Gruszka 已提交
989
	il_clear_bit(il, CSR_GP_CNTRL,
990 991
				CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
}
S
Stanislaw Gruszka 已提交
992
EXPORT_SYMBOL(il_apm_stop);
993 994 995 996


/*
 * Start up NIC's basic functionality after it has been reset
S
Stanislaw Gruszka 已提交
997
 * (e.g. after platform boot, or shutdown via il_apm_stop())
998 999
 * NOTE:  This does not load uCode nor start the embedded processor
 */
S
Stanislaw Gruszka 已提交
1000
int il_apm_init(struct il_priv *il)
1001 1002 1003 1004
{
	int ret = 0;
	u16 lctl;

1005
	D_INFO("Init card's basic functions\n");
1006 1007 1008 1009 1010 1011 1012

	/*
	 * Use "set_bit" below rather than "write", to preserve any hardware
	 * bits already set by default after reset.
	 */

	/* Disable L0S exit timer (platform NMI Work/Around) */
S
Stanislaw Gruszka 已提交
1013
	il_set_bit(il, CSR_GIO_CHICKEN_BITS,
1014 1015 1016 1017 1018 1019
			  CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);

	/*
	 * Disable L0s without affecting L1;
	 *  don't wait for ICH L0s (ICH bug W/A)
	 */
S
Stanislaw Gruszka 已提交
1020
	il_set_bit(il, CSR_GIO_CHICKEN_BITS,
1021 1022 1023
			  CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);

	/* Set FH wait threshold to maximum (HW error during stress W/A) */
S
Stanislaw Gruszka 已提交
1024
	il_set_bit(il, CSR_DBG_HPET_MEM_REG,
1025 1026 1027 1028 1029
					CSR_DBG_HPET_MEM_REG_VAL);

	/*
	 * Enable HAP INTA (interrupt from management bus) to
	 * wake device's PCI Express link L1a -> L0s
L
Lucas De Marchi 已提交
1030
	 * NOTE:  This is no-op for 3945 (non-existent bit)
1031
	 */
S
Stanislaw Gruszka 已提交
1032
	il_set_bit(il, CSR_HW_IF_CONFIG_REG,
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
				    CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);

	/*
	 * HW bug W/A for instability in PCIe bus L0->L0S->L1 transition.
	 * Check if BIOS (or OS) enabled L1-ASPM on this device.
	 * If so (likely), disable L0S, so device moves directly L0->L1;
	 *    costs negligible amount of power savings.
	 * If not (unlikely), enable L0S, so there is at least some
	 *    power savings, even without L1.
	 */
S
Stanislaw Gruszka 已提交
1043 1044
	if (il->cfg->base_params->set_l0s) {
		lctl = il_pcie_link_ctl(il);
1045 1046 1047
		if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
					PCI_CFG_LINK_CTRL_VAL_L1_EN) {
			/* L1-ASPM enabled; disable(!) L0S  */
S
Stanislaw Gruszka 已提交
1048
			il_set_bit(il, CSR_GIO_REG,
1049
					CSR_GIO_REG_VAL_L0S_ENABLED);
1050
			D_POWER("L1 Enabled; Disabling L0S\n");
1051 1052
		} else {
			/* L1-ASPM disabled; enable(!) L0S */
S
Stanislaw Gruszka 已提交
1053
			il_clear_bit(il, CSR_GIO_REG,
1054
					CSR_GIO_REG_VAL_L0S_ENABLED);
1055
			D_POWER("L1 Disabled; Enabling L0S\n");
1056 1057 1058 1059
		}
	}

	/* Configure analog phase-lock-loop before activating to D0A */
S
Stanislaw Gruszka 已提交
1060 1061 1062
	if (il->cfg->base_params->pll_cfg_val)
		il_set_bit(il, CSR_ANA_PLL_CFG,
			    il->cfg->base_params->pll_cfg_val);
1063 1064 1065 1066 1067

	/*
	 * Set "initialization complete" bit to move adapter from
	 * D0U* --> D0A* (powered-up active) state.
	 */
S
Stanislaw Gruszka 已提交
1068
	il_set_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
1069 1070 1071

	/*
	 * Wait for clock stabilization; once stabilized, access to
S
Stanislaw Gruszka 已提交
1072
	 * device-internal resources is supported, e.g. il_write_prph()
1073 1074
	 * and accesses to uCode SRAM.
	 */
1075
	ret = _il_poll_bit(il, CSR_GP_CNTRL,
1076 1077 1078
			CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
			CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
	if (ret < 0) {
1079
		D_INFO("Failed to init the card\n");
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
		goto out;
	}

	/*
	 * Enable DMA and BSM (if used) clocks, wait for them to stabilize.
	 * BSM (Boostrap State Machine) is only in 3945 and 4965.
	 *
	 * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
	 * do not disable clocks.  This preserves any hardware bits already
	 * set by default in "CLK_CTRL_REG" after reset.
	 */
S
Stanislaw Gruszka 已提交
1091 1092
	if (il->cfg->base_params->use_bsm)
		il_write_prph(il, APMG_CLK_EN_REG,
1093 1094
			APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
	else
S
Stanislaw Gruszka 已提交
1095
		il_write_prph(il, APMG_CLK_EN_REG,
1096 1097 1098 1099
			APMG_CLK_VAL_DMA_CLK_RQT);
	udelay(20);

	/* Disable L1-Active */
S
Stanislaw Gruszka 已提交
1100
	il_set_bits_prph(il, APMG_PCIDEV_STT_REG,
1101 1102 1103 1104 1105
			  APMG_PCIDEV_STT_VAL_L1_ACT_DIS);

out:
	return ret;
}
S
Stanislaw Gruszka 已提交
1106
EXPORT_SYMBOL(il_apm_init);
1107 1108


S
Stanislaw Gruszka 已提交
1109
int il_set_tx_power(struct il_priv *il, s8 tx_power, bool force)
1110 1111 1112
{
	int ret;
	s8 prev_tx_power;
1113
	bool defer;
S
Stanislaw Gruszka 已提交
1114
	struct il_rxon_context *ctx = &il->contexts[IL_RXON_CTX_BSS];
1115

S
Stanislaw Gruszka 已提交
1116
	lockdep_assert_held(&il->mutex);
1117

S
Stanislaw Gruszka 已提交
1118
	if (il->tx_power_user_lmt == tx_power && !force)
1119 1120
		return 0;

S
Stanislaw Gruszka 已提交
1121
	if (!il->cfg->ops->lib->send_tx_power)
1122 1123
		return -EOPNOTSUPP;

1124 1125
	/* 0 dBm mean 1 milliwatt */
	if (tx_power < 0) {
1126
		IL_WARN(
1127 1128
			 "Requested user TXPOWER %d below 1 mW.\n",
			 tx_power);
1129 1130 1131
		return -EINVAL;
	}

S
Stanislaw Gruszka 已提交
1132
	if (tx_power > il->tx_power_device_lmt) {
1133
		IL_WARN(
1134
			"Requested user TXPOWER %d above upper limit %d.\n",
S
Stanislaw Gruszka 已提交
1135
			 tx_power, il->tx_power_device_lmt);
1136 1137 1138
		return -EINVAL;
	}

S
Stanislaw Gruszka 已提交
1139
	if (!il_is_ready_rf(il))
1140 1141
		return -EIO;

1142 1143
	/* scan complete and commit_rxon use tx_power_next value,
	 * it always need to be updated for newest request */
S
Stanislaw Gruszka 已提交
1144
	il->tx_power_next = tx_power;
1145 1146

	/* do not set tx power when scanning or channel changing */
S
Stanislaw Gruszka 已提交
1147
	defer = test_bit(STATUS_SCANNING, &il->status) ||
1148 1149
		memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
	if (defer && !force) {
1150
		D_INFO("Deferring tx power set\n");
1151 1152 1153
		return 0;
	}

S
Stanislaw Gruszka 已提交
1154 1155
	prev_tx_power = il->tx_power_user_lmt;
	il->tx_power_user_lmt = tx_power;
1156

S
Stanislaw Gruszka 已提交
1157
	ret = il->cfg->ops->lib->send_tx_power(il);
1158 1159 1160

	/* if fail to set tx_power, restore the orig. tx power */
	if (ret) {
S
Stanislaw Gruszka 已提交
1161 1162
		il->tx_power_user_lmt = prev_tx_power;
		il->tx_power_next = prev_tx_power;
1163 1164 1165
	}
	return ret;
}
S
Stanislaw Gruszka 已提交
1166
EXPORT_SYMBOL(il_set_tx_power);
1167

S
Stanislaw Gruszka 已提交
1168
void il_send_bt_config(struct il_priv *il)
1169
{
S
Stanislaw Gruszka 已提交
1170
	struct il_bt_cmd bt_cmd = {
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
		.lead_time = BT_LEAD_TIME_DEF,
		.max_kill = BT_MAX_KILL_DEF,
		.kill_ack_mask = 0,
		.kill_cts_mask = 0,
	};

	if (!bt_coex_active)
		bt_cmd.flags = BT_COEX_DISABLE;
	else
		bt_cmd.flags = BT_COEX_ENABLE;

1182
	D_INFO("BT coex %s\n",
1183 1184
		(bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");

S
Stanislaw Gruszka 已提交
1185
	if (il_send_cmd_pdu(il, REPLY_BT_CONFIG,
S
Stanislaw Gruszka 已提交
1186
			     sizeof(struct il_bt_cmd), &bt_cmd))
1187
		IL_ERR("failed to send BT Coex Config\n");
1188
}
S
Stanislaw Gruszka 已提交
1189
EXPORT_SYMBOL(il_send_bt_config);
1190

S
Stanislaw Gruszka 已提交
1191
int il_send_statistics_request(struct il_priv *il, u8 flags, bool clear)
1192
{
S
Stanislaw Gruszka 已提交
1193
	struct il_statistics_cmd statistics_cmd = {
1194
		.configuration_flags =
S
Stanislaw Gruszka 已提交
1195
			clear ? IL_STATS_CONF_CLEAR_STATS : 0,
1196 1197 1198
	};

	if (flags & CMD_ASYNC)
S
Stanislaw Gruszka 已提交
1199
		return il_send_cmd_pdu_async(il, REPLY_STATISTICS_CMD,
S
Stanislaw Gruszka 已提交
1200
					sizeof(struct il_statistics_cmd),
1201 1202
					&statistics_cmd, NULL);
	else
S
Stanislaw Gruszka 已提交
1203
		return il_send_cmd_pdu(il, REPLY_STATISTICS_CMD,
S
Stanislaw Gruszka 已提交
1204
					sizeof(struct il_statistics_cmd),
1205 1206
					&statistics_cmd);
}
S
Stanislaw Gruszka 已提交
1207
EXPORT_SYMBOL(il_send_statistics_request);
1208

S
Stanislaw Gruszka 已提交
1209
void il_rx_pm_sleep_notif(struct il_priv *il,
S
Stanislaw Gruszka 已提交
1210
			   struct il_rx_mem_buffer *rxb)
1211 1212
{
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
S
Stanislaw Gruszka 已提交
1213 1214
	struct il_rx_packet *pkt = rxb_addr(rxb);
	struct il_sleep_notification *sleep = &(pkt->u.sleep_notif);
1215
	D_RX("sleep mode: %d, src: %d\n",
1216 1217 1218
		     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
#endif
}
S
Stanislaw Gruszka 已提交
1219
EXPORT_SYMBOL(il_rx_pm_sleep_notif);
1220

S
Stanislaw Gruszka 已提交
1221
void il_rx_pm_debug_statistics_notif(struct il_priv *il,
S
Stanislaw Gruszka 已提交
1222
				      struct il_rx_mem_buffer *rxb)
1223
{
S
Stanislaw Gruszka 已提交
1224
	struct il_rx_packet *pkt = rxb_addr(rxb);
1225
	u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
1226
	D_RADIO("Dumping %d bytes of unhandled "
1227
			"notification for %s:\n", len,
S
Stanislaw Gruszka 已提交
1228
			il_get_cmd_string(pkt->hdr.cmd));
S
Stanislaw Gruszka 已提交
1229
	il_print_hex_dump(il, IL_DL_RADIO, pkt->u.raw, len);
1230
}
S
Stanislaw Gruszka 已提交
1231
EXPORT_SYMBOL(il_rx_pm_debug_statistics_notif);
1232

S
Stanislaw Gruszka 已提交
1233
void il_rx_reply_error(struct il_priv *il,
S
Stanislaw Gruszka 已提交
1234
			struct il_rx_mem_buffer *rxb)
1235
{
S
Stanislaw Gruszka 已提交
1236
	struct il_rx_packet *pkt = rxb_addr(rxb);
1237

1238
	IL_ERR("Error Reply type 0x%08X cmd %s (0x%02X) "
1239 1240
		"seq 0x%04X ser 0x%08X\n",
		le32_to_cpu(pkt->u.err_resp.error_type),
S
Stanislaw Gruszka 已提交
1241
		il_get_cmd_string(pkt->u.err_resp.cmd_id),
1242 1243 1244 1245
		pkt->u.err_resp.cmd_id,
		le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
		le32_to_cpu(pkt->u.err_resp.error_info));
}
S
Stanislaw Gruszka 已提交
1246
EXPORT_SYMBOL(il_rx_reply_error);
1247

S
Stanislaw Gruszka 已提交
1248
void il_clear_isr_stats(struct il_priv *il)
1249
{
S
Stanislaw Gruszka 已提交
1250
	memset(&il->isr_stats, 0, sizeof(il->isr_stats));
1251 1252
}

S
Stanislaw Gruszka 已提交
1253
int il_mac_conf_tx(struct ieee80211_hw *hw,
1254
			   struct ieee80211_vif *vif, u16 queue,
1255 1256
			   const struct ieee80211_tx_queue_params *params)
{
S
Stanislaw Gruszka 已提交
1257
	struct il_priv *il = hw->priv;
S
Stanislaw Gruszka 已提交
1258
	struct il_rxon_context *ctx;
1259 1260 1261
	unsigned long flags;
	int q;

1262
	D_MAC80211("enter\n");
1263

S
Stanislaw Gruszka 已提交
1264
	if (!il_is_ready_rf(il)) {
1265
		D_MAC80211("leave - RF not ready\n");
1266 1267 1268 1269
		return -EIO;
	}

	if (queue >= AC_NUM) {
1270
		D_MAC80211("leave - queue >= AC_NUM %d\n", queue);
1271 1272 1273 1274 1275
		return 0;
	}

	q = AC_NUM - 1 - queue;

S
Stanislaw Gruszka 已提交
1276
	spin_lock_irqsave(&il->lock, flags);
1277

S
Stanislaw Gruszka 已提交
1278
	for_each_context(il, ctx) {
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
		ctx->qos_data.def_qos_parm.ac[q].cw_min =
			cpu_to_le16(params->cw_min);
		ctx->qos_data.def_qos_parm.ac[q].cw_max =
			cpu_to_le16(params->cw_max);
		ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
		ctx->qos_data.def_qos_parm.ac[q].edca_txop =
				cpu_to_le16((params->txop * 32));

		ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
	}

S
Stanislaw Gruszka 已提交
1290
	spin_unlock_irqrestore(&il->lock, flags);
1291

1292
	D_MAC80211("leave\n");
1293 1294
	return 0;
}
S
Stanislaw Gruszka 已提交
1295
EXPORT_SYMBOL(il_mac_conf_tx);
1296

S
Stanislaw Gruszka 已提交
1297
int il_mac_tx_last_beacon(struct ieee80211_hw *hw)
1298
{
S
Stanislaw Gruszka 已提交
1299
	struct il_priv *il = hw->priv;
1300

S
Stanislaw Gruszka 已提交
1301
	return il->ibss_manager == IL_IBSS_MANAGER;
1302
}
S
Stanislaw Gruszka 已提交
1303
EXPORT_SYMBOL_GPL(il_mac_tx_last_beacon);
1304 1305

static int
S
Stanislaw Gruszka 已提交
1306
il_set_mode(struct il_priv *il, struct il_rxon_context *ctx)
1307
{
S
Stanislaw Gruszka 已提交
1308
	il_connection_init_rx_config(il, ctx);
1309

S
Stanislaw Gruszka 已提交
1310 1311
	if (il->cfg->ops->hcmd->set_rxon_chain)
		il->cfg->ops->hcmd->set_rxon_chain(il, ctx);
1312

S
Stanislaw Gruszka 已提交
1313
	return il_commit_rxon(il, ctx);
1314 1315
}

S
Stanislaw Gruszka 已提交
1316
static int il_setup_interface(struct il_priv *il,
S
Stanislaw Gruszka 已提交
1317
			       struct il_rxon_context *ctx)
1318 1319 1320 1321
{
	struct ieee80211_vif *vif = ctx->vif;
	int err;

S
Stanislaw Gruszka 已提交
1322
	lockdep_assert_held(&il->mutex);
1323 1324 1325 1326 1327 1328

	/*
	 * This variable will be correct only when there's just
	 * a single context, but all code using it is for hardware
	 * that supports only one context.
	 */
S
Stanislaw Gruszka 已提交
1329
	il->iw_mode = vif->type;
1330 1331 1332

	ctx->is_active = true;

S
Stanislaw Gruszka 已提交
1333
	err = il_set_mode(il, ctx);
1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
	if (err) {
		if (!ctx->always_active)
			ctx->is_active = false;
		return err;
	}

	return 0;
}

int
S
Stanislaw Gruszka 已提交
1344
il_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
1345
{
S
Stanislaw Gruszka 已提交
1346
	struct il_priv *il = hw->priv;
S
Stanislaw Gruszka 已提交
1347 1348
	struct il_vif_priv *vif_priv = (void *)vif->drv_priv;
	struct il_rxon_context *tmp, *ctx = NULL;
1349 1350
	int err;

1351
	D_MAC80211("enter: type %d, addr %pM\n",
1352 1353
			   vif->type, vif->addr);

S
Stanislaw Gruszka 已提交
1354
	mutex_lock(&il->mutex);
1355

S
Stanislaw Gruszka 已提交
1356
	if (!il_is_ready_rf(il)) {
1357
		IL_WARN("Try to add interface when device not ready\n");
1358 1359 1360 1361
		err = -EINVAL;
		goto out;
	}

S
Stanislaw Gruszka 已提交
1362
	for_each_context(il, tmp) {
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
		u32 possible_modes =
			tmp->interface_modes | tmp->exclusive_interface_modes;

		if (tmp->vif) {
			/* check if this busy context is exclusive */
			if (tmp->exclusive_interface_modes &
						BIT(tmp->vif->type)) {
				err = -EINVAL;
				goto out;
			}
			continue;
		}

		if (!(possible_modes & BIT(vif->type)))
			continue;

		/* have maybe usable context w/o interface */
		ctx = tmp;
		break;
	}

	if (!ctx) {
		err = -EOPNOTSUPP;
		goto out;
	}

	vif_priv->ctx = ctx;
	ctx->vif = vif;

S
Stanislaw Gruszka 已提交
1392
	err = il_setup_interface(il, ctx);
1393 1394 1395 1396
	if (!err)
		goto out;

	ctx->vif = NULL;
S
Stanislaw Gruszka 已提交
1397
	il->iw_mode = NL80211_IFTYPE_STATION;
1398
 out:
S
Stanislaw Gruszka 已提交
1399
	mutex_unlock(&il->mutex);
1400

1401
	D_MAC80211("leave\n");
1402 1403
	return err;
}
S
Stanislaw Gruszka 已提交
1404
EXPORT_SYMBOL(il_mac_add_interface);
1405

S
Stanislaw Gruszka 已提交
1406
static void il_teardown_interface(struct il_priv *il,
1407 1408 1409
				   struct ieee80211_vif *vif,
				   bool mode_change)
{
S
Stanislaw Gruszka 已提交
1410
	struct il_rxon_context *ctx = il_rxon_ctx_from_vif(vif);
1411

S
Stanislaw Gruszka 已提交
1412
	lockdep_assert_held(&il->mutex);
1413

S
Stanislaw Gruszka 已提交
1414 1415 1416
	if (il->scan_vif == vif) {
		il_scan_cancel_timeout(il, 200);
		il_force_scan_end(il);
1417 1418 1419
	}

	if (!mode_change) {
S
Stanislaw Gruszka 已提交
1420
		il_set_mode(il, ctx);
1421 1422 1423 1424 1425
		if (!ctx->always_active)
			ctx->is_active = false;
	}
}

S
Stanislaw Gruszka 已提交
1426
void il_mac_remove_interface(struct ieee80211_hw *hw,
1427 1428
			      struct ieee80211_vif *vif)
{
S
Stanislaw Gruszka 已提交
1429
	struct il_priv *il = hw->priv;
S
Stanislaw Gruszka 已提交
1430
	struct il_rxon_context *ctx = il_rxon_ctx_from_vif(vif);
1431

1432
	D_MAC80211("enter\n");
1433

S
Stanislaw Gruszka 已提交
1434
	mutex_lock(&il->mutex);
1435 1436 1437 1438

	WARN_ON(ctx->vif != vif);
	ctx->vif = NULL;

S
Stanislaw Gruszka 已提交
1439
	il_teardown_interface(il, vif, false);
1440

S
Stanislaw Gruszka 已提交
1441 1442
	memset(il->bssid, 0, ETH_ALEN);
	mutex_unlock(&il->mutex);
1443

1444
	D_MAC80211("leave\n");
1445 1446

}
S
Stanislaw Gruszka 已提交
1447
EXPORT_SYMBOL(il_mac_remove_interface);
1448

S
Stanislaw Gruszka 已提交
1449
int il_alloc_txq_mem(struct il_priv *il)
1450
{
S
Stanislaw Gruszka 已提交
1451 1452
	if (!il->txq)
		il->txq = kzalloc(
S
Stanislaw Gruszka 已提交
1453
			sizeof(struct il_tx_queue) *
S
Stanislaw Gruszka 已提交
1454
				il->cfg->base_params->num_of_queues,
1455
			GFP_KERNEL);
S
Stanislaw Gruszka 已提交
1456
	if (!il->txq) {
1457
		IL_ERR("Not enough memory for txq\n");
1458 1459 1460 1461
		return -ENOMEM;
	}
	return 0;
}
S
Stanislaw Gruszka 已提交
1462
EXPORT_SYMBOL(il_alloc_txq_mem);
1463

S
Stanislaw Gruszka 已提交
1464
void il_txq_mem(struct il_priv *il)
1465
{
S
Stanislaw Gruszka 已提交
1466 1467
	kfree(il->txq);
	il->txq = NULL;
1468
}
S
Stanislaw Gruszka 已提交
1469
EXPORT_SYMBOL(il_txq_mem);
1470 1471 1472

#ifdef CONFIG_IWLWIFI_LEGACY_DEBUGFS

S
Stanislaw Gruszka 已提交
1473
#define IL_TRAFFIC_DUMP_SIZE	(IL_TRAFFIC_ENTRY_SIZE * IL_TRAFFIC_ENTRIES)
1474

S
Stanislaw Gruszka 已提交
1475
void il_reset_traffic_log(struct il_priv *il)
1476
{
S
Stanislaw Gruszka 已提交
1477 1478 1479 1480 1481 1482
	il->tx_traffic_idx = 0;
	il->rx_traffic_idx = 0;
	if (il->tx_traffic)
		memset(il->tx_traffic, 0, IL_TRAFFIC_DUMP_SIZE);
	if (il->rx_traffic)
		memset(il->rx_traffic, 0, IL_TRAFFIC_DUMP_SIZE);
1483 1484
}

S
Stanislaw Gruszka 已提交
1485
int il_alloc_traffic_mem(struct il_priv *il)
1486
{
S
Stanislaw Gruszka 已提交
1487
	u32 traffic_size = IL_TRAFFIC_DUMP_SIZE;
1488

1489
	if (il_debug_level & IL_DL_TX) {
S
Stanislaw Gruszka 已提交
1490 1491
		if (!il->tx_traffic) {
			il->tx_traffic =
1492
				kzalloc(traffic_size, GFP_KERNEL);
S
Stanislaw Gruszka 已提交
1493
			if (!il->tx_traffic)
1494 1495 1496
				return -ENOMEM;
		}
	}
1497
	if (il_debug_level & IL_DL_RX) {
S
Stanislaw Gruszka 已提交
1498 1499
		if (!il->rx_traffic) {
			il->rx_traffic =
1500
				kzalloc(traffic_size, GFP_KERNEL);
S
Stanislaw Gruszka 已提交
1501
			if (!il->rx_traffic)
1502 1503 1504
				return -ENOMEM;
		}
	}
S
Stanislaw Gruszka 已提交
1505
	il_reset_traffic_log(il);
1506 1507
	return 0;
}
S
Stanislaw Gruszka 已提交
1508
EXPORT_SYMBOL(il_alloc_traffic_mem);
1509

S
Stanislaw Gruszka 已提交
1510
void il_free_traffic_mem(struct il_priv *il)
1511
{
S
Stanislaw Gruszka 已提交
1512 1513
	kfree(il->tx_traffic);
	il->tx_traffic = NULL;
1514

S
Stanislaw Gruszka 已提交
1515 1516
	kfree(il->rx_traffic);
	il->rx_traffic = NULL;
1517
}
S
Stanislaw Gruszka 已提交
1518
EXPORT_SYMBOL(il_free_traffic_mem);
1519

S
Stanislaw Gruszka 已提交
1520
void il_dbg_log_tx_data_frame(struct il_priv *il,
1521 1522 1523 1524 1525
		      u16 length, struct ieee80211_hdr *header)
{
	__le16 fc;
	u16 len;

1526
	if (likely(!(il_debug_level & IL_DL_TX)))
1527 1528
		return;

S
Stanislaw Gruszka 已提交
1529
	if (!il->tx_traffic)
1530 1531 1532 1533
		return;

	fc = header->frame_control;
	if (ieee80211_is_data(fc)) {
S
Stanislaw Gruszka 已提交
1534 1535
		len = (length > IL_TRAFFIC_ENTRY_SIZE)
		       ? IL_TRAFFIC_ENTRY_SIZE : length;
S
Stanislaw Gruszka 已提交
1536 1537
		memcpy((il->tx_traffic +
		       (il->tx_traffic_idx * IL_TRAFFIC_ENTRY_SIZE)),
1538
		       header, len);
S
Stanislaw Gruszka 已提交
1539 1540
		il->tx_traffic_idx =
			(il->tx_traffic_idx + 1) % IL_TRAFFIC_ENTRIES;
1541 1542
	}
}
S
Stanislaw Gruszka 已提交
1543
EXPORT_SYMBOL(il_dbg_log_tx_data_frame);
1544

S
Stanislaw Gruszka 已提交
1545
void il_dbg_log_rx_data_frame(struct il_priv *il,
1546 1547 1548 1549 1550
		      u16 length, struct ieee80211_hdr *header)
{
	__le16 fc;
	u16 len;

1551
	if (likely(!(il_debug_level & IL_DL_RX)))
1552 1553
		return;

S
Stanislaw Gruszka 已提交
1554
	if (!il->rx_traffic)
1555 1556 1557 1558
		return;

	fc = header->frame_control;
	if (ieee80211_is_data(fc)) {
S
Stanislaw Gruszka 已提交
1559 1560
		len = (length > IL_TRAFFIC_ENTRY_SIZE)
		       ? IL_TRAFFIC_ENTRY_SIZE : length;
S
Stanislaw Gruszka 已提交
1561 1562
		memcpy((il->rx_traffic +
		       (il->rx_traffic_idx * IL_TRAFFIC_ENTRY_SIZE)),
1563
		       header, len);
S
Stanislaw Gruszka 已提交
1564 1565
		il->rx_traffic_idx =
			(il->rx_traffic_idx + 1) % IL_TRAFFIC_ENTRIES;
1566 1567
	}
}
S
Stanislaw Gruszka 已提交
1568
EXPORT_SYMBOL(il_dbg_log_rx_data_frame);
1569

S
Stanislaw Gruszka 已提交
1570
const char *il_get_mgmt_string(int cmd)
1571 1572
{
	switch (cmd) {
S
Stanislaw Gruszka 已提交
1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584
		IL_CMD(MANAGEMENT_ASSOC_REQ);
		IL_CMD(MANAGEMENT_ASSOC_RESP);
		IL_CMD(MANAGEMENT_REASSOC_REQ);
		IL_CMD(MANAGEMENT_REASSOC_RESP);
		IL_CMD(MANAGEMENT_PROBE_REQ);
		IL_CMD(MANAGEMENT_PROBE_RESP);
		IL_CMD(MANAGEMENT_BEACON);
		IL_CMD(MANAGEMENT_ATIM);
		IL_CMD(MANAGEMENT_DISASSOC);
		IL_CMD(MANAGEMENT_AUTH);
		IL_CMD(MANAGEMENT_DEAUTH);
		IL_CMD(MANAGEMENT_ACTION);
1585 1586 1587 1588 1589 1590
	default:
		return "UNKNOWN";

	}
}

S
Stanislaw Gruszka 已提交
1591
const char *il_get_ctrl_string(int cmd)
1592 1593
{
	switch (cmd) {
S
Stanislaw Gruszka 已提交
1594 1595 1596 1597 1598 1599 1600 1601
		IL_CMD(CONTROL_BACK_REQ);
		IL_CMD(CONTROL_BACK);
		IL_CMD(CONTROL_PSPOLL);
		IL_CMD(CONTROL_RTS);
		IL_CMD(CONTROL_CTS);
		IL_CMD(CONTROL_ACK);
		IL_CMD(CONTROL_CFEND);
		IL_CMD(CONTROL_CFENDACK);
1602 1603 1604 1605 1606 1607
	default:
		return "UNKNOWN";

	}
}

S
Stanislaw Gruszka 已提交
1608
void il_clear_traffic_stats(struct il_priv *il)
1609
{
S
Stanislaw Gruszka 已提交
1610 1611
	memset(&il->tx_stats, 0, sizeof(struct traffic_stats));
	memset(&il->rx_stats, 0, sizeof(struct traffic_stats));
1612 1613 1614 1615
}

/*
 * if CONFIG_IWLWIFI_LEGACY_DEBUGFS defined,
S
Stanislaw Gruszka 已提交
1616
 * il_update_stats function will
1617 1618 1619 1620
 * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass
 * Use debugFs to display the rx/rx_statistics
 * if CONFIG_IWLWIFI_LEGACY_DEBUGFS not being defined, then no MGMT and CTRL
 * information will be recorded, but DATA pkt still will be recorded
S
Stanislaw Gruszka 已提交
1621
 * for the reason of il_led.c need to control the led blinking based on
1622 1623 1624 1625
 * number of tx and rx data.
 *
 */
void
S
Stanislaw Gruszka 已提交
1626
il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len)
1627 1628 1629 1630
{
	struct traffic_stats	*stats;

	if (is_tx)
S
Stanislaw Gruszka 已提交
1631
		stats = &il->tx_stats;
1632
	else
S
Stanislaw Gruszka 已提交
1633
		stats = &il->rx_stats;
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706

	if (ieee80211_is_mgmt(fc)) {
		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
		case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
			stats->mgmt[MANAGEMENT_ASSOC_REQ]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
			stats->mgmt[MANAGEMENT_ASSOC_RESP]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
			stats->mgmt[MANAGEMENT_REASSOC_REQ]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
			stats->mgmt[MANAGEMENT_REASSOC_RESP]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
			stats->mgmt[MANAGEMENT_PROBE_REQ]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
			stats->mgmt[MANAGEMENT_PROBE_RESP]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_BEACON):
			stats->mgmt[MANAGEMENT_BEACON]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_ATIM):
			stats->mgmt[MANAGEMENT_ATIM]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
			stats->mgmt[MANAGEMENT_DISASSOC]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_AUTH):
			stats->mgmt[MANAGEMENT_AUTH]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
			stats->mgmt[MANAGEMENT_DEAUTH]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_ACTION):
			stats->mgmt[MANAGEMENT_ACTION]++;
			break;
		}
	} else if (ieee80211_is_ctl(fc)) {
		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
		case cpu_to_le16(IEEE80211_STYPE_BACK_REQ):
			stats->ctrl[CONTROL_BACK_REQ]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_BACK):
			stats->ctrl[CONTROL_BACK]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_PSPOLL):
			stats->ctrl[CONTROL_PSPOLL]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_RTS):
			stats->ctrl[CONTROL_RTS]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_CTS):
			stats->ctrl[CONTROL_CTS]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_ACK):
			stats->ctrl[CONTROL_ACK]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_CFEND):
			stats->ctrl[CONTROL_CFEND]++;
			break;
		case cpu_to_le16(IEEE80211_STYPE_CFENDACK):
			stats->ctrl[CONTROL_CFENDACK]++;
			break;
		}
	} else {
		/* data */
		stats->data_cnt++;
		stats->data_bytes += len;
	}
}
S
Stanislaw Gruszka 已提交
1707
EXPORT_SYMBOL(il_update_stats);
1708 1709
#endif

S
Stanislaw Gruszka 已提交
1710
int il_force_reset(struct il_priv *il, bool external)
1711
{
S
Stanislaw Gruszka 已提交
1712
	struct il_force_reset *force_reset;
1713

S
Stanislaw Gruszka 已提交
1714
	if (test_bit(STATUS_EXIT_PENDING, &il->status))
1715 1716
		return -EINVAL;

S
Stanislaw Gruszka 已提交
1717
	force_reset = &il->force_reset;
1718 1719 1720 1721 1722
	force_reset->reset_request_count++;
	if (!external) {
		if (force_reset->last_force_reset_jiffies &&
		    time_after(force_reset->last_force_reset_jiffies +
		    force_reset->reset_duration, jiffies)) {
1723
			D_INFO("force reset rejected\n");
1724 1725 1726 1727 1728 1729
			force_reset->reset_reject_count++;
			return -EAGAIN;
		}
	}
	force_reset->reset_success_count++;
	force_reset->last_force_reset_jiffies = jiffies;
1730 1731 1732 1733 1734 1735 1736 1737 1738 1739

	/*
	 * if the request is from external(ex: debugfs),
	 * then always perform the request in regardless the module
	 * parameter setting
	 * if the request is from internal (uCode error or driver
	 * detect failure), then fw_restart module parameter
	 * need to be check before performing firmware reload
	 */

S
Stanislaw Gruszka 已提交
1740
	if (!external && !il->cfg->mod_params->restart_fw) {
1741
		D_INFO("Cancel firmware reload based on "
1742 1743
			       "module parameter setting\n");
		return 0;
1744
	}
1745

1746
	IL_ERR("On demand firmware reload\n");
1747

S
Stanislaw Gruszka 已提交
1748
	/* Set the FW error flag -- cleared on il_down */
S
Stanislaw Gruszka 已提交
1749 1750
	set_bit(STATUS_FW_ERROR, &il->status);
	wake_up(&il->wait_command_queue);
1751 1752 1753 1754
	/*
	 * Keep the restart process from trying to send host
	 * commands by clearing the INIT status bit
	 */
S
Stanislaw Gruszka 已提交
1755 1756
	clear_bit(STATUS_READY, &il->status);
	queue_work(il->workqueue, &il->restart);
1757

1758 1759 1760 1761
	return 0;
}

int
S
Stanislaw Gruszka 已提交
1762
il_mac_change_interface(struct ieee80211_hw *hw,
1763 1764 1765
			struct ieee80211_vif *vif,
			enum nl80211_iftype newtype, bool newp2p)
{
S
Stanislaw Gruszka 已提交
1766
	struct il_priv *il = hw->priv;
S
Stanislaw Gruszka 已提交
1767 1768
	struct il_rxon_context *ctx = il_rxon_ctx_from_vif(vif);
	struct il_rxon_context *tmp;
1769 1770 1771 1772 1773
	u32 interface_modes;
	int err;

	newtype = ieee80211_iftype_p2p(newtype, newp2p);

S
Stanislaw Gruszka 已提交
1774
	mutex_lock(&il->mutex);
1775

S
Stanislaw Gruszka 已提交
1776
	if (!ctx->vif || !il_is_ready_rf(il)) {
1777 1778 1779 1780 1781 1782 1783 1784
		/*
		 * Huh? But wait ... this can maybe happen when
		 * we're in the middle of a firmware restart!
		 */
		err = -EBUSY;
		goto out;
	}

1785 1786 1787 1788 1789 1790 1791 1792
	interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;

	if (!(interface_modes & BIT(newtype))) {
		err = -EBUSY;
		goto out;
	}

	if (ctx->exclusive_interface_modes & BIT(newtype)) {
S
Stanislaw Gruszka 已提交
1793
		for_each_context(il, tmp) {
1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809
			if (ctx == tmp)
				continue;

			if (!tmp->vif)
				continue;

			/*
			 * The current mode switch would be exclusive, but
			 * another context is active ... refuse the switch.
			 */
			err = -EBUSY;
			goto out;
		}
	}

	/* success */
S
Stanislaw Gruszka 已提交
1810
	il_teardown_interface(il, vif, true);
1811
	vif->type = newtype;
1812
	vif->p2p = newp2p;
S
Stanislaw Gruszka 已提交
1813
	err = il_setup_interface(il, ctx);
1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824
	WARN_ON(err);
	/*
	 * We've switched internally, but submitting to the
	 * device may have failed for some reason. Mask this
	 * error, because otherwise mac80211 will not switch
	 * (and set the interface type back) and we'll be
	 * out of sync with it.
	 */
	err = 0;

 out:
S
Stanislaw Gruszka 已提交
1825
	mutex_unlock(&il->mutex);
1826 1827
	return err;
}
S
Stanislaw Gruszka 已提交
1828
EXPORT_SYMBOL(il_mac_change_interface);
1829 1830 1831 1832 1833

/*
 * On every watchdog tick we check (latest) time stamp. If it does not
 * change during timeout period and queue is not empty we reset firmware.
 */
S
Stanislaw Gruszka 已提交
1834
static int il_check_stuck_queue(struct il_priv *il, int cnt)
1835
{
S
Stanislaw Gruszka 已提交
1836
	struct il_tx_queue *txq = &il->txq[cnt];
S
Stanislaw Gruszka 已提交
1837
	struct il_queue *q = &txq->q;
1838 1839 1840 1841 1842 1843 1844 1845 1846
	unsigned long timeout;
	int ret;

	if (q->read_ptr == q->write_ptr) {
		txq->time_stamp = jiffies;
		return 0;
	}

	timeout = txq->time_stamp +
S
Stanislaw Gruszka 已提交
1847
		  msecs_to_jiffies(il->cfg->base_params->wd_timeout);
1848 1849

	if (time_after(jiffies, timeout)) {
1850
		IL_ERR("Queue %d stuck for %u ms.\n",
S
Stanislaw Gruszka 已提交
1851 1852
				q->id, il->cfg->base_params->wd_timeout);
		ret = il_force_reset(il, false);
1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
		return (ret == -EAGAIN) ? 0 : 1;
	}

	return 0;
}

/*
 * Making watchdog tick be a quarter of timeout assure we will
 * discover the queue hung between timeout and 1.25*timeout
 */
S
Stanislaw Gruszka 已提交
1863
#define IL_WD_TICK(timeout) ((timeout) / 4)
1864 1865 1866 1867 1868

/*
 * Watchdog timer callback, we check each tx queue for stuck, if if hung
 * we reset the firmware. If everything is fine just rearm the timer.
 */
S
Stanislaw Gruszka 已提交
1869
void il_bg_watchdog(unsigned long data)
1870
{
S
Stanislaw Gruszka 已提交
1871
	struct il_priv *il = (struct il_priv *)data;
1872 1873 1874
	int cnt;
	unsigned long timeout;

S
Stanislaw Gruszka 已提交
1875
	if (test_bit(STATUS_EXIT_PENDING, &il->status))
1876 1877
		return;

S
Stanislaw Gruszka 已提交
1878
	timeout = il->cfg->base_params->wd_timeout;
1879 1880 1881 1882
	if (timeout == 0)
		return;

	/* monitor and check for stuck cmd queue */
S
Stanislaw Gruszka 已提交
1883
	if (il_check_stuck_queue(il, il->cmd_queue))
1884 1885 1886
		return;

	/* monitor and check for other stuck queues */
S
Stanislaw Gruszka 已提交
1887 1888
	if (il_is_any_associated(il)) {
		for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) {
1889
			/* skip as we already checked the command queue */
S
Stanislaw Gruszka 已提交
1890
			if (cnt == il->cmd_queue)
1891
				continue;
S
Stanislaw Gruszka 已提交
1892
			if (il_check_stuck_queue(il, cnt))
1893 1894 1895 1896
				return;
		}
	}

S
Stanislaw Gruszka 已提交
1897
	mod_timer(&il->watchdog, jiffies +
S
Stanislaw Gruszka 已提交
1898
		  msecs_to_jiffies(IL_WD_TICK(timeout)));
1899
}
S
Stanislaw Gruszka 已提交
1900
EXPORT_SYMBOL(il_bg_watchdog);
1901

S
Stanislaw Gruszka 已提交
1902
void il_setup_watchdog(struct il_priv *il)
1903
{
S
Stanislaw Gruszka 已提交
1904
	unsigned int timeout = il->cfg->base_params->wd_timeout;
1905 1906

	if (timeout)
S
Stanislaw Gruszka 已提交
1907
		mod_timer(&il->watchdog,
S
Stanislaw Gruszka 已提交
1908
			  jiffies + msecs_to_jiffies(IL_WD_TICK(timeout)));
1909
	else
S
Stanislaw Gruszka 已提交
1910
		del_timer(&il->watchdog);
1911
}
S
Stanislaw Gruszka 已提交
1912
EXPORT_SYMBOL(il_setup_watchdog);
1913 1914 1915 1916 1917 1918 1919 1920

/*
 * extended beacon time format
 * time in usec will be changed into a 32-bit value in extended:internal format
 * the extended part is the beacon counts
 * the internal part is the time in usec within one beacon interval
 */
u32
S
Stanislaw Gruszka 已提交
1921
il_usecs_to_beacons(struct il_priv *il,
1922 1923 1924 1925 1926 1927 1928 1929 1930 1931
					u32 usec, u32 beacon_interval)
{
	u32 quot;
	u32 rem;
	u32 interval = beacon_interval * TIME_UNIT;

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

	quot = (usec / interval) &
S
Stanislaw Gruszka 已提交
1932 1933 1934 1935 1936
		(il_beacon_time_mask_high(il,
		il->hw_params.beacon_time_tsf_bits) >>
		il->hw_params.beacon_time_tsf_bits);
	rem = (usec % interval) & il_beacon_time_mask_low(il,
				   il->hw_params.beacon_time_tsf_bits);
1937

S
Stanislaw Gruszka 已提交
1938
	return (quot << il->hw_params.beacon_time_tsf_bits) + rem;
1939
}
S
Stanislaw Gruszka 已提交
1940
EXPORT_SYMBOL(il_usecs_to_beacons);
1941 1942 1943 1944

/* base is usually what we get from ucode with each received frame,
 * the same as HW timer counter counting down
 */
S
Stanislaw Gruszka 已提交
1945
__le32 il_add_beacon_time(struct il_priv *il, u32 base,
1946 1947
			   u32 addon, u32 beacon_interval)
{
S
Stanislaw Gruszka 已提交
1948 1949 1950 1951
	u32 base_low = base & il_beacon_time_mask_low(il,
					il->hw_params.beacon_time_tsf_bits);
	u32 addon_low = addon & il_beacon_time_mask_low(il,
					il->hw_params.beacon_time_tsf_bits);
1952
	u32 interval = beacon_interval * TIME_UNIT;
S
Stanislaw Gruszka 已提交
1953 1954 1955 1956
	u32 res = (base & il_beacon_time_mask_high(il,
				il->hw_params.beacon_time_tsf_bits)) +
				(addon & il_beacon_time_mask_high(il,
				il->hw_params.beacon_time_tsf_bits));
1957 1958 1959 1960 1961

	if (base_low > addon_low)
		res += base_low - addon_low;
	else if (base_low < addon_low) {
		res += interval + base_low - addon_low;
S
Stanislaw Gruszka 已提交
1962
		res += (1 << il->hw_params.beacon_time_tsf_bits);
1963
	} else
S
Stanislaw Gruszka 已提交
1964
		res += (1 << il->hw_params.beacon_time_tsf_bits);
1965 1966 1967

	return cpu_to_le32(res);
}
S
Stanislaw Gruszka 已提交
1968
EXPORT_SYMBOL(il_add_beacon_time);
1969 1970 1971

#ifdef CONFIG_PM

S
Stanislaw Gruszka 已提交
1972
int il_pci_suspend(struct device *device)
1973 1974
{
	struct pci_dev *pdev = to_pci_dev(device);
S
Stanislaw Gruszka 已提交
1975
	struct il_priv *il = pci_get_drvdata(pdev);
1976 1977 1978

	/*
	 * This function is called when system goes into suspend state
S
Stanislaw Gruszka 已提交
1979 1980
	 * mac80211 will call il_mac_stop() from the mac80211 suspend function
	 * first but since il_mac_stop() has no knowledge of who the caller is,
1981 1982 1983
	 * it will not call apm_ops.stop() to stop the DMA operation.
	 * Calling apm_ops.stop here to make sure we stop the DMA.
	 */
S
Stanislaw Gruszka 已提交
1984
	il_apm_stop(il);
1985 1986 1987

	return 0;
}
S
Stanislaw Gruszka 已提交
1988
EXPORT_SYMBOL(il_pci_suspend);
1989

S
Stanislaw Gruszka 已提交
1990
int il_pci_resume(struct device *device)
1991 1992
{
	struct pci_dev *pdev = to_pci_dev(device);
S
Stanislaw Gruszka 已提交
1993
	struct il_priv *il = pci_get_drvdata(pdev);
1994 1995 1996 1997 1998 1999 2000 2001
	bool hw_rfkill = false;

	/*
	 * We disable the RETRY_TIMEOUT register (0x41) to keep
	 * PCI Tx retries from interfering with C3 CPU state.
	 */
	pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);

S
Stanislaw Gruszka 已提交
2002
	il_enable_interrupts(il);
2003

2004
	if (!(_il_rd(il, CSR_GP_CNTRL) &
2005 2006 2007 2008
				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
		hw_rfkill = true;

	if (hw_rfkill)
S
Stanislaw Gruszka 已提交
2009
		set_bit(STATUS_RF_KILL_HW, &il->status);
2010
	else
S
Stanislaw Gruszka 已提交
2011
		clear_bit(STATUS_RF_KILL_HW, &il->status);
2012

S
Stanislaw Gruszka 已提交
2013
	wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rfkill);
2014 2015 2016

	return 0;
}
S
Stanislaw Gruszka 已提交
2017
EXPORT_SYMBOL(il_pci_resume);
2018

S
Stanislaw Gruszka 已提交
2019 2020 2021 2022 2023 2024 2025
const struct dev_pm_ops il_pm_ops = {
	.suspend = il_pci_suspend,
	.resume = il_pci_resume,
	.freeze = il_pci_suspend,
	.thaw = il_pci_resume,
	.poweroff = il_pci_suspend,
	.restore = il_pci_resume,
2026
};
S
Stanislaw Gruszka 已提交
2027
EXPORT_SYMBOL(il_pm_ops);
2028 2029 2030 2031

#endif /* CONFIG_PM */

static void
S
Stanislaw Gruszka 已提交
2032
il_update_qos(struct il_priv *il, struct il_rxon_context *ctx)
2033
{
S
Stanislaw Gruszka 已提交
2034
	if (test_bit(STATUS_EXIT_PENDING, &il->status))
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048
		return;

	if (!ctx->is_active)
		return;

	ctx->qos_data.def_qos_parm.qos_flags = 0;

	if (ctx->qos_data.qos_active)
		ctx->qos_data.def_qos_parm.qos_flags |=
			QOS_PARAM_FLG_UPDATE_EDCA_MSK;

	if (ctx->ht.enabled)
		ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;

2049
	D_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n",
2050 2051 2052
		      ctx->qos_data.qos_active,
		      ctx->qos_data.def_qos_parm.qos_flags);

S
Stanislaw Gruszka 已提交
2053
	il_send_cmd_pdu_async(il, ctx->qos_cmd,
S
Stanislaw Gruszka 已提交
2054
			       sizeof(struct il_qosparam_cmd),
2055 2056 2057 2058
			       &ctx->qos_data.def_qos_parm, NULL);
}

/**
S
Stanislaw Gruszka 已提交
2059
 * il_mac_config - mac80211 config callback
2060
 */
S
Stanislaw Gruszka 已提交
2061
int il_mac_config(struct ieee80211_hw *hw, u32 changed)
2062
{
S
Stanislaw Gruszka 已提交
2063
	struct il_priv *il = hw->priv;
S
Stanislaw Gruszka 已提交
2064
	const struct il_channel_info *ch_info;
2065 2066
	struct ieee80211_conf *conf = &hw->conf;
	struct ieee80211_channel *channel = conf->channel;
S
Stanislaw Gruszka 已提交
2067
	struct il_ht_config *ht_conf = &il->current_ht_config;
S
Stanislaw Gruszka 已提交
2068
	struct il_rxon_context *ctx;
2069 2070 2071 2072
	unsigned long flags = 0;
	int ret = 0;
	u16 ch;
	int scan_active = 0;
S
Stanislaw Gruszka 已提交
2073
	bool ht_changed[NUM_IL_RXON_CTX] = {};
2074

S
Stanislaw Gruszka 已提交
2075
	if (WARN_ON(!il->cfg->ops->legacy))
2076 2077
		return -EOPNOTSUPP;

S
Stanislaw Gruszka 已提交
2078
	mutex_lock(&il->mutex);
2079

2080
	D_MAC80211("enter to channel %d changed 0x%X\n",
2081 2082
					channel->hw_value, changed);

S
Stanislaw Gruszka 已提交
2083
	if (unlikely(test_bit(STATUS_SCANNING, &il->status))) {
2084
		scan_active = 1;
2085
		D_MAC80211("scan active\n");
2086 2087 2088 2089 2090
	}

	if (changed & (IEEE80211_CONF_CHANGE_SMPS |
		       IEEE80211_CONF_CHANGE_CHANNEL)) {
		/* mac80211 uses static for non-HT which is what we want */
S
Stanislaw Gruszka 已提交
2091
		il->current_ht_config.smps = conf->smps_mode;
2092 2093 2094 2095 2096 2097 2098 2099

		/*
		 * Recalculate chain counts.
		 *
		 * If monitor mode is enabled then mac80211 will
		 * set up the SM PS mode to OFF if an HT channel is
		 * configured.
		 */
S
Stanislaw Gruszka 已提交
2100 2101 2102
		if (il->cfg->ops->hcmd->set_rxon_chain)
			for_each_context(il, ctx)
				il->cfg->ops->hcmd->set_rxon_chain(il, ctx);
2103 2104 2105 2106 2107 2108 2109 2110 2111 2112
	}

	/* during scanning mac80211 will delay channel setting until
	 * scan finish with changed = 0
	 */
	if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
		if (scan_active)
			goto set_ch_out;

		ch = channel->hw_value;
S
Stanislaw Gruszka 已提交
2113
		ch_info = il_get_channel_info(il, channel->band, ch);
S
Stanislaw Gruszka 已提交
2114
		if (!il_is_channel_valid(ch_info)) {
2115
			D_MAC80211("leave - invalid channel\n");
2116 2117 2118 2119
			ret = -EINVAL;
			goto set_ch_out;
		}

S
Stanislaw Gruszka 已提交
2120
		if (il->iw_mode == NL80211_IFTYPE_ADHOC &&
S
Stanislaw Gruszka 已提交
2121
		    !il_is_channel_ibss(ch_info)) {
2122
			D_MAC80211("leave - not IBSS channel\n");
2123 2124 2125 2126
			ret = -EINVAL;
			goto set_ch_out;
		}

S
Stanislaw Gruszka 已提交
2127
		spin_lock_irqsave(&il->lock, flags);
2128

S
Stanislaw Gruszka 已提交
2129
		for_each_context(il, ctx) {
2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153
			/* Configure HT40 channels */
			if (ctx->ht.enabled != conf_is_ht(conf)) {
				ctx->ht.enabled = conf_is_ht(conf);
				ht_changed[ctx->ctxid] = true;
			}
			if (ctx->ht.enabled) {
				if (conf_is_ht40_minus(conf)) {
					ctx->ht.extension_chan_offset =
					IEEE80211_HT_PARAM_CHA_SEC_BELOW;
					ctx->ht.is_40mhz = true;
				} else if (conf_is_ht40_plus(conf)) {
					ctx->ht.extension_chan_offset =
					IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
					ctx->ht.is_40mhz = true;
				} else {
					ctx->ht.extension_chan_offset =
					IEEE80211_HT_PARAM_CHA_SEC_NONE;
					ctx->ht.is_40mhz = false;
				}
			} else
				ctx->ht.is_40mhz = false;

			/*
			 * Default to no protection. Protection mode will
S
Stanislaw Gruszka 已提交
2154
			 * later be set from BSS config in il_ht_conf
2155 2156 2157 2158 2159 2160 2161 2162 2163 2164
			 */
			ctx->ht.protection =
					IEEE80211_HT_OP_MODE_PROTECTION_NONE;

			/* if we are switching from ht to 2.4 clear flags
			 * from any ht related info since 2.4 does not
			 * support ht */
			if ((le16_to_cpu(ctx->staging.channel) != ch))
				ctx->staging.flags = 0;

S
Stanislaw Gruszka 已提交
2165 2166
			il_set_rxon_channel(il, channel, ctx);
			il_set_rxon_ht(il, ht_conf);
2167

S
Stanislaw Gruszka 已提交
2168
			il_set_flags_for_band(il, ctx, channel->band,
2169 2170 2171
					       ctx->vif);
		}

S
Stanislaw Gruszka 已提交
2172
		spin_unlock_irqrestore(&il->lock, flags);
2173

S
Stanislaw Gruszka 已提交
2174
		if (il->cfg->ops->legacy->update_bcast_stations)
2175
			ret =
S
Stanislaw Gruszka 已提交
2176
			il->cfg->ops->legacy->update_bcast_stations(il);
2177 2178 2179 2180 2181

 set_ch_out:
		/* The list of supported rates and rate mask can be different
		 * for each band; since the band may have changed, reset
		 * the rate mask to what mac80211 lists */
S
Stanislaw Gruszka 已提交
2182
		il_set_rate(il);
2183 2184 2185 2186
	}

	if (changed & (IEEE80211_CONF_CHANGE_PS |
			IEEE80211_CONF_CHANGE_IDLE)) {
S
Stanislaw Gruszka 已提交
2187
		ret = il_power_update_mode(il, false);
2188
		if (ret)
2189
			D_MAC80211("Error setting sleep level\n");
2190 2191 2192
	}

	if (changed & IEEE80211_CONF_CHANGE_POWER) {
2193
		D_MAC80211("TX Power old=%d new=%d\n",
S
Stanislaw Gruszka 已提交
2194
			il->tx_power_user_lmt, conf->power_level);
2195

S
Stanislaw Gruszka 已提交
2196
		il_set_tx_power(il, conf->power_level, false);
2197 2198
	}

S
Stanislaw Gruszka 已提交
2199
	if (!il_is_ready(il)) {
2200
		D_MAC80211("leave - not ready\n");
2201 2202 2203 2204 2205 2206
		goto out;
	}

	if (scan_active)
		goto out;

S
Stanislaw Gruszka 已提交
2207
	for_each_context(il, ctx) {
2208
		if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)))
S
Stanislaw Gruszka 已提交
2209
			il_commit_rxon(il, ctx);
2210
		else
2211
			D_INFO(
2212 2213
				"Not re-sending same RXON configuration.\n");
		if (ht_changed[ctx->ctxid])
S
Stanislaw Gruszka 已提交
2214
			il_update_qos(il, ctx);
2215 2216 2217
	}

out:
2218
	D_MAC80211("leave\n");
S
Stanislaw Gruszka 已提交
2219
	mutex_unlock(&il->mutex);
2220 2221
	return ret;
}
S
Stanislaw Gruszka 已提交
2222
EXPORT_SYMBOL(il_mac_config);
2223

S
Stanislaw Gruszka 已提交
2224
void il_mac_reset_tsf(struct ieee80211_hw *hw,
2225
			      struct ieee80211_vif *vif)
2226
{
S
Stanislaw Gruszka 已提交
2227
	struct il_priv *il = hw->priv;
2228
	unsigned long flags;
S
Stanislaw Gruszka 已提交
2229
	/* IBSS can only be the IL_RXON_CTX_BSS context */
S
Stanislaw Gruszka 已提交
2230
	struct il_rxon_context *ctx = &il->contexts[IL_RXON_CTX_BSS];
2231

S
Stanislaw Gruszka 已提交
2232
	if (WARN_ON(!il->cfg->ops->legacy))
2233 2234
		return;

S
Stanislaw Gruszka 已提交
2235
	mutex_lock(&il->mutex);
2236
	D_MAC80211("enter\n");
2237

S
Stanislaw Gruszka 已提交
2238 2239 2240
	spin_lock_irqsave(&il->lock, flags);
	memset(&il->current_ht_config, 0, sizeof(struct il_ht_config));
	spin_unlock_irqrestore(&il->lock, flags);
2241

S
Stanislaw Gruszka 已提交
2242
	spin_lock_irqsave(&il->lock, flags);
2243 2244

	/* new association get rid of ibss beacon skb */
S
Stanislaw Gruszka 已提交
2245 2246
	if (il->beacon_skb)
		dev_kfree_skb(il->beacon_skb);
2247

S
Stanislaw Gruszka 已提交
2248
	il->beacon_skb = NULL;
2249

S
Stanislaw Gruszka 已提交
2250
	il->timestamp = 0;
2251

S
Stanislaw Gruszka 已提交
2252
	spin_unlock_irqrestore(&il->lock, flags);
2253

S
Stanislaw Gruszka 已提交
2254 2255
	il_scan_cancel_timeout(il, 100);
	if (!il_is_ready_rf(il)) {
2256
		D_MAC80211("leave - not ready\n");
S
Stanislaw Gruszka 已提交
2257
		mutex_unlock(&il->mutex);
2258 2259 2260 2261 2262 2263 2264
		return;
	}

	/* we are restarting association process
	 * clear RXON_FILTER_ASSOC_MSK bit
	 */
	ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
S
Stanislaw Gruszka 已提交
2265
	il_commit_rxon(il, ctx);
2266

S
Stanislaw Gruszka 已提交
2267
	il_set_rate(il);
2268

S
Stanislaw Gruszka 已提交
2269
	mutex_unlock(&il->mutex);
2270

2271
	D_MAC80211("leave\n");
2272
}
S
Stanislaw Gruszka 已提交
2273
EXPORT_SYMBOL(il_mac_reset_tsf);
2274

S
Stanislaw Gruszka 已提交
2275
static void il_ht_conf(struct il_priv *il,
2276 2277
			struct ieee80211_vif *vif)
{
S
Stanislaw Gruszka 已提交
2278
	struct il_ht_config *ht_conf = &il->current_ht_config;
2279 2280
	struct ieee80211_sta *sta;
	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
S
Stanislaw Gruszka 已提交
2281
	struct il_rxon_context *ctx = il_rxon_ctx_from_vif(vif);
2282

2283
	D_ASSOC("enter:\n");
2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331

	if (!ctx->ht.enabled)
		return;

	ctx->ht.protection =
		bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
	ctx->ht.non_gf_sta_present =
		!!(bss_conf->ht_operation_mode &
				IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);

	ht_conf->single_chain_sufficient = false;

	switch (vif->type) {
	case NL80211_IFTYPE_STATION:
		rcu_read_lock();
		sta = ieee80211_find_sta(vif, bss_conf->bssid);
		if (sta) {
			struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
			int maxstreams;

			maxstreams = (ht_cap->mcs.tx_params &
			      IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
				>> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
			maxstreams += 1;

			if ((ht_cap->mcs.rx_mask[1] == 0) &&
			    (ht_cap->mcs.rx_mask[2] == 0))
				ht_conf->single_chain_sufficient = true;
			if (maxstreams <= 1)
				ht_conf->single_chain_sufficient = true;
		} else {
			/*
			 * If at all, this can only happen through a race
			 * when the AP disconnects us while we're still
			 * setting up the connection, in that case mac80211
			 * will soon tell us about that.
			 */
			ht_conf->single_chain_sufficient = true;
		}
		rcu_read_unlock();
		break;
	case NL80211_IFTYPE_ADHOC:
		ht_conf->single_chain_sufficient = true;
		break;
	default:
		break;
	}

2332
	D_ASSOC("leave\n");
2333 2334
}

S
Stanislaw Gruszka 已提交
2335
static inline void il_set_no_assoc(struct il_priv *il,
2336 2337
				    struct ieee80211_vif *vif)
{
S
Stanislaw Gruszka 已提交
2338
	struct il_rxon_context *ctx = il_rxon_ctx_from_vif(vif);
2339 2340 2341 2342 2343 2344 2345 2346

	/*
	 * inform the ucode that there is no longer an
	 * association and that no more packets should be
	 * sent
	 */
	ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
	ctx->staging.assoc_id = 0;
S
Stanislaw Gruszka 已提交
2347
	il_commit_rxon(il, ctx);
2348 2349
}

S
Stanislaw Gruszka 已提交
2350
static void il_beacon_update(struct ieee80211_hw *hw,
2351 2352
				  struct ieee80211_vif *vif)
{
S
Stanislaw Gruszka 已提交
2353
	struct il_priv *il = hw->priv;
2354 2355 2356 2357 2358 2359 2360
	unsigned long flags;
	__le64 timestamp;
	struct sk_buff *skb = ieee80211_beacon_get(hw, vif);

	if (!skb)
		return;

2361
	D_MAC80211("enter\n");
2362

S
Stanislaw Gruszka 已提交
2363
	lockdep_assert_held(&il->mutex);
2364

S
Stanislaw Gruszka 已提交
2365
	if (!il->beacon_ctx) {
2366
		IL_ERR("update beacon but no beacon context!\n");
2367 2368 2369 2370
		dev_kfree_skb(skb);
		return;
	}

S
Stanislaw Gruszka 已提交
2371
	spin_lock_irqsave(&il->lock, flags);
2372

S
Stanislaw Gruszka 已提交
2373 2374
	if (il->beacon_skb)
		dev_kfree_skb(il->beacon_skb);
2375

S
Stanislaw Gruszka 已提交
2376
	il->beacon_skb = skb;
2377 2378

	timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
S
Stanislaw Gruszka 已提交
2379
	il->timestamp = le64_to_cpu(timestamp);
2380

2381
	D_MAC80211("leave\n");
S
Stanislaw Gruszka 已提交
2382
	spin_unlock_irqrestore(&il->lock, flags);
2383

S
Stanislaw Gruszka 已提交
2384
	if (!il_is_ready_rf(il)) {
2385
		D_MAC80211("leave - RF not ready\n");
2386 2387 2388
		return;
	}

S
Stanislaw Gruszka 已提交
2389
	il->cfg->ops->legacy->post_associate(il);
2390 2391
}

S
Stanislaw Gruszka 已提交
2392
void il_mac_bss_info_changed(struct ieee80211_hw *hw,
2393 2394 2395 2396
				     struct ieee80211_vif *vif,
				     struct ieee80211_bss_conf *bss_conf,
				     u32 changes)
{
S
Stanislaw Gruszka 已提交
2397
	struct il_priv *il = hw->priv;
S
Stanislaw Gruszka 已提交
2398
	struct il_rxon_context *ctx = il_rxon_ctx_from_vif(vif);
2399 2400
	int ret;

S
Stanislaw Gruszka 已提交
2401
	if (WARN_ON(!il->cfg->ops->legacy))
2402 2403
		return;

2404
	D_MAC80211("changes = 0x%X\n", changes);
2405

S
Stanislaw Gruszka 已提交
2406
	mutex_lock(&il->mutex);
2407

S
Stanislaw Gruszka 已提交
2408 2409
	if (!il_is_alive(il)) {
		mutex_unlock(&il->mutex);
2410 2411 2412
		return;
	}

2413 2414 2415
	if (changes & BSS_CHANGED_QOS) {
		unsigned long flags;

S
Stanislaw Gruszka 已提交
2416
		spin_lock_irqsave(&il->lock, flags);
2417
		ctx->qos_data.qos_active = bss_conf->qos;
S
Stanislaw Gruszka 已提交
2418 2419
		il_update_qos(il, ctx);
		spin_unlock_irqrestore(&il->lock, flags);
2420 2421 2422 2423 2424 2425 2426 2427 2428
	}

	if (changes & BSS_CHANGED_BEACON_ENABLED) {
		/*
		 * the add_interface code must make sure we only ever
		 * have a single interface that could be beaconing at
		 * any time.
		 */
		if (vif->bss_conf.enable_beacon)
S
Stanislaw Gruszka 已提交
2429
			il->beacon_ctx = ctx;
2430
		else
S
Stanislaw Gruszka 已提交
2431
			il->beacon_ctx = NULL;
2432 2433 2434
	}

	if (changes & BSS_CHANGED_BSSID) {
2435
		D_MAC80211("BSSID %pM\n", bss_conf->bssid);
2436 2437 2438 2439 2440 2441

		/*
		 * If there is currently a HW scan going on in the
		 * background then we need to cancel it else the RXON
		 * below/in post_associate will fail.
		 */
S
Stanislaw Gruszka 已提交
2442
		if (il_scan_cancel_timeout(il, 100)) {
2443
			IL_WARN(
2444
				"Aborted scan still in progress after 100ms\n");
2445
			D_MAC80211(
2446
				"leaving - scan abort failed.\n");
S
Stanislaw Gruszka 已提交
2447
			mutex_unlock(&il->mutex);
2448 2449 2450 2451 2452 2453 2454 2455 2456
			return;
		}

		/* mac80211 only sets assoc when in STATION mode */
		if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) {
			memcpy(ctx->staging.bssid_addr,
			       bss_conf->bssid, ETH_ALEN);

			/* currently needed in a few places */
S
Stanislaw Gruszka 已提交
2457
			memcpy(il->bssid, bss_conf->bssid, ETH_ALEN);
2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470
		} else {
			ctx->staging.filter_flags &=
				~RXON_FILTER_ASSOC_MSK;
		}

	}

	/*
	 * This needs to be after setting the BSSID in case
	 * mac80211 decides to do both changes at once because
	 * it will invoke post_associate.
	 */
	if (vif->type == NL80211_IFTYPE_ADHOC && changes & BSS_CHANGED_BEACON)
S
Stanislaw Gruszka 已提交
2471
		il_beacon_update(hw, vif);
2472 2473

	if (changes & BSS_CHANGED_ERP_PREAMBLE) {
2474
		D_MAC80211("ERP_PREAMBLE %d\n",
2475 2476 2477 2478 2479 2480 2481 2482
				   bss_conf->use_short_preamble);
		if (bss_conf->use_short_preamble)
			ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
		else
			ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
	}

	if (changes & BSS_CHANGED_ERP_CTS_PROT) {
2483
		D_MAC80211(
2484 2485
			"ERP_CTS %d\n", bss_conf->use_cts_prot);
		if (bss_conf->use_cts_prot &&
S
Stanislaw Gruszka 已提交
2486
			(il->band != IEEE80211_BAND_5GHZ))
2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498
			ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
		else
			ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
		if (bss_conf->use_cts_prot)
			ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
		else
			ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
	}

	if (changes & BSS_CHANGED_BASIC_RATES) {
		/* XXX use this information
		 *
S
Stanislaw Gruszka 已提交
2499
		 * To do that, remove code from il_set_rate() and put something
2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513
		 * like this here:
		 *
		if (A-band)
			ctx->staging.ofdm_basic_rates =
				bss_conf->basic_rates;
		else
			ctx->staging.ofdm_basic_rates =
				bss_conf->basic_rates >> 4;
			ctx->staging.cck_basic_rates =
				bss_conf->basic_rates & 0xF;
		 */
	}

	if (changes & BSS_CHANGED_HT) {
S
Stanislaw Gruszka 已提交
2514
		il_ht_conf(il, vif);
2515

S
Stanislaw Gruszka 已提交
2516 2517
		if (il->cfg->ops->hcmd->set_rxon_chain)
			il->cfg->ops->hcmd->set_rxon_chain(il, ctx);
2518 2519 2520
	}

	if (changes & BSS_CHANGED_ASSOC) {
2521
		D_MAC80211("ASSOC %d\n", bss_conf->assoc);
2522
		if (bss_conf->assoc) {
S
Stanislaw Gruszka 已提交
2523
			il->timestamp = bss_conf->timestamp;
2524

S
Stanislaw Gruszka 已提交
2525 2526
			if (!il_is_rfkill(il))
				il->cfg->ops->legacy->post_associate(il);
2527
		} else
S
Stanislaw Gruszka 已提交
2528
			il_set_no_assoc(il, vif);
2529 2530
	}

S
Stanislaw Gruszka 已提交
2531
	if (changes && il_is_associated_ctx(ctx) && bss_conf->aid) {
2532
		D_MAC80211("Changes (%#x) while associated\n",
2533
				   changes);
S
Stanislaw Gruszka 已提交
2534
		ret = il_send_rxon_assoc(il, ctx);
2535 2536 2537 2538
		if (!ret) {
			/* Sync active_rxon with latest change. */
			memcpy((void *)&ctx->active,
				&ctx->staging,
S
Stanislaw Gruszka 已提交
2539
				sizeof(struct il_rxon_cmd));
2540 2541 2542 2543 2544 2545 2546
		}
	}

	if (changes & BSS_CHANGED_BEACON_ENABLED) {
		if (vif->bss_conf.enable_beacon) {
			memcpy(ctx->staging.bssid_addr,
			       bss_conf->bssid, ETH_ALEN);
S
Stanislaw Gruszka 已提交
2547 2548
			memcpy(il->bssid, bss_conf->bssid, ETH_ALEN);
			il->cfg->ops->legacy->config_ap(il);
2549
		} else
S
Stanislaw Gruszka 已提交
2550
			il_set_no_assoc(il, vif);
2551 2552 2553
	}

	if (changes & BSS_CHANGED_IBSS) {
S
Stanislaw Gruszka 已提交
2554
		ret = il->cfg->ops->legacy->manage_ibss_station(il, vif,
2555 2556
							bss_conf->ibss_joined);
		if (ret)
2557
			IL_ERR("failed to %s IBSS station %pM\n",
2558 2559 2560 2561
				bss_conf->ibss_joined ? "add" : "remove",
				bss_conf->bssid);
	}

S
Stanislaw Gruszka 已提交
2562
	mutex_unlock(&il->mutex);
2563

2564
	D_MAC80211("leave\n");
2565
}
S
Stanislaw Gruszka 已提交
2566
EXPORT_SYMBOL(il_mac_bss_info_changed);
2567

S
Stanislaw Gruszka 已提交
2568
irqreturn_t il_isr(int irq, void *data)
2569
{
S
Stanislaw Gruszka 已提交
2570
	struct il_priv *il = data;
2571 2572 2573
	u32 inta, inta_mask;
	u32 inta_fh;
	unsigned long flags;
S
Stanislaw Gruszka 已提交
2574
	if (!il)
2575 2576
		return IRQ_NONE;

S
Stanislaw Gruszka 已提交
2577
	spin_lock_irqsave(&il->lock, flags);
2578 2579 2580 2581 2582

	/* Disable (but don't clear!) interrupts here to avoid
	 *    back-to-back ISRs and sporadic interrupts from our NIC.
	 * If we have something to service, the tasklet will re-enable ints.
	 * If we *don't* have something, we'll re-enable before leaving here. */
2583 2584
	inta_mask = _il_rd(il, CSR_INT_MASK);  /* just for debug */
	_il_wr(il, CSR_INT_MASK, 0x00000000);
2585 2586

	/* Discover which interrupts are active/pending */
2587 2588
	inta = _il_rd(il, CSR_INT);
	inta_fh = _il_rd(il, CSR_FH_INT_STATUS);
2589 2590 2591 2592 2593

	/* Ignore interrupt if there's nothing in NIC to service.
	 * This may be due to IRQ shared with another device,
	 * or due to sporadic interrupts thrown from our NIC. */
	if (!inta && !inta_fh) {
2594
		D_ISR(
2595 2596 2597 2598 2599 2600 2601
			"Ignore interrupt, inta == 0, inta_fh == 0\n");
		goto none;
	}

	if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
		/* Hardware disappeared. It might have already raised
		 * an interrupt */
2602
		IL_WARN("HARDWARE GONE?? INTA == 0x%08x\n", inta);
2603 2604 2605
		goto unplugged;
	}

2606
	D_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
2607 2608 2609 2610
		      inta, inta_mask, inta_fh);

	inta &= ~CSR_INT_BIT_SCD;

S
Stanislaw Gruszka 已提交
2611
	/* il_irq_tasklet() will service interrupts and re-enable them */
2612
	if (likely(inta || inta_fh))
S
Stanislaw Gruszka 已提交
2613
		tasklet_schedule(&il->irq_tasklet);
2614 2615

unplugged:
S
Stanislaw Gruszka 已提交
2616
	spin_unlock_irqrestore(&il->lock, flags);
2617 2618 2619 2620
	return IRQ_HANDLED;

none:
	/* re-enable interrupts here since we don't have anything to service. */
2621
	/* only Re-enable if disabled by irq */
S
Stanislaw Gruszka 已提交
2622 2623 2624
	if (test_bit(STATUS_INT_ENABLED, &il->status))
		il_enable_interrupts(il);
	spin_unlock_irqrestore(&il->lock, flags);
2625 2626
	return IRQ_NONE;
}
S
Stanislaw Gruszka 已提交
2627
EXPORT_SYMBOL(il_isr);
2628 2629

/*
S
Stanislaw Gruszka 已提交
2630
 *  il_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this
2631 2632
 *  function.
 */
S
Stanislaw Gruszka 已提交
2633
void il_tx_cmd_protection(struct il_priv *il,
2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660
			       struct ieee80211_tx_info *info,
			       __le16 fc, __le32 *tx_flags)
{
	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
		*tx_flags |= TX_CMD_FLG_RTS_MSK;
		*tx_flags &= ~TX_CMD_FLG_CTS_MSK;
		*tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;

		if (!ieee80211_is_mgmt(fc))
			return;

		switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
		case cpu_to_le16(IEEE80211_STYPE_AUTH):
		case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
		case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
		case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
			*tx_flags &= ~TX_CMD_FLG_RTS_MSK;
			*tx_flags |= TX_CMD_FLG_CTS_MSK;
			break;
		}
	} else if (info->control.rates[0].flags &
		   IEEE80211_TX_RC_USE_CTS_PROTECT) {
		*tx_flags &= ~TX_CMD_FLG_RTS_MSK;
		*tx_flags |= TX_CMD_FLG_CTS_MSK;
		*tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
	}
}
S
Stanislaw Gruszka 已提交
2661
EXPORT_SYMBOL(il_tx_cmd_protection);