aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/nvm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/nvm.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c102
1 files changed, 56 insertions, 46 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index cf2d09f53782..808f78f6fbf9 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -74,6 +74,12 @@
74#define NVM_WRITE_OPCODE 1 74#define NVM_WRITE_OPCODE 1
75#define NVM_READ_OPCODE 0 75#define NVM_READ_OPCODE 0
76 76
77/* load nvm chunk response */
78enum {
79 READ_NVM_CHUNK_SUCCEED = 0,
80 READ_NVM_CHUNK_NOT_VALID_ADDRESS = 1
81};
82
77/* 83/*
78 * prepare the NVM host command w/ the pointers to the nvm buffer 84 * prepare the NVM host command w/ the pointers to the nvm buffer
79 * and send it to fw 85 * and send it to fw
@@ -90,7 +96,7 @@ static int iwl_nvm_write_chunk(struct iwl_mvm *mvm, u16 section,
90 struct iwl_host_cmd cmd = { 96 struct iwl_host_cmd cmd = {
91 .id = NVM_ACCESS_CMD, 97 .id = NVM_ACCESS_CMD,
92 .len = { sizeof(struct iwl_nvm_access_cmd), length }, 98 .len = { sizeof(struct iwl_nvm_access_cmd), length },
93 .flags = CMD_SYNC | CMD_SEND_IN_RFKILL, 99 .flags = CMD_SEND_IN_RFKILL,
94 .data = { &nvm_access_cmd, data }, 100 .data = { &nvm_access_cmd, data },
95 /* data may come from vmalloc, so use _DUP */ 101 /* data may come from vmalloc, so use _DUP */
96 .dataflags = { 0, IWL_HCMD_DFL_DUP }, 102 .dataflags = { 0, IWL_HCMD_DFL_DUP },
@@ -112,7 +118,7 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
112 struct iwl_rx_packet *pkt; 118 struct iwl_rx_packet *pkt;
113 struct iwl_host_cmd cmd = { 119 struct iwl_host_cmd cmd = {
114 .id = NVM_ACCESS_CMD, 120 .id = NVM_ACCESS_CMD,
115 .flags = CMD_SYNC | CMD_WANT_SKB | CMD_SEND_IN_RFKILL, 121 .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL,
116 .data = { &nvm_access_cmd, }, 122 .data = { &nvm_access_cmd, },
117 }; 123 };
118 int ret, bytes_read, offset_read; 124 int ret, bytes_read, offset_read;
@@ -139,10 +145,26 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
139 offset_read = le16_to_cpu(nvm_resp->offset); 145 offset_read = le16_to_cpu(nvm_resp->offset);
140 resp_data = nvm_resp->data; 146 resp_data = nvm_resp->data;
141 if (ret) { 147 if (ret) {
142 IWL_ERR(mvm, 148 if ((offset != 0) &&
143 "NVM access command failed with status %d (device: %s)\n", 149 (ret == READ_NVM_CHUNK_NOT_VALID_ADDRESS)) {
144 ret, mvm->cfg->name); 150 /*
145 ret = -EINVAL; 151 * meaning of NOT_VALID_ADDRESS:
152 * driver try to read chunk from address that is
153 * multiple of 2K and got an error since addr is empty.
154 * meaning of (offset != 0): driver already
155 * read valid data from another chunk so this case
156 * is not an error.
157 */
158 IWL_DEBUG_EEPROM(mvm->trans->dev,
159 "NVM access command failed on offset 0x%x since that section size is multiple 2K\n",
160 offset);
161 ret = 0;
162 } else {
163 IWL_DEBUG_EEPROM(mvm->trans->dev,
164 "NVM access command failed with status %d (device: %s)\n",
165 ret, mvm->cfg->name);
166 ret = -EIO;
167 }
146 goto exit; 168 goto exit;
147 } 169 }
148 170
@@ -211,9 +233,9 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
211 while (ret == length) { 233 while (ret == length) {
212 ret = iwl_nvm_read_chunk(mvm, section, offset, length, data); 234 ret = iwl_nvm_read_chunk(mvm, section, offset, length, data);
213 if (ret < 0) { 235 if (ret < 0) {
214 IWL_ERR(mvm, 236 IWL_DEBUG_EEPROM(mvm->trans->dev,
215 "Cannot read NVM from section %d offset %d, length %d\n", 237 "Cannot read NVM from section %d offset %d, length %d\n",
216 section, offset, length); 238 section, offset, length);
217 return ret; 239 return ret;
218 } 240 }
219 offset += ret; 241 offset += ret;
@@ -238,13 +260,20 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
238 return NULL; 260 return NULL;
239 } 261 }
240 } else { 262 } else {
263 /* SW and REGULATORY sections are mandatory */
241 if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || 264 if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
242 !mvm->nvm_sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data ||
243 !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) { 265 !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) {
244 IWL_ERR(mvm, 266 IWL_ERR(mvm,
245 "Can't parse empty family 8000 NVM sections\n"); 267 "Can't parse empty family 8000 NVM sections\n");
246 return NULL; 268 return NULL;
247 } 269 }
270 /* MAC_OVERRIDE or at least HW section must exist */
271 if (!mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data &&
272 !mvm->nvm_sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data) {
273 IWL_ERR(mvm,
274 "Can't parse mac_address, empty sections\n");
275 return NULL;
276 }
248 } 277 }
249 278
250 if (WARN_ON(!mvm->cfg)) 279 if (WARN_ON(!mvm->cfg))
@@ -311,16 +340,16 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
311 * get here after that we assume the NVM request can be satisfied 340 * get here after that we assume the NVM request can be satisfied
312 * synchronously. 341 * synchronously.
313 */ 342 */
314 ret = request_firmware(&fw_entry, iwlwifi_mod_params.nvm_file, 343 ret = request_firmware(&fw_entry, mvm->nvm_file_name,
315 mvm->trans->dev); 344 mvm->trans->dev);
316 if (ret) { 345 if (ret) {
317 IWL_ERR(mvm, "ERROR: %s isn't available %d\n", 346 IWL_ERR(mvm, "ERROR: %s isn't available %d\n",
318 iwlwifi_mod_params.nvm_file, ret); 347 mvm->nvm_file_name, ret);
319 return ret; 348 return ret;
320 } 349 }
321 350
322 IWL_INFO(mvm, "Loaded NVM file %s (%zu bytes)\n", 351 IWL_INFO(mvm, "Loaded NVM file %s (%zu bytes)\n",
323 iwlwifi_mod_params.nvm_file, fw_entry->size); 352 mvm->nvm_file_name, fw_entry->size);
324 353
325 if (fw_entry->size < sizeof(*file_sec)) { 354 if (fw_entry->size < sizeof(*file_sec)) {
326 IWL_ERR(mvm, "NVM file too small\n"); 355 IWL_ERR(mvm, "NVM file too small\n");
@@ -427,53 +456,28 @@ int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm)
427 return ret; 456 return ret;
428} 457}
429 458
430int iwl_nvm_init(struct iwl_mvm *mvm) 459int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
431{ 460{
432 int ret, i, section; 461 int ret, section;
433 u8 *nvm_buffer, *temp; 462 u8 *nvm_buffer, *temp;
434 int nvm_to_read[NVM_MAX_NUM_SECTIONS];
435 int num_of_sections_to_read;
436 463
437 if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS)) 464 if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS))
438 return -EINVAL; 465 return -EINVAL;
439 466
440 /* load external NVM if configured */ 467 /* load NVM values from nic */
441 if (iwlwifi_mod_params.nvm_file) { 468 if (read_nvm_from_nic) {
442 /* move to External NVM flow */
443 ret = iwl_mvm_read_external_nvm(mvm);
444 if (ret)
445 return ret;
446 } else {
447 /* list of NVM sections we are allowed/need to read */
448 if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
449 nvm_to_read[0] = mvm->cfg->nvm_hw_section_num;
450 nvm_to_read[1] = NVM_SECTION_TYPE_SW;
451 nvm_to_read[2] = NVM_SECTION_TYPE_CALIBRATION;
452 nvm_to_read[3] = NVM_SECTION_TYPE_PRODUCTION;
453 num_of_sections_to_read = 4;
454 } else {
455 nvm_to_read[0] = NVM_SECTION_TYPE_SW;
456 nvm_to_read[1] = NVM_SECTION_TYPE_CALIBRATION;
457 nvm_to_read[2] = NVM_SECTION_TYPE_PRODUCTION;
458 nvm_to_read[3] = NVM_SECTION_TYPE_REGULATORY;
459 nvm_to_read[4] = NVM_SECTION_TYPE_MAC_OVERRIDE;
460 num_of_sections_to_read = 5;
461 }
462
463 /* Read From FW NVM */ 469 /* Read From FW NVM */
464 IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); 470 IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n");
465 471
466 /* TODO: find correct NVM max size for a section */
467 nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, 472 nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
468 GFP_KERNEL); 473 GFP_KERNEL);
469 if (!nvm_buffer) 474 if (!nvm_buffer)
470 return -ENOMEM; 475 return -ENOMEM;
471 for (i = 0; i < num_of_sections_to_read; i++) { 476 for (section = 0; section < NVM_MAX_NUM_SECTIONS; section++) {
472 section = nvm_to_read[i];
473 /* we override the constness for initial read */ 477 /* we override the constness for initial read */
474 ret = iwl_nvm_read_section(mvm, section, nvm_buffer); 478 ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
475 if (ret < 0) 479 if (ret < 0)
476 break; 480 continue;
477 temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); 481 temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
478 if (!temp) { 482 if (!temp) {
479 ret = -ENOMEM; 483 ret = -ENOMEM;
@@ -502,15 +506,21 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
502 mvm->nvm_hw_blob.size = ret; 506 mvm->nvm_hw_blob.size = ret;
503 break; 507 break;
504 } 508 }
505 WARN(1, "section: %d", section);
506 } 509 }
507#endif 510#endif
508 } 511 }
509 kfree(nvm_buffer); 512 kfree(nvm_buffer);
510 if (ret < 0) 513 }
514
515 /* load external NVM if configured */
516 if (mvm->nvm_file_name) {
517 /* move to External NVM flow */
518 ret = iwl_mvm_read_external_nvm(mvm);
519 if (ret)
511 return ret; 520 return ret;
512 } 521 }
513 522
523 /* parse the relevant nvm sections */
514 mvm->nvm_data = iwl_parse_nvm_sections(mvm); 524 mvm->nvm_data = iwl_parse_nvm_sections(mvm);
515 if (!mvm->nvm_data) 525 if (!mvm->nvm_data)
516 return -ENODATA; 526 return -ENODATA;