Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00eacde4 authored by Shahar S Matityahu's avatar Shahar S Matityahu Committed by Luca Coelho
Browse files

iwlwifi: dbg_ini: separate cfg and dump flows to different modules



separate configuration flows and dump collection flows.
make ini configuration flows be in iwl-dbg-tlv.c and dump related flows
in dbg.c to better reflect their logical difference.

Signed-off-by: default avatarShahar S Matityahu <shahar.s.matityahu@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent dd36a507
Loading
Loading
Loading
Loading
+0 −429
Original line number Diff line number Diff line
@@ -2438,435 +2438,6 @@ void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt)
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_read_d3_debug_data);

static void iwl_fw_dbg_info_apply(struct iwl_fw_runtime *fwrt,
				  struct iwl_fw_ini_debug_info_tlv *dbg_info,
				  bool ext, enum iwl_fw_ini_apply_point pnt)
{
	u32 img_name_len = le32_to_cpu(dbg_info->img_name_len);
	u32 dbg_cfg_name_len = le32_to_cpu(dbg_info->dbg_cfg_name_len);

	if (img_name_len != IWL_FW_INI_MAX_IMG_NAME_LEN) {
		IWL_WARN(fwrt,
			 "WRT: ext=%d. Invalid image name length %d, expected %d\n",
			 ext, img_name_len,
			 IWL_FW_INI_MAX_IMG_NAME_LEN);
		return;
	}

	if (dbg_cfg_name_len != IWL_FW_INI_MAX_DBG_CFG_NAME_LEN) {
		IWL_WARN(fwrt,
			 "WRT: ext=%d. Invalid debug cfg name length %d, expected %d\n",
			 ext, dbg_cfg_name_len,
			 IWL_FW_INI_MAX_DBG_CFG_NAME_LEN);
		return;
	}

	if (ext) {
		memcpy(fwrt->dump.external_dbg_cfg_name, dbg_info->dbg_cfg_name,
		       sizeof(fwrt->dump.external_dbg_cfg_name));
	} else {
		memcpy(fwrt->dump.img_name, dbg_info->img_name,
		       sizeof(fwrt->dump.img_name));
		memcpy(fwrt->dump.internal_dbg_cfg_name, dbg_info->dbg_cfg_name,
		       sizeof(fwrt->dump.internal_dbg_cfg_name));
	}
}

static void
iwl_fw_dbg_buffer_allocation(struct iwl_fw_runtime *fwrt, u32 size)
{
	struct iwl_trans *trans = fwrt->trans;
	void *virtual_addr = NULL;
	dma_addr_t phys_addr;

	if (WARN_ON_ONCE(trans->dbg.num_blocks ==
			 ARRAY_SIZE(trans->dbg.fw_mon)))
		return;

	virtual_addr =
		dma_alloc_coherent(fwrt->trans->dev, size, &phys_addr,
				   GFP_KERNEL | __GFP_NOWARN);

	/* TODO: alloc fragments if needed */
	if (!virtual_addr)
		IWL_ERR(fwrt, "Failed to allocate debug memory\n");

	IWL_DEBUG_FW(trans,
		     "Allocated DRAM buffer[%d], size=0x%x\n",
		     trans->dbg.num_blocks, size);

	trans->dbg.fw_mon[trans->dbg.num_blocks].block = virtual_addr;
	trans->dbg.fw_mon[trans->dbg.num_blocks].physical = phys_addr;
	trans->dbg.fw_mon[trans->dbg.num_blocks].size = size;
	trans->dbg.num_blocks++;
}

static void iwl_fw_dbg_buffer_apply(struct iwl_fw_runtime *fwrt,
				    struct iwl_fw_ini_allocation_tlv *alloc,
				    enum iwl_fw_ini_apply_point pnt)
{
	struct iwl_trans *trans = fwrt->trans;
	struct iwl_ldbg_config_cmd ldbg_cmd = {
		.type = cpu_to_le32(BUFFER_ALLOCATION),
	};
	struct iwl_buffer_allocation_cmd *cmd = &ldbg_cmd.buffer_allocation;
	struct iwl_host_cmd hcmd = {
		.id = LDBG_CONFIG_CMD,
		.flags = CMD_ASYNC,
		.data[0] = &ldbg_cmd,
		.len[0] = sizeof(ldbg_cmd),
	};
	int block_idx = trans->dbg.num_blocks;
	u32 buf_location = le32_to_cpu(alloc->buffer_location);
	u32 alloc_id = le32_to_cpu(alloc->allocation_id);

