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

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

iwlwifi: dbg_ini: remove apply point, switch to time point API



Remove the "apply points" mechanism as preparation for the changed
debug API where this is now a "time point" instead. Use a new API
across the code at the trigger points ("time points"), but don't
yet implement it since that requires some more preparation.

Signed-off-by: default avatarShahar S Matityahu <shahar.s.matityahu@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent a29f6576
Loading
Loading
Loading
Loading
+68 −21
Original line number Diff line number Diff line
@@ -397,27 +397,6 @@ enum iwl_fw_ini_trigger_id {
	IWL_FW_TRIGGER_ID_NUM,
}; /* FW_DEBUG_TLV_TRIGGER_ID_E_VER_1 */

/**
 * enum iwl_fw_ini_apply_point
 *
 * @IWL_FW_INI_APPLY_INVALID: invalid
 * @IWL_FW_INI_APPLY_EARLY: pre loading FW
 * @IWL_FW_INI_APPLY_AFTER_ALIVE: first cmd from host after alive
 * @IWL_FW_INI_APPLY_POST_INIT: last cmd in initialization sequence
 * @IWL_FW_INI_APPLY_MISSED_BEACONS: missed beacons notification
 * @IWL_FW_INI_APPLY_SCAN_COMPLETE: scan completed
 * @IWL_FW_INI_APPLY_NUM: number of apply points
*/
enum iwl_fw_ini_apply_point {
	IWL_FW_INI_APPLY_INVALID,
	IWL_FW_INI_APPLY_EARLY,
	IWL_FW_INI_APPLY_AFTER_ALIVE,
	IWL_FW_INI_APPLY_POST_INIT,
	IWL_FW_INI_APPLY_MISSED_BEACONS,
	IWL_FW_INI_APPLY_SCAN_COMPLETE,
	IWL_FW_INI_APPLY_NUM,
}; /* FW_DEBUG_TLV_APPLY_POINT_E_VER_1 */

/**
 * enum iwl_fw_ini_allocation_id
 *
@@ -510,4 +489,72 @@ enum iwl_fw_ini_region_type {
	IWL_FW_INI_REGION_NUM
}; /* FW_DEBUG_TLV_REGION_TYPE_E_VER_1 */

/**
 * enum iwl_fw_ini_time_point
 *
 * Hard coded time points in which the driver can send hcmd or perform dump
 * collection
 *
 * @IWL_FW_INI_TIME_POINT_EARLY: pre loading the FW
 * @IWL_FW_INI_TIME_POINT_AFTER_ALIVE: first cmd from host after alive notif
 * @IWL_FW_INI_TIME_POINT_POST_INIT: last cmd in series of init sequence
 * @IWL_FW_INI_TIME_POINT_FW_ASSERT: FW assert
 * @IWL_FW_INI_TIME_POINT_FW_HW_ERROR: FW HW error
 * @IWL_FW_INI_TIME_POINT_FW_TFD_Q_HANG: TFD queue hang
 * @IWL_FW_INI_TIME_POINT_FW_DHC_NOTIFOCATION: DHC cmd response and notif
 * @IWL_FW_INI_TIME_POINT_FW_RSP_OR_NOTIF: FW response or notification.
 *	data field holds id and group
 * @IWL_FW_INI_TIME_POINT_USER_TRIGGER: user trigger time point
 * @IWL_FW_INI_TIME_POINT_PERIODIC: periodic timepoint that fires in constant
 *	intervals. data field holds the interval time in msec
 * @IWL_FW_INI_TIME_POINT_WDG_TIMEOUT: watchdog timeout
 * @IWL_FW_INI_TIME_POINT_HOST_ASSERT: Unused
 * @IWL_FW_INI_TIME_POINT_HOST_ALIVE_TIMEOUT: alive timeout
 * @IWL_FW_INI_TIME_POINT_HOST_DEVICE_ENABLE: device enable
 * @IWL_FW_INI_TIME_POINT_HOST_DEVICE_DISABLE: device disable
 * @IWL_FW_INI_TIME_POINT_HOST_D3_START: D3 start
 * @IWL_FW_INI_TIME_POINT_HOST_D3_END: D3 end
 * @IWL_FW_INI_TIME_POINT_MISSED_BEACONS: missed beacons
 * @IWL_FW_INI_TIME_POINT_ASSOC_FAILED: association failure
 * @IWL_FW_INI_TIME_POINT_TX_FAILED: Tx frame failed
 * @IWL_FW_INI_TIME_POINT_TX_WFD_ACTION_FRAME_FAILED: wifi direct action
 *	frame failed
 * @IWL_FW_INI_TIME_POINT_TX_LATENCY_THRESHOLD: Tx latency threshold
 * @IWL_FW_INI_TIME_POINT_HANG_OCCURRED: hang occurred
 * @IWL_FW_INI_TIME_POINT_EAPOL_FAILED: EAPOL failed
 * @IWL_FW_INI_TIME_POINT_FAKE_TX: fake Tx
 * @IWL_FW_INI_TIME_POINT_DEASSOC: de association
 * @IWL_FW_INI_TIME_POINT_NUM: number of time points
 */
