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

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

iwlwifi: dbg_ini: implement Tx fifos dump



Implement Tx fifos dump in the new dump mechanism.

Signed-off-by: default avatarShahar S Matityahu <shahar.s.matityahu@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 2dbf3aea
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
 *
 * GPL LICENSE SUMMARY
 *
 * Copyright (C) 2018 Intel Corporation
 * Copyright (C) 2018 - 2019 Intel Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
@@ -25,7 +25,7 @@
 *
 * BSD LICENSE
 *
 * Copyright (C) 2018 Intel Corporation
 * Copyright (C) 2018 - 2019 Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
@@ -146,16 +146,17 @@ struct iwl_fw_ini_region_cfg_internal {

/**
 * struct iwl_fw_ini_region_cfg_fifos - meta data of fifos region
 * @lmac1_id: bit map of lmac1 fifos to include in the region.
 * @lmac2_id: bit map of lmac2 fifos to include in the region.
 * @fid1: fifo id 1 - bitmap of lmac tx/rx fifos to include in the region
 * @fid2: fifo id 2 - bitmap of umac rx fifos to include in the region.
 *	It is unused for tx.
 * @num_of_registers: number of prph registers in the region, each register is
 *	4 bytes size.
 * @header_only: none zero value indicates that this region does not include
 *	fifo data and includes only the given registers.
 */
struct iwl_fw_ini_region_cfg_fifos {
	__le32 lmac1_id;
	__le32 lmac2_id;
	__le32 fid1;
	__le32 fid2;
	__le32 num_of_registers;
	__le32 header_only;
} __packed; /* FW_DEBUG_TLV_REGION_FIFOS_S */
+183 −6
Original line number Diff line number Diff line
@@ -1058,7 +1058,7 @@ static int iwl_dump_ini_prph_iter(struct iwl_fw_runtime *fwrt,
		addr = le32_to_cpu(range->start_addr) + i;
		prph_val = iwl_read_prph(fwrt->trans, addr + offset);
		if (prph_val == 0x5a5a5a5a)
			return -1;
			return -EBUSY;
		*val++ = cpu_to_le32(prph_val);
	}

@@ -1150,7 +1150,7 @@ iwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt,
					    MON_BUFF_BASE_ADDR_VER2);

	if (start_addr == 0x5a5a5a5a)
		return -1;
		return -EBUSY;

	range->start_addr = cpu_to_le32(start_addr);
	range->range_data_size = cpu_to_le32(fwrt->trans->fw_mon[idx].size);
@@ -1161,6 +1161,124 @@ iwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt,
	return sizeof(*range) + le32_to_cpu(range->range_data_size);
}

struct iwl_ini_txf_iter_data {
	int fifo;
	int lmac;
	u32 fifo_size;
	bool internal_txf;
	bool init;
};

static bool iwl_ini_txf_iter(struct iwl_fw_runtime *fwrt,
			     struct iwl_fw_ini_region_cfg *reg)
{
	struct iwl_ini_txf_iter_data *iter = fwrt->dump.fifo_iter;
	struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg;
	int txf_num = cfg->num_txfifo_entries;
	int int_txf_num = ARRAY_SIZE(cfg->internal_txfifo_size);
	u32 lmac_bitmap = le32_to_cpu(reg->fifos.fid1);

	if (!iter)
		return false;

	if (iter->init) {
		if (le32_to_cpu(reg->offset) &&
		    WARN_ONCE(cfg->num_lmacs == 1,
			      "Invalid lmac offset: 0x%x\n",
			      le32_to_cpu(reg->offset)))
			return false;

		iter->init = false;
		iter->internal_txf = false;
		iter->fifo_size = 0;
		iter->fifo = -1;
		if (le32_to_cpu(reg->offset))
			iter->lmac = 1;
		else
			iter->lmac = 0;
	}

	if (!iter->internal_txf)
		for (iter->fifo++; iter->fifo < txf_num; iter->fifo++) {
			iter->fifo_size =
				cfg->lmac[iter->lmac].txfifo_size[iter->fifo];
			if (iter->fifo_size && (lmac_bitmap & BIT(iter->fifo)))
				return true;
		}

	iter->internal_txf = true;

	if (!fw_has_capa(&fwrt->fw->ucode_capa,
			 IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG))
		return false;

	for (iter->fifo++; iter->fifo < int_txf_num + txf_num; iter->fifo++) {
		iter->fifo_size =
			cfg->internal_txfifo_size[iter->fifo - txf_num];
		if (iter->fifo_size && (lmac_bitmap & BIT(iter->fifo)))
			return true;
	}