	if (alloc_id <= IWL_FW_INI_ALLOCATION_INVALID ||
	    alloc_id >= IWL_FW_INI_ALLOCATION_NUM) {
		IWL_ERR(fwrt, "WRT: Invalid allocation id %d\n", alloc_id);
		return;
	}

	if (fwrt->trans->dbg.ini_dest == IWL_FW_INI_LOCATION_INVALID)
		fwrt->trans->dbg.ini_dest = buf_location;

	if (buf_location != fwrt->trans->dbg.ini_dest) {
		WARN(fwrt,
		     "WRT: attempt to override buffer location on apply point %d\n",
		     pnt);

		return;
	}

	if (buf_location == IWL_FW_INI_LOCATION_SRAM_PATH) {
		IWL_DEBUG_FW(trans, "WRT: Applying SMEM buffer destination\n");
		/* set sram monitor by enabling bit 7 */
		iwl_set_bit(fwrt->trans, CSR_HW_IF_CONFIG_REG,
			    CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM);

		return;
	}

	if (buf_location != IWL_FW_INI_LOCATION_DRAM_PATH)
		return;

	if (!(BIT(alloc_id) & fwrt->trans->dbg.is_alloc)) {
		iwl_fw_dbg_buffer_allocation(fwrt, le32_to_cpu(alloc->size));
		if (block_idx == trans->dbg.num_blocks)
			return;
		fwrt->trans->dbg.is_alloc |= BIT(alloc_id);
	}

	/* First block is assigned via registers / context info */
	if (trans->dbg.num_blocks == 1)
		return;

	IWL_DEBUG_FW(trans,
		     "WRT: Applying DRAM buffer[%d] destination\n", block_idx);

	cmd->num_frags = cpu_to_le32(1);
	cmd->fragments[0].address =
		cpu_to_le64(trans->dbg.fw_mon[block_idx].physical);
	cmd->fragments[0].size = alloc->size;
	cmd->allocation_id = alloc->allocation_id;
	cmd->buffer_location = alloc->buffer_location;

	iwl_trans_send_cmd(trans, &hcmd);
}

static void iwl_fw_dbg_send_hcmd(struct iwl_fw_runtime *fwrt,
				 struct iwl_ucode_tlv *tlv)
{
	struct iwl_fw_ini_hcmd_tlv *hcmd_tlv = (void *)&tlv->data[0];
	struct iwl_fw_ini_hcmd *data = &hcmd_tlv->hcmd;
	u16 len = le32_to_cpu(tlv->length) - sizeof(*hcmd_tlv);

	struct iwl_host_cmd hcmd = {
		.id = WIDE_ID(data->group, data->id),
		.len = { len, },
		.data = { data->data, },
	};

	/* currently the driver supports always on domain only */
	if (le32_to_cpu(hcmd_tlv->domain) != IWL_FW_INI_DBG_DOMAIN_ALWAYS_ON)
		return;

	IWL_DEBUG_FW(fwrt, "WRT: Sending host command id=0x%x, group=0x%x\n",
		     data->id, data->group);

	iwl_trans_send_cmd(fwrt->trans, &hcmd);
}

static void iwl_fw_dbg_update_regions(struct iwl_fw_runtime *fwrt,
				      struct iwl_fw_ini_region_tlv *tlv,
				      enum iwl_fw_ini_apply_point pnt)
{
	void *iter = (void *)tlv->region_config;
	int i, size = le32_to_cpu(tlv->num_regions);
	const char *err_st =
		"WRT: Invalid region %s %d for apply point %d\n";

	for (i = 0; i < size; i++) {
		struct iwl_fw_ini_region_cfg *reg = iter, **active;
		int id = le32_to_cpu(reg->region_id);
		u32 type = le32_to_cpu(reg->region_type);

		if (WARN(id >= ARRAY_SIZE(fwrt->dump.active_regs), err_st, "id",
			 id, pnt))
			break;

		if (WARN(type == 0 || type >= IWL_FW_INI_REGION_NUM, err_st,
			 "type", type, pnt))
			break;

		active = &fwrt->dump.active_regs[id];

		if (*active)
			IWL_WARN(fwrt->trans, "WRT: Region id %d override\n",
				 id);

		IWL_DEBUG_FW(fwrt, "WRT: Activating region id %d\n", id);

		*active = reg;

		if (type == IWL_FW_INI_REGION_TXF ||
		    type == IWL_FW_INI_REGION_RXF)
			iter += le32_to_cpu(reg->fifos.num_of_registers) *
				sizeof(__le32);
		else if (type == IWL_FW_INI_REGION_DEVICE_MEMORY ||
			 type == IWL_FW_INI_REGION_PERIPHERY_MAC ||
			 type == IWL_FW_INI_REGION_PERIPHERY_PHY ||
			 type == IWL_FW_INI_REGION_PERIPHERY_AUX ||
			 type == IWL_FW_INI_REGION_INTERNAL_BUFFER ||
			 type == IWL_FW_INI_REGION_PAGING ||
			 type == IWL_FW_INI_REGION_CSR ||
			 type == IWL_FW_INI_REGION_LMAC_ERROR_TABLE ||
			 type == IWL_FW_INI_REGION_UMAC_ERROR_TABLE)
			iter += le32_to_cpu(reg->internal.num_of_ranges) *
				sizeof(__le32);

		iter += sizeof(*reg);
	}
}