enum iwl_fw_ini_time_point {
	IWL_FW_INI_TIME_POINT_INVALID,
	IWL_FW_INI_TIME_POINT_EARLY,
	IWL_FW_INI_TIME_POINT_AFTER_ALIVE,
	IWL_FW_INI_TIME_POINT_POST_INIT,
	IWL_FW_INI_TIME_POINT_FW_ASSERT,
	IWL_FW_INI_TIME_POINT_FW_HW_ERROR,
	IWL_FW_INI_TIME_POINT_FW_TFD_Q_HANG,
	IWL_FW_INI_TIME_POINT_FW_DHC_NOTIFOCATION,
	IWL_FW_INI_TIME_POINT_FW_RSP_OR_NOTIF,
	IWL_FW_INI_TIME_POINT_USER_TRIGGER,
	IWL_FW_INI_TIME_POINT_PERIODIC,
	IWL_FW_INI_TIME_POINT_WDG_TIMEOUT,
	IWL_FW_INI_TIME_POINT_HOST_ASSERT,
	IWL_FW_INI_TIME_POINT_HOST_ALIVE_TIMEOUT,
	IWL_FW_INI_TIME_POINT_HOST_DEVICE_ENABLE,
	IWL_FW_INI_TIME_POINT_HOST_DEVICE_DISABLE,
	IWL_FW_INI_TIME_POINT_HOST_D3_START,
	IWL_FW_INI_TIME_POINT_HOST_D3_END,
	IWL_FW_INI_TIME_POINT_MISSED_BEACONS,
	IWL_FW_INI_TIME_POINT_ASSOC_FAILED,
	IWL_FW_INI_TIME_POINT_TX_FAILED,
	IWL_FW_INI_TIME_POINT_TX_WFD_ACTION_FRAME_FAILED,
	IWL_FW_INI_TIME_POINT_TX_LATENCY_THRESHOLD,
	IWL_FW_INI_TIME_POINT_HANG_OCCURRED,
	IWL_FW_INI_TIME_POINT_EAPOL_FAILED,
	IWL_FW_INI_TIME_POINT_FAKE_TX,
	IWL_FW_INI_TIME_POINT_DEASSOC,
	IWL_FW_INI_TIME_POINT_NUM,
}; /* FW_TLV_DEBUG_TIME_POINT_API_E */

#endif
+0 −45
Original line number Diff line number Diff line
@@ -352,51 +352,6 @@ struct iwl_dbg_mem_access_rsp {
	__le32 data[];
} __packed; /* DEBUG_(U|L)MAC_RD_WR_RSP_API_S_VER_1 */

#define LDBG_CFG_COMMAND_SIZE	80
#define BUFFER_ALLOCATION	0x27
#define START_DEBUG_RECORDING	0x29
#define STOP_DEBUG_RECORDING	0x2A

/* maximum fragments to be allocated per target of allocationId */
#define IWL_BUFFER_LOCATION_MAX_FRAGS	2

/**
 * struct iwl_fragment_data single fragment structure
 * @address: 64bit start address
 * @size: size in bytes
 */
struct iwl_fragment_data {
	__le64 address;
	__le32 size;
} __packed; /* FRAGMENT_STRUCTURE_API_S_VER_1 */

/**
 * struct iwl_buffer_allocation_cmd - buffer allocation command structure
 * @allocation_id: id of the allocation
 * @buffer_location: location of the buffer
 * @num_frags: number of fragments
 * @fragments: memory fragments
 */
struct iwl_buffer_allocation_cmd {
	__le32 allocation_id;
	__le32 buffer_location;
	__le32 num_frags;
	struct iwl_fragment_data fragments[IWL_BUFFER_LOCATION_MAX_FRAGS];
} __packed; /* BUFFER_ALLOCATION_CMD_API_S_VER_1 */

