Commit eef187a7 authored by Sara Sharon's avatar Sara Sharon Committed by Luca Coelho

iwlwifi: enlarge number of ucode sections

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: default avatarSara Sharon <sara.sharon@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 850fe9af
......@@ -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)) {
......
......@@ -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,
......
......@@ -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);
}
......
......@@ -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
......
......@@ -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;
};
......
......@@ -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;
......
......@@ -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)) {
......
......@@ -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;
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment