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

Commit 7174beb6 authored by Johannes Berg's avatar Johannes Berg Committed by Luca Coelho
Browse files

iwlwifi: refactor firmware debug code



Split out the firmware debug code to be more general, so that it
can be used by different subdrivers.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 702e975d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ iwlwifi-$(CONFIG_IWLDVM) += cfg/1000.o cfg/2000.o cfg/5000.o cfg/6000.o
iwlwifi-$(CONFIG_IWLMVM) += cfg/7000.o cfg/8000.o cfg/9000.o cfg/a000.o
iwlwifi-objs		+= iwl-trans.o
iwlwifi-objs		+= fw/notif-wait.o
iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o
iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o fw/dbg.o

iwlwifi-objs += $(iwlwifi-m)

+82 −43
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@
 *
 * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
 * Copyright(c) 2015        Intel Deutschland GmbH
 * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
 *
 * 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
@@ -32,7 +32,7 @@
 *
 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
 * Copyright(c) 2015        Intel Deutschland GmbH
 * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
@@ -63,24 +63,46 @@
 *
 *****************************************************************************/

#ifndef __mvm_fw_dbg_h__
#define __mvm_fw_dbg_h__
#include "fw/file.h"
#include "fw/error-dump.h"
#include "mvm.h"
#ifndef __iwl_fw_dbg_h__
#define __iwl_fw_dbg_h__
#include <linux/workqueue.h>
#include <net/cfg80211.h>
#include "runtime.h"
#include "file.h"
#include "error-dump.h"

/**
 * struct iwl_fw_dump_desc - describes the dump
 * @len: length of trig_desc->data
 * @trig_desc: the description of the dump
 */
struct iwl_fw_dump_desc {
	size_t len;
	/* must be last */
	struct iwl_fw_error_dump_trigger_desc trig_desc;
};

extern const struct iwl_fw_dump_desc iwl_dump_desc_assert;

static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt)
{
	if (fwrt->dump.desc != &iwl_dump_desc_assert)
		kfree(fwrt->dump.desc);
	fwrt->dump.desc = NULL;
}

void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm);
int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
				const struct iwl_mvm_dump_desc *desc,
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,
			    const struct iwl_fw_dbg_trigger_tlv *trigger);
int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
		       enum iwl_fw_dbg_trigger trig,
		       const char *str, size_t len,
		       const struct iwl_fw_dbg_trigger_tlv *trigger);
int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
			    struct iwl_fw_dbg_trigger_tlv *trigger,
			    const char *fmt, ...) __printf(3, 4);
int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 id);
int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 id);

#define iwl_fw_dbg_trigger_enabled(fw, id) ({			\
	void *__dbg_trigger = (fw)->dbg_trigger_tlv[(id)];	\
@@ -101,25 +123,25 @@ _iwl_fw_dbg_get_trigger(const struct iwl_fw *fw, enum iwl_fw_dbg_trigger id)

static inline bool
iwl_fw_dbg_trigger_vif_match(struct iwl_fw_dbg_trigger_tlv *trig,
			     struct ieee80211_vif *vif)
			     struct wireless_dev *wdev)
{
	u32 trig_vif = le32_to_cpu(trig->vif_type);

	return trig_vif == IWL_FW_DBG_CONF_VIF_ANY ||
	       ieee80211_vif_type_p2p(vif) == trig_vif;
	       wdev->iftype == trig_vif;
}

static inline bool
iwl_fw_dbg_trigger_stop_conf_match(struct iwl_mvm *mvm,
iwl_fw_dbg_trigger_stop_conf_match(struct iwl_fw_runtime *fwrt,
				   struct iwl_fw_dbg_trigger_tlv *trig)
{
	return ((trig->mode & IWL_FW_DBG_TRIGGER_STOP) &&
		(mvm->fw_dbg_conf == FW_DBG_INVALID ||
		(BIT(mvm->fw_dbg_conf) & le32_to_cpu(trig->stop_conf_ids))));
		(fwrt->dump.conf == FW_DBG_INVALID ||
		(BIT(fwrt->dump.conf) & le32_to_cpu(trig->stop_conf_ids))));
}

