iwl-core.c 14.5 KB
Newer Older
T
Tomas Winkler 已提交
1 2 3 4
/******************************************************************************
 *
 * GPL LICENSE SUMMARY
 *
W
Wey-Yi Guy 已提交
5
 * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
T
Tomas Winkler 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * 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:
25
 *  Intel Linux Wireless <ilw@linux.intel.com>
T
Tomas Winkler 已提交
26 27 28 29 30
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *****************************************************************************/

#include <linux/kernel.h>
#include <linux/module.h>
31
#include <linux/sched.h>
32
#include <linux/slab.h>
33
#include <net/mac80211.h>
T
Tomas Winkler 已提交
34

A
Assaf Krauss 已提交
35
#include "iwl-eeprom.h"
W
Winkler, Tomas 已提交
36
#include "iwl-debug.h"
T
Tomas Winkler 已提交
37
#include "iwl-core.h"
38
#include "iwl-io.h"
M
Mohamed Abbas 已提交
39
#include "iwl-power.h"
40
#include "iwl-shared.h"
D
Don Fry 已提交
41
#include "iwl-agn.h"
42
#include "iwl-trans.h"
T
Tomas Winkler 已提交
43

44 45
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

46
void iwl_set_rate(struct iwl_priv *priv)
47
{
48
	struct iwl_rxon_context *ctx;
49

50 51 52
	for_each_context(priv, ctx) {
		ctx->staging.cck_basic_rates =
		    (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
53

54 55 56
		ctx->staging.ofdm_basic_rates =
		   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
	}
57
}
58 59 60

void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
{
61 62
	/*
	 * MULTI-FIXME
63
	 * See iwlagn_mac_channel_switch.
64 65 66
	 */
	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];

D
Don Fry 已提交
67
	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
68 69
		return;

D
Don Fry 已提交
70
	if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
71
		ieee80211_chswitch_done(ctx->vif, is_success);
72
}
73 74

#ifdef CONFIG_IWLWIFI_DEBUG
75 76
void iwl_print_rx_config_cmd(struct iwl_priv *priv,
			     enum iwl_rxon_context_id ctxid)
77
{
78
	struct iwl_rxon_context *ctx = &priv->contexts[ctxid];
79
	struct iwl_rxon_cmd *rxon = &ctx->staging;
80

81
	IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
82
	iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
83 84 85
	IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
	IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
	IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
86
			le32_to_cpu(rxon->filter_flags));
87 88
	IWL_DEBUG_RADIO(priv, "u8 dev_type: 0x%x\n", rxon->dev_type);
	IWL_DEBUG_RADIO(priv, "u8 ofdm_basic_rates: 0x%02x\n",
89
			rxon->ofdm_basic_rates);
90 91 92 93
	IWL_DEBUG_RADIO(priv, "u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
	IWL_DEBUG_RADIO(priv, "u8[6] node_addr: %pM\n", rxon->node_addr);
	IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
	IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
94
}
95
#endif
96

97
void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
98
{
99 100 101
	unsigned int reload_msec;
	unsigned long reload_jiffies;

102
#ifdef CONFIG_IWLWIFI_DEBUG
103
	if (iwl_have_debug_level(IWL_DL_FW_ERRORS))
104 105 106
		iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS);
#endif

107 108 109
	/* uCode is no longer loaded. */
	priv->ucode_loaded = false;

110
	/* Set the FW error flag -- cleared on iwl_down */
D
Don Fry 已提交
111
	set_bit(STATUS_FW_ERROR, &priv->status);
112 113

	/* Cancel currently queued command. */
114
	clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status);
115

116
	iwl_abort_notification_waits(&priv->notif_wait);
117

118 119
	/* Keep the restart process from trying to send host
	 * commands by clearing the ready bit */
D
Don Fry 已提交
120
	clear_bit(STATUS_READY, &priv->status);
121

