#define MAX_NVM_FILE_LEN 16384
/*
+ * Reads external NVM from a file into mvm->nvm_sections
+ *
* HOW TO CREATE THE NVM FILE FORMAT:
* ------------------------------
* 1. create hex file, format:
*
* 4. save as "iNVM_xxx.bin" under /lib/firmware
*/
-static int iwl_mvm_load_external_nvm(struct iwl_mvm *mvm)
+static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
{
- int ret, section_id, section_size;
+ int ret, section_size;
+ u16 section_id;
const struct firmware *fw_entry;
const struct {
__le16 word1;
__le16 word2;
u8 data[];
} *file_sec;
- const u8 *eof;
+ const u8 *eof, *temp;
#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
#define NVM_WORD2_ID(x) (x >> 12)
+ IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");
+
/*
* Obtain NVM image via request_firmware. Since we already used
* request_firmware_nowait() for the firmware binary load and only
break;
}
- ret = iwl_nvm_write_section(mvm, section_id, file_sec->data,
- section_size);
- if (ret < 0) {
- IWL_ERR(mvm, "iwl_mvm_send_cmd failed: %d\n", ret);
+ temp = kmemdup(file_sec->data, section_size, GFP_KERNEL);
+ if (!temp) {
+ ret = -ENOMEM;
+ break;
+ }
+ if (WARN_ON(section_id >= NVM_NUM_OF_SECTIONS)) {
+ IWL_ERR(mvm, "Invalid NVM section ID\n");
+ ret = -EINVAL;
break;
}
+ mvm->nvm_sections[section_id].data = temp;
+ mvm->nvm_sections[section_id].length = section_size;
/* advance to the next section */
file_sec = (void *)(file_sec->data + section_size);
return ret;
}
+/* Loads the NVM data stored in mvm->nvm_sections into the NIC */
+int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm)
+{
+ int i, ret;
+ u16 section_id;
+ struct iwl_nvm_section *sections = mvm->nvm_sections;
+
+ IWL_DEBUG_EEPROM(mvm->trans->dev, "'Write to NVM\n");
+
+ for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
+ section_id = nvm_to_read[i];
+ ret = iwl_nvm_write_section(mvm, section_id,
+ sections[section_id].data,
+ sections[section_id].length);
+ if (ret < 0) {
+ IWL_ERR(mvm, "iwl_mvm_send_cmd failed: %d\n", ret);
+ break;
+ }
+ }
+ return ret;
+}
+
int iwl_nvm_init(struct iwl_mvm *mvm)
{
int ret, i, section;
/* load external NVM if configured */
if (iwlwifi_mod_params.nvm_file) {
/* move to External NVM flow */
- ret = iwl_mvm_load_external_nvm(mvm);
+ ret = iwl_mvm_read_external_nvm(mvm);
if (ret)
return ret;
- }
-
- /* Read From FW NVM */
- IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n");
-
- /* TODO: find correct NVM max size for a section */
- nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
- GFP_KERNEL);
- if (!nvm_buffer)
- return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
- section = nvm_to_read[i];
- /* we override the constness for initial read */
- ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
- if (ret < 0)
- break;
- temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
- if (!temp) {
- ret = -ENOMEM;
- break;
+ } else {
+ /* Read From FW NVM */
+ IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n");
+
+ /* TODO: find correct NVM max size for a section */
+ nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
+ GFP_KERNEL);
+ if (!nvm_buffer)
+ return -ENOMEM;
+ for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
+ section = nvm_to_read[i];
+ /* we override the constness for initial read */
+ ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
+ if (ret < 0)
+ break;
+ temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
+ if (!temp) {
+ ret = -ENOMEM;
+ break;
+ }
+ mvm->nvm_sections[section].data = temp;
+ mvm->nvm_sections[section].length = ret;
}
- mvm->nvm_sections[section].data = temp;
- mvm->nvm_sections[section].length = ret;
+ kfree(nvm_buffer);
+ if (ret < 0)
+ return ret;
}
- kfree(nvm_buffer);
- if (ret < 0)
- return ret;
mvm->nvm_data = iwl_parse_nvm_sections(mvm);
if (!mvm->nvm_data)
IWL_INFO(mvm, "Detected %s, REV=0x%X\n",
mvm->cfg->name, mvm->trans->hw_rev);
- err = iwl_trans_start_hw(mvm->trans);
- if (err)
- goto out_free;
-
iwl_mvm_tt_initialize(mvm);
- mutex_lock(&mvm->mutex);
- err = iwl_run_init_mvm_ucode(mvm, true);
- mutex_unlock(&mvm->mutex);
- /* returns 0 if successful, 1 if success but in rfkill */
- if (err < 0 && !iwlmvm_mod_params.init_dbg) {
- IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
- goto out_free;
- }
+ /*
+ * If the NVM exists in an external file,
+ * there is no need to unnecessarily power up the NIC at driver load
+ */
+ if (iwlwifi_mod_params.nvm_file) {
+ iwl_nvm_init(mvm);
+ } else {
+ err = iwl_trans_start_hw(mvm->trans);
+ if (err)
+ goto out_free;
+
+ mutex_lock(&mvm->mutex);
+ err = iwl_run_init_mvm_ucode(mvm, true);
+ mutex_unlock(&mvm->mutex);
+ /* returns 0 if successful, 1 if success but in rfkill */
+ if (err < 0 && !iwlmvm_mod_params.init_dbg) {
+ IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
+ goto out_free;
+ }
- /* Stop the hw after the ALIVE and NVM has been read */
- if (!iwlmvm_mod_params.init_dbg)
- iwl_trans_stop_hw(mvm->trans, false);
+ /* Stop the hw after the ALIVE and NVM has been read */
+ if (!iwlmvm_mod_params.init_dbg)
+ iwl_trans_stop_hw(mvm->trans, false);
+ }
scan_size = sizeof(struct iwl_scan_cmd) +
mvm->fw->ucode_capa.max_probe_length +
out_free:
iwl_phy_db_free(mvm->phy_db);
kfree(mvm->scan_cmd);
- iwl_trans_stop_hw(trans, true);
+ if (!iwlwifi_mod_params.nvm_file)
+ iwl_trans_stop_hw(trans, true);
ieee80211_free_hw(mvm->hw);
return NULL;
}