Commit 40b7d22d authored by Shahar S Matityahu's avatar Shahar S Matityahu Committed by Luca Coelho
Browse files

iwlwifi: dbg_ini: use linked list to store debug TLVs



Use a linked list to maintain the debug TLVs instead of a single buffer.
This way, the driver does not need to iterate over the binary file twice
and allocates smaller chunks of memory. Also, in case one allocation
fails the driver will work with the partial configuration instead of
aborting the entire debug configuration.

Signed-off-by: default avatarShahar S Matityahu <shahar.s.matityahu@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent ccdc3d6d
Loading
Loading
Loading
Loading
+8 −7
Original line number Original line Diff line number Diff line
@@ -2783,10 +2783,13 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
				    enum iwl_fw_ini_apply_point pnt,
				    enum iwl_fw_ini_apply_point pnt,
				    bool ext)
				    bool ext)
{
{
	void *iter = data->data;
	struct iwl_apply_point_data *iter;


	while (iter && iter < data->data + data->size) {
	if (!data->list.next)
		struct iwl_ucode_tlv *tlv = iter;
		return;

	list_for_each_entry(iter, &data->list, list) {
		struct iwl_ucode_tlv *tlv = &iter->tlv;
		void *ini_tlv = (void *)tlv->data;
		void *ini_tlv = (void *)tlv->data;
		u32 type = le32_to_cpu(tlv->type);
		u32 type = le32_to_cpu(tlv->type);


@@ -2799,7 +2802,7 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
				IWL_ERR(fwrt,
				IWL_ERR(fwrt,
					"WRT: ext=%d. Invalid apply point %d for buffer allocation\n",
					"WRT: ext=%d. Invalid apply point %d for buffer allocation\n",
					ext, pnt);
					ext, pnt);
				goto next;
				break;
			}
			}
			iwl_fw_dbg_buffer_apply(fwrt, ini_tlv, pnt);
			iwl_fw_dbg_buffer_apply(fwrt, ini_tlv, pnt);
			break;
			break;
@@ -2808,7 +2811,7 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
				IWL_ERR(fwrt,
				IWL_ERR(fwrt,
					"WRT: ext=%d. Invalid apply point %d for host command\n",
					"WRT: ext=%d. Invalid apply point %d for host command\n",
					ext, pnt);
					ext, pnt);
				goto next;
				break;
			}
			}
			iwl_fw_dbg_send_hcmd(fwrt, tlv, ext);
			iwl_fw_dbg_send_hcmd(fwrt, tlv, ext);
			break;
			break;
@@ -2826,8 +2829,6 @@ static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
				  ext, type);
				  ext, type);
			break;
			break;
		}
		}
next:
		iter += sizeof(*tlv) + le32_to_cpu(tlv->length);
	}
	}
}
}


+37 −84
Original line number Original line Diff line number Diff line
@@ -66,102 +66,56 @@
void iwl_dbg_tlv_copy(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv,
void iwl_dbg_tlv_copy(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv,
		      bool ext)
		      bool ext)
{
{
	struct iwl_apply_point_data *data;
	struct iwl_apply_point_data *dbg_cfg, *tlv_copy;
	struct iwl_fw_ini_header *header = (void *)&tlv->data[0];
	struct iwl_fw_ini_header *header = (void *)&tlv->data[0];
	u32 tlv_type = le32_to_cpu(tlv->type);
	u32 len = le32_to_cpu(tlv->length);
	u32 apply_point = le32_to_cpu(header->apply_point);
	u32 apply_point = le32_to_cpu(header->apply_point);


	int copy_size = le32_to_cpu(tlv->length) + sizeof(*tlv);
	int offset_size = copy_size;

	if (le32_to_cpu(header->tlv_version) != 1)
	if (le32_to_cpu(header->tlv_version) != 1)
		return;
		return;


	if (WARN_ONCE(apply_point >= IWL_FW_INI_APPLY_NUM,
	if (WARN_ONCE(apply_point >= IWL_FW_INI_APPLY_NUM,
		      "Invalid apply point id %d\n", apply_point))
		      "Invalid apply point %d\n", apply_point))
		return;
		return;


	IWL_DEBUG_FW(trans, "WRT: read TLV 0x%x, apply point %d\n",
		     tlv_type, apply_point);

	if (ext)
	if (ext)
		data = &trans->dbg.apply_points_ext[apply_point];
		dbg_cfg = &trans->dbg.apply_points_ext[apply_point];
	else
	else
		data = &trans->dbg.apply_points[apply_point];
		dbg_cfg = &trans->dbg.apply_points[apply_point];

	/*
	 * Make sure we still have room to copy this TLV. Offset points to the
	 * location the last copy ended.
	 */
	if (WARN_ONCE(data->offset + offset_size > data->size,
		      "Not enough memory for apply point %d\n",
		      apply_point))
		return;


	memcpy(data->data + data->offset, (void *)tlv, copy_size);
	tlv_copy = kzalloc(sizeof(*tlv_copy) + len, GFP_KERNEL);
	data->offset += offset_size;
	if (!tlv_copy) {
}
		IWL_ERR(trans, "WRT: No memory for TLV 0x%x, apply point %d\n",

			tlv_type, apply_point);
void iwl_dbg_tlv_alloc(struct iwl_trans *trans, size_t len, const u8 *data,
		       bool ext)
{
	struct iwl_ucode_tlv *tlv;
	u32 size[IWL_FW_INI_APPLY_NUM] = {0};
	int i;

	while (len >= sizeof(*tlv)) {
		u32 tlv_len, tlv_type, apply;
		struct iwl_fw_ini_header *hdr;

		len -= sizeof(*tlv);
		tlv = (void *)data;

		tlv_len = le32_to_cpu(tlv->length);
		tlv_type = le32_to_cpu(tlv->type);

		if (len < tlv_len)
		return;
		return;
	}


		len -= ALIGN(tlv_len, 4);
	INIT_LIST_HEAD(&tlv_copy->list);
		data += sizeof(*tlv) + ALIGN(tlv_len, 4);
	memcpy(&tlv_copy->tlv, tlv, sizeof(*tlv) + len);

		if (tlv_type < IWL_UCODE_TLV_DEBUG_BASE ||
		    tlv_type > IWL_UCODE_TLV_DEBUG_MAX)
			continue;

		hdr = (void *)&tlv->data[0];
		apply = le32_to_cpu(hdr->apply_point);

		if (le32_to_cpu(hdr->tlv_version) != 1)
			continue;


		IWL_DEBUG_FW(trans, "WRT: read TLV 0x%x, apply point %d\n",
	if (!dbg_cfg->list.next)
			     le32_to_cpu(tlv->type), apply);
		INIT_LIST_HEAD(&dbg_cfg->list);


		if (WARN_ON(apply >= IWL_FW_INI_APPLY_NUM))
	list_add_tail(&tlv_copy->list, &dbg_cfg->list);
			continue;


		size[apply] += sizeof(*tlv) + tlv_len;
	trans->dbg.ini_valid = true;
}
}


	for (i = 0; i < ARRAY_SIZE(size); i++) {
static void iwl_dbg_tlv_free_list(struct list_head *list)
		void *mem;
{

	if (!list || !list->next)
		if (!size[i])
			continue;

		mem = kzalloc(size[i], GFP_KERNEL);

		if (!mem) {
			IWL_ERR(trans, "No memory for apply point %d\n", i);
		return;
		return;
		}


		if (ext) {
	while (!list_empty(list)) {
			trans->dbg.apply_points_ext[i].data = mem;
		struct iwl_apply_point_data *node =
			trans->dbg.apply_points_ext[i].size = size[i];
			list_entry(list->next, typeof(*node), list);
		} else {
			trans->dbg.apply_points[i].data = mem;
			trans->dbg.apply_points[i].size = size[i];
		}


		trans->dbg.ini_valid = true;
		list_del(&node->list);
		kfree(node);
	}
	}
}
}