122
	wake_up(&trans(priv)->wait_command_queue);
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

	if (!ondemand) {
		/*
		 * If firmware keep reloading, then it indicate something
		 * serious wrong and firmware having problem to recover
		 * from it. Instead of keep trying which will fill the syslog
		 * and hang the system, let's just stop it
		 */
		reload_jiffies = jiffies;
		reload_msec = jiffies_to_msecs((long) reload_jiffies -
					(long) priv->reload_jiffies);
		priv->reload_jiffies = reload_jiffies;
		if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
			priv->reload_count++;
			if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
				IWL_ERR(priv, "BUG_ON, Stop restarting\n");
				return;
			}
		} else
			priv->reload_count = 0;
	}

D
Don Fry 已提交
145
	if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
D
Don Fry 已提交
146
		if (iwlagn_mod_params.restart_fw) {
147
			IWL_DEBUG_FW_ERRORS(priv,
148
				  "Restarting adapter due to uCode error.\n");
J
Johannes Berg 已提交
149
			queue_work(priv->workqueue, &priv->restart);
150
		} else
151
			IWL_DEBUG_FW_ERRORS(priv,
152 153 154 155
				  "Detected FW error, but not restarting\n");
	}
}

156 157
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
{
158 159
	int ret;
	s8 prev_tx_power;
160 161
	bool defer;
	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
162

163
	lockdep_assert_held(&priv->mutex);
164 165 166 167

	if (priv->tx_power_user_lmt == tx_power && !force)
		return 0;

168 169 170
	if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
		IWL_WARN(priv,
			 "Requested user TXPOWER %d below lower limit %d.\n",
171
			 tx_power,
172
			 IWLAGN_TX_POWER_TARGET_POWER_MIN);
173 174 175
		return -EINVAL;
	}

176
	if (tx_power > priv->tx_power_device_lmt) {
177 178
		IWL_WARN(priv,
			"Requested user TXPOWER %d above upper limit %d.\n",
179
			 tx_power, priv->tx_power_device_lmt);
180 181 182
		return -EINVAL;
	}

D
Don Fry 已提交
183
	if (!iwl_is_ready_rf(priv))
184
		return -EIO;
185

186 187
	/* scan complete and commit_rxon use tx_power_next value,
	 * it always need to be updated for newest request */
188
	priv->tx_power_next = tx_power;
189 190

	/* do not set tx power when scanning or channel changing */
D
Don Fry 已提交
191
	defer = test_bit(STATUS_SCANNING, &priv->status) ||
192 193 194
		memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging));
	if (defer && !force) {
		IWL_DEBUG_INFO(priv, "Deferring tx power set\n");
195
		return 0;
196
	}
197

198 199 200
	prev_tx_power = priv->tx_power_user_lmt;
	priv->tx_power_user_lmt = tx_power;

201
	ret = iwlagn_send_tx_power(priv);
202 203 204 205 206 207

	/* if fail to set tx_power, restore the orig. tx power */
	if (ret) {
		priv->tx_power_user_lmt = prev_tx_power;
		priv->tx_power_next = prev_tx_power;
	}
208 209 210
	return ret;
}

211
void iwl_send_bt_config(struct iwl_priv *priv)
212 213
{
	struct iwl_bt_cmd bt_cmd = {
214 215
		.lead_time = BT_LEAD_TIME_DEF,
		.max_kill = BT_MAX_KILL_DEF,
216 217 218 219
		.kill_ack_mask = 0,
		.kill_cts_mask = 0,
	};

220
	if (!iwlagn_mod_params.bt_coex_active)
221 222 223 224
		bt_cmd.flags = BT_COEX_DISABLE;
	else
		bt_cmd.flags = BT_COEX_ENABLE;

225
	priv->bt_enable_flag = bt_cmd.flags;
226 227 228
	IWL_DEBUG_INFO(priv, "BT coex %s\n",
		(bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");

229
	if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG,
230
			     CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd))
231
		IWL_ERR(priv, "failed to send BT Coex Config\n");
232 233
}

