aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm
diff options
context:
space:
mode:
authorEytan Lifshitz <eytan.lifshitz@intel.com>2013-09-11 06:39:18 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-10-11 03:56:58 -0400
commit81a67e32c444f05b9f7ba5d33c9221db9d0133e1 (patch)
tree35dc981ffa2be4eb0916151a578de85c75eba7f2 /drivers/net/wireless/iwlwifi/mvm
parent64b928c4e2898dea07d5850a0708dceeb118fa3b (diff)
iwlwifi: mvm: prevent the NIC to be powered at driver load time.
Some NICs aren't allowed to be powered up at driver load time. Fix it, and move the external NVM loading from driver load time to driver up time (parsing the external nvm file remains at driver load time). Signed-off-by: Eytan Lifshitz <eytan.lifshitz@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c5
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c99
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c41
4 files changed, 97 insertions, 49 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index 8c784e622802..f171dca83cd2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -264,6 +264,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
264 if (ret) 264 if (ret)
265 goto error; 265 goto error;
266 266
267 /* Read the NVM only at driver load time, no need to do this twice */
267 if (read_nvm) { 268 if (read_nvm) {
268 /* Read nvm */ 269 /* Read nvm */
269 ret = iwl_nvm_init(mvm); 270 ret = iwl_nvm_init(mvm);
@@ -273,6 +274,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
273 } 274 }
274 } 275 }
275 276
277 /* In case we read the NVM from external file, load it to the NIC */
278 if (iwlwifi_mod_params.nvm_file)
279 iwl_mvm_load_nvm_to_nic(mvm);
280
276 ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); 281 ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans);
277 WARN_ON(ret); 282 WARN_ON(ret);
278 283
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index a5d609749755..6bce6e168ae4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -629,6 +629,7 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
629 629
630/* NVM */ 630/* NVM */
631int iwl_nvm_init(struct iwl_mvm *mvm); 631int iwl_nvm_init(struct iwl_mvm *mvm);
632int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm);
632 633
633int iwl_mvm_up(struct iwl_mvm *mvm); 634int iwl_mvm_up(struct iwl_mvm *mvm);
634int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm); 635int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm);
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index edb94ea31654..e4edda6e5306 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -259,6 +259,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
259#define MAX_NVM_FILE_LEN 16384 259#define MAX_NVM_FILE_LEN 16384
260 260
261/* 261/*
262 * Reads external NVM from a file into mvm->nvm_sections
263 *
262 * HOW TO CREATE THE NVM FILE FORMAT: 264 * HOW TO CREATE THE NVM FILE FORMAT:
263 * ------------------------------ 265 * ------------------------------
264 * 1. create hex file, format: 266 * 1. create hex file, format:
@@ -277,20 +279,23 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
277 * 279 *
278 * 4. save as "iNVM_xxx.bin" under /lib/firmware 280 * 4. save as "iNVM_xxx.bin" under /lib/firmware
279 */ 281 */
280static int iwl_mvm_load_external_nvm(struct iwl_mvm *mvm) 282static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
281{ 283{
282 int ret, section_id, section_size; 284 int ret, section_size;
285 u16 section_id;
283 const struct firmware *fw_entry; 286 const struct firmware *fw_entry;
284 const struct { 287 const struct {
285 __le16 word1; 288 __le16 word1;
286 __le16 word2; 289 __le16 word2;
287 u8 data[]; 290 u8 data[];
288 } *file_sec; 291 } *file_sec;
289 const u8 *eof; 292 const u8 *eof, *temp;
290 293
291#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) 294#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
292#define NVM_WORD2_ID(x) (x >> 12) 295#define NVM_WORD2_ID(x) (x >> 12)
293 296
297 IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");
298
294 /* 299 /*
295 * Obtain NVM image via request_firmware. Since we already used 300 * Obtain NVM image via request_firmware. Since we already used
296 * request_firmware_nowait() for the firmware binary load and only 301 * request_firmware_nowait() for the firmware binary load and only
@@ -362,12 +367,18 @@ static int iwl_mvm_load_external_nvm(struct iwl_mvm *mvm)
362 break; 367 break;
363 } 368 }
364 369
365 ret = iwl_nvm_write_section(mvm, section_id, file_sec->data, 370 temp = kmemdup(file_sec->data, section_size, GFP_KERNEL);
366 section_size); 371 if (!temp) {
367 if (ret < 0) { 372 ret = -ENOMEM;
368 IWL_ERR(mvm, "iwl_mvm_send_cmd failed: %d\n", ret); 373 break;
374 }
375 if (WARN_ON(section_id >= NVM_NUM_OF_SECTIONS)) {
376 IWL_ERR(mvm, "Invalid NVM section ID\n");
377 ret = -EINVAL;
369 break; 378 break;
370 } 379 }
380 mvm->nvm_sections[section_id].data = temp;
381 mvm->nvm_sections[section_id].length = section_size;
371 382
372 /* advance to the next section */ 383 /* advance to the next section */
373 file_sec = (void *)(file_sec->data + section_size); 384 file_sec = (void *)(file_sec->data + section_size);
@@ -377,6 +388,28 @@ out:
377 return ret; 388 return ret;
378} 389}
379 390
391/* Loads the NVM data stored in mvm->nvm_sections into the NIC */
392int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm)
393{
394 int i, ret;
395 u16 section_id;
396 struct iwl_nvm_section *sections = mvm->nvm_sections;
397
398 IWL_DEBUG_EEPROM(mvm->trans->dev, "'Write to NVM\n");
399
400 for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
401 section_id = nvm_to_read[i];
402 ret = iwl_nvm_write_section(mvm, section_id,
403 sections[section_id].data,
404 sections[section_id].length);
405 if (ret < 0) {
406 IWL_ERR(mvm, "iwl_mvm_send_cmd failed: %d\n", ret);
407 break;
408 }
409 }
410 return ret;
411}
412
380int iwl_nvm_init(struct iwl_mvm *mvm) 413int iwl_nvm_init(struct iwl_mvm *mvm)
381{ 414{
382 int ret, i, section; 415 int ret, i, section;
@@ -385,36 +418,36 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
385 /* load external NVM if configured */ 418 /* load external NVM if configured */
386 if (iwlwifi_mod_params.nvm_file) { 419 if (iwlwifi_mod_params.nvm_file) {
387 /* move to External NVM flow */ 420 /* move to External NVM flow */
388 ret = iwl_mvm_load_external_nvm(mvm); 421 ret = iwl_mvm_read_external_nvm(mvm);
389 if (ret) 422 if (ret)
390 return ret; 423 return ret;
391 } 424 } else {
392 425 /* Read From FW NVM */
393 /* Read From FW NVM */ 426 IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n");
394 IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); 427
395 428 /* TODO: find correct NVM max size for a section */
396 /* TODO: find correct NVM max size for a section */ 429 nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
397 nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, 430 GFP_KERNEL);
398 GFP_KERNEL); 431 if (!nvm_buffer)
399 if (!nvm_buffer) 432 return -ENOMEM;
400 return -ENOMEM; 433 for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
401 for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) { 434 section = nvm_to_read[i];
402 section = nvm_to_read[i]; 435 /* we override the constness for initial read */
403 /* we override the constness for initial read */ 436 ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
404 ret = iwl_nvm_read_section(mvm, section, nvm_buffer); 437 if (ret < 0)
405 if (ret < 0) 438 break;
406 break; 439 temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
407 temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); 440 if (!temp) {
408 if (!temp) { 441 ret = -ENOMEM;
409 ret = -ENOMEM; 442 break;
410 break; 443 }
444 mvm->nvm_sections[section].data = temp;
445 mvm->nvm_sections[section].length = ret;
411 } 446 }
412 mvm->nvm_sections[section].data = temp; 447 kfree(nvm_buffer);
413 mvm->nvm_sections[section].length = ret; 448 if (ret < 0)
449 return ret;
414 } 450 }
415 kfree(nvm_buffer);
416 if (ret < 0)
417 return ret;
418 451
419 mvm->nvm_data = iwl_parse_nvm_sections(mvm); 452 mvm->nvm_data = iwl_parse_nvm_sections(mvm);
420 if (!mvm->nvm_data) 453 if (!mvm->nvm_data)
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index a8af7aceeaca..d232e83994df 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -409,24 +409,32 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
409 IWL_INFO(mvm, "Detected %s, REV=0x%X\n", 409 IWL_INFO(mvm, "Detected %s, REV=0x%X\n",
410 mvm->cfg->name, mvm->trans->hw_rev); 410 mvm->cfg->name, mvm->trans->hw_rev);
411 411
412 err = iwl_trans_start_hw(mvm->trans);
413 if (err)
414 goto out_free;
415
416 iwl_mvm_tt_initialize(mvm); 412 iwl_mvm_tt_initialize(mvm);
417 413
418 mutex_lock(&mvm->mutex); 414 /*
419 err = iwl_run_init_mvm_ucode(mvm, true); 415 * If the NVM exists in an external file,
420 mutex_unlock(&mvm->mutex); 416 * there is no need to unnecessarily power up the NIC at driver load
421 /* returns 0 if successful, 1 if success but in rfkill */ 417 */
422 if (err < 0 && !iwlmvm_mod_params.init_dbg) { 418 if (iwlwifi_mod_params.nvm_file) {
423 IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); 419 iwl_nvm_init(mvm);
424 goto out_free; 420 } else {
425 } 421 err = iwl_trans_start_hw(mvm->trans);
422 if (err)
423 goto out_free;
424
425 mutex_lock(&mvm->mutex);
426 err = iwl_run_init_mvm_ucode(mvm, true);
427 mutex_unlock(&mvm->mutex);
428 /* returns 0 if successful, 1 if success but in rfkill */
429 if (err < 0 && !iwlmvm_mod_params.init_dbg) {
430 IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
431 goto out_free;
432 }
426 433
427 /* Stop the hw after the ALIVE and NVM has been read */ 434 /* Stop the hw after the ALIVE and NVM has been read */
428 if (!iwlmvm_mod_params.init_dbg) 435 if (!iwlmvm_mod_params.init_dbg)
429 iwl_trans_stop_hw(mvm->trans, false); 436 iwl_trans_stop_hw(mvm->trans, false);
437 }
430 438
431 scan_size = sizeof(struct iwl_scan_cmd) + 439 scan_size = sizeof(struct iwl_scan_cmd) +
432 mvm->fw->ucode_capa.max_probe_length + 440 mvm->fw->ucode_capa.max_probe_length +
@@ -457,7 +465,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
457 out_free: 465 out_free:
458 iwl_phy_db_free(mvm->phy_db); 466 iwl_phy_db_free(mvm->phy_db);
459 kfree(mvm->scan_cmd); 467 kfree(mvm->scan_cmd);
460 iwl_trans_stop_hw(trans, true); 468 if (!iwlwifi_mod_params.nvm_file)
469 iwl_trans_stop_hw(trans, true);
461 ieee80211_free_hw(mvm->hw); 470 ieee80211_free_hw(mvm->hw);
462 return NULL; 471 return NULL;
463} 472}