	return false;
}

static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt,
				 struct iwl_fw_ini_region_cfg *reg,
				 void *range_ptr, int idx)
{
	struct iwl_fw_ini_fifo_error_dump_range *range = range_ptr;
	struct iwl_ini_txf_iter_data *iter;
	u32 offs = le32_to_cpu(reg->offset), addr;
	u32 registers_size =
		le32_to_cpu(reg->fifos.num_of_registers) * sizeof(__le32);
	__le32 *val = range->data;
	unsigned long flags;
	int i;

	if (!iwl_ini_txf_iter(fwrt, reg))
		return -EIO;

	if (!iwl_trans_grab_nic_access(fwrt->trans, &flags))
		return -EBUSY;

	iter = fwrt->dump.fifo_iter;

	range->fifo_num = cpu_to_le32(iter->fifo);
	range->num_of_registers = reg->fifos.num_of_registers;
	range->range_data_size = cpu_to_le32(iter->fifo_size + registers_size);

	iwl_write_prph_no_grab(fwrt->trans, TXF_LARC_NUM + offs, iter->fifo);

	/* read txf registers */
	for (i = 0; i < le32_to_cpu(reg->fifos.num_of_registers); i++) {
		addr = le32_to_cpu(reg->start_addr[i]) + offs;

		*val++ = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, addr));
	}

	if (reg->fifos.header_only) {
		range->range_data_size = cpu_to_le32(registers_size);
		goto out;
	}

	/* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */
	iwl_write_prph_no_grab(fwrt->trans, TXF_READ_MODIFY_ADDR + offs,
			       TXF_WR_PTR + offs);

	/* Dummy-read to advance the read pointer to the head */
	iwl_read_prph_no_grab(fwrt->trans, TXF_READ_MODIFY_DATA + offs);

	/* Read FIFO */
	addr = TXF_READ_MODIFY_DATA + offs;
	for (i = 0; i < iter->fifo_size; i += sizeof(__le32))
		*val++ = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, addr));

out:
	iwl_trans_release_nic_access(fwrt->trans, &flags);

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

static void *iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt,
					  struct iwl_fw_ini_region_cfg *reg,
					  void *data)
@@ -1195,6 +1313,15 @@ static void
	return mon_dump->ranges;
}

static void *iwl_dump_ini_fifo_fill_header(struct iwl_fw_runtime *fwrt,
					   struct iwl_fw_ini_region_cfg *reg,
					   void *data)
{
	struct iwl_fw_ini_fifo_error_dump *dump = data;

	return dump->ranges;
}

static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt,
				   struct iwl_fw_ini_region_cfg *reg)
{
@@ -1219,6 +1346,22 @@ static u32 iwl_dump_ini_mon_dram_ranges(struct iwl_fw_runtime *fwrt,
	return 1;
}

static u32 iwl_dump_ini_txf_ranges(struct iwl_fw_runtime *fwrt,
				   struct iwl_fw_ini_region_cfg *reg)
{
	struct iwl_ini_txf_iter_data iter = { .init = true };
	void *fifo_iter = fwrt->dump.fifo_iter;
	u32 num_of_fifos = 0;

	fwrt->dump.fifo_iter = &iter;
	while (iwl_ini_txf_iter(fwrt, reg))
		num_of_fifos++;

	fwrt->dump.fifo_iter = fifo_iter;

	return num_of_fifos;
}

static u32 iwl_dump_ini_mem_get_size(struct iwl_fw_runtime *fwrt,
				     struct iwl_fw_ini_region_cfg *reg)
{
@@ -1266,6 +1409,30 @@ static u32 iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt,
	return size;
}

static u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt,
				     struct iwl_fw_ini_region_cfg *reg)
{
	struct iwl_ini_txf_iter_data iter = { .init = true };
	void *fifo_iter = fwrt->dump.fifo_iter;
	u32 size = 0;
	u32 fifo_hdr = sizeof(struct iwl_fw_ini_fifo_error_dump_range) +
		le32_to_cpu(reg->fifos.num_of_registers) * sizeof(__le32);

	fwrt->dump.fifo_iter = &iter;
	while (iwl_ini_txf_iter(fwrt, reg)) {
		size += fifo_hdr;
		if (!reg->fifos.header_only)
			size += iter.fifo_size;
	}

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

	fwrt->dump.fifo_iter = fifo_iter;

	return size;
}

