iwlwifi: enlarge number of ucode sections
authorSara Sharon <sara.sharon@intel.com>
Tue, 25 Oct 2016 08:38:31 +0000 (11:38 +0300)
committerLuca Coelho <luciano.coelho@intel.com>
Thu, 26 Jan 2017 07:38:57 +0000 (09:38 +0200)
The maximum number of firmware sections is now 32 instead of 16 for
a000 devices. Set the appropriate define.  Avoid out of bounds access
in case there are more sections than the maximum set by driver.

Make the driver extensible to FW size changes by allocating the
section memory dynamically.

Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/dvm/ucode.c
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
drivers/net/wireless/intel/iwlwifi/iwl-fw.h
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c

index 8c0719468d00514572a0cc6e76c4f084f850a335..2a04d0cd71aefc5b09022daee9e6470e924075a7 100644 (file)
@@ -163,7 +163,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
                                       REGULATORY_DISABLE_BEACON_HINTS;
 
 #ifdef CONFIG_PM_SLEEP
-       if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
+       if (priv->fw->img[IWL_UCODE_WOWLAN].num_sec &&
            priv->trans->ops->d3_suspend &&
            priv->trans->ops->d3_resume &&
            device_can_wakeup(priv->trans->dev)) {
index c7509c51e9d94cfa18c856b468ca1a809a48c299..d6013bfe991cde5f28b694ff72a0bb46812b0081 100644 (file)
@@ -407,7 +407,7 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
        lockdep_assert_held(&priv->mutex);
 
        /* No init ucode required? Curious, but maybe ok */
-       if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len)
+       if (!priv->fw->img[IWL_UCODE_INIT].num_sec)
                return 0;
 
        iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
index a6719d67ac00b7dd732440628dc9ede40214f8fb..1d1af4bc1530482780d5655a911df02d9908f767 100644 (file)
@@ -166,8 +166,9 @@ static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc)
 static void iwl_free_fw_img(struct iwl_drv *drv, struct fw_img *img)
 {
        int i;
-       for (i = 0; i < IWL_UCODE_SECTION_MAX; i++)
+       for (i = 0; i < img->num_sec; i++)
                iwl_free_fw_desc(drv, &img->sec[i]);
+       kfree(img->sec);
 }
 
 static void iwl_dealloc_ucode(struct iwl_drv *drv)
@@ -240,7 +241,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
 }
 
 struct fw_img_parsing {
-       struct fw_sec sec[IWL_UCODE_SECTION_MAX];
+       struct fw_sec *sec;
        int sec_counter;
 };
 