static int iwl_fw_dbg_trig_realloc(struct iwl_fw_runtime *fwrt,
				   struct iwl_fw_ini_active_triggers *active,
				   u32 id, int size)
{
	void *ptr;

	if (size <= active->size)
		return 0;

	ptr = krealloc(active->trig, size, GFP_KERNEL);
	if (!ptr) {
		IWL_ERR(fwrt, "WRT: Failed to allocate memory for trigger %d\n",
			id);
		return -ENOMEM;
	}
	active->trig = ptr;
	active->size = size;

	return 0;
}

static void iwl_fw_dbg_update_triggers(struct iwl_fw_runtime *fwrt,
				       struct iwl_fw_ini_trigger_tlv *tlv,
				       enum iwl_fw_ini_apply_point apply_point)
{
	int i, size = le32_to_cpu(tlv->num_triggers);
	void *iter = (void *)tlv->trigger_config;

	for (i = 0; i < size; i++) {
		struct iwl_fw_ini_trigger *trig = iter;
		struct iwl_fw_ini_active_triggers *active;
		int id = le32_to_cpu(trig->trigger_id);
		u32 trig_regs_size = le32_to_cpu(trig->num_regions) *
			sizeof(__le32);

		if (WARN(id >= ARRAY_SIZE(fwrt->dump.active_trigs),
			 "WRT: Invalid trigger id %d for apply point %d\n", id,
			 apply_point))
			break;

		active = &fwrt->dump.active_trigs[id];

		if (!active->active) {
			size_t trig_size = sizeof(*trig) + trig_regs_size;

			IWL_DEBUG_FW(fwrt, "WRT: Activating trigger %d\n", id);

			if (iwl_fw_dbg_trig_realloc(fwrt, active, id,
						    trig_size))
				goto next;

			memcpy(active->trig, trig, trig_size);

		} else {
			u32 conf_override =
				!(le32_to_cpu(trig->override_trig) & 0xff);
			u32 region_override =
				!(le32_to_cpu(trig->override_trig) & 0xff00);
			u32 offset = 0;
			u32 active_regs =
				le32_to_cpu(active->trig->num_regions);
			u32 new_regs = le32_to_cpu(trig->num_regions);
			int mem_to_add = trig_regs_size;

			if (region_override) {
				IWL_DEBUG_FW(fwrt,
					     "WRT: Trigger %d regions override\n",
					     id);

				mem_to_add -= active_regs * sizeof(__le32);
			} else {
				IWL_DEBUG_FW(fwrt,
					     "WRT: Trigger %d regions appending\n",
					     id);

				offset += active_regs;
				new_regs += active_regs;
			}

			if (iwl_fw_dbg_trig_realloc(fwrt, active, id,
						    active->size + mem_to_add))
				goto next;

			if (conf_override) {
				IWL_DEBUG_FW(fwrt,
					     "WRT: Trigger %d configuration override\n",
					     id);

				memcpy(active->trig, trig, sizeof(*trig));
			}

			memcpy(active->trig->data + offset, trig->data,
			       trig_regs_size);
			active->trig->num_regions = cpu_to_le32(new_regs);
		}

		/* Since zero means infinity - just set to -1 */
		if (!le32_to_cpu(active->trig->occurrences))
			active->trig->occurrences = cpu_to_le32(-1);

		active->active = true;

		if (id == IWL_FW_TRIGGER_ID_PERIODIC_TRIGGER) {
			u32 collect_interval = le32_to_cpu(trig->trigger_data);

			/* the minimum allowed interval is 50ms */
			if (collect_interval < 50) {
				collect_interval = 50;
				trig->trigger_data =
					cpu_to_le32(collect_interval);
			}

			mod_timer(&fwrt->dump.periodic_trig,
				  jiffies + msecs_to_jiffies(collect_interval));
		}
next:
		iter += sizeof(*trig) + trig_regs_size;

	}
}