@@ -170,13 +124,13 @@ void iwl_dbg_tlv_free(struct iwl_trans *trans)
	int i;
	int i;


	for (i = 0; i < ARRAY_SIZE(trans->dbg.apply_points); i++) {
	for (i = 0; i < ARRAY_SIZE(trans->dbg.apply_points); i++) {
		kfree(trans->dbg.apply_points[i].data);
		struct iwl_apply_point_data *data;
		trans->dbg.apply_points[i].size = 0;

		trans->dbg.apply_points[i].offset = 0;
		data = &trans->dbg.apply_points[i];
		iwl_dbg_tlv_free_list(&data->list);


		kfree(trans->dbg.apply_points_ext[i].data);
		data = &trans->dbg.apply_points_ext[i];
		trans->dbg.apply_points_ext[i].size = 0;
		iwl_dbg_tlv_free_list(&data->list);
		trans->dbg.apply_points_ext[i].offset = 0;
	}
	}
}
}


@@ -232,7 +186,6 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans)
	if (res)
	if (res)
		return;
		return;


	iwl_dbg_tlv_alloc(trans, fw->size, fw->data, true);
	iwl_dbg_tlv_parse_bin(trans, fw->data, fw->size);
	iwl_dbg_tlv_parse_bin(trans, fw->data, fw->size);


	trans->dbg.external_ini_loaded = true;
	trans->dbg.external_ini_loaded = true;
+4 −8
Original line number Original line Diff line number Diff line
@@ -66,14 +66,12 @@


/**
/**
 * struct iwl_apply_point_data
 * struct iwl_apply_point_data
 * @data: start address of this apply point data
 * @list: list to go through the TLVs of the apply point
 * @size total size of the data
 * @tlv: a debug TLV
 * @offset: current offset of the copied data
 */
 */
struct iwl_apply_point_data {
struct iwl_apply_point_data {
	void *data;
	struct list_head list;
	int size;
	struct iwl_ucode_tlv tlv;
	int offset;
};
};


struct iwl_trans;
struct iwl_trans;
@@ -81,7 +79,5 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans);
void iwl_dbg_tlv_free(struct iwl_trans *trans);
void iwl_dbg_tlv_free(struct iwl_trans *trans);
void iwl_dbg_tlv_copy(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv,
void iwl_dbg_tlv_copy(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv,
		      bool ext);
		      bool ext);
void iwl_dbg_tlv_alloc(struct iwl_trans *trans, size_t len, const u8 *data,
		       bool ext);


#endif /* __iwl_dbg_tlv_h__*/
#endif /* __iwl_dbg_tlv_h__*/
+0 −3
Original line number Original line Diff line number Diff line
@@ -647,9 +647,6 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,


	len -= sizeof(*ucode);
	len -= sizeof(*ucode);


	if (iwlwifi_mod_params.enable_ini)
		iwl_dbg_tlv_alloc(drv->trans, len, data, false);

	while (len >= sizeof(*tlv)) {
	while (len >= sizeof(*tlv)) {
		len -= sizeof(*tlv);
		len -= sizeof(*tlv);
		tlv = (void *)data;
		tlv = (void *)data;