iwl-ucode.c 17.9 KB
Newer Older
1 2 3 4
/******************************************************************************
 *
 * GPL LICENSE SUMMARY
 *
W
Wey-Yi Guy 已提交
5
 * Copyright(c) 2008 - 2012 Intel Corporation. All rights reserved.
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
 *
 * 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/init.h>
32
#include <linux/sched.h>
33 34 35

#include "iwl-dev.h"
#include "iwl-core.h"
36
#include "iwl-io.h"
37
#include "iwl-agn-hw.h"
38
#include "iwl-agn.h"
J
Johannes Berg 已提交
39
#include "iwl-agn-calib.h"
40
#include "iwl-trans.h"
41
#include "iwl-fh.h"
42
#include "iwl-op-mode.h"
43

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
	{COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
	 0, COEX_UNASSOC_IDLE_FLAGS},
	{COEX_CU_UNASSOC_MANUAL_SCAN_RP, COEX_CU_UNASSOC_MANUAL_SCAN_WP,
	 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
	{COEX_CU_UNASSOC_AUTO_SCAN_RP, COEX_CU_UNASSOC_AUTO_SCAN_WP,
	 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
	{COEX_CU_CALIBRATION_RP, COEX_CU_CALIBRATION_WP,
	 0, COEX_CALIBRATION_FLAGS},
	{COEX_CU_PERIODIC_CALIBRATION_RP, COEX_CU_PERIODIC_CALIBRATION_WP,
	 0, COEX_PERIODIC_CALIBRATION_FLAGS},
	{COEX_CU_CONNECTION_ESTAB_RP, COEX_CU_CONNECTION_ESTAB_WP,
	 0, COEX_CONNECTION_ESTAB_FLAGS},
	{COEX_CU_ASSOCIATED_IDLE_RP, COEX_CU_ASSOCIATED_IDLE_WP,
	 0, COEX_ASSOCIATED_IDLE_FLAGS},
	{COEX_CU_ASSOC_MANUAL_SCAN_RP, COEX_CU_ASSOC_MANUAL_SCAN_WP,
	 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
	{COEX_CU_ASSOC_AUTO_SCAN_RP, COEX_CU_ASSOC_AUTO_SCAN_WP,
	 0, COEX_ASSOC_AUTO_SCAN_FLAGS},
	{COEX_CU_ASSOC_ACTIVE_LEVEL_RP, COEX_CU_ASSOC_ACTIVE_LEVEL_WP,
	 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS},
	{COEX_CU_RF_ON_RP, COEX_CU_RF_ON_WP, 0, COEX_CU_RF_ON_FLAGS},
	{COEX_CU_RF_OFF_RP, COEX_CU_RF_OFF_WP, 0, COEX_RF_OFF_FLAGS},
	{COEX_CU_STAND_ALONE_DEBUG_RP, COEX_CU_STAND_ALONE_DEBUG_WP,
	 0, COEX_STAND_ALONE_DEBUG_FLAGS},
	{COEX_CU_IPAN_ASSOC_LEVEL_RP, COEX_CU_IPAN_ASSOC_LEVEL_WP,
	 0, COEX_IPAN_ASSOC_LEVEL_FLAGS},
	{COEX_CU_RSRVD1_RP, COEX_CU_RSRVD1_WP, 0, COEX_RSRVD1_FLAGS},
	{COEX_CU_RSRVD2_RP, COEX_CU_RSRVD2_WP, 0, COEX_RSRVD2_FLAGS}
};

75 76 77 78 79 80
/******************************************************************************
 *
 * uCode download functions
 *
 ******************************************************************************/

81 82
static inline const struct fw_img *
iwl_get_ucode_image(struct iwl_priv *priv, enum iwl_ucode_type ucode_type)
83 84 85
{
	switch (ucode_type) {
	case IWL_UCODE_INIT:
86
		return &priv->fw->ucode_init;
87
	case IWL_UCODE_WOWLAN:
88
		return &priv->fw->ucode_wowlan;
89
	case IWL_UCODE_REGULAR:
90
		return &priv->fw->ucode_rt;
91 92 93 94 95 96
	case IWL_UCODE_NONE:
		break;
	}
	return NULL;
}

