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

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

iwlwifi: Fix pre operational dumping flows



There are several dumping flows in the driver in case of a fail
prior to operational.

In some cases we get 2 dumps while in others we get none.

Fix this by uniting the different flows.
Add a different dump type to driver triggered dumps in case we want
a dump but did not got assert, and make all dumping go through
iwl_fw_dbg_collect_desc to avoid multiple dumps.

Signed-off-by: default avatarShahar S Matityahu <shahar.s.matityahu@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 6032c062
Loading
Loading
Loading
Loading
+51 −38
Original line number Diff line number Diff line
@@ -1365,44 +1365,6 @@ const struct iwl_fw_dump_desc iwl_dump_desc_assert = {
};
IWL_EXPORT_SYMBOL(iwl_dump_desc_assert);

void iwl_fw_assert_error_dump(struct iwl_fw_runtime *fwrt)
{
	IWL_INFO(fwrt, "error dump due to fw assert\n");
	fwrt->dump.desc = &iwl_dump_desc_assert;
	iwl_fw_error_dump(fwrt);
}
IWL_EXPORT_SYMBOL(iwl_fw_assert_error_dump);

void iwl_fw_alive_timeout_dump(struct iwl_fw_runtime *fwrt)
{
	struct iwl_fw_dump_desc *iwl_dump_desc_alive_timeout;

	if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status))
		return;

	iwl_dump_desc_alive_timeout =
		kmalloc(sizeof(*iwl_dump_desc_alive_timeout), GFP_KERNEL);
	if (!iwl_dump_desc_alive_timeout)
		return;

	iwl_dump_desc_alive_timeout->trig_desc.type =
		cpu_to_le32(FW_DBG_TRIGGER_ALIVE_TIMEOUT);
	iwl_dump_desc_alive_timeout->len = 0;

	if (WARN_ON(fwrt->dump.desc))
		iwl_fw_free_dump_desc(fwrt);

	IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n",
		 FW_DBG_TRIGGER_ALIVE_TIMEOUT);

	/* set STATUS_FW_ERROR to collect all memory regions. */
	set_bit(STATUS_FW_ERROR, &fwrt->trans->status);

	fwrt->dump.desc = iwl_dump_desc_alive_timeout;
	iwl_fw_error_dump(fwrt);
}
IWL_EXPORT_SYMBOL(iwl_fw_alive_timeout_dump);

int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
			    const struct iwl_fw_dump_desc *desc,
			    bool monitor_only,
@@ -1442,6 +1404,33 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_desc);

int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt,
			     enum iwl_fw_dbg_trigger trig_type)
{
	int ret;
	struct iwl_fw_dump_desc *iwl_dump_error_desc =
		kmalloc(sizeof(*iwl_dump_error_desc), GFP_KERNEL);

	if (!iwl_dump_error_desc)
		return -ENOMEM;

	iwl_dump_error_desc->trig_desc.type = cpu_to_le32(trig_type);
	iwl_dump_error_desc->len = 0;

	ret = iwl_fw_dbg_collect_desc(fwrt, iwl_dump_error_desc, false, 0);
	if (ret) {
		kfree(iwl_dump_error_desc);
	} else {
		set_bit(STATUS_FW_WAIT_DUMP, &fwrt->trans->status);

		/* trigger nmi to halt the fw */
		iwl_force_nmi(fwrt->trans);
	}

	return ret;
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_error_collect);

int _iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
			enum iwl_fw_dbg_trigger trig,
			const char *str, size_t len,
@@ -1893,3 +1882,27 @@ void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
	_iwl_fw_dbg_apply_point(fwrt, data, apply_point, true);
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_apply_point);

void iwl_fwrt_stop_device(struct iwl_fw_runtime *fwrt)
{
	/* if the wait event timeout elapses instead of wake up then
	 * the driver did not receive NMI interrupt and can not assume the FW
	 * is halted
	 */
	int ret = wait_event_timeout(fwrt->trans->fw_halt_waitq,
				     !test_bit(STATUS_FW_WAIT_DUMP,
					       &fwrt->trans->status),
				     msecs_to_jiffies(2000));
	if (!ret) {
		/* failed to receive NMI interrupt, assuming the FW is stuck */
		set_bit(STATUS_FW_ERROR, &fwrt->trans->status);

		clear_bit(STATUS_FW_WAIT_DUMP, &fwrt->trans->status);
	}

	/* Assuming the op mode mutex is held at this point */
	iwl_fw_dbg_collect_sync(fwrt);

	iwl_trans_stop_device(fwrt->trans);
}
IWL_EXPORT_SYMBOL(iwl_fwrt_stop_device);
+3 −2
Original line number Diff line number Diff line
@@ -112,6 +112,8 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt);
int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
			    const struct iwl_fw_dump_desc *desc,
			    bool monitor_only, unsigned int delay);
int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt,
			     enum iwl_fw_dbg_trigger trig_type);
int _iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
			enum iwl_fw_dbg_trigger trig,
			const char *str, size_t len,
@@ -434,10 +436,9 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}

#endif /* CONFIG_IWLWIFI_DEBUGFS */

void iwl_fw_assert_error_dump(struct iwl_fw_runtime *fwrt);
void iwl_fw_alive_timeout_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);

void iwl_fwrt_stop_device(struct iwl_fw_runtime *fwrt);
#endif  /* __iwl_fw_dbg_h__ */
+3 −0
Original line number Diff line number Diff line
@@ -356,6 +356,8 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
 * @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when
 *  the firmware sends a tx reply.
 * @FW_DBG_TRIGGER_ALIVE_TIMEOUT: trigger log collection if alive flow timeouts
 * @FW_DBG_TRIGGER_DRIVER: trigger log collection upon a flow failure
 *	in the driver.
 */
enum iwl_fw_dbg_trigger {
	FW_DBG_TRIGGER_INVALID = 0,
@@ -374,6 +376,7 @@ enum iwl_fw_dbg_trigger {
	FW_DBG_TRIGGER_TDLS,
	FW_DBG_TRIGGER_TX_STATUS,
	FW_DBG_TRIGGER_ALIVE_TIMEOUT,
	FW_DBG_TRIGGER_DRIVER,

	/* must be last */
	FW_DBG_TRIGGER_MAX,
+3 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
 * GPL LICENSE SUMMARY
 *
 * Copyright(c) 2017 Intel Deutschland GmbH
 * Copyright(c) 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
@@ -26,6 +27,7 @@
 * BSD LICENSE
 *
 * Copyright(c) 2017 Intel Deutschland GmbH
 * Copyright(c) 2019 Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
@@ -74,6 +76,7 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
	fwrt->ops_ctx = ops_ctx;
	INIT_DELAYED_WORK(&fwrt->dump.wk, iwl_fw_error_dump_wk);
	iwl_fwrt_dbgfs_register(fwrt, dbgfs_dir);
	init_waitqueue_head(&fwrt->trans->fw_halt_waitq);
}
IWL_EXPORT_SYMBOL(iwl_fw_runtime_init);

+13 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
 * 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
@@ -30,6 +31,7 @@
 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
 * Copyright(c) 2018 - 2019 Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
@@ -330,6 +332,7 @@ enum iwl_d3_status {
 *	are sent
 * @STATUS_TRANS_IDLE: the trans is idle - general commands are not to be sent
 * @STATUS_TRANS_DEAD: trans is dead - avoid any read/write operation
 * @STATUS_FW_WAIT_DUMP: if set, wait until cleared before collecting dump
 */
enum iwl_trans_status {
	STATUS_SYNC_HCMD_ACTIVE,
@@ -342,6 +345,7 @@ enum iwl_trans_status {
	STATUS_TRANS_GOING_IDLE,
	STATUS_TRANS_IDLE,
	STATUS_TRANS_DEAD,
	STATUS_FW_WAIT_DUMP,
};

static inline int
@@ -796,6 +800,11 @@ struct iwl_trans {
	bool suspending;
	bool dbg_rec_on;

	u32 lmac_error_event_table[2];
	u32 umac_error_event_table;
	unsigned int error_event_table_tlv_status;
	wait_queue_head_t fw_halt_waitq;

	/* pointer to trans specific struct */
	/*Ensure that this pointer will always be aligned to sizeof pointer */
	char trans_specific[0] __aligned(sizeof(void *));
@@ -1202,6 +1211,10 @@ static inline void iwl_trans_fw_error(struct iwl_trans *trans)
	/* prevent double restarts due to the same erroneous FW */
	if (!test_and_set_bit(STATUS_FW_ERROR, &trans->status))
		iwl_op_mode_nic_error(trans->op_mode);

	if (test_and_clear_bit(STATUS_FW_WAIT_DUMP, &trans->status))
		wake_up(&trans->fw_halt_waitq);

}

/*****************************************************
Loading