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

Commit d47902f9 authored by Sara Sharon's avatar Sara Sharon Committed by Luca Coelho
Browse files

iwlwifi: dbg: add apply point logic



Add a function to be called when apply point occurs.
For each of the TLVs, the function will perform the
apply point logic:
- For HCMD - send the stored host command
- For buffer allocation - allocate the memory and send the
  buffer allocation command
- For trigger and region - update the stored configuration

Signed-off-by: default avatarSara Sharon <sara.sharon@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 74374223
Loading
Loading
Loading
Loading
+207 −0
Original line number Diff line number Diff line
@@ -1263,3 +1263,210 @@ void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt)
				 cfg->d3_debug_data_length);
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_read_d3_debug_data);

static void
iwl_fw_dbg_buffer_allocation(struct iwl_fw_runtime *fwrt,
			     struct iwl_fw_ini_allocation_tlv *alloc)
{
	struct iwl_trans *trans = fwrt->trans;
	struct iwl_continuous_record_cmd cont_rec = {};
	struct iwl_buffer_allocation_cmd *cmd = (void *)&cont_rec.pad[0];
	struct iwl_host_cmd hcmd = {
		.id = LDBG_CONFIG_CMD,
		.flags = CMD_ASYNC,
		.data[0] = &cont_rec,
		.len[0] = sizeof(cont_rec),
	};
	void *virtual_addr = NULL;
	u32 size = le32_to_cpu(alloc->size);
	dma_addr_t phys_addr;

	cont_rec.record_mode.enable_recording = cpu_to_le16(BUFFER_ALLOCATION);

	if (!trans->num_blocks &&
	    le32_to_cpu(alloc->buffer_location) !=
	    IWL_FW_INI_LOCATION_DRAM_PATH)
		return;

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

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

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

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

	IWL_DEBUG_FW(trans, "Allocated debug block of size %d\n", size);

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

	cmd->num_frags = cpu_to_le32(1);
	cmd->fragments[0].address = cpu_to_le64(phys_addr);
	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, },
	};

	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,
				      bool ext, enum iwl_fw_ini_apply_point pnt)
{
	void *iter = (void *)tlv->region_config;
	int i, size = le32_to_cpu(tlv->num_regions);

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

		if (WARN_ON(id >= ARRAY_SIZE(fwrt->dump.active_regs)))
			break;

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

		if (ext && active->apply_point == pnt)
			IWL_WARN(fwrt->trans,
				 "External region TLV overrides FW default %x\n",
				 id);

		IWL_DEBUG_FW(fwrt,
			     "%s: apply point %d, activating region ID %d\n",
			     __func__, pnt, id);

		active->reg = reg;
		active->apply_point = pnt;

		if (le32_to_cpu(reg->region_type) !=
		    IWL_FW_INI_REGION_DRAM_BUFFER)
			iter += le32_to_cpu(reg->num_regions) * sizeof(__le32);

		iter += sizeof(*reg);
	}
}

static void iwl_fw_dbg_update_triggers(struct iwl_fw_runtime *fwrt,
				       struct iwl_fw_ini_trigger_tlv *tlv,
				       bool ext,
				       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 num;

		if (WARN_ON(id >= ARRAY_SIZE(fwrt->dump.active_trigs)))
			break;

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

		if (active->apply_point != apply_point) {
			active->conf = NULL;
			active->conf_ext = NULL;
		}

		num = le32_to_cpu(trig->num_regions);

		if (ext && active->apply_point == apply_point) {
			num += le32_to_cpu(active->conf->num_regions);
			if (trig->ignore_default) {
				active->conf_ext = active->conf;
				active->conf = trig;
			} else {
				active->conf_ext = trig;
			}
		} else {
			active->conf = trig;
		}

		iter += sizeof(*trig) +
			le32_to_cpu(trig->num_regions) * sizeof(__le32);

		active->active = num;
		active->apply_point = apply_point;
	}
}

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)
{
	void *iter = data->data;

	while (iter && iter < data->data + data->size) {
		struct iwl_ucode_tlv *tlv = iter;
		void *ini_tlv = (void *)tlv->data;
		u32 type = le32_to_cpu(tlv->type);

		switch (type) {
		case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
			iwl_fw_dbg_buffer_allocation(fwrt, ini_tlv);
			break;
		case IWL_UCODE_TLV_TYPE_HCMD:
			if (pnt < IWL_FW_INI_APPLY_AFTER_ALIVE) {
				IWL_ERR(fwrt,
					"Invalid apply point %x for host command\n",
					pnt);
				goto next;
			}
			iwl_fw_dbg_send_hcmd(fwrt, tlv);
			break;
		case IWL_UCODE_TLV_TYPE_REGIONS:
			iwl_fw_dbg_update_regions(fwrt, ini_tlv, ext, pnt);
			break;
		case IWL_UCODE_TLV_TYPE_TRIGGERS:
			iwl_fw_dbg_update_triggers(fwrt, ini_tlv, ext, pnt);
			break;
		case IWL_UCODE_TLV_TYPE_DEBUG_FLOW:
			break;
		default:
			WARN_ONCE(1, "Invalid TLV %x for apply point\n", type);
			break;
		}
next:
		iter += sizeof(*tlv) + le32_to_cpu(tlv->length);
	}
}