97 98 99
/*
 *  Calibration
 */
100
static int iwl_set_Xtal_calib(struct iwl_priv *priv)
101 102 103
{
	struct iwl_calib_xtal_freq_cmd cmd;
	__le16 *xtal_calib =
104
		(__le16 *)iwl_eeprom_query_addr(priv->shrd, EEPROM_XTAL);
105

106
	iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD);
107 108
	cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
	cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]);
109
	return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
110 111
}

112
static int iwl_set_temperature_offset_calib(struct iwl_priv *priv)
113 114 115
{
	struct iwl_calib_temperature_offset_cmd cmd;
	__le16 *offset_calib =
116
		(__le16 *)iwl_eeprom_query_addr(priv->shrd,
117
						EEPROM_RAW_TEMPERATURE);
118 119 120

	memset(&cmd, 0, sizeof(cmd));
	iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
J
Johannes Berg 已提交
121
	memcpy(&cmd.radio_sensor_offset, offset_calib, sizeof(*offset_calib));
122 123
	if (!(cmd.radio_sensor_offset))
		cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET;
124

125
	IWL_DEBUG_CALIB(priv, "Radio sensor offset: %d\n",
126
			le16_to_cpu(cmd.radio_sensor_offset));
127
	return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
128 129
}

130
static int iwl_set_temperature_offset_calib_v2(struct iwl_priv *priv)
131 132
{
	struct iwl_calib_temperature_offset_v2_cmd cmd;
133
	__le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv->shrd,
134 135
				     EEPROM_KELVIN_TEMPERATURE);
	__le16 *offset_calib_low =
136
		(__le16 *)iwl_eeprom_query_addr(priv->shrd,
137
						EEPROM_RAW_TEMPERATURE);
138
	struct iwl_eeprom_calib_hdr *hdr;
139 140 141

	memset(&cmd, 0, sizeof(cmd));
	iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
142
	hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv->shrd,
143
							EEPROM_CALIB_ALL);
144
	memcpy(&cmd.radio_sensor_offset_high, offset_calib_high,
145
		sizeof(*offset_calib_high));
146
	memcpy(&cmd.radio_sensor_offset_low, offset_calib_low,
147
		sizeof(*offset_calib_low));
148
	if (!(cmd.radio_sensor_offset_low)) {
149
		IWL_DEBUG_CALIB(priv, "no info in EEPROM, use default\n");
150 151 152
		cmd.radio_sensor_offset_low = DEFAULT_RADIO_SENSOR_OFFSET;
		cmd.radio_sensor_offset_high = DEFAULT_RADIO_SENSOR_OFFSET;
	}
153 154
	memcpy(&cmd.burntVoltageRef, &hdr->voltage,
		sizeof(hdr->voltage));
155

156
	IWL_DEBUG_CALIB(priv, "Radio sensor offset high: %d\n",
157
			le16_to_cpu(cmd.radio_sensor_offset_high));
158
	IWL_DEBUG_CALIB(priv, "Radio sensor offset low: %d\n",
159
			le16_to_cpu(cmd.radio_sensor_offset_low));
160
	IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n",
161 162
			le16_to_cpu(cmd.burntVoltageRef));

163
	return iwl_calib_set(priv, (void *)&cmd, sizeof(cmd));
164 165
}

166
static int iwl_send_calib_cfg(struct iwl_priv *priv)
167 168 169 170
{
	struct iwl_calib_cfg_cmd calib_cfg_cmd;
	struct iwl_host_cmd cmd = {
		.id = CALIBRATION_CFG_CMD,
171 172
		.len = { sizeof(struct iwl_calib_cfg_cmd), },
		.data = { &calib_cfg_cmd, },
173 174 175 176 177 178
	};

	memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
	calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
	calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
	calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
179 180
	calib_cfg_cmd.ucd_calib_cfg.flags =
		IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK;
181

182
	return iwl_dvm_send_cmd(priv, &cmd);
183 184
}

