|
@@ -179,8 +179,7 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
|
|
|
kfree(drv->fw.dbg_conf_tlv[i]);
|
|
|
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_trigger_tlv); i++)
|
|
|
kfree(drv->fw.dbg_trigger_tlv[i]);
|
|
|
- for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_mem_tlv); i++)
|
|
|
- kfree(drv->fw.dbg_mem_tlv[i]);
|
|
|
+ kfree(drv->fw.dbg_mem_tlv);
|
|
|
|
|
|
for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
|
|
|
iwl_free_fw_img(drv, drv->fw.img + i);
|
|
@@ -276,7 +275,8 @@ struct iwl_firmware_pieces {
|
|
|
size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
|
|
|
struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
|
|
|
size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
|
|
|
- struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv[FW_DBG_MEM_MAX];
|
|
|
+ struct iwl_fw_dbg_mem_seg_tlv *dbg_mem_tlv;
|
|
|
+ size_t n_dbg_mem_tlv;
|
|
|
};
|
|
|
|
|
|
/*
|
|
@@ -1009,31 +1009,25 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|
|
struct iwl_fw_dbg_mem_seg_tlv *dbg_mem =
|
|
|
(void *)tlv_data;
|
|
|
u32 type;
|
|
|
+ size_t size;
|
|
|
+ struct iwl_fw_dbg_mem_seg_tlv *n;
|
|
|
|
|
|
if (tlv_len != (sizeof(*dbg_mem)))
|
|
|
goto invalid_tlv_len;
|
|
|
|
|
|
type = le32_to_cpu(dbg_mem->data_type);
|
|
|
- drv->fw.dbg_dynamic_mem = true;
|
|
|
-
|
|
|
- if (type >= ARRAY_SIZE(drv->fw.dbg_mem_tlv)) {
|
|
|
- IWL_ERR(drv,
|
|
|
- "Skip unknown dbg mem segment: %u\n",
|
|
|
- dbg_mem->data_type);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (pieces->dbg_mem_tlv[type]) {
|
|
|
- IWL_ERR(drv,
|
|
|
- "Ignore duplicate mem segment: %u\n",
|
|
|
- dbg_mem->data_type);
|
|
|
- break;
|
|
|
- }
|
|
|
|
|
|
IWL_DEBUG_INFO(drv, "Found debug memory segment: %u\n",
|
|
|
dbg_mem->data_type);
|
|
|
|
|
|
- pieces->dbg_mem_tlv[type] = dbg_mem;
|
|
|
+ size = sizeof(*pieces->dbg_mem_tlv) *
|
|
|
+ (pieces->n_dbg_mem_tlv + 1);
|
|
|
+ n = krealloc(pieces->dbg_mem_tlv, size, GFP_KERNEL);
|
|
|
+ if (!n)
|
|
|
+ return -ENOMEM;
|
|
|
+ pieces->dbg_mem_tlv = n;
|
|
|
+ pieces->dbg_mem_tlv[pieces->n_dbg_mem_tlv] = *dbg_mem;
|
|
|
+ pieces->n_dbg_mem_tlv++;
|
|
|
break;
|
|
|
}
|
|
|
default:
|
|
@@ -1345,19 +1339,12 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_mem_tlv); i++) {
|
|
|
- if (pieces->dbg_mem_tlv[i]) {
|
|
|
- drv->fw.dbg_mem_tlv[i] =
|
|
|
- kmemdup(pieces->dbg_mem_tlv[i],
|
|
|
- sizeof(*drv->fw.dbg_mem_tlv[i]),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!drv->fw.dbg_mem_tlv[i])
|
|
|
- goto out_free_fw;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/* Now that we can no longer fail, copy information */
|
|
|
|
|
|
+ drv->fw.dbg_mem_tlv = pieces->dbg_mem_tlv;
|
|
|
+ pieces->dbg_mem_tlv = NULL;
|
|
|
+ drv->fw.n_dbg_mem_tlv = pieces->n_dbg_mem_tlv;
|
|
|
+
|
|
|
/*
|
|
|
* The (size - 16) / 12 formula is based on the information recorded
|
|
|
* for each event, which is of mode 1 (including timestamp) for all
|
|
@@ -1441,25 +1428,25 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
|
|
op->name, err);
|
|
|
#endif
|
|
|
}
|
|
|
- kfree(pieces);
|
|
|
- return;
|
|
|
+ goto free;
|
|
|
|
|
|
try_again:
|
|
|
/* try next, if any */
|
|
|
release_firmware(ucode_raw);
|
|
|
if (iwl_request_firmware(drv, false))
|
|
|
goto out_unbind;
|
|
|
- kfree(pieces);
|
|
|
- return;
|
|
|
+ goto free;
|
|
|
|
|
|
out_free_fw:
|
|
|
IWL_ERR(drv, "failed to allocate pci memory\n");
|
|
|
iwl_dealloc_ucode(drv);
|
|
|
release_firmware(ucode_raw);
|
|
|
out_unbind:
|
|
|
- kfree(pieces);
|
|
|
complete(&drv->request_firmware_complete);
|
|
|
device_release_driver(drv->trans->dev);
|
|
|
+ free:
|
|
|
+ kfree(pieces->dbg_mem_tlv);
|
|
|
+ kfree(pieces);
|
|
|
}
|
|
|
|
|
|
struct iwl_drv *iwl_drv_start(struct iwl_trans *trans,
|