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

Commit 4d075007 authored by Johannes Berg's avatar Johannes Berg Committed by Emmanuel Grumbach
Browse files

iwlwifi: mvm/pcie: capture last commands on firmware error



When a firmware error occurs, capture the last 32 commands
(which are still in memory) in the error dump debugfs file.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent 83f32a4b
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -72,11 +72,14 @@
 * @IWL_FW_ERROR_DUMP_SRAM:
 * @IWL_FW_ERROR_DUMP_REG:
 * @IWL_FW_ERROR_DUMP_RXF:
 * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as
 *	&struct iwl_fw_error_dump_txcmd packets
 */
enum iwl_fw_error_dump_type {
	IWL_FW_ERROR_DUMP_SRAM = 0,
	IWL_FW_ERROR_DUMP_REG = 1,
	IWL_FW_ERROR_DUMP_RXF = 2,
	IWL_FW_ERROR_DUMP_TXCMD = 3,

	IWL_FW_ERROR_DUMP_MAX,
};
@@ -105,4 +108,27 @@ struct iwl_fw_error_dump_file {
	u8 data[0];
} __packed;

/**
 * struct iwl_fw_error_dump_txcmd - TX command data
 * @cmdlen: original length of command
 * @caplen: captured length of command (may be less)
 * @data: captured command data, @caplen bytes
 */
struct iwl_fw_error_dump_txcmd {
	__le32 cmdlen;
	__le32 caplen;
	u8 data[];
} __packed;

/**
 * iwl_mvm_fw_error_next_data - advance fw error dump data pointer
 * @data: previous data block
 * Returns: next data block
 */
static inline struct iwl_fw_error_dump_data *
iwl_mvm_fw_error_next_data(struct iwl_fw_error_dump_data *data)
{
	return (void *)(data->data + le32_to_cpu(data->len));
}

#endif /* __fw_error_dump_h__ */
+19 −0
Original line number Diff line number Diff line
@@ -463,6 +463,11 @@ struct iwl_trans;
 * @unref: release a reference previously taken with @ref. Note that
 *	initially the reference count is 1, making an initial @unref
 *	necessary to allow low power states.
 * @dump_data: fill a data dump with debug data, maybe containing last
 *	TX'ed commands and similar. When called with a NULL buffer and
 *	zero buffer length, provide only the (estimated) required buffer
 *	length. Return the used buffer length.
 *	Note that the transport must fill in the proper file headers.
 */
struct iwl_trans_ops {

@@ -511,6 +516,10 @@ struct iwl_trans_ops {
			      u32 value);
	void (*ref)(struct iwl_trans *trans);
	void (*unref)(struct iwl_trans *trans);

#ifdef CONFIG_IWLWIFI_DEBUGFS
	u32 (*dump_data)(struct iwl_trans *trans, void *buf, u32 buflen);
#endif
};

/**
@@ -664,6 +673,16 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)
		trans->ops->unref(trans);
}

#ifdef CONFIG_IWLWIFI_DEBUGFS
static inline u32 iwl_trans_dump_data(struct iwl_trans *trans,
				      void *buf, u32 buflen)
{
	if (!trans->ops->dump_data)
		return 0;
	return trans->ops->dump_data(trans, buf, buflen);
}
#endif

static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
				     struct iwl_host_cmd *cmd)
{
+1 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@
#include "iwl-io.h"
#include "iwl-prph.h"
#include "debugfs.h"
#include "fw-error-dump.h"
#include "iwl-fw-error-dump.h"

static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
					size_t count, loff_t *ppos)
+16 −2
Original line number Diff line number Diff line
@@ -79,8 +79,8 @@
#include "iwl-prph.h"
#include "rs.h"
#include "fw-api-scan.h"
#include "fw-error-dump.h"
#include "time-event.h"
#include "iwl-fw-error-dump.h"

/*
 * module name, copyright, version, etc.
@@ -822,6 +822,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
	struct iwl_fw_error_dump_file *dump_file;
	struct iwl_fw_error_dump_data *dump_data;
	u32 file_len;
	u32 trans_len;

	lockdep_assert_held(&mvm->mutex);

@@ -833,6 +834,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
		   sizeof(*dump_file) +
		   sizeof(*dump_data) * 2;

	trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0);
	if (trans_len)
		file_len += trans_len;

	dump_file = vmalloc(file_len);
	if (!dump_file)
		return;
@@ -846,7 +851,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
	dump_data->len = cpu_to_le32(mvm->fw_error_rxf_len);
	memcpy(dump_data->data, mvm->fw_error_rxf, mvm->fw_error_rxf_len);

	dump_data = (void *)((u8 *)dump_data->data + mvm->fw_error_rxf_len);
	dump_data = iwl_mvm_fw_error_next_data(dump_data);
	dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM);
	dump_data->len = cpu_to_le32(mvm->fw_error_sram_len);

@@ -864,6 +869,15 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
	kfree(mvm->fw_error_sram);
	mvm->fw_error_sram = NULL;
	mvm->fw_error_sram_len = 0;

	if (trans_len) {
		void *buf = iwl_mvm_fw_error_next_data(dump_data);
		u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf,
							 trans_len);
		dump_data = (void *)((u8 *)buf + real_trans_len);
		dump_file->file_len =
			cpu_to_le32(file_len - trans_len + real_trans_len);
	}
}
#endif

+7 −0
Original line number Diff line number Diff line
@@ -370,6 +370,13 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
			    struct sk_buff_head *skbs);
void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);

static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
{
	struct iwl_tfd_tb *tb = &tfd->tbs[idx];

	return le16_to_cpu(tb->hi_n_len) >> 4;
}

/*****************************************************
* Error handling
******************************************************/
Loading