static inline bool
iwl_fw_dbg_no_trig_window(struct iwl_mvm *mvm,
iwl_fw_dbg_no_trig_window(struct iwl_fw_runtime *fwrt,
			  struct iwl_fw_dbg_trigger_tlv *trig)
{
	unsigned long wind_jiff =
@@ -127,49 +149,66 @@ iwl_fw_dbg_no_trig_window(struct iwl_mvm *mvm,
	u32 id = le32_to_cpu(trig->id);

	/* If this is the first event checked, jump to update start ts */
	if (mvm->fw_dbg_non_collect_ts_start[id] &&
	    (time_after(mvm->fw_dbg_non_collect_ts_start[id] + wind_jiff,
	if (fwrt->dump.non_collect_ts_start[id] &&
	    (time_after(fwrt->dump.non_collect_ts_start[id] + wind_jiff,
			jiffies)))
		return true;

	mvm->fw_dbg_non_collect_ts_start[id] = jiffies;
	fwrt->dump.non_collect_ts_start[id] = jiffies;
	return false;
}

static inline bool
iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm,
			      struct ieee80211_vif *vif,
iwl_fw_dbg_trigger_check_stop(struct iwl_fw_runtime *fwrt,
			      struct wireless_dev *wdev,
			      struct iwl_fw_dbg_trigger_tlv *trig)
{
	if (vif && !iwl_fw_dbg_trigger_vif_match(trig, vif))
	if (wdev && !iwl_fw_dbg_trigger_vif_match(trig, wdev))
		return false;

	if (iwl_fw_dbg_no_trig_window(mvm, trig)) {
		IWL_WARN(mvm, "Trigger %d occurred while no-collect window.\n",
	if (iwl_fw_dbg_no_trig_window(fwrt, trig)) {
		IWL_WARN(fwrt, "Trigger %d occurred while no-collect window.\n",
			 trig->id);
		return false;
	}

	return iwl_fw_dbg_trigger_stop_conf_match(mvm, trig);
	return iwl_fw_dbg_trigger_stop_conf_match(fwrt, trig);
}

static inline void
_iwl_fw_dbg_trigger_simple_stop(struct iwl_mvm *mvm,
				struct ieee80211_vif *vif,
_iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt,
				struct wireless_dev *wdev,
				struct iwl_fw_dbg_trigger_tlv *trigger)
{
	if (!trigger)
		return;

	if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trigger))
	if (!iwl_fw_dbg_trigger_check_stop(fwrt, wdev, trigger))
		return;

	iwl_mvm_fw_dbg_collect_trig(mvm, trigger, NULL);
	iwl_fw_dbg_collect_trig(fwrt, trigger, NULL);
}

#define iwl_fw_dbg_trigger_simple_stop(mvm, vif, trig)	\
	_iwl_fw_dbg_trigger_simple_stop((mvm), (vif),	\
					iwl_fw_dbg_get_trigger((mvm)->fw,\
#define iwl_fw_dbg_trigger_simple_stop(fwrt, wdev, trig)	\
	_iwl_fw_dbg_trigger_simple_stop((fwrt), (wdev),		\
					iwl_fw_dbg_get_trigger((fwrt)->fw,\
							       (trig)))

#endif  /* __mvm_fw_dbg_h__ */
static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt)
{
	fwrt->dump.conf = FW_DBG_INVALID;
}

void iwl_fw_error_dump_wk(struct work_struct *work);

static inline void iwl_fw_flush_dump(struct iwl_fw_runtime *fwrt)
{
	flush_delayed_work(&fwrt->dump.wk);
}

static inline void iwl_fw_cancel_dump(struct iwl_fw_runtime *fwrt)
{
	cancel_delayed_work_sync(&fwrt->dump.wk);
}

#endif  /* __iwl_fw_dbg_h__ */
+75 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 * This file is provided under a dual BSD/GPLv2 license.  When using or
 * redistributing this file, you may do so under either license.
 *
 * GPL LICENSE SUMMARY
 *
 * Copyright(c) 2017 Intel Deutschland GmbH
 *
 * 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
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * The full GNU General Public License is included in this distribution
 * in the file called COPYING.
 *
 * Contact Information:
 *  Intel Linux Wireless <linuxwifi@intel.com>
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *
 * BSD LICENSE
 *
 * Copyright(c) 2017 Intel Deutschland GmbH
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name Intel Corporation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/
#include "iwl-drv.h"
#include "runtime.h"
#include "dbg.h"

void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
			 const struct iwl_fw *fw,
			 const struct iwl_fw_runtime_ops *ops, void *ops_ctx)
{
	memset(fwrt, 0, sizeof(*fwrt));
	fwrt->trans = trans;
	fwrt->fw = fw;
	fwrt->dev = trans->dev;
	fwrt->dump.conf = FW_DBG_INVALID;
	fwrt->ops = ops;
	fwrt->ops_ctx = ops_ctx;
	INIT_DELAYED_WORK(&fwrt->dump.wk, iwl_fw_error_dump_wk);
}
IWL_EXPORT_SYMBOL(iwl_fw_runtime_init);
+33 −9
Original line number Diff line number Diff line
@@ -63,6 +63,11 @@
#include "img.h"
#include "api.h"

struct iwl_fw_runtime_ops {
	int (*dump_start)(void *ctx);
	void (*dump_end)(void *ctx);
};

#define MAX_NUM_LMAC 2
struct iwl_fwrt_shared_mem_cfg {
	int num_lmacs;
@@ -76,23 +81,36 @@ struct iwl_fwrt_shared_mem_cfg {
	u32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM];
};

enum iwl_fw_runtime_status {
	IWL_FWRT_STATUS_DUMPING = 0,
};

/**
 * struct iwl_fw_runtime - runtime data for firmware
 * @fw: firmware image
 * @cfg: NIC configuration
 * @dev: device pointer
 * @ops: user ops
 * @ops_ctx: user ops context
 * @status: status flags
 * @fw_paging_db: paging database
 * @num_of_paging_blk: number of paging blocks
 * @num_of_pages_in_last_blk: number of pages in the last block
 * @smem_cfg: saved firmware SMEM configuration
 * @cur_fw_img: current firmware image, must be maintained by
 *	the driver by calling &iwl_fw_set_current_image()
 * @dump: debug dump data
 */
struct iwl_fw_runtime {
	struct iwl_trans *trans;
	const struct iwl_fw *fw;
	struct device *dev;

	const struct iwl_fw_runtime_ops *ops;
	void *ops_ctx;

	unsigned long status;

	/* Paging */
	struct iwl_fw_paging fw_paging_db[NUM_OF_FW_PAGING_BLOCKS];
	u16 num_of_paging_blk;
@@ -102,17 +120,23 @@ struct iwl_fw_runtime {

	/* memory configuration */
	struct iwl_fwrt_shared_mem_cfg smem_cfg;

	/* debug */
	struct {
		const struct iwl_fw_dump_desc *desc;
		const struct iwl_fw_dbg_trigger_tlv *trig;
		struct delayed_work wk;

		u8 conf;

		/* ts of the beginning of a non-collect fw dbg data period */
		unsigned long non_collect_ts_start[FW_DBG_TRIGGER_MAX - 1];
	} dump;
};

static inline void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt,
				       struct iwl_trans *trans,
				       const struct iwl_fw *fw)
{
	memset(fwrt, 0, sizeof(*fwrt));
	fwrt->trans = trans;
	fwrt->fw = fw;
	fwrt->dev = trans->dev;
}
void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
			 const struct iwl_fw *fw,
			 const struct iwl_fw_runtime_ops *ops, void *ops_ctx);

static inline void iwl_fw_set_current_image(struct iwl_fw_runtime *fwrt,
					    enum iwl_ucode_type cur_fw_img)
Loading