@@ -383,6 +384,7 @@ static int iwl_store_ucode_sec(struct iwl_firmware_pieces *pieces,
        struct fw_img_parsing *img;
        struct fw_sec *sec;
        struct fw_sec_parsing *sec_parse;
+       size_t alloc_size;
 
        if (WARN_ON(!pieces || !data || type >= IWL_UCODE_TYPE_MAX))
                return -1;
@@ -390,6 +392,13 @@ static int iwl_store_ucode_sec(struct iwl_firmware_pieces *pieces,
        sec_parse = (struct fw_sec_parsing *)data;
 
        img = &pieces->img[type];
+
+       alloc_size = sizeof(*img->sec) * (img->sec_counter + 1);
+       sec = krealloc(img->sec, alloc_size, GFP_KERNEL);
+       if (!sec)
+               return -ENOMEM;
+       img->sec = sec;
+
        sec = &img->sec[img->sec_counter];
 
        sec->offset = le32_to_cpu(sec_parse->offset);
@@ -1089,12 +1098,18 @@ static int iwl_alloc_ucode(struct iwl_drv *drv,
                           enum iwl_ucode_type type)
 {
        int i;
-       for (i = 0;
-            i < IWL_UCODE_SECTION_MAX && get_sec_size(pieces, type, i);
-            i++)
-               if (iwl_alloc_fw_desc(drv, &(drv->fw.img[type].sec[i]),
-                                     get_sec(pieces, type, i)))
+       struct fw_desc *sec;
+
+       sec = kcalloc(pieces->img[type].sec_counter, sizeof(*sec), GFP_KERNEL);
+       if (!sec)
+               return -ENOMEM;
+       drv->fw.img[type].sec = sec;
+       drv->fw.img[type].num_sec = pieces->img[type].sec_counter;
+
+       for (i = 0; i < pieces->img[type].sec_counter; i++)
+               if (iwl_alloc_fw_desc(drv, &sec[i], get_sec(pieces, type, i)))
                        return -ENOMEM;
+
        return 0;
 }
 
@@ -1457,6 +1472,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
        complete(&drv->request_firmware_complete);
        device_release_driver(drv->trans->dev);
  free:
+       for (i = 0; i < ARRAY_SIZE(pieces->img); i++)
+               kfree(pieces->img[i].sec);
        kfree(pieces->dbg_mem_tlv);
        kfree(pieces);
 }
index c842075765874323071004abb10c812bde1e56e4..d01701ee477702272d4597a33d7c5710510f4fda 100644 (file)
@@ -379,7 +379,6 @@ enum iwl_ucode_tlv_capa {
  * For 16.0 uCode and above, there is no differentiation between sections,
  * just an offset to the HW address.
  */
-#define IWL_UCODE_SECTION_MAX 16
 #define CPU1_CPU2_SEPARATOR_SECTION    0xFFFFCCCC
 #define PAGING_SEPARATOR_SECTION       0xAAAABBBB
 
index 710ecb490bfc1c2a792122617ba45eda10112249..d323b70b510a1f5d795a56b82be267567b71360f 100644 (file)
@@ -132,7 +132,8 @@ struct fw_desc {
 };
 
 struct fw_img {
-       struct fw_desc sec[IWL_UCODE_SECTION_MAX];
+       struct fw_desc *sec;
+       int num_sec;
        bool is_dual_cpus;
        u32 paging_mem_size;
 };
index 606b3fc18d46e0993023813b3a43f0807e20016e..b278e44e97add715b29fdb951d26228376e4400a 100644 (file)
@@ -190,7 +190,7 @@ static int iwl_fill_paging_mem(struct iwl_mvm *mvm, const struct fw_img *image)
         * CPU2 paging CSS
         * CPU2 paging image (including instruction and data)
         */
-       for (sec_idx = 0; sec_idx < IWL_UCODE_SECTION_MAX; sec_idx++) {
+       for (sec_idx = 0; sec_idx < image->num_sec; sec_idx++) {
                if (image->sec[sec_idx].offset == PAGING_SEPARATOR_SECTION) {
                        sec_idx++;
                        break;
@@ -201,7 +201,7 @@ static int iwl_fill_paging_mem(struct iwl_mvm *mvm, const struct fw_img *image)
         * If paging is enabled there should be at least 2 more sections left
         * (one for CSS and one for Paging data)
         */
-       if (sec_idx >= ARRAY_SIZE(image->sec) - 1) {
+       if (sec_idx >= image->num_sec - 1) {
                IWL_ERR(mvm, "Paging: Missing CSS and/or paging sections\n");
                iwl_free_fw_paging(mvm);
                return -EINVAL;
index 039cb2ad2d3e3cfca341ed0610d87dd2aef4cdf3..71f9aa9f7c7d62542865af5faefa7bbce296275b 100644 (file)
@@ -677,7 +677,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                hw->wiphy->wowlan = &mvm->wowlan;
        }
 
-       if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
+       if (mvm->fw->img[IWL_UCODE_WOWLAN].num_sec &&
            mvm->trans->ops->d3_suspend &&
            mvm->trans->ops->d3_resume &&
            device_can_wakeup(mvm->trans->dev)) {
index b10e3633df1a91ac67061502a332af0bef3c8014..bf0ecdcf740247086fa87681cb137eecbb88baef 100644 (file)
@@ -805,7 +805,7 @@ static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans,
                (*first_ucode_section)++;
        }
 
-       for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) {
+       for (i = *first_ucode_section; i < image->num_sec; i++) {
                last_read_idx = i;
 
                /*
@@ -880,7 +880,7 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
                (*first_ucode_section)++;
        }
 
-       for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) {
+       for (i = *first_ucode_section; i < image->num_sec; i++) {
                last_read_idx = i;
 
                /*