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

Commit fd527eb5 authored by Golan Ben Ami's avatar Golan Ben Ami Committed by Luca Coelho
Browse files

iwlwifi: support internal debug data collection for new devices



Support internal debug data collection on 9000 and newer
devices.
The method for finding the base and end address has changed
on new HW's, so introduce a new version of debug destination
tlv.

Signed-off-by: default avatarGolan Ben Ami <golan.ben.ami@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent f39a5c01
Loading
Loading
Loading
Loading
+24 −4
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) 2016        Intel Deutschland GmbH
 * Copyright(c) 2016 - 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
@@ -34,7 +34,7 @@
 *
 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
 * Copyright(c) 2016        Intel Deutschland GmbH
 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
@@ -540,7 +540,7 @@ struct iwl_fw_dbg_mem_seg_tlv {
} __packed;

/**
 * struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data
 * struct iwl_fw_dbg_dest_tlv_v1 - configures the destination of the debug data
 *
 * @version: version of the TLV - currently 0
 * @monitor_mode: &enum iwl_fw_dbg_monitor_mode
@@ -555,7 +555,7 @@ struct iwl_fw_dbg_mem_seg_tlv {
 *
 * This parses IWL_UCODE_TLV_FW_DBG_DEST
 */
struct iwl_fw_dbg_dest_tlv {
struct iwl_fw_dbg_dest_tlv_v1 {
	u8 version;
	u8 monitor_mode;
	u8 size_power;
@@ -569,6 +569,26 @@ struct iwl_fw_dbg_dest_tlv {
	struct iwl_fw_dbg_reg_op reg_ops[0];
} __packed;

/* Mask of the register for defining the LDBG MAC2SMEM buffer SMEM size */
#define IWL_LDBG_M2S_BUF_SIZE_MSK	0x0fff0000
/* Mask of the register for defining the LDBG MAC2SMEM SMEM base address */
#define IWL_LDBG_M2S_BUF_BA_MSK		0x00000fff
/* The smem buffer chunks are in units of 256 bits */
#define IWL_M2S_UNIT_SIZE			0x100

struct iwl_fw_dbg_dest_tlv {
	u8 version;
	u8 monitor_mode;
	u8 size_power;
	u8 reserved;
	__le32 cfg_reg;
	__le32 write_ptr_reg;
	__le32 wrap_count;
	u8 base_shift;
	u8 size_shift;
	struct iwl_fw_dbg_reg_op reg_ops[0];
} __packed;

struct iwl_fw_dbg_conf_hcmd {
	u8 id;
	u8 reserved;
+1 −1
Original line number Diff line number Diff line
@@ -284,7 +284,7 @@ struct iwl_fw {
	struct iwl_fw_cipher_scheme cs[IWL_UCODE_MAX_CS];
	u8 human_readable[FW_VER_HUMAN_READABLE_SZ];

	struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
	struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv;
	struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
	size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
	struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
+84 −15
Original line number Diff line number Diff line
@@ -296,7 +296,12 @@ struct iwl_firmware_pieces {
	u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;

	/* FW debug data parsed for driver usage */
	bool dbg_dest_tlv_init;
	u8 *dbg_dest_ver;
	union {
		struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
		struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv_v1;
	};
	struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
	size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
	struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
@@ -930,21 +935,49 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
			break;
			}
		case IWL_UCODE_TLV_FW_DBG_DEST: {
			struct iwl_fw_dbg_dest_tlv *dest = (void *)tlv_data;
			struct iwl_fw_dbg_dest_tlv *dest = NULL;
			struct iwl_fw_dbg_dest_tlv_v1 *dest_v1 = NULL;
			u8 mon_mode;

			pieces->dbg_dest_ver = (u8 *)tlv_data;
			if (*pieces->dbg_dest_ver == 1) {
				dest = (void *)tlv_data;
			} else if (*pieces->dbg_dest_ver == 0) {
				dest_v1 = (void *)tlv_data;
			} else {
				IWL_ERR(drv,
					"The version is %d, and it is invalid\n",
					*pieces->dbg_dest_ver);
				break;
			}

			if (pieces->dbg_dest_tlv) {
			if (pieces->dbg_dest_tlv_init) {
				IWL_ERR(drv,
					"dbg destination ignored, already exists\n");
				break;
			}

			pieces->dbg_dest_tlv_init = true;

			if (dest_v1) {
				pieces->dbg_dest_tlv_v1 = dest_v1;
				mon_mode = dest_v1->monitor_mode;
			} else {
				pieces->dbg_dest_tlv = dest;
			IWL_INFO(drv, "Found debug destination: %s\n",
				 get_fw_dbg_mode_string(dest->monitor_mode));
				mon_mode = dest->monitor_mode;
			}

			drv->fw.dbg_dest_reg_num =
				tlv_len - offsetof(struct iwl_fw_dbg_dest_tlv,
			IWL_INFO(drv, "Found debug destination: %s\n",
				 get_fw_dbg_mode_string(mon_mode));

			drv->fw.dbg_dest_reg_num = (dest_v1) ?
				tlv_len -
				offsetof(struct iwl_fw_dbg_dest_tlv_v1,
					 reg_ops) :
				tlv_len -
				offsetof(struct iwl_fw_dbg_dest_tlv,
					 reg_ops);

			drv->fw.dbg_dest_reg_num /=
				sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]);

@@ -953,7 +986,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
		case IWL_UCODE_TLV_FW_DBG_CONF: {
			struct iwl_fw_dbg_conf_tlv *conf = (void *)tlv_data;

			if (!pieces->dbg_dest_tlv) {
			if (!pieces->dbg_dest_tlv_init) {
				IWL_ERR(drv,
					"Ignore dbg config %d - no destination configured\n",
					conf->id);
@@ -1340,15 +1373,51 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
		if (iwl_alloc_ucode(drv, pieces, i))
			goto out_free_fw;

	if (pieces->dbg_dest_tlv) {
		drv->fw.dbg_dest_tlv =
			kmemdup(pieces->dbg_dest_tlv,
				sizeof(*pieces->dbg_dest_tlv) +
				sizeof(pieces->dbg_dest_tlv->reg_ops[0]) *
				drv->fw.dbg_dest_reg_num, GFP_KERNEL);
	if (pieces->dbg_dest_tlv_init) {
		size_t dbg_dest_size = sizeof(*drv->fw.dbg_dest_tlv) +
			sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) *
			drv->fw.dbg_dest_reg_num;

		drv->fw.dbg_dest_tlv = kmalloc(dbg_dest_size, GFP_KERNEL);

		if (!drv->fw.dbg_dest_tlv)
			goto out_free_fw;

		if (*pieces->dbg_dest_ver == 0) {
			memcpy(drv->fw.dbg_dest_tlv, pieces->dbg_dest_tlv_v1,
			       dbg_dest_size);
		} else {
			struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv =
				drv->fw.dbg_dest_tlv;

			dest_tlv->version = pieces->dbg_dest_tlv->version;
			dest_tlv->monitor_mode =
				pieces->dbg_dest_tlv->monitor_mode;
			dest_tlv->size_power =
				pieces->dbg_dest_tlv->size_power;
			dest_tlv->wrap_count =
				pieces->dbg_dest_tlv->wrap_count;
			dest_tlv->write_ptr_reg =
				pieces->dbg_dest_tlv->write_ptr_reg;
			dest_tlv->base_shift =
				pieces->dbg_dest_tlv->base_shift;
			memcpy(dest_tlv->reg_ops,
			       pieces->dbg_dest_tlv->reg_ops,
			       sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) *
			       drv->fw.dbg_dest_reg_num);

			/* In version 1 of the destination tlv, which is
			 * relevant for internal buffer exclusively,
			 * the base address is part of given with the length
			 * of the buffer, and the size shift is give instead of
			 * end shift. We now store these values in base_reg,
			 * and end shift, and when dumping the data we'll
			 * manipulate it for extracting both the length and
			 * base address */
			dest_tlv->base_reg = pieces->dbg_dest_tlv->cfg_reg;
			dest_tlv->end_shift =
				pieces->dbg_dest_tlv->size_shift;
		}
	}

	for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) {
+1 −1
Original line number Diff line number Diff line
@@ -744,7 +744,7 @@ struct iwl_trans {
	struct lockdep_map sync_cmd_lockdep_map;
#endif

	const struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
	const struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv;
	const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
	struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv;
	u8 dbg_dest_reg_num;
+1 −1
Original line number Diff line number Diff line
@@ -1221,7 +1221,7 @@ static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm,
					      loff_t *ppos)
{
	struct iwl_trans *trans = mvm->trans;
	const struct iwl_fw_dbg_dest_tlv *dest = trans->dbg_dest_tlv;
	const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg_dest_tlv;
	struct iwl_continuous_record_cmd cont_rec = {};
	int ret, rec_mode;

Loading