185
int iwlagn_rx_calib_result(struct iwl_priv *priv,
186
			    struct iwl_rx_cmd_buffer *rxb,
187
			    struct iwl_device_cmd *cmd)
188 189 190 191 192 193 194 195
{
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
	struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
	int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;

	/* reduce the size of the length field itself */
	len -= 4;

196
	if (iwl_calib_set(priv, hdr, len))
197 198 199
		IWL_ERR(priv, "Failed to record calibration data %d\n",
			hdr->op_code);

200
	return 0;
201 202
}

203
int iwl_init_alive_start(struct iwl_priv *priv)
204
{
205
	int ret;
206

207 208
	if (cfg(priv)->bt_params &&
	    cfg(priv)->bt_params->advanced_bt_coexist) {
209 210 211 212 213 214
		/*
		 * Tell uCode we are ready to perform calibration
		 * need to perform this before any calibration
		 * no need to close the envlope since we are going
		 * to load the runtime uCode later.
		 */
215
		ret = iwl_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
216
			BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
217 218
		if (ret)
			return ret;
219 220

	}
221

222
	ret = iwl_send_calib_cfg(priv);
223 224
	if (ret)
		return ret;
225 226 227 228 229

	/**
	 * temperature offset calibration is only needed for runtime ucode,
	 * so prepare the value now.
	 */
230 231 232
	if (cfg(priv)->need_temp_offset_calib) {
		if (cfg(priv)->temp_offset_v2)
			return iwl_set_temperature_offset_calib_v2(priv);
233
		else
234
			return iwl_set_temperature_offset_calib(priv);
235
	}
236

237
	return 0;
238 239
}

240
static int iwl_send_wimax_coex(struct iwl_priv *priv)
241 242 243
{
	struct iwl_wimax_coex_cmd coex_cmd;

244
	if (cfg(priv)->base_params->support_wimax_coexist) {
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
		/* UnMask wake up src at associated sleep */
		coex_cmd.flags = COEX_FLAGS_ASSOC_WA_UNMASK_MSK;

		/* UnMask wake up src at unassociated sleep */
		coex_cmd.flags |= COEX_FLAGS_UNASSOC_WA_UNMASK_MSK;
		memcpy(coex_cmd.sta_prio, cu_priorities,
			sizeof(struct iwl_wimax_coex_event_entry) *
			 COEX_NUM_OF_EVENTS);

		/* enabling the coexistence feature */
		coex_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK;

		/* enabling the priorities tables */
		coex_cmd.flags |= COEX_FLAGS_STA_TABLE_VALID_MSK;
	} else {
		/* coexistence is disabled */
		memset(&coex_cmd, 0, sizeof(coex_cmd));
	}
263
	return iwl_dvm_send_cmd_pdu(priv,
264
				COEX_PRIORITY_TABLE_CMD, CMD_SYNC,
265 266 267
				sizeof(coex_cmd), &coex_cmd);
}

268
static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
	((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
	((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
		(1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
	((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
	((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
		(1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
	((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
	((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
		(1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
	((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
	((BT_COEX_PRIO_TBL_PRIO_COEX_OFF << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
	((BT_COEX_PRIO_TBL_PRIO_COEX_ON << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
		(0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
	0, 0, 0, 0, 0, 0, 0
};

290
void iwl_send_prio_tbl(struct iwl_priv *priv)
291 292 293
{
	struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd;

294 295
	memcpy(prio_tbl_cmd.prio_tbl, iwl_bt_prio_tbl,
		sizeof(iwl_bt_prio_tbl));
296
	if (iwl_dvm_send_cmd_pdu(priv,
297
				REPLY_BT_COEX_PRIO_TABLE, CMD_SYNC,
298
				sizeof(prio_tbl_cmd), &prio_tbl_cmd))
299
		IWL_ERR(priv, "failed to send BT prio tbl command\n");
300 301
}

302
int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
303 304
{
	struct iwl_bt_coex_prot_env_cmd env_cmd;
305
	int ret;
306 307 308

	env_cmd.action = action;
	env_cmd.type = type;
309
	ret = iwl_dvm_send_cmd_pdu(priv,
310
			       REPLY_BT_COEX_PROT_ENV, CMD_SYNC,
311 312
			       sizeof(env_cmd), &env_cmd);
	if (ret)
313
		IWL_ERR(priv, "failed to send BT env command\n");
314
	return ret;
315 316 317
}


318
static int iwl_alive_notify(struct iwl_priv *priv)
319
{
320
	struct iwl_rxon_context *ctx;
321
	int ret;
322

323 324
	if (!priv->tx_cmd_pool)
		priv->tx_cmd_pool =
325
			kmem_cache_create("iwl_dev_cmd",
326 327 328 329 330 331
					  sizeof(struct iwl_device_cmd),
					  sizeof(void *), 0, NULL);

	if (!priv->tx_cmd_pool)
		return -ENOMEM;

332
	iwl_trans_fw_alive(trans(priv));
333 334
	for_each_context(priv, ctx)
		ctx->last_tx_rejected = false;
335

336
	ret = iwl_send_wimax_coex(priv);
337 338 339
	if (ret)
		return ret;

340
	if (!cfg(priv)->no_xtal_calib) {
341
		ret = iwl_set_Xtal_calib(priv);
342 343 344
		if (ret)
			return ret;
	}
345

346
	return iwl_send_calib_results(priv);
347
}
348 349 350 351 352 353 354


/**
 * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
 *   using sample data 100 bytes apart.  If these sample points are good,
 *   it's a pretty good bet that everything between them is good, too.
 */
355
static int iwl_verify_inst_sparse(struct iwl_priv *priv,
356
				  const struct fw_desc *fw_desc)
357
{
J
Johannes Berg 已提交
358 359
	__le32 *image = (__le32 *)fw_desc->v_addr;
	u32 len = fw_desc->len;
360 361 362
	u32 val;
	u32 i;

363
	IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
364 365 366 367 368

	for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
		/* read data comes through single port, auto-incr addr */
		/* NOTE: Use the debugless read so we don't flood kernel log
		 * if IWL_DL_IO is set */
369
		iwl_write_direct32(trans(priv), HBUS_TARG_MEM_RADDR,
370
			i + IWLAGN_RTC_INST_LOWER_BOUND);
371
		val = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
372 373
		if (val != le32_to_cpu(*image))
			return -EIO;
374 375
	}

376
	return 0;
377 378
}

379
static void iwl_print_mismatch_inst(struct iwl_priv *priv,
380
				    const struct fw_desc *fw_desc)
381
{
J
Johannes Berg 已提交
382 383
	__le32 *image = (__le32 *)fw_desc->v_addr;
	u32 len = fw_desc->len;
384
	u32 val;
385 386
	u32 offs;
	int errors = 0;
387

388
	IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
389

390
	iwl_write_direct32(trans(priv), HBUS_TARG_MEM_RADDR,
391 392
			   IWLAGN_RTC_INST_LOWER_BOUND);

393 394 395
	for (offs = 0;
	     offs < len && errors < 20;
	     offs += sizeof(u32), image++) {
396
		/* read data comes through single port, auto-incr addr */
397
		val = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT);
398
		if (val != le32_to_cpu(*image)) {
399
			IWL_ERR(priv, "uCode INST section at "
400 401 402
				"offset 0x%x, is 0x%x, s/b 0x%x\n",
				offs, val, le32_to_cpu(*image));
			errors++;
403 404 405 406 407 408 409 410
		}
	}
}

/**
 * iwl_verify_ucode - determine which instruction image is in SRAM,
 *    and verify its contents
 */
411
static int iwl_verify_ucode(struct iwl_priv *priv,
412
			    enum iwl_ucode_type ucode_type)
413
{
414
	const struct fw_img *img = iwl_get_ucode_image(priv, ucode_type);
415 416

	if (!img) {
417
		IWL_ERR(priv, "Invalid ucode requested (%d)\n", ucode_type);
418 419 420
		return -EINVAL;
	}

421 422
	if (!iwl_verify_inst_sparse(priv, &img->code)) {
		IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
423 424 425
		return 0;
	}

426
	IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
427

428
	iwl_print_mismatch_inst(priv, &img->code);
429
	return -EIO;
430
}
431

432
struct iwl_alive_data {
433 434 435 436
	bool valid;
	u8 subtype;
};

437
static void iwl_alive_fn(struct iwl_priv *priv,
438 439 440
			    struct iwl_rx_packet *pkt,
			    void *data)
{
441
	struct iwl_alive_data *alive_data = data;
442 443 444 445
	struct iwl_alive_resp *palive;

	palive = &pkt->u.alive_frame;

446
	IWL_DEBUG_FW(priv, "Alive ucode status 0x%08X revision "
447 448 449 450
		       "0x%01X 0x%01X\n",
		       palive->is_valid, palive->ver_type,
		       palive->ver_subtype);

451
	priv->shrd->device_pointers.error_event_table =
452
		le32_to_cpu(palive->error_event_table_ptr);
453
	priv->shrd->device_pointers.log_event_table =
454 455 456 457 458 459
		le32_to_cpu(palive->log_event_table_ptr);

	alive_data->subtype = palive->ver_subtype;
	alive_data->valid = palive->is_valid == UCODE_VALID_OK;
}

460 461
/* notification wait support */
void iwl_init_notification_wait(struct iwl_shared *shrd,
462 463 464 465 466 467
				struct iwl_notification_wait *wait_entry,
				u8 cmd,
				void (*fn)(struct iwl_priv *priv,
					   struct iwl_rx_packet *pkt,
					   void *data),
				void *fn_data)
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
{
	wait_entry->fn = fn;
	wait_entry->fn_data = fn_data;
	wait_entry->cmd = cmd;
	wait_entry->triggered = false;
	wait_entry->aborted = false;

	spin_lock_bh(&shrd->notif_wait_lock);
	list_add(&wait_entry->list, &shrd->notif_waits);
	spin_unlock_bh(&shrd->notif_wait_lock);
}

int iwl_wait_notification(struct iwl_shared *shrd,
			     struct iwl_notification_wait *wait_entry,
			     unsigned long timeout)
{
	int ret;

	ret = wait_event_timeout(shrd->notif_waitq,
				 wait_entry->triggered || wait_entry->aborted,
				 timeout);

	spin_lock_bh(&shrd->notif_wait_lock);
	list_del(&wait_entry->list);
	spin_unlock_bh(&shrd->notif_wait_lock);

	if (wait_entry->aborted)
		return -EIO;

	/* return value is always >= 0 */
	if (ret <= 0)
		return -ETIMEDOUT;
	return 0;
}

void iwl_remove_notification(struct iwl_shared *shrd,
				struct iwl_notification_wait *wait_entry)
{
	spin_lock_bh(&shrd->notif_wait_lock);
	list_del(&wait_entry->list);
	spin_unlock_bh(&shrd->notif_wait_lock);
}

void iwl_abort_notification_waits(struct iwl_shared *shrd)
{
	unsigned long flags;
	struct iwl_notification_wait *wait_entry;

	spin_lock_irqsave(&shrd->notif_wait_lock, flags);
	list_for_each_entry(wait_entry, &shrd->notif_waits, list)
		wait_entry->aborted = true;
	spin_unlock_irqrestore(&shrd->notif_wait_lock, flags);

	wake_up_all(&shrd->notif_waitq);
}

524 525 526
#define UCODE_ALIVE_TIMEOUT	HZ
#define UCODE_CALIB_TIMEOUT	(2*HZ)

527
int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
528
				 enum iwl_ucode_type ucode_type)
529 530
{
	struct iwl_notification_wait alive_wait;
531
	struct iwl_alive_data alive_data;
532
	const struct fw_img *fw;
533
	int ret;
534
	enum iwl_ucode_type old_type;
535

536
	iwl_init_notification_wait(priv->shrd, &alive_wait, REPLY_ALIVE,
537
				      iwl_alive_fn, &alive_data);
538

539 540 541
	old_type = priv->shrd->ucode_type;
	priv->shrd->ucode_type = ucode_type;
	fw = iwl_get_ucode_image(priv, ucode_type);
542

543 544 545
	if (!fw)
		return -EINVAL;

546
	ret = iwl_trans_start_fw(trans(priv), fw);
547
	if (ret) {
548 549
		priv->shrd->ucode_type = old_type;
		iwl_remove_notification(priv->shrd, &alive_wait);
550 551 552 553 554 555 556
		return ret;
	}

	/*
	 * Some things may run in the background now, but we
	 * just wait for the ALIVE notification here.
	 */
557
	ret = iwl_wait_notification(priv->shrd, &alive_wait,
558
					UCODE_ALIVE_TIMEOUT);
559
	if (ret) {
560
		priv->shrd->ucode_type = old_type;
561 562 563 564
		return ret;
	}

	if (!alive_data.valid) {
565 566
		IWL_ERR(priv, "Loaded ucode is not valid!\n");
		priv->shrd->ucode_type = old_type;
567 568 569
		return -EIO;
	}

J
Johannes Berg 已提交
570 571 572 573 574 575
	/*
	 * This step takes a long time (60-80ms!!) and
	 * WoWLAN image should be loaded quickly, so
	 * skip it for WoWLAN.
	 */
	if (ucode_type != IWL_UCODE_WOWLAN) {
576
		ret = iwl_verify_ucode(priv, ucode_type);
J
Johannes Berg 已提交
577
		if (ret) {
578
			priv->shrd->ucode_type = old_type;
J
Johannes Berg 已提交
579 580
			return ret;
		}
581

J
Johannes Berg 已提交
582 583 584
		/* delay a bit to give rfkill time to run */
		msleep(5);
	}
585

586
	ret = iwl_alive_notify(priv);
587
	if (ret) {
588
		IWL_WARN(priv,
589
			"Could not complete ALIVE transition: %d\n", ret);
590
		priv->shrd->ucode_type = old_type;
591 592 593 594 595 596
		return ret;
	}

	return 0;
}

597
int iwl_run_init_ucode(struct iwl_priv *priv)
598 599 600 601
{
	struct iwl_notification_wait calib_wait;
	int ret;

602
	lockdep_assert_held(&priv->shrd->mutex);
603 604

	/* No init ucode required? Curious, but maybe ok */
605
	if (!priv->fw->ucode_init.code.len)
606 607
		return 0;

608
	if (priv->shrd->ucode_type != IWL_UCODE_NONE)
609 610
		return 0;

611
	iwl_init_notification_wait(priv->shrd, &calib_wait,
612 613 614 615
				      CALIBRATION_COMPLETE_NOTIFICATION,
				      NULL, NULL);

	/* Will also start the device */
616
	ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
617 618 619
	if (ret)
		goto error;

620
	ret = iwl_init_alive_start(priv);
621 622 623 624 625 626 627
	if (ret)
		goto error;

	/*
	 * Some things may run in the background now, but we
	 * just wait for the calibration complete notification.
	 */
628
	ret = iwl_wait_notification(priv->shrd, &calib_wait,
629
					UCODE_CALIB_TIMEOUT);
630 631 632 633

	goto out;

 error:
634
	iwl_remove_notification(priv->shrd, &calib_wait);
635 636
 out:
	/* Whatever happened, stop the device */
637
	iwl_trans_stop_device(trans(priv));
638 639
	return ret;
}