void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
			    enum iwl_fw_ini_apply_point apply_point)
{
	void *data = &fwrt->trans->apply_points[apply_point];

	_iwl_fw_dbg_apply_point(fwrt, data, apply_point, false);

	data = &fwrt->trans->apply_points_ext[apply_point];
	_iwl_fw_dbg_apply_point(fwrt, data, apply_point, true);
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_apply_point);
+4 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@
#include "file.h"
#include "error-dump.h"
#include "api/commands.h"
#include "api/dbg-tlv.h"

/**
 * struct iwl_fw_dump_desc - describes the dump
@@ -384,4 +385,7 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}
void iwl_fw_assert_error_dump(struct iwl_fw_runtime *fwrt);
void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt);
void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt);
void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
			    enum iwl_fw_ini_apply_point apply_point);

#endif  /* __iwl_fw_dbg_h__ */
+26 −0
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@
#define __iwl_fw_img_h__
#include <linux/types.h>

#include "api/dbg-tlv.h"

#include "file.h"
#include "error-dump.h"

@@ -220,6 +222,30 @@ struct iwl_fw_dbg {
	u32 dump_mask;
};

/**
 * struct iwl_fw_ini_active_triggers
 * @active: is this trigger active
 * @apply_point: last apply point that updated this trigger
 * @conf: active trigger
 * @conf_ext: second trigger, contains extra regions to dump
 */
struct iwl_fw_ini_active_triggers {
	bool active;
	enum iwl_fw_ini_apply_point apply_point;
	struct iwl_fw_ini_trigger *conf;
	struct iwl_fw_ini_trigger *conf_ext;
};

/**
 * struct iwl_fw_ini_active_regs
 * @reg: active region from TLV
 * @apply_point: apply point where it became active
 */
struct iwl_fw_ini_active_regs {
	struct iwl_fw_ini_region_cfg *reg;
	enum iwl_fw_ini_apply_point apply_point;
};

/**
 * struct iwl_fw - variables associated with the firmware
 *
+3 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@
#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"

@@ -139,6 +140,8 @@ struct iwl_fw_runtime {
		/* ts of the beginning of a non-collect fw dbg data period */
		unsigned long non_collect_ts_start[FW_DBG_TRIGGER_MAX - 1];
		u32 *d3_debug_data;
		struct iwl_fw_ini_active_regs active_regs[IWL_FW_INI_MAX_REGION_ID];
		struct iwl_fw_ini_active_triggers active_trigs[IWL_FW_TRIGGER_ID_NUM];
	} dump;
#ifdef CONFIG_IWLWIFI_DEBUGFS
	struct {
+3 −0
Original line number Diff line number Diff line
@@ -123,6 +123,9 @@ void iwl_alloc_dbg_tlv(struct iwl_trans *trans, size_t len, const u8 *data,
		hdr = (void *)&tlv->data[0];
		apply = le32_to_cpu(hdr->apply_point);

		IWL_DEBUG_FW(trans, "Read TLV %x, apply point %d\n",
			     le32_to_cpu(tlv->type), apply);

		if (WARN_ON(apply >= IWL_FW_INI_APPLY_NUM))
			continue;

Loading