iwlwifi: move all NVM parsing code to the common files
authorShaul Triebitz <shaul.triebitz@intel.com>
Sun, 14 Jan 2018 17:06:09 +0000 (19:06 +0200)
committerLuca Coelho <luciano.coelho@intel.com>
Fri, 20 Apr 2018 07:57:16 +0000 (10:57 +0300)
Move all the NVM file handling code to iwl-nvm-parse.c where all this
stuff belongs.  This cleans up the MVM specific code and allows easier
reuse by other opmodes if needed.

Signed-off-by: Shaul Triebitz <shaul.triebitz@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/nvm.c

index 8928613e033e4f803b37a94ff2d3f5bd99f565ec..3437ed480e31b0e6c0eb3ed3b74e4cb71b41dee7 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  *
  * 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
@@ -35,6 +36,7 @@
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -68,6 +70,7 @@
 #include <linux/export.h>
 #include <linux/etherdevice.h>
 #include <linux/pci.h>
+#include <linux/firmware.h>
 
 #include "iwl-drv.h"
 #include "iwl-modparams.h"
@@ -76,6 +79,7 @@
 #include "iwl-io.h"
 #include "iwl-csr.h"
 #include "fw/acpi.h"
+#include "fw/api/nvm-reg.h"
 
 /* NVM offsets (in words) definitions */
 enum nvm_offsets {
@@ -146,8 +150,8 @@ static const u8 iwl_ext_nvm_channels[] = {
        149, 153, 157, 161, 165, 169, 173, 177, 181
 };
 
-#define IWL_NUM_CHANNELS               ARRAY_SIZE(iwl_nvm_channels)
-#define IWL_NUM_CHANNELS_EXT   ARRAY_SIZE(iwl_ext_nvm_channels)
+#define IWL_NVM_NUM_CHANNELS           ARRAY_SIZE(iwl_nvm_channels)
+#define IWL_NVM_NUM_CHANNELS_EXT       ARRAY_SIZE(iwl_ext_nvm_channels)
 #define NUM_2GHZ_CHANNELS              14
 #define NUM_2GHZ_CHANNELS_EXT  14
 #define FIRST_2GHZ_HT_MINUS            5
@@ -301,11 +305,11 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
        const u8 *nvm_chan;
 
        if (cfg->nvm_type != IWL_NVM_EXT) {
-               num_of_ch = IWL_NUM_CHANNELS;
+               num_of_ch = IWL_NVM_NUM_CHANNELS;
                nvm_chan = &iwl_nvm_channels[0];
                num_2ghz_channels = NUM_2GHZ_CHANNELS;
        } else {
-               num_of_ch = IWL_NUM_CHANNELS_EXT;
+               num_of_ch = IWL_NVM_NUM_CHANNELS_EXT;
                nvm_chan = &iwl_ext_nvm_channels[0];
                num_2ghz_channels = NUM_2GHZ_CHANNELS_EXT;
        }
@@ -720,12 +724,12 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        if (cfg->nvm_type != IWL_NVM_EXT)
                data = kzalloc(sizeof(*data) +
                               sizeof(struct ieee80211_channel) *
-                              IWL_NUM_CHANNELS,
+                              IWL_NVM_NUM_CHANNELS,
                               GFP_KERNEL);
        else
                data = kzalloc(sizeof(*data) +
                               sizeof(struct ieee80211_channel) *
-                              IWL_NUM_CHANNELS_EXT,
+                              IWL_NVM_NUM_CHANNELS_EXT,
                               GFP_KERNEL);
        if (!data)
                return NULL;
@@ -859,7 +863,7 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
        int valid_rules = 0;
        bool new_rule;
        int max_num_ch = cfg->nvm_type == IWL_NVM_EXT ?
-                        IWL_NUM_CHANNELS_EXT : IWL_NUM_CHANNELS;
+                        IWL_NVM_NUM_CHANNELS_EXT : IWL_NVM_NUM_CHANNELS;
 
        if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES))
                return ERR_PTR(-EINVAL);
@@ -938,3 +942,199 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
        return regd;
 }
 IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info);