/**
 * struct iwl_ldbg_config_cmd - LDBG config command
 * @type: configuration type
 * @pad: reserved space for type-dependent data
 */
struct iwl_ldbg_config_cmd {
	__le32 type;
	union {
		u8 pad[LDBG_CFG_COMMAND_SIZE - sizeof(__le32)];
		struct iwl_buffer_allocation_cmd buffer_allocation;
	}; /* LDBG_CFG_BODY_API_U_VER_2 (partially) */
} __packed; /* LDBG_CFG_CMD_API_S_VER_2 */

/**
 * struct iwl_dbg_suspend_resume_cmd - dbgc suspend resume command
 * @operation: suspend or resume operation, uses
+6 −483
Original line number Diff line number Diff line
@@ -104,26 +104,6 @@ dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = {
	[IWL_DBG_TLV_TYPE_TRIGGER]	= {.min_ver = 1, .max_ver = 1,},
};

static int iwl_dbg_tlv_copy(struct iwl_ucode_tlv *tlv, struct list_head *list)
{
	struct iwl_apply_point_data *tlv_copy;
	u32 len = le32_to_cpu(tlv->length);

	tlv_copy = kzalloc(sizeof(*tlv_copy) + len, GFP_KERNEL);
	if (!tlv_copy)
		return -ENOMEM;

	INIT_LIST_HEAD(&tlv_copy->list);
	memcpy(&tlv_copy->tlv, tlv, sizeof(*tlv) + len);

	if (!list->next)
		INIT_LIST_HEAD(list);

	list_add_tail(&tlv_copy->list, list);

	return 0;
}

static bool iwl_dbg_tlv_ver_support(struct iwl_ucode_tlv *tlv)
{
	struct iwl_fw_ini_header *hdr = (void *)&tlv->data[0];
@@ -147,9 +127,6 @@ void iwl_dbg_tlv_alloc(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv,
	u32 tlv_idx = type - IWL_UCODE_TLV_DEBUG_BASE;
	enum iwl_ini_cfg_state *cfg_state = ext ?
		&trans->dbg.external_ini_cfg : &trans->dbg.internal_ini_cfg;
	struct list_head *dbg_cfg_list = ext ?
		&trans->dbg.apply_points_ext[pnt].list :
		&trans->dbg.apply_points[pnt].list;

	IWL_DEBUG_FW(trans, "WRT: read TLV 0x%x, apply point %d\n",
		     type, pnt);
@@ -159,24 +136,12 @@ void iwl_dbg_tlv_alloc(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv,
		goto out_err;
	}

	if (pnt >= IWL_FW_INI_APPLY_NUM) {
		IWL_ERR(trans, "WRT: Invalid apply point %d\n", pnt);
		goto out_err;
	}

	if (!iwl_dbg_tlv_ver_support(tlv)) {
		IWL_ERR(trans, "WRT: Unsupported TLV 0x%x version %u\n", type,
			le32_to_cpu(hdr->tlv_version));
		goto out_err;
	}

	if (iwl_dbg_tlv_copy(tlv, dbg_cfg_list)) {
		IWL_ERR(trans,
			"WRT: Failed to allocate TLV 0x%x, apply point %d\n",
			type, pnt);
		goto out_err;
	}

	if (*cfg_state == IWL_INI_CFG_STATE_NOT_LOADED)
		*cfg_state = IWL_INI_CFG_STATE_LOADED;

@@ -186,33 +151,9 @@ void iwl_dbg_tlv_alloc(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv,
	*cfg_state = IWL_INI_CFG_STATE_CORRUPTED;
}

static void iwl_dbg_tlv_free_list(struct list_head *list)
{
	if (!list || !list->next)
		return;

	while (!list_empty(list)) {
		struct iwl_apply_point_data *node =
			list_entry(list->next, typeof(*node), list);

		list_del(&node->list);
		kfree(node);
	}
}

void iwl_dbg_tlv_free(struct iwl_trans *trans)
{
	int i;

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

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

		data = &trans->dbg.apply_points_ext[i];
		iwl_dbg_tlv_free_list(&data->list);
	}
	/* will be used again later */
}

static int iwl_dbg_tlv_parse_bin(struct iwl_trans *trans, const u8 *data,
@@ -258,428 +199,10 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans)
	release_firmware(fw);
}