234
int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
235
{
236 237 238
	struct iwl_statistics_cmd statistics_cmd = {
		.configuration_flags =
			clear ? IWL_STATS_CONF_CLEAR_STATS : 0,
239
	};
240 241

	if (flags & CMD_ASYNC)
242
		return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
243
					      CMD_ASYNC,
244
					       sizeof(struct iwl_statistics_cmd),
245
					       &statistics_cmd);
246
	else
247
		return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
248
					CMD_SYNC,
249 250
					sizeof(struct iwl_statistics_cmd),
					&statistics_cmd);
251
}
252

A
Abhijeet Kolekar 已提交
253

254

255

256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
#ifdef CONFIG_IWLWIFI_DEBUGFS

#define IWL_TRAFFIC_DUMP_SIZE	(IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)

void iwl_reset_traffic_log(struct iwl_priv *priv)
{
	priv->tx_traffic_idx = 0;
	priv->rx_traffic_idx = 0;
	if (priv->tx_traffic)
		memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
	if (priv->rx_traffic)
		memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE);
}

int iwl_alloc_traffic_mem(struct iwl_priv *priv)
{
	u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE;

274
	if (iwl_have_debug_level(IWL_DL_TX)) {
275 276 277 278 279 280 281
		if (!priv->tx_traffic) {
			priv->tx_traffic =
				kzalloc(traffic_size, GFP_KERNEL);
			if (!priv->tx_traffic)
				return -ENOMEM;
		}
	}
282
	if (iwl_have_debug_level(IWL_DL_RX)) {
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
		if (!priv->rx_traffic) {
			priv->rx_traffic =
				kzalloc(traffic_size, GFP_KERNEL);
			if (!priv->rx_traffic)
				return -ENOMEM;
		}
	}
	iwl_reset_traffic_log(priv);
	return 0;
}

void iwl_free_traffic_mem(struct iwl_priv *priv)
{
	kfree(priv->tx_traffic);
	priv->tx_traffic = NULL;

	kfree(priv->rx_traffic);
	priv->rx_traffic = NULL;
}

void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv,
		      u16 length, struct ieee80211_hdr *header)
{
	__le16 fc;
	u16 len;

309
	if (likely(!iwl_have_debug_level(IWL_DL_TX)))
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
		return;

	if (!priv->tx_traffic)
		return;

	fc = header->frame_control;
	if (ieee80211_is_data(fc)) {
		len = (length > IWL_TRAFFIC_ENTRY_SIZE)
		       ? IWL_TRAFFIC_ENTRY_SIZE : length;
		memcpy((priv->tx_traffic +
		       (priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
		       header, len);
		priv->tx_traffic_idx =
			(priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
	}
}

void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv,
		      u16 length, struct ieee80211_hdr *header)
{
	__le16 fc;
	u16 len;

333
	if (likely(!iwl_have_debug_level(IWL_DL_RX)))
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
		return;

	if (!priv->rx_traffic)
		return;

	fc = header->frame_control;
	if (ieee80211_is_data(fc)) {
		len = (length > IWL_TRAFFIC_ENTRY_SIZE)
		       ? IWL_TRAFFIC_ENTRY_SIZE : length;
		memcpy((priv->rx_traffic +
		       (priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)),
		       header, len);
		priv->rx_traffic_idx =
			(priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES;
	}
}
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388

const char *get_mgmt_string(int cmd)
{
	switch (cmd) {
		IWL_CMD(MANAGEMENT_ASSOC_REQ);
		IWL_CMD(MANAGEMENT_ASSOC_RESP);
		IWL_CMD(MANAGEMENT_REASSOC_REQ);
		IWL_CMD(MANAGEMENT_REASSOC_RESP);
		IWL_CMD(MANAGEMENT_PROBE_REQ);
		IWL_CMD(MANAGEMENT_PROBE_RESP);
		IWL_CMD(MANAGEMENT_BEACON);
		IWL_CMD(MANAGEMENT_ATIM);
		IWL_CMD(MANAGEMENT_DISASSOC);
		IWL_CMD(MANAGEMENT_AUTH);
		IWL_CMD(MANAGEMENT_DEAUTH);
		IWL_CMD(MANAGEMENT_ACTION);
	default:
		return "UNKNOWN";

	}
}

const char *get_ctrl_string(int cmd)
{
	switch (cmd) {
		IWL_CMD(CONTROL_BACK_REQ);
		IWL_CMD(CONTROL_BACK);
		IWL_CMD(CONTROL_PSPOLL);
		IWL_CMD(CONTROL_RTS);
		IWL_CMD(CONTROL_CTS);
		IWL_CMD(CONTROL_ACK);
		IWL_CMD(CONTROL_CFEND);
		IWL_CMD(CONTROL_CFENDACK);
	default:
		return "UNKNOWN";

	}
}

389
void iwl_clear_traffic_stats(struct iwl_priv *priv)
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
{
	memset(&priv->tx_stats, 0, sizeof(struct traffic_stats));
	memset(&priv->rx_stats, 0, sizeof(struct traffic_stats));
}

/*
 * if CONFIG_IWLWIFI_DEBUGFS defined, iwl_update_stats function will
 * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass.
 * Use debugFs to display the rx/rx_statistics
 * if CONFIG_IWLWIFI_DEBUGFS not being defined, then no MGMT and CTRL
 * information will be recorded, but DATA pkt still will be recorded
 * for the reason of iwl_led.c need to control the led blinking based on
 * number of tx and rx data.
 *
 */
void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
{
	struct traffic_stats	*stats;

	if (is_tx)
		stats = &priv->tx_stats;
	else
		stats = &priv->rx_stats;

	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;
	}
}
486 487
#endif

488
int iwl_force_rf_reset(struct iwl_priv *priv, bool external)
489
{
490 491
	struct iwl_rf_reset *rf_reset;

D
Don Fry 已提交
492
	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
493
		return -EAGAIN;
494

495
	if (!iwl_is_any_associated(priv)) {
496
		IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
497
		return -ENOLINK;
498
	}
499 500 501 502 503 504 505 506 507 508 509 510 511

	rf_reset = &priv->rf_reset;
	rf_reset->reset_request_count++;
	if (!external && rf_reset->last_reset_jiffies &&
	    time_after(rf_reset->last_reset_jiffies +
		       IWL_DELAY_NEXT_FORCE_RF_RESET, jiffies)) {
		IWL_DEBUG_INFO(priv, "RF reset rejected\n");
		rf_reset->reset_reject_count++;
		return -EAGAIN;
	}
	rf_reset->reset_success_count++;
	rf_reset->last_reset_jiffies = jiffies;

512 513 514 515 516 517 518 519 520 521 522
	/*
	 * There is no easy and better way to force reset the radio,
	 * the only known method is switching channel which will force to
	 * reset and tune the radio.
	 * Use internal short scan (single channel) operation to should
	 * achieve this objective.
	 * Driver should reset the radio when number of consecutive missed
	 * beacon, or any other uCode error condition detected.
	 */
	IWL_DEBUG_INFO(priv, "perform radio reset.\n");
	iwl_internal_short_hw_scan(priv);
W
Wey-Yi Guy 已提交
523 524
	return 0;
}
525

526

527 528
int iwl_cmd_echo_test(struct iwl_priv *priv)
{
529
	int ret;
530 531
	struct iwl_host_cmd cmd = {
		.id = REPLY_ECHO,
532
		.len = { 0 },
533 534 535
		.flags = CMD_SYNC,
	};

536
	ret = iwl_dvm_send_cmd(priv, &cmd);
537 538 539 540 541
	if (ret)
		IWL_ERR(priv, "echo testing fail: 0X%x\n", ret);
	else
		IWL_DEBUG_INFO(priv, "echo testing pass\n");
	return ret;
542
}