static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
				    struct iwl_apply_point_data *data,
				    enum iwl_fw_ini_apply_point pnt,
				    bool ext)
{
	struct iwl_apply_point_data *iter;

	if (!data->list.next)
		return;

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

		switch (type) {
		case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
			iwl_fw_dbg_info_apply(fwrt, ini_tlv, ext, pnt);
			break;
		case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
			if (pnt != IWL_FW_INI_APPLY_EARLY) {
				IWL_ERR(fwrt,
					"WRT: ext=%d. Invalid apply point %d for buffer allocation\n",
					ext, pnt);
				break;
			}
			iwl_fw_dbg_buffer_apply(fwrt, ini_tlv, pnt);
			break;
		case IWL_UCODE_TLV_TYPE_HCMD:
			if (pnt < IWL_FW_INI_APPLY_AFTER_ALIVE) {
				IWL_ERR(fwrt,
					"WRT: ext=%d. Invalid apply point %d for host command\n",
					ext, pnt);
				break;
			}
			iwl_fw_dbg_send_hcmd(fwrt, tlv);
			break;
		case IWL_UCODE_TLV_TYPE_REGIONS:
			iwl_fw_dbg_update_regions(fwrt, ini_tlv, pnt);
			break;
		case IWL_UCODE_TLV_TYPE_TRIGGERS:
			iwl_fw_dbg_update_triggers(fwrt, ini_tlv, pnt);
			break;
		default:
			WARN_ONCE(1, "WRT: Invalid TLV 0x%x for apply point\n",
				  type);
			break;
		}
	}
}

static void iwl_fw_dbg_ini_reset_cfg(struct iwl_fw_runtime *fwrt)
{
	int i;

	for (i = 0; i < IWL_FW_INI_MAX_REGION_ID; i++)
		fwrt->dump.active_regs[i] = NULL;

	/* disable the triggers, used in recovery flow */
	for (i = 0; i < IWL_FW_TRIGGER_ID_NUM; i++)
		fwrt->dump.active_trigs[i].active = false;

	memset(fwrt->dump.img_name, 0,
	       sizeof(fwrt->dump.img_name));
	memset(fwrt->dump.internal_dbg_cfg_name, 0,
	       sizeof(fwrt->dump.internal_dbg_cfg_name));
	memset(fwrt->dump.external_dbg_cfg_name, 0,
	       sizeof(fwrt->dump.external_dbg_cfg_name));

	fwrt->trans->dbg.ini_dest = IWL_FW_INI_LOCATION_INVALID;
}

void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
			    enum iwl_fw_ini_apply_point apply_point)
{
	void *data;

	if (apply_point == IWL_FW_INI_APPLY_EARLY)
		iwl_fw_dbg_ini_reset_cfg(fwrt);

	if (fwrt->trans->dbg.internal_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED) {
		IWL_DEBUG_FW(fwrt,
			     "WRT: Enabling internal configuration apply point %d\n",
			     apply_point);
		data = &fwrt->trans->dbg.apply_points[apply_point];
		_iwl_fw_dbg_apply_point(fwrt, data, apply_point, false);
	}

	if (fwrt->trans->dbg.external_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED) {
		IWL_DEBUG_FW(fwrt,
			     "WRT: Enabling external configuration apply point %d\n",
			     apply_point);
		data = &fwrt->trans->dbg.apply_points_ext[apply_point];
		_iwl_fw_dbg_apply_point(fwrt, data, apply_point, true);
	}
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_apply_point);

void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt)
{
	int i;
+0 −3
Original line number Diff line number Diff line
@@ -368,9 +368,6 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}

#endif /* CONFIG_IWLWIFI_DEBUGFS */

void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
			    enum iwl_fw_ini_apply_point apply_point);

void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt);

static inline void iwl_fw_lmac1_set_alive_err_table(struct iwl_trans *trans,
+0 −1
Original line number Diff line number Diff line
@@ -64,7 +64,6 @@
#include "iwl-trans.h"
#include "img.h"
#include "fw/api/debug.h"
#include "fw/api/dbg-tlv.h"
#include "fw/api/paging.h"
#include "iwl-eeprom-parse.h"

+429 −0

File changed.

Preview size limit exceeded, changes collapsed.

+4 −0
Original line number Diff line number Diff line
@@ -75,9 +75,13 @@ struct iwl_apply_point_data {
};

struct iwl_trans;
struct iwl_fw_runtime;

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_alloc(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv,
		       bool ext);
void iwl_dbg_tlv_apply_point(struct iwl_fw_runtime *fwrt,
			     enum iwl_fw_ini_apply_point apply_point);

#endif /* __iwl_dbg_tlv_h__*/
Loading