static void
iwl_dbg_tlv_apply_debug_info(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);
	const char err_str[] =
		"WRT: Invalid %s name length %d, expected %d\n";

	if (img_name_len != IWL_FW_INI_MAX_IMG_NAME_LEN) {
		IWL_WARN(fwrt, err_str, "image", 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, err_str, "debug cfg", 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_dbg_tlv_alloc_buffer(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_dbg_tlv_apply_buffer(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_dbg_tlv_alloc_buffer(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_dbg_tlv_apply_hcmd(struct iwl_fw_runtime *fwrt,
				   struct iwl_ucode_tlv *tlv)
void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
			    enum iwl_fw_ini_time_point tp_id,
			    union iwl_dbg_tlv_tp_data *tp_data)
{
	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_dbg_tlv_apply_region(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_dbg_tlv_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_dbg_tlv_apply_trigger(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_dbg_tlv_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_dbg_tlv_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_dbg_tlv_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);
		const char invalid_ap_str[] =
			"WRT: Invalid apply point %d for %s\n";

		switch (type) {
		case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
			iwl_dbg_tlv_apply_debug_info(fwrt, ini_tlv, ext, pnt);
			break;
		case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
			if (pnt != IWL_FW_INI_APPLY_EARLY) {
				IWL_ERR(fwrt, invalid_ap_str, pnt,
					"buffer allocation");
				break;
			}
			iwl_dbg_tlv_apply_buffer(fwrt, ini_tlv, pnt);
			break;
		case IWL_UCODE_TLV_TYPE_HCMD:
			if (pnt < IWL_FW_INI_APPLY_AFTER_ALIVE) {
				IWL_ERR(fwrt, invalid_ap_str, pnt,
					"host command");
				break;
			}
			iwl_dbg_tlv_apply_hcmd(fwrt, tlv);
			break;
		case IWL_UCODE_TLV_TYPE_REGIONS:
			iwl_dbg_tlv_apply_region(fwrt, ini_tlv, pnt);
			break;
		case IWL_UCODE_TLV_TYPE_TRIGGERS:
			iwl_dbg_tlv_apply_trigger(fwrt, ini_tlv, pnt);
			break;
		default:
			WARN_ONCE(1, "WRT: Invalid TLV 0x%x for apply point\n",
				  type);
			break;
		}
	}
}

static void iwl_dbg_tlv_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_dbg_tlv_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_dbg_tlv_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_dbg_tlv_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_dbg_tlv_apply_point(fwrt, data, apply_point, true);
	}
	/* will be used later */
}
IWL_EXPORT_SYMBOL(iwl_dbg_tlv_apply_point);
IWL_EXPORT_SYMBOL(iwl_dbg_tlv_time_point);
+11 −2
Original line number Diff line number Diff line
@@ -74,6 +74,14 @@ struct iwl_apply_point_data {
	struct iwl_ucode_tlv tlv;
};

/**
 * union iwl_dbg_tlv_tp_data - data that is given in a time point
 * @fw_pkt: a packet received from the FW
 */
union iwl_dbg_tlv_tp_data {
	struct iwl_rx_packet *fw_pkt;
};

struct iwl_trans;
struct iwl_fw_runtime;

@@ -81,7 +89,8 @@ 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);
void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
			    enum iwl_fw_ini_time_point tp_id,
			    union iwl_dbg_tlv_tp_data *tp_data);

#endif /* __iwl_dbg_tlv_h__*/
+0 −5
Original line number Diff line number Diff line
@@ -708,7 +708,6 @@ struct iwl_self_init_dram {
 * @external_ini_cfg: external debug cfg state. Uses &enum iwl_ini_cfg_state
 * @num_blocks: number of blocks in fw_mon
 * @fw_mon: address of the buffers for firmware monitor
 * @is_alloc: bit i is set if buffer i was allocated
 * @hw_error: equals true if hw error interrupt was received from the FW
 * @ini_dest: debug monitor destination uses &enum iwl_fw_ini_buffer_location
 */
@@ -727,12 +726,8 @@ struct iwl_trans_debug {
	enum iwl_ini_cfg_state internal_ini_cfg;
	enum iwl_ini_cfg_state external_ini_cfg;

	struct iwl_apply_point_data apply_points[IWL_FW_INI_APPLY_NUM];
	struct iwl_apply_point_data apply_points_ext[IWL_FW_INI_APPLY_NUM];

	int num_blocks;
	struct iwl_dram_data fw_mon[IWL_FW_INI_ALLOCATION_NUM];
	u32 is_alloc;

	bool hw_error;
	enum iwl_fw_ini_buffer_location ini_dest;
Loading