+
+#define IWL_MAX_NVM_SECTION_SIZE       0x1b58
+#define IWL_MAX_EXT_NVM_SECTION_SIZE   0x1ffc
+#define MAX_NVM_FILE_LEN       16384
+
+void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data,
+                   unsigned int len)
+{
+#define IWL_4165_DEVICE_ID     0x5501
+#define NVM_SKU_CAP_MIMO_DISABLE BIT(5)
+
+       if (section == NVM_SECTION_TYPE_PHY_SKU &&
+           hw_id == IWL_4165_DEVICE_ID && data && len >= 5 &&
+           (data[4] & NVM_SKU_CAP_MIMO_DISABLE))
+               /* OTP 0x52 bug work around: it's a 1x1 device */
+               data[3] = ANT_B | (ANT_B << 4);
+}
+IWL_EXPORT_SYMBOL(iwl_nvm_fixups);
+
+/*
+ * Reads external NVM from a file into mvm->nvm_sections
+ *
+ * HOW TO CREATE THE NVM FILE FORMAT:
+ * ------------------------------
+ * 1. create hex file, format:
+ *      3800 -> header
+ *      0000 -> header
+ *      5a40 -> data
+ *
+ *   rev - 6 bit (word1)
+ *   len - 10 bit (word1)
+ *   id - 4 bit (word2)
+ *   rsv - 12 bit (word2)
+ *
+ * 2. flip 8bits with 8 bits per line to get the right NVM file format
+ *
+ * 3. create binary file from the hex file
+ *
+ * 4. save as "iNVM_xxx.bin" under /lib/firmware
+ */
+int iwl_read_external_nvm(struct iwl_trans *trans,
+                         const char *nvm_file_name,
+                         struct iwl_nvm_section *nvm_sections)
+{
+       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;
+       u8 *temp;
+       int max_section_size;
+       const __le32 *dword_buff;
+
+#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
+#define NVM_WORD2_ID(x) (x >> 12)
+#define EXT_NVM_WORD2_LEN(x) (2 * (((x) & 0xFF) << 8 | (x) >> 8))
+#define EXT_NVM_WORD1_ID(x) ((x) >> 4)
+#define NVM_HEADER_0   (0x2A504C54)
+#define NVM_HEADER_1   (0x4E564D2A)
+#define NVM_HEADER_SIZE        (4 * sizeof(u32))
+
+       IWL_DEBUG_EEPROM(trans->dev, "Read from external NVM\n");
+
+       /* Maximal size depends on NVM version */
+       if (trans->cfg->nvm_type != IWL_NVM_EXT)
+               max_section_size = IWL_MAX_NVM_SECTION_SIZE;
+       else
+               max_section_size = IWL_MAX_EXT_NVM_SECTION_SIZE;
+
+       /*
+        * Obtain NVM image via request_firmware. Since we already used
+        * request_firmware_nowait() for the firmware binary load and only
+        * get here after that we assume the NVM request can be satisfied
+        * synchronously.
+        */
+       ret = request_firmware(&fw_entry, nvm_file_name, trans->dev);
+       if (ret) {
+               IWL_ERR(trans, "ERROR: %s isn't available %d\n",
+                       nvm_file_name, ret);
+               return ret;
+       }
+
+       IWL_INFO(trans, "Loaded NVM file %s (%zu bytes)\n",
+                nvm_file_name, fw_entry->size);
+
+       if (fw_entry->size > MAX_NVM_FILE_LEN) {
+               IWL_ERR(trans, "NVM file too large\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       eof = fw_entry->data + fw_entry->size;
+       dword_buff = (__le32 *)fw_entry->data;
+
+       /* some NVM file will contain a header.
+        * The header is identified by 2 dwords header as follow:
+        * dword[0] = 0x2A504C54
+        * dword[1] = 0x4E564D2A
+        *
+        * This header must be skipped when providing the NVM data to the FW.
+        */
+       if (fw_entry->size > NVM_HEADER_SIZE &&
+           dword_buff[0] == cpu_to_le32(NVM_HEADER_0) &&
+           dword_buff[1] == cpu_to_le32(NVM_HEADER_1)) {
+               file_sec = (void *)(fw_entry->data + NVM_HEADER_SIZE);
+               IWL_INFO(trans, "NVM Version %08X\n", le32_to_cpu(dword_buff[2]));
+               IWL_INFO(trans, "NVM Manufacturing date %08X\n",
+                        le32_to_cpu(dword_buff[3]));
+
+               /* nvm file validation, dword_buff[2] holds the file version */
+               if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
+                   CSR_HW_REV_STEP(trans->hw_rev) == SILICON_C_STEP &&
+                   le32_to_cpu(dword_buff[2]) < 0xE4A) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+       } else {
+               file_sec = (void *)fw_entry->data;
+       }
+
+       while (true) {
+               if (file_sec->data > eof) {
+                       IWL_ERR(trans,
+                               "ERROR - NVM file too short for section header\n");
+                       ret = -EINVAL;
+                       break;
+               }
+
+               /* check for EOF marker */
+               if (!file_sec->word1 && !file_sec->word2) {
+                       ret = 0;
+                       break;
+               }
+
+               if (trans->cfg->nvm_type != IWL_NVM_EXT) {
+                       section_size =
+                               2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
+                       section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
+               } else {
+                       section_size = 2 * EXT_NVM_WORD2_LEN(
+                                               le16_to_cpu(file_sec->word2));
+                       section_id = EXT_NVM_WORD1_ID(
+                                               le16_to_cpu(file_sec->word1));
+               }
+
+               if (section_size > max_section_size) {
+                       IWL_ERR(trans, "ERROR - section too large (%d)\n",
+                               section_size);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (!section_size) {
+                       IWL_ERR(trans, "ERROR - section empty\n");
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (file_sec->data + section_size > eof) {
+                       IWL_ERR(trans,
+                               "ERROR - NVM file too short for section (%d bytes)\n",
+                               section_size);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (WARN(section_id >= NVM_MAX_NUM_SECTIONS,
+                        "Invalid NVM section ID %d\n", section_id)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               temp = kmemdup(file_sec->data, section_size, GFP_KERNEL);
+               if (!temp) {
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               iwl_nvm_fixups(trans->hw_id, section_id, temp, section_size);
+
+               kfree(nvm_sections[section_id].data);
+               nvm_sections[section_id].data = temp;
+               nvm_sections[section_id].length = section_size;
+
+               /* advance to the next section */
+               file_sec = (void *)(file_sec->data + section_size);
+       }
+out:
+       release_firmware(fw_entry);
+       return ret;
+}
+IWL_EXPORT_SYMBOL(iwl_read_external_nvm);
index 306736c7a042b34c7632b50bbf90bcd66e00ab51..6b108cae61b899e4db15765a0c0efee7e150ee4e 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2008 - 2015 Intel Corporation. All rights reserved.
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  *
  * 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
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -109,4 +111,25 @@ struct ieee80211_regdomain *
 iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
                       int num_of_ch, __le32 *channels, u16 fw_mcc);
 
+/**
+ * struct iwl_nvm_section - describes an NVM section in memory.
+ *
+ * This struct holds an NVM section read from the NIC using NVM_ACCESS_CMD,
+ * and saved for later use by the driver. Not all NVM sections are saved
+ * this way, only the needed ones.
+ */
+struct iwl_nvm_section {
+       u16 length;
+       const u8 *data;
+};
+
+/**
+ * iwl_read_external_nvm - Reads external NVM from a file into nvm_sections
+ */
+int iwl_read_external_nvm(struct iwl_trans *trans,
+                         const char *nvm_file_name,
+                         struct iwl_nvm_section *nvm_sections);
+void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data,
+                   unsigned int len);
+
 #endif /* __iwl_nvm_parse_h__ */
index 4cf3e32e3dba3bd85821a753a8fe7689c336dfac..d5a612add59fe3767a0802cf0a1cabb1e35fcfcc 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  *
  * 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
@@ -35,6 +36,7 @@
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -79,6 +81,8 @@
 #include "mvm.h"
 #include "fw/dbg.h"
 #include "iwl-phy-db.h"
+#include "iwl-modparams.h"
+#include "iwl-nvm-parse.h"
 
 #define MVM_UCODE_ALIVE_TIMEOUT        HZ
 #define MVM_UCODE_CALIB_TIMEOUT        (2*HZ)
@@ -381,7 +385,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
 
        /* Load NVM to NIC if needed */
        if (mvm->nvm_file_name) {
-               iwl_mvm_read_external_nvm(mvm);
+               iwl_read_external_nvm(mvm->trans, mvm->nvm_file_name,
+                                     mvm->nvm_sections);
                iwl_mvm_load_nvm_to_nic(mvm);
        }
 
index 2411cc91f833b53a8d300ef6b73892254d7fa95a..6a4ba160c59ed4accd1a56136e5b5d9ebdbd8061 100644 (file)
@@ -92,7 +92,7 @@
 #include "fw/runtime.h"
 #include "fw/dbg.h"
 #include "fw/acpi.h"
-#include "fw/debugfs.h"
+#include "iwl-nvm-parse.h"
 
 #include <linux/average.h>
 
@@ -508,18 +508,6 @@ enum iwl_mvm_sched_scan_pass_all_states {
        SCHED_SCAN_PASS_ALL_FOUND,
 };
 
-/**
- * struct iwl_nvm_section - describes an NVM section in memory.
- *
- * This struct holds an NVM section read from the NIC using NVM_ACCESS_CMD,
- * and saved for later use by the driver. Not all NVM sections are saved
- * this way, only the needed ones.
- */
-struct iwl_nvm_section {
-       u16 length;
-       const u8 *data;
-};
-
 /**
  * struct iwl_mvm_tt_mgnt - Thermal Throttling Management structure
  * @ct_kill_exit: worker to exit thermal kill
@@ -1511,7 +1499,6 @@ void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm);
 /* NVM */
 int iwl_nvm_init(struct iwl_mvm *mvm);
 int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm);
-int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm);
 
 static inline u8 iwl_mvm_get_valid_tx_ant(struct iwl_mvm *mvm)
 {
index 5bfe5306524c0b8a40ad3a4894e065f4c92b38d4..cf48517944ecf25f6876d0f07713f2fed7e8d8bc 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  *
  * 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
@@ -35,6 +36,7 @@
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -76,9 +78,7 @@
 #include "fw/acpi.h"
 
 /* Default NVM size to read */
-#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024)
-#define IWL_MAX_NVM_SECTION_SIZE       0x1b58
-#define IWL_MAX_EXT_NVM_SECTION_SIZE   0x1ffc
+#define IWL_NVM_DEFAULT_CHUNK_SIZE (2 * 1024)
 
 #define NVM_WRITE_OPCODE 1
 #define NVM_READ_OPCODE 0
@@ -229,19 +229,6 @@ static int iwl_nvm_write_section(struct iwl_mvm *mvm, u16 section,
        return 0;
 }
 
-static void iwl_mvm_nvm_fixups(struct iwl_mvm *mvm, unsigned int section,
-                              u8 *data, unsigned int len)
-{
-#define IWL_4165_DEVICE_ID     0x5501
-#define NVM_SKU_CAP_MIMO_DISABLE BIT(5)
-
-       if (section == NVM_SECTION_TYPE_PHY_SKU &&
-           mvm->trans->hw_id == IWL_4165_DEVICE_ID && data && len >= 5 &&
-           (data[4] & NVM_SKU_CAP_MIMO_DISABLE))
-               /* OTP 0x52 bug work around: it's a 1x1 device */
-               data[3] = ANT_B | (ANT_B << 4);
-}
-
 /*
  * Reads an NVM section completely.
  * NICs prior to 7000 family doesn't have a real NVM, but just read
@@ -282,7 +269,7 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
                offset += ret;
        }
 
-       iwl_mvm_nvm_fixups(mvm, section, data, offset);
+       iwl_nvm_fixups(mvm->trans->hw_id, section, data, offset);
 
        IWL_DEBUG_EEPROM(mvm->trans->dev,
                         "NVM section %d read completed\n", section);
@@ -355,184 +342,6 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
                                  lar_enabled);
 }
 
-#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:
- *      3800 -> header
- *      0000 -> header
- *      5a40 -> data
- *
- *   rev - 6 bit (word1)
- *   len - 10 bit (word1)
- *   id - 4 bit (word2)
- *   rsv - 12 bit (word2)
- *
- * 2. flip 8bits with 8 bits per line to get the right NVM file format
- *
- * 3. create binary file from the hex file
- *
- * 4. save as "iNVM_xxx.bin" under /lib/firmware
- */
-int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
-{
-       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;
-       u8 *temp;
-       int max_section_size;
-       const __le32 *dword_buff;
-
-#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
-#define NVM_WORD2_ID(x) (x >> 12)
-#define EXT_NVM_WORD2_LEN(x) (2 * (((x) & 0xFF) << 8 | (x) >> 8))
-#define EXT_NVM_WORD1_ID(x) ((x) >> 4)
-#define NVM_HEADER_0   (0x2A504C54)
-#define NVM_HEADER_1   (0x4E564D2A)
-#define NVM_HEADER_SIZE        (4 * sizeof(u32))
-
-       IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");
-
-       /* Maximal size depends on NVM version */
-       if (mvm->trans->cfg->nvm_type != IWL_NVM_EXT)
-               max_section_size = IWL_MAX_NVM_SECTION_SIZE;
-       else
-               max_section_size = IWL_MAX_EXT_NVM_SECTION_SIZE;
-
-       /*
-        * Obtain NVM image via request_firmware. Since we already used
-        * request_firmware_nowait() for the firmware binary load and only
-        * get here after that we assume the NVM request can be satisfied
-        * synchronously.
-        */
-       ret = request_firmware(&fw_entry, mvm->nvm_file_name,
-                              mvm->trans->dev);
-       if (ret) {
-               IWL_ERR(mvm, "ERROR: %s isn't available %d\n",
-                       mvm->nvm_file_name, ret);
-               return ret;
-       }
-
-       IWL_INFO(mvm, "Loaded NVM file %s (%zu bytes)\n",
-                mvm->nvm_file_name, fw_entry->size);
-
-       if (fw_entry->size > MAX_NVM_FILE_LEN) {
-               IWL_ERR(mvm, "NVM file too large\n");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       eof = fw_entry->data + fw_entry->size;
-       dword_buff = (__le32 *)fw_entry->data;
-
-       /* some NVM file will contain a header.
-        * The header is identified by 2 dwords header as follow:
-        * dword[0] = 0x2A504C54
-        * dword[1] = 0x4E564D2A
-        *
-        * This header must be skipped when providing the NVM data to the FW.
-        */
-       if (fw_entry->size > NVM_HEADER_SIZE &&
-           dword_buff[0] == cpu_to_le32(NVM_HEADER_0) &&
-           dword_buff[1] == cpu_to_le32(NVM_HEADER_1)) {
-               file_sec = (void *)(fw_entry->data + NVM_HEADER_SIZE);
-               IWL_INFO(mvm, "NVM Version %08X\n", le32_to_cpu(dword_buff[2]));
-               IWL_INFO(mvm, "NVM Manufacturing date %08X\n",
-                        le32_to_cpu(dword_buff[3]));
-
-               /* nvm file validation, dword_buff[2] holds the file version */
-               if (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
-                   CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_C_STEP &&
-                   le32_to_cpu(dword_buff[2]) < 0xE4A) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-       } else {
-               file_sec = (void *)fw_entry->data;
-       }
-
-       while (true) {
-               if (file_sec->data > eof) {
-                       IWL_ERR(mvm,
-                               "ERROR - NVM file too short for section header\n");
-                       ret = -EINVAL;
-                       break;
-               }
-
-               /* check for EOF marker */
-               if (!file_sec->word1 && !file_sec->word2) {
-                       ret = 0;
-                       break;
-               }
-
-               if (mvm->trans->cfg->nvm_type != IWL_NVM_EXT) {
-                       section_size =
-                               2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
-                       section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
-               } else {
-                       section_size = 2 * EXT_NVM_WORD2_LEN(
-                                               le16_to_cpu(file_sec->word2));
-                       section_id = EXT_NVM_WORD1_ID(
-                                               le16_to_cpu(file_sec->word1));
-               }
-
-               if (section_size > max_section_size) {
-                       IWL_ERR(mvm, "ERROR - section too large (%d)\n",
-                               section_size);
-                       ret = -EINVAL;
-                       break;
-               }
-
-               if (!section_size) {
-                       IWL_ERR(mvm, "ERROR - section empty\n");
-                       ret = -EINVAL;
-                       break;
-               }
-
-               if (file_sec->data + section_size > eof) {
-                       IWL_ERR(mvm,
-                               "ERROR - NVM file too short for section (%d bytes)\n",
-                               section_size);
-                       ret = -EINVAL;
-                       break;
-               }
-
-               if (WARN(section_id >= NVM_MAX_NUM_SECTIONS,
-                        "Invalid NVM section ID %d\n", section_id)) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               temp = kmemdup(file_sec->data, section_size, GFP_KERNEL);
-               if (!temp) {
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               iwl_mvm_nvm_fixups(mvm, section_id, temp, section_size);
-
-               kfree(mvm->nvm_sections[section_id].data);
-               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);
-       }
-out:
-       release_firmware(fw_entry);
-       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)
 {
@@ -585,7 +394,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
                        break;
                }
 
-               iwl_mvm_nvm_fixups(mvm, section, temp, ret);
+               iwl_nvm_fixups(mvm->trans->hw_id, section, temp, ret);
 
                mvm->nvm_sections[section].data = temp;
                mvm->nvm_sections[section].length = ret;
@@ -624,14 +433,17 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
        /* Only if PNVM selected in the mod param - load external NVM  */
        if (mvm->nvm_file_name) {
                /* read External NVM file from the mod param */
-               ret = iwl_mvm_read_external_nvm(mvm);
+               ret = iwl_read_external_nvm(mvm->trans, mvm->nvm_file_name,
+                                           mvm->nvm_sections);
                if (ret) {
                        mvm->nvm_file_name = nvm_file_C;
 
                        if ((ret == -EFAULT || ret == -ENOENT) &&
                            mvm->nvm_file_name) {
                                /* in case nvm file was failed try again */
-                               ret = iwl_mvm_read_external_nvm(mvm);
+                               ret = iwl_read_external_nvm(mvm->trans,
+                                                           mvm->nvm_file_name,
+                                                           mvm->nvm_sections);
                                if (ret)
                                        return ret;
                        } else {