/**
 * struct iwl_dump_ini_mem_ops - ini memory dump operations
 * @get_num_of_ranges: returns the number of memory ranges in the region.
@@ -1273,7 +1440,7 @@ static u32 iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt,
 * @fill_mem_hdr: fills region type specific headers and returns pointer to
 *	the first range or NULL if failed to fill headers.
 * @fill_range: copies a given memory range into the dump.
 *	Returns the size of the range or -1 otherwise.
 *	Returns the size of the range or negative error value otherwise.
 */
struct iwl_dump_ini_mem_ops {
	u32 (*get_num_of_ranges)(struct iwl_fw_runtime *fwrt,
@@ -1369,7 +1536,7 @@ static int iwl_fw_ini_get_trigger_len(struct iwl_fw_runtime *fwrt,
			size += hdr_len + iwl_dump_ini_mem_get_size(fwrt, reg);
			break;
		case IWL_FW_INI_REGION_TXF:
			size += iwl_fw_txf_len(fwrt, &fwrt->smem_cfg);
			size += hdr_len + iwl_dump_ini_txf_get_size(fwrt, reg);
			break;
		case IWL_FW_INI_REGION_RXF:
			size += iwl_fw_rxf_len(fwrt, &fwrt->smem_cfg);
@@ -1463,9 +1630,19 @@ static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
			iwl_dump_ini_mem(fwrt, type, data, reg, &ops);
			break;
		}
		case IWL_FW_INI_REGION_TXF:
			iwl_fw_dump_txf(fwrt, data);
		case IWL_FW_INI_REGION_TXF: {
			struct iwl_ini_txf_iter_data iter = { .init = true };
			void *fifo_iter = fwrt->dump.fifo_iter;

			fwrt->dump.fifo_iter = &iter;
			ops.get_num_of_ranges = iwl_dump_ini_txf_ranges;
			ops.get_size = iwl_dump_ini_txf_get_size;
			ops.fill_mem_hdr = iwl_dump_ini_fifo_fill_header;
			ops.fill_range = iwl_dump_ini_txf_iter;
			iwl_dump_ini_mem(fwrt, type, data, reg, &ops);
			fwrt->dump.fifo_iter = fifo_iter;
			break;
		}
		case IWL_FW_INI_REGION_RXF:
			iwl_fw_dump_rxf(fwrt, data);
			break;
+27 −2
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@
 * Copyright(c) 2014 Intel Corporation. All rights reserved.
 * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH
 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
 * Copyright (C) 2018 Intel Corporation
 * Copyright (C) 2018 - 2019 Intel Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
@@ -31,7 +31,7 @@
 * Copyright(c) 2014 Intel Corporation. All rights reserved.
 * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH
 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
 * Copyright (C) 2018 Intel Corporation
 * Copyright (C) 2018 - 2019 Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
@@ -308,6 +308,31 @@ struct iwl_fw_ini_error_dump {
	struct iwl_fw_ini_error_dump_range ranges[];
} __packed;

/**
 * struct iwl_fw_ini_fifo_error_dump_range - ini fifo range dump
 * @fifo_num: the fifo num. In case of rxf and umac rxf, set BIT(31) to
 *	distinguish between lmac and umac
 * @num_of_registers: num of registers to dump, dword size each
 * @range_data_size: the size of the registers and fifo data
 * @data: fifo data
 */
struct iwl_fw_ini_fifo_error_dump_range {
	__le32 fifo_num;
	__le32 num_of_registers;
	__le32 range_data_size;
	__le32 data[];
} __packed;

/**
 * struct iwl_fw_ini_fifo_error_dump - ini fifo region dump
 * @header: the header of this region
 * @ranges: the memory ranges of this region
 */
struct iwl_fw_ini_fifo_error_dump {
	struct iwl_fw_ini_error_dump_header header;
	struct iwl_fw_ini_fifo_error_dump_range ranges[];
} __packed;

/**
 * struct iwl_fw_error_dump_rb - content of an Receive Buffer
 * @index: the index of the Receive Buffer in the Rx queue
+1 −0
Original line number Diff line number Diff line
@@ -144,6 +144,7 @@ struct iwl_fw_runtime {
		struct iwl_fw_ini_active_triggers active_trigs[IWL_FW_TRIGGER_ID_NUM];
		u32 lmac_err_id[MAX_NUM_LMAC];
		u32 umac_err_id;
		void *fifo_iter;
	} dump;
#ifdef CONFIG_IWLWIFI_DEBUGFS
	struct {