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

iwlwifi: dbg_ini: add monitor dumping support



Allow collecting monitor data in ini debug mode.
Implement both SMEM and DRAM monitor regions dumping.
For DRAM monitor, support DBGC1, DBGC2 and DBGC3 and support several
DRAM fragments per DBGC.

Signed-off-by: default avatarShahar S Matityahu <shahar.s.matityahu@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 69f0e505
Loading
Loading
Loading
Loading
+48 −7
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@
#include <linux/module.h>
#include <linux/stringify.h>
#include "iwl-config.h"
#include "iwl-prph.h"

/* Highest firmware API version supported */
#define IWL_22000_UCODE_API_MAX	50
@@ -183,23 +184,49 @@ static const struct iwl_ht_params iwl_22000_ht_params = {
	.min_umac_error_event_table = 0x400000,				\
	.d3_debug_data_base_addr = 0x401000,				\
	.d3_debug_data_length = 60 * 1024,				\
	.fw_mon_smem_write_ptr_addr = 0xa0c16c,				\
	.fw_mon_smem_write_ptr_msk = 0xfffff,				\
	.fw_mon_smem_cycle_cnt_ptr_addr = 0xa0c174,			\
	.fw_mon_smem_cycle_cnt_ptr_msk = 0xfffff
	.mon_smem_regs = {						\
		.write_ptr = {						\
			.addr = LDBG_M2S_BUF_WPTR,			\
			.mask = LDBG_M2S_BUF_WPTR_VAL_MSK,		\
	},								\
		.cycle_cnt = {						\
			.addr = LDBG_M2S_BUF_WRAP_CNT,			\
			.mask = LDBG_M2S_BUF_WRAP_CNT_VAL_MSK,		\
		},							\
	}

#define IWL_DEVICE_22500						\
	IWL_DEVICE_22000_COMMON,					\
	.trans.device_family = IWL_DEVICE_FAMILY_22000,			\
	.trans.base_params = &iwl_22000_base_params,			\
	.trans.csr = &iwl_csr_v1,					\
	.gp2_reg_addr = 0xa02c68
	.gp2_reg_addr = 0xa02c68,					\
	.mon_dram_regs = {						\
		.write_ptr = {						\
			.addr = MON_BUFF_WRPTR_VER2,			\
			.mask = 0xffffffff,				\
		},							\
		.cycle_cnt = {						\
			.addr = MON_BUFF_CYCLE_CNT_VER2,		\
			.mask = 0xffffffff,				\
		},							\
	}

#define IWL_DEVICE_22560						\
	IWL_DEVICE_22000_COMMON,					\
	.trans.device_family = IWL_DEVICE_FAMILY_22560,			\
	.trans.base_params = &iwl_22560_base_params,			\
	.trans.csr = &iwl_csr_v2
	.trans.csr = &iwl_csr_v2,					\
	.mon_dram_regs = {						\
		.write_ptr = {						\
			.addr = MON_BUFF_WRPTR_VER2,			\
			.mask = 0xffffffff,				\
		},							\
		.cycle_cnt = {						\
			.addr = MON_BUFF_CYCLE_CNT_VER2,		\
			.mask = 0xffffffff,				\
		},							\
	}

#define IWL_DEVICE_AX210						\
	IWL_DEVICE_22000_COMMON,					\
@@ -209,7 +236,21 @@ static const struct iwl_ht_params iwl_22000_ht_params = {
	.trans.csr = &iwl_csr_v1,					\
	.min_txq_size = 128,						\
	.gp2_reg_addr = 0xd02c68,					\
	.min_256_ba_txq_size = 512
	.min_256_ba_txq_size = 512,					\
	.mon_dram_regs = {						\
		.write_ptr = {						\
			.addr = DBGC_CUR_DBGBUF_STATUS,			\
			.mask = DBGC_CUR_DBGBUF_STATUS_OFFSET_MSK,	\
		},							\
		.cycle_cnt = {						\
			.addr = DBGC_DBGBUF_WRAP_AROUND,		\
			.mask = 0xffffffff,				\
		},							\
		.cur_frag = {						\
			.addr = DBGC_CUR_DBGBUF_STATUS,			\
			.mask = DBGC_CUR_DBGBUF_STATUS_IDX_MSK,		\
		},							\
	}

const struct iwl_cfg iwl22000_2ac_cfg_hr = {
	.name = "Intel(R) Dual Band Wireless AC 22000",
+21 −4
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@
#include <linux/stringify.h>
#include "iwl-config.h"
#include "fw/file.h"
#include "iwl-prph.h"

/* Highest firmware API version supported */
#define IWL9000_UCODE_API_MAX	46
@@ -149,10 +150,26 @@ static const struct iwl_tt_params iwl9000_tt_params = {
	.ht_params = &iwl9000_ht_params,				\
	.nvm_ver = IWL9000_NVM_VERSION,					\
	.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,		\
	.fw_mon_smem_write_ptr_addr = 0xa0476c,				\
	.fw_mon_smem_write_ptr_msk = 0xfffff,				\
	.fw_mon_smem_cycle_cnt_ptr_addr = 0xa04774,			\
	.fw_mon_smem_cycle_cnt_ptr_msk = 0xfffff
	.mon_smem_regs = {						\
		.write_ptr = {						\
			.addr = LDBG_M2S_BUF_WPTR,			\
			.mask = LDBG_M2S_BUF_WPTR_VAL_MSK,		\
		},							\
		.cycle_cnt = {						\
			.addr = LDBG_M2S_BUF_WRAP_CNT,			\
			.mask = LDBG_M2S_BUF_WRAP_CNT_VAL_MSK,		\
		},							\
	},								\
	.mon_dram_regs = {						\
		.write_ptr = {						\
			.addr = MON_BUFF_WRPTR_VER2,			\
			.mask = 0xffffffff,				\
		},							\
		.cycle_cnt = {						\
			.addr = MON_BUFF_CYCLE_CNT_VER2,		\
			.mask = 0xffffffff,				\
		},							\
	}


const struct iwl_cfg iwl9160_2ac_cfg = {
+19 −22
Original line number Diff line number Diff line
@@ -73,28 +73,6 @@ struct iwl_fw_ini_header {
	u8 data[];
} __packed; /* FW_DEBUG_TLV_HEADER_S */

/**
 * struct iwl_fw_ini_allocation_tlv - (IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION)
 * buffer allocation TLV - for debug
 *
 * @iwl_fw_ini_header: header
 * @allocation_id: &enum iwl_fw_ini_allocation_id - to bind allocation and hcmd
 *	if needed (DBGC1/DBGC2/SDFX/...)
 * @buffer_location: type of iwl_fw_ini_buffer_location
 * @size: size in bytes
 * @max_fragments: the maximum allowed fragmentation in the desired memory
 *	allocation above
 * @min_frag_size: the minimum allowed fragmentation size in bytes
 */
struct iwl_fw_ini_allocation_tlv {
	struct iwl_fw_ini_header header;
	__le32 allocation_id;
	__le32 buffer_location;
	__le32 size;
	__le32 max_fragments;
	__le32 min_frag_size;
} __packed; /* FW_DEBUG_TLV_BUFFER_ALLOCATION_TLV_S_VER_1 */

/**
 * enum iwl_fw_ini_dbg_domain - debug domains
 * allows to send host cmd or collect memory region if a given domain is enabled
@@ -350,6 +328,25 @@ struct iwl_fw_ini_trigger {
	__le32 data[];
} __packed; /* FW_TLV_DEBUG_TRIGGER_CONFIG_API_S_VER_1 */

/**
 * struct iwl_fw_ini_allocation_tlv - Allocates DRAM buffers
 *
 * @hdr: debug header
 * @alloc_id: allocation id. One of &enum iwl_fw_ini_allocation_id
 * @buf_location: buffer location. One of &enum iwl_fw_ini_buffer_location
 * @req_size: requested buffer size
 * @max_frags_num: maximum number of fragments
 * @min_size: minimum buffer size
 */
struct iwl_fw_ini_allocation_tlv {
	struct iwl_fw_ini_header hdr;
	__le32 alloc_id;
	__le32 buf_location;
	__le32 req_size;
	__le32 max_frags_num;
	__le32 min_size;
} __packed; /* FW_TLV_DEBUG_BUFFER_ALLOCATION_API_S_VER_1 */

/**
 * struct iwl_fw_ini_trigger_tlv - trigger TLV
 *
+200 −2
Original line number Diff line number Diff line
@@ -1165,6 +1165,42 @@ static int iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt,
	return sizeof(*range) + le32_to_cpu(range->range_data_size);
}

static int
iwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt,
			   struct iwl_dump_ini_region_data *reg_data,
			   void *range_ptr, int idx)
{
	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
	struct iwl_fw_ini_error_dump_range *range = range_ptr;
	struct iwl_dram_data *frag;
	u32 alloc_id = le32_to_cpu(reg->dram_alloc_id);

	frag = &fwrt->trans->dbg.fw_mon_ini[alloc_id].frags[idx];

	range->dram_base_addr = cpu_to_le64(frag->physical);
	range->range_data_size = cpu_to_le32(frag->size);

	memcpy(range->data, frag->block, frag->size);

	return sizeof(*range) + le32_to_cpu(range->range_data_size);
}

static int iwl_dump_ini_mon_smem_iter(struct iwl_fw_runtime *fwrt,
				      struct iwl_dump_ini_region_data *reg_data,
				      void *range_ptr, int idx)
{
	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
	struct iwl_fw_ini_error_dump_range *range = range_ptr;
	u32 addr = le32_to_cpu(reg->internal_buffer.base_addr);

	range->internal_base_addr = cpu_to_le32(addr);
	range->range_data_size = reg->internal_buffer.size;
	iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
				 le32_to_cpu(reg->internal_buffer.size));

	return sizeof(*range) + le32_to_cpu(range->range_data_size);
}

static bool iwl_ini_txf_iter(struct iwl_fw_runtime *fwrt,
			     struct iwl_dump_ini_region_data *reg_data, int idx)
{
@@ -1406,6 +1442,88 @@ iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt,
	return dump->ranges;
}

/**
 * mask_apply_and_normalize - applies mask on val and normalize the result
 *
 * The normalization is based on the first set bit in the mask
 *
 * @val: value
 * @mask: mask to apply and to normalize with
 */
static u32 mask_apply_and_normalize(u32 val, u32 mask)
{
	return (val & mask) >> (ffs(mask) - 1);
}

static __le32 iwl_get_mon_reg(struct iwl_fw_runtime *fwrt, u32 alloc_id,
			      const struct iwl_fw_mon_reg *reg_info)
{
	u32 val, offs;

	/* The header addresses of DBGCi is calculate as follows:
	 * DBGC1 address + (0x100 * i)
	 */
	offs = (alloc_id - IWL_FW_INI_ALLOCATION_ID_DBGC1) * 0x100;

	if (!reg_info || !reg_info->addr || !reg_info->mask)
		return 0;

	val = iwl_read_prph_no_grab(fwrt->trans, reg_info->addr + offs);

	return cpu_to_le32(mask_apply_and_normalize(val, reg_info->mask));
}

static void *
iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt,
			     struct iwl_dump_ini_region_data *reg_data,
			     struct iwl_fw_ini_monitor_dump *data,
			     const struct iwl_fw_mon_regs *addrs)
{
	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
	u32 alloc_id = le32_to_cpu(reg->dram_alloc_id);
	unsigned long flags;

	if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) {
		IWL_ERR(fwrt, "Failed to get monitor header\n");
		return NULL;
	}

	data->write_ptr = iwl_get_mon_reg(fwrt, alloc_id,
					  &addrs->write_ptr);
	data->cycle_cnt = iwl_get_mon_reg(fwrt, alloc_id,
					  &addrs->cycle_cnt);
	data->cur_frag = iwl_get_mon_reg(fwrt, alloc_id,
					 &addrs->cur_frag);

	iwl_trans_release_nic_access(fwrt->trans, &flags);

	data->header.version = cpu_to_le32(IWL_INI_DUMP_VER);

	return data->ranges;
}

static void *
iwl_dump_ini_mon_dram_fill_header(struct iwl_fw_runtime *fwrt,
				  struct iwl_dump_ini_region_data *reg_data,
				  void *data)
{
	struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data;

	return iwl_dump_ini_mon_fill_header(fwrt, reg_data, mon_dump,
					    &fwrt->trans->cfg->mon_dram_regs);
}

static void *
iwl_dump_ini_mon_smem_fill_header(struct iwl_fw_runtime *fwrt,
				  struct iwl_dump_ini_region_data *reg_data,
				  void *data)
{
	struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data;

	return iwl_dump_ini_mon_fill_header(fwrt, reg_data, mon_dump,
					    &fwrt->trans->cfg->mon_smem_regs);
}

static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt,
				   struct iwl_dump_ini_region_data *reg_data)
{
@@ -1423,6 +1541,27 @@ static u32 iwl_dump_ini_paging_ranges(struct iwl_fw_runtime *fwrt,
	return fwrt->num_of_paging_blk;
}

static u32
iwl_dump_ini_mon_dram_ranges(struct iwl_fw_runtime *fwrt,
			     struct iwl_dump_ini_region_data *reg_data)
{
	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
	struct iwl_fw_mon *fw_mon;
	u32 ranges = 0, alloc_id = le32_to_cpu(reg->dram_alloc_id);
	int i;

	fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id];

	for (i = 0; i < fw_mon->num_frags; i++) {
		if (!fw_mon->frags[i].size)
			break;

		ranges++;
	}

	return ranges;
}

static u32 iwl_dump_ini_txf_ranges(struct iwl_fw_runtime *fwrt,
				   struct iwl_dump_ini_region_data *reg_data)
{
@@ -1476,6 +1615,55 @@ iwl_dump_ini_paging_get_size(struct iwl_fw_runtime *fwrt,
	return size;
}

static u32
iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt,
			       struct iwl_dump_ini_region_data *reg_data)
{
	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
	struct iwl_fw_mon *fw_mon;
	u32 size = 0, alloc_id = le32_to_cpu(reg->dram_alloc_id);
	int i;

	fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id];

	for (i = 0; i < fw_mon->num_frags; i++) {
		struct iwl_dram_data *frag = &fw_mon->frags[i];

		if (!frag->size)
			break;

		size += sizeof(struct iwl_fw_ini_error_dump_range) + frag->size;
	}

	if (size)
		size += sizeof(struct iwl_fw_ini_monitor_dump);

	return size;
}

static u32
iwl_dump_ini_mon_smem_get_size(struct iwl_fw_runtime *fwrt,
			       struct iwl_dump_ini_region_data *reg_data)
{
	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
	struct iwl_fw_ini_allocation_tlv *fw_mon_cfg;
	u32 alloc_id = le32_to_cpu(reg->internal_buffer.alloc_id), size;

	fw_mon_cfg = &fwrt->trans->dbg.fw_mon_cfg[alloc_id];
	if (le32_to_cpu(fw_mon_cfg->buf_location) !=
	    IWL_FW_INI_LOCATION_SRAM_PATH)
		return 0;

	size = le32_to_cpu(reg->internal_buffer.size);
	if (!size)
		return 0;

	size += sizeof(struct iwl_fw_ini_monitor_dump) +
		sizeof(struct iwl_fw_ini_error_dump_range);

	return size;
}

static u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt,
				     struct iwl_dump_ini_region_data *reg_data)
{
@@ -1680,8 +1868,18 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt,

static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = {
	[IWL_FW_INI_REGION_INVALID] = {},
	[IWL_FW_INI_REGION_INTERNAL_BUFFER] = {},
	[IWL_FW_INI_REGION_DRAM_BUFFER] = {},
	[IWL_FW_INI_REGION_INTERNAL_BUFFER] = {
		.get_num_of_ranges = iwl_dump_ini_single_range,
		.get_size = iwl_dump_ini_mon_smem_get_size,
		.fill_mem_hdr = iwl_dump_ini_mon_smem_fill_header,
		.fill_range = iwl_dump_ini_mon_smem_iter,
	},
	[IWL_FW_INI_REGION_DRAM_BUFFER] = {
		.get_num_of_ranges = iwl_dump_ini_mon_dram_ranges,
		.get_size = iwl_dump_ini_mon_dram_get_size,
		.fill_mem_hdr = iwl_dump_ini_mon_dram_fill_header,
		.fill_range = iwl_dump_ini_mon_dram_iter,
	},
	[IWL_FW_INI_REGION_TXF] = {
		.get_num_of_ranges = iwl_dump_ini_txf_ranges,
		.get_size = iwl_dump_ini_txf_get_size,
+2 −0
Original line number Diff line number Diff line
@@ -456,12 +456,14 @@ struct iwl_fw_error_dump_rb {
 * @header: header of the region
 * @write_ptr: write pointer position in the buffer
 * @cycle_cnt: cycles count
 * @cur_frag: current fragment in use
 * @ranges: the memory ranges of this this region
 */
struct iwl_fw_ini_monitor_dump {
	struct iwl_fw_ini_error_dump_header header;
	__le32 write_ptr;
	__le32 cycle_cnt;
	__le32 cur_frag;
	struct iwl_fw_ini_error_dump_range ranges[];
} __packed;

Loading