diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/nvm.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/nvm.c | 101 |
1 files changed, 67 insertions, 34 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index edb94ea31654..2beffd028b67 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c | |||
@@ -77,7 +77,7 @@ static const int nvm_to_read[] = { | |||
77 | 77 | ||
78 | /* Default NVM size to read */ | 78 | /* Default NVM size to read */ |
79 | #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) | 79 | #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) |
80 | #define IWL_MAX_NVM_SECTION_SIZE 6000 | 80 | #define IWL_MAX_NVM_SECTION_SIZE 7000 |
81 | 81 | ||
82 | #define NVM_WRITE_OPCODE 1 | 82 | #define NVM_WRITE_OPCODE 1 |
83 | #define NVM_READ_OPCODE 0 | 83 | #define NVM_READ_OPCODE 0 |
@@ -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 | */ |
280 | static int iwl_mvm_load_external_nvm(struct iwl_mvm *mvm) | 282 | static 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 */ | ||
392 | int 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 | |||
380 | int iwl_nvm_init(struct iwl_mvm *mvm) | 413 | int 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) |