iwl-core.c 67.6 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

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

318
#ifdef CONFIG_IWLEGACY_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
{
	enum ieee80211_band band = ch->band;
	u16 channel = ch->hw_value;

711
	if (le16_to_cpu(ctx->staging.channel) == channel && il->band == band)
712 713 714 715 716 717 718 719
		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 已提交
720
	il->band = band;
721

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

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

S
Stanislaw Gruszka 已提交
728
void il_set_flags_for_band(struct il_priv *il,
S
Stanislaw Gruszka 已提交
729
			    struct il_rxon_context *ctx,
730 731 732 733 734 735 736 737 738
			    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 已提交
739
		/* Copied from il_post_associate() */
740 741 742 743 744 745 746 747 748 749
		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 已提交
750
EXPORT_SYMBOL(il_set_flags_for_band);
751 752 753 754

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

	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:
780
		IL_ERR("Unsupported interface type %d\n",
781 782 783 784 785 786 787
			ctx->vif->type);
		break;
	}

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

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

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

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

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

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

	/* 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 已提交
819
EXPORT_SYMBOL(il_connection_init_rx_config);
820

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

S
Stanislaw Gruszka 已提交
930 931 932
	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);
933
#ifdef CONFIG_IWLEGACY_DEBUG
S
Stanislaw Gruszka 已提交
934 935 936
	if (il_get_debug_level(il) & IL_DL_FW_ERRORS)
		il_print_rx_config_cmd(il,
					&il->contexts[IL_RXON_CTX_BSS]);
937 938
#endif

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

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

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

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

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

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

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

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

	return ret;
}

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

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

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

	udelay(10);

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


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

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

	/*
	 * 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 已提交
1012
	il_set_bit(il, CSR_GIO_CHICKEN_BITS,
1013 1014 1015 1016 1017 1018
			  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 已提交
1019
	il_set_bit(il, CSR_GIO_CHICKEN_BITS,
1020 1021 1022
			  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 已提交
1023
	il_set_bit(il, CSR_DBG_HPET_MEM_REG,
1024 1025 1026 1027 1028
					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 已提交
1029
	 * NOTE:  This is no-op for 3945 (non-existent bit)
1030
	 */
S
Stanislaw Gruszka 已提交
1031
	il_set_bit(il, CSR_HW_IF_CONFIG_REG,
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
				    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 已提交
1042 1043
	if (il->cfg->base_params->set_l0s) {
		lctl = il_pcie_link_ctl(il);
1044 1045 1046
		if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
					PCI_CFG_LINK_CTRL_VAL_L1_EN) {
			/* L1-ASPM enabled; disable(!) L0S  */
S
Stanislaw Gruszka 已提交
1047
			il_set_bit(il, CSR_GIO_REG,
1048
					CSR_GIO_REG_VAL_L0S_ENABLED);
1049
			D_POWER("L1 Enabled; Disabling L0S\n");
1050 1051
		} else {
			/* L1-ASPM disabled; enable(!) L0S */
S
Stanislaw Gruszka 已提交
1052
			il_clear_bit(il, CSR_GIO_REG,
1053
					CSR_GIO_REG_VAL_L0S_ENABLED);
1054
			D_POWER("L1 Disabled; Enabling L0S\n");
1055 1056 1057 1058
		}
	}

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

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

	/*
	 * Wait for clock stabilization; once stabilized, access to
1071
	 * device-internal resources is supported, e.g. il_wr_prph()
1072 1073
	 * and accesses to uCode SRAM.
	 */
1074
	ret = _il_poll_bit(il, CSR_GP_CNTRL,
1075 1076 1077
			CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
			CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
	if (ret < 0) {
1078
		D_INFO("Failed to init the card\n");
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
		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 已提交
1090
	if (il->cfg->base_params->use_bsm)
1091
		il_wr_prph(il, APMG_CLK_EN_REG,
1092 1093
			APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
	else
1094
		il_wr_prph(il, APMG_CLK_EN_REG,
1095 1096 1097 1098
			APMG_CLK_VAL_DMA_CLK_RQT);
	udelay(20);

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

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


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

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

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

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

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

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

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

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

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

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

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

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

S
Stanislaw Gruszka 已提交
1167
void il_send_bt_config(struct il_priv *il)
1168
{
S
Stanislaw Gruszka 已提交
1169
	struct il_bt_cmd bt_cmd = {
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
		.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;

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

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

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

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

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

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

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

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

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

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

1261
	D_MAC80211("enter\n");
1262

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

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

	q = AC_NUM - 1 - queue;

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

S
Stanislaw Gruszka 已提交
1277
	for_each_context(il, ctx) {
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
		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 已提交
1289
	spin_unlock_irqrestore(&il->lock, flags);
1290

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

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

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

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

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

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

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

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

	/*
	 * 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 已提交
1328
	il->iw_mode = vif->type;
1329 1330 1331

	ctx->is_active = true;

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

	return 0;
}

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

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

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

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

S
Stanislaw Gruszka 已提交
1361
	for_each_context(il, tmp) {
1362 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
		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 已提交
1391
	err = il_setup_interface(il, ctx);
1392 1393 1394 1395
	if (!err)
		goto out;

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

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

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

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

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

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

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

1431
	D_MAC80211("enter\n");
1432

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

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

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

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

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

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

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

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

1470
#ifdef CONFIG_IWLEGACY_DEBUGFS
1471

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

S
Stanislaw Gruszka 已提交
1474
void il_reset_traffic_log(struct il_priv *il)
1475
{
S
Stanislaw Gruszka 已提交
1476 1477 1478 1479 1480 1481
	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);
1482 1483
}

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

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

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

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

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

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

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

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

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

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

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

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

S
Stanislaw Gruszka 已提交
1569
const char *il_get_mgmt_string(int cmd)
1570 1571
{
	switch (cmd) {
S
Stanislaw Gruszka 已提交
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583
		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);
1584 1585 1586 1587 1588 1589
	default:
		return "UNKNOWN";

	}
}

S
Stanislaw Gruszka 已提交
1590
const char *il_get_ctrl_string(int cmd)
1591 1592
{
	switch (cmd) {
S
Stanislaw Gruszka 已提交
1593 1594 1595 1596 1597 1598 1599 1600
		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);
1601 1602 1603 1604 1605 1606
	default:
		return "UNKNOWN";

	}
}

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

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

	if (is_tx)
S
Stanislaw Gruszka 已提交
1630
		stats = &il->tx_stats;
1631
	else
S
Stanislaw Gruszka 已提交
1632
		stats = &il->rx_stats;
1633 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

	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 已提交
1706
EXPORT_SYMBOL(il_update_stats);
1707 1708
#endif

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

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

S
Stanislaw Gruszka 已提交
1716
	force_reset = &il->force_reset;
1717 1718 1719 1720 1721
	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)) {
1722
			D_INFO("force reset rejected\n");
1723 1724 1725 1726 1727 1728
			force_reset->reset_reject_count++;
			return -EAGAIN;
		}
	}
	force_reset->reset_success_count++;
	force_reset->last_force_reset_jiffies = jiffies;
1729 1730 1731 1732 1733 1734 1735 1736 1737 1738

	/*
	 * 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 已提交
1739
	if (!external && !il->cfg->mod_params->restart_fw) {
1740
		D_INFO("Cancel firmware reload based on "
1741 1742
			       "module parameter setting\n");
		return 0;
1743
	}
1744

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

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

1757 1758 1759 1760
	return 0;
}

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

	newtype = ieee80211_iftype_p2p(newtype, newp2p);

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

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

1784 1785 1786 1787 1788 1789 1790 1791
	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 已提交
1792
		for_each_context(il, tmp) {
1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808
			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 已提交
1809
	il_teardown_interface(il, vif, true);
1810
	vif->type = newtype;
1811
	vif->p2p = newp2p;
S
Stanislaw Gruszka 已提交
1812
	err = il_setup_interface(il, ctx);
1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823
	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 已提交
1824
	mutex_unlock(&il->mutex);
1825 1826
	return err;
}
S
Stanislaw Gruszka 已提交
1827
EXPORT_SYMBOL(il_mac_change_interface);
1828 1829 1830 1831 1832

/*
 * 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 已提交
1833
static int il_check_stuck_queue(struct il_priv *il, int cnt)
1834
{
S
Stanislaw Gruszka 已提交
1835
	struct il_tx_queue *txq = &il->txq[cnt];
S
Stanislaw Gruszka 已提交
1836
	struct il_queue *q = &txq->q;
1837 1838 1839 1840 1841 1842 1843 1844 1845
	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 已提交
1846
		  msecs_to_jiffies(il->cfg->base_params->wd_timeout);
1847 1848

	if (time_after(jiffies, timeout)) {
1849
		IL_ERR("Queue %d stuck for %u ms.\n",
S
Stanislaw Gruszka 已提交
1850 1851
				q->id, il->cfg->base_params->wd_timeout);
		ret = il_force_reset(il, false);
1852 1853 1854 1855 1856 1857 1858 1859 1860 1861
		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 已提交
1862
#define IL_WD_TICK(timeout) ((timeout) / 4)
1863 1864 1865 1866 1867

/*
 * 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 已提交
1868
void il_bg_watchdog(unsigned long data)
1869
{
S
Stanislaw Gruszka 已提交
1870
	struct il_priv *il = (struct il_priv *)data;
1871 1872 1873
	int cnt;
	unsigned long timeout;

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

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

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

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

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

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

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

/*
 * 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 已提交
1920
il_usecs_to_beacons(struct il_priv *il,
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930
					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 已提交
1931 1932 1933 1934 1935
		(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);
1936

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

/* base is usually what we get from ucode with each received frame,
 * the same as HW timer counter counting down
 */
S
Stanislaw Gruszka 已提交
1944
__le32 il_add_beacon_time(struct il_priv *il, u32 base,
1945 1946
			   u32 addon, u32 beacon_interval)
{
S
Stanislaw Gruszka 已提交
1947 1948 1949 1950
	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);
1951
	u32 interval = beacon_interval * TIME_UNIT;
S
Stanislaw Gruszka 已提交
1952 1953 1954 1955
	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));
1956 1957 1958 1959 1960

	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 已提交
1961
		res += (1 << il->hw_params.beacon_time_tsf_bits);
1962
	} else
S
Stanislaw Gruszka 已提交
1963
		res += (1 << il->hw_params.beacon_time_tsf_bits);
1964 1965 1966

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

#ifdef CONFIG_PM

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

	/*
	 * This function is called when system goes into suspend state
S
Stanislaw Gruszka 已提交
1978 1979
	 * 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,
1980 1981 1982
	 * 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 已提交
1983
	il_apm_stop(il);
1984 1985 1986

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

S
Stanislaw Gruszka 已提交
1989
int il_pci_resume(struct device *device)
1990 1991
{
	struct pci_dev *pdev = to_pci_dev(device);
S
Stanislaw Gruszka 已提交
1992
	struct il_priv *il = pci_get_drvdata(pdev);
1993 1994 1995 1996 1997 1998 1999 2000
	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 已提交
2001
	il_enable_interrupts(il);
2002

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

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

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

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

S
Stanislaw Gruszka 已提交
2018 2019 2020 2021 2022 2023 2024
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,
2025
};
S
Stanislaw Gruszka 已提交
2026
EXPORT_SYMBOL(il_pm_ops);
2027 2028 2029 2030

#endif /* CONFIG_PM */

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

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

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

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

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

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

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

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

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

		/*
		 * 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 已提交
2099 2100 2101
		if (il->cfg->ops->hcmd->set_rxon_chain)
			for_each_context(il, ctx)
				il->cfg->ops->hcmd->set_rxon_chain(il, ctx);
2102 2103 2104 2105 2106 2107 2108 2109 2110 2111
	}

	/* 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 已提交
2112
		ch_info = il_get_channel_info(il, channel->band, ch);
S
Stanislaw Gruszka 已提交
2113
		if (!il_is_channel_valid(ch_info)) {
2114
			D_MAC80211("leave - invalid channel\n");
2115 2116 2117 2118
			ret = -EINVAL;
			goto set_ch_out;
		}

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

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

S
Stanislaw Gruszka 已提交
2128
		for_each_context(il, ctx) {
2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152
			/* 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 已提交
2153
			 * later be set from BSS config in il_ht_conf
2154 2155 2156 2157 2158 2159 2160 2161 2162 2163
			 */
			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 已提交
2164 2165
			il_set_rxon_channel(il, channel, ctx);
			il_set_rxon_ht(il, ht_conf);
2166

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

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

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

 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 已提交
2181
		il_set_rate(il);
2182 2183 2184 2185
	}

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

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

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

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

	if (scan_active)
		goto out;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2282
	D_ASSOC("enter:\n");
2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307

	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;

2308 2309
			if (ht_cap->mcs.rx_mask[1] == 0 &&
			    ht_cap->mcs.rx_mask[2] == 0)
2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330
				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;
	}

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

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

	/*
	 * 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 已提交
2346
	il_commit_rxon(il, ctx);
2347 2348
}

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

	if (!skb)
		return;

2360
	D_MAC80211("enter\n");
2361

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	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 已提交
2428
			il->beacon_ctx = ctx;
2429
		else
S
Stanislaw Gruszka 已提交
2430
			il->beacon_ctx = NULL;
2431 2432 2433
	}

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

		/*
		 * 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 已提交
2441
		if (il_scan_cancel_timeout(il, 100)) {
2442
			IL_WARN(
2443
				"Aborted scan still in progress after 100ms\n");
2444
			D_MAC80211(
2445
				"leaving - scan abort failed.\n");
S
Stanislaw Gruszka 已提交
2446
			mutex_unlock(&il->mutex);
2447 2448 2449 2450 2451 2452 2453 2454 2455
			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 已提交
2456
			memcpy(il->bssid, bss_conf->bssid, ETH_ALEN);
2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468
		} 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.
	 */
2469
	if (vif->type == NL80211_IFTYPE_ADHOC && (changes & BSS_CHANGED_BEACON))
S
Stanislaw Gruszka 已提交
2470
		il_beacon_update(hw, vif);
2471 2472

	if (changes & BSS_CHANGED_ERP_PREAMBLE) {
2473
		D_MAC80211("ERP_PREAMBLE %d\n",
2474 2475 2476 2477 2478 2479 2480 2481
				   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) {
2482
		D_MAC80211(
2483
			"ERP_CTS %d\n", bss_conf->use_cts_prot);
2484
		if (bss_conf->use_cts_prot && il->band != IEEE80211_BAND_5GHZ)
2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496
			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 已提交
2497
		 * To do that, remove code from il_set_rate() and put something
2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511
		 * 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 已提交
2512
		il_ht_conf(il, vif);
2513

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

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

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

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

	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 已提交
2545 2546
			memcpy(il->bssid, bss_conf->bssid, ETH_ALEN);
			il->cfg->ops->legacy->config_ap(il);
2547
		} else
S
Stanislaw Gruszka 已提交
2548
			il_set_no_assoc(il, vif);
2549 2550 2551
	}

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

S
Stanislaw Gruszka 已提交
2560
	mutex_unlock(&il->mutex);
2561

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

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

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

	/* 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. */
2581 2582
	inta_mask = _il_rd(il, CSR_INT_MASK);  /* just for debug */
	_il_wr(il, CSR_INT_MASK, 0x00000000);
2583 2584

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

	/* 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) {
2592
		D_ISR(
2593 2594 2595 2596
			"Ignore interrupt, inta == 0, inta_fh == 0\n");
		goto none;
	}

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

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

	inta &= ~CSR_INT_BIT_SCD;

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

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

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

/*
S
Stanislaw Gruszka 已提交
2628
 *  il_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this
2629 2630
 *  function.
 */
S
Stanislaw Gruszka 已提交
2631
void il_tx_cmd_protection(struct il_priv *il,
2632 2633 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
			       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 已提交
2659
EXPORT_SYMBOL(il_tx_cmd_protection);