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

Commit 520f03ea authored by Shahar S Matityahu's avatar Shahar S Matityahu Committed by Luca Coelho
Browse files

iwlwifi: allow masking out memory areas from the fw dump



Reading and dumping memory areas takes time, and sometimes
dumping all of the areas isn't necessary.

Allow choosing the memory areas which should be dumped.

Signed-off-by: default avatarShahar S Matityahu <shahar.s.matityahu@intel.com>
Signed-off-by: default avatarGolan Ben Ami <golan.ben.ami@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 92536c96
Loading
Loading
Loading
Loading
+165 −119
Original line number Diff line number Diff line
@@ -243,39 +243,47 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt,
	if (!iwl_trans_grab_nic_access(fwrt->trans, &flags))
		return;

	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) {
		/* Pull RXF1 */
	iwl_fwrt_dump_rxf(fwrt, dump_data, cfg->lmac[0].rxfifo1_size, 0, 0);
		iwl_fwrt_dump_rxf(fwrt, dump_data,
				  cfg->lmac[0].rxfifo1_size, 0, 0);
		/* Pull RXF2 */
		iwl_fwrt_dump_rxf(fwrt, dump_data, cfg->rxfifo2_size,
				  RXF_DIFF_FROM_PREV, 1);
		/* Pull LMAC2 RXF1 */
		if (fwrt->smem_cfg.num_lmacs > 1)
		iwl_fwrt_dump_rxf(fwrt, dump_data, cfg->lmac[1].rxfifo1_size,
			iwl_fwrt_dump_rxf(fwrt, dump_data,
					  cfg->lmac[1].rxfifo1_size,
					  LMAC2_PRPH_OFFSET, 2);
	}

	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) {
		/* Pull TXF data from LMAC1 */
		for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) {
			/* Mark the number of TXF we're pulling now */
			iwl_trans_write_prph(fwrt->trans, TXF_LARC_NUM, i);
		iwl_fwrt_dump_txf(fwrt, dump_data, cfg->lmac[0].txfifo_size[i],
				  0, i);
			iwl_fwrt_dump_txf(fwrt, dump_data,
					  cfg->lmac[0].txfifo_size[i], 0, i);
		}

		/* Pull TXF data from LMAC2 */
		if (fwrt->smem_cfg.num_lmacs > 1) {
		for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) {
			for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries;
			     i++) {
				/* Mark the number of TXF we're pulling now */
				iwl_trans_write_prph(fwrt->trans,
					     TXF_LARC_NUM + LMAC2_PRPH_OFFSET,
					     i);
						     TXF_LARC_NUM +
						     LMAC2_PRPH_OFFSET, i);
				iwl_fwrt_dump_txf(fwrt, dump_data,
						  cfg->lmac[1].txfifo_size[i],
						  LMAC2_PRPH_OFFSET,
						  i + cfg->num_txfifo_entries);
			}
		}
	}

	if (fw_has_capa(&fwrt->fw->ucode_capa,
	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF) &&
	    fw_has_capa(&fwrt->fw->ucode_capa,
			IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) {
		/* Pull UMAC internal TXF data from all TXFs */
		for (i = 0;
@@ -600,10 +608,13 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
	if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) {
		fifo_data_len = 0;

		if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) {

			/* Count RXF2 size */
			if (mem_cfg->rxfifo2_size) {
				/* Add header info */
			fifo_data_len += mem_cfg->rxfifo2_size +
				fifo_data_len +=
					mem_cfg->rxfifo2_size +
					sizeof(*dump_data) +
					sizeof(struct iwl_fw_error_dump_fifo);
			}
@@ -614,28 +625,37 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
					continue;

				/* Add header info */
			fifo_data_len += mem_cfg->lmac[i].rxfifo1_size +
				fifo_data_len +=
					mem_cfg->lmac[i].rxfifo1_size +
					sizeof(*dump_data) +
					sizeof(struct iwl_fw_error_dump_fifo);
			}
		}

		if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) {
			size_t fifo_const_len = sizeof(*dump_data) +
				sizeof(struct iwl_fw_error_dump_fifo);

			/* Count TXF sizes */
			for (i = 0; i < mem_cfg->num_lmacs; i++) {
				int j;

			for (j = 0; j < mem_cfg->num_txfifo_entries; j++) {
				for (j = 0; j < mem_cfg->num_txfifo_entries;
				     j++) {
					if (!mem_cfg->lmac[i].txfifo_size[j])
						continue;

					/* Add header info */
					fifo_data_len +=
					mem_cfg->lmac[i].txfifo_size[j] +
					sizeof(*dump_data) +
					sizeof(struct iwl_fw_error_dump_fifo);
						fifo_const_len +
						mem_cfg->lmac[i].txfifo_size[j];
				}
			}
		}

		if (fw_has_capa(&fwrt->fw->ucode_capa,
		if ((fwrt->fw->dbg_dump_mask &
		    BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF)) &&
		    fw_has_capa(&fwrt->fw->ucode_capa,
				IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) {
			for (i = 0;
			     i < ARRAY_SIZE(mem_cfg->internal_txfifo_size);
@@ -652,7 +672,8 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
		}

		/* Make room for PRPH registers */
		if (!fwrt->trans->cfg->gen2) {
		if (!fwrt->trans->cfg->gen2 &&
		    fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH)) {
			for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm);
			     i++) {
				/* The range includes both boundaries */
@@ -667,7 +688,8 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
		}

		if (!fwrt->trans->cfg->gen2 &&
		    fwrt->trans->cfg->mq_rx_supported) {
		    fwrt->trans->cfg->mq_rx_supported &&
		    fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH)) {
			for (i = 0; i <
				ARRAY_SIZE(iwl_prph_dump_addr_9000); i++) {
				/* The range includes both boundaries */
@@ -681,34 +703,42 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
			}
		}

		if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000)
		if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000 &&
		    fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RADIO_REG))
			radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ;
	}

	file_len = sizeof(*dump_file) +
		   sizeof(*dump_data) * 3 +
		   sizeof(*dump_smem_cfg) +
		   fifo_data_len +
		   prph_len +
		   radio_len +
		   sizeof(*dump_info);
		   radio_len;

	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO))
		file_len += sizeof(*dump_data) + sizeof(*dump_info);
	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG))
		file_len += sizeof(*dump_data) + sizeof(*dump_smem_cfg);

	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
		/* Make room for the SMEM, if it exists */
		if (smem_len)
		file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len;
			file_len += sizeof(*dump_data) + sizeof(*dump_mem) +
				smem_len;

		/* Make room for the secondary SRAM, if it exists */
		if (sram2_len)
		file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len;
			file_len += sizeof(*dump_data) + sizeof(*dump_mem) +
				sram2_len;

		/* Make room for MEM segments */
		for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) {
			file_len += sizeof(*dump_data) + sizeof(*dump_mem) +
				    le32_to_cpu(fw_dbg_mem[i].len);
		}
	}

	/* Make room for fw's virtual image pages, if it exists */
	if (!fwrt->trans->cfg->gen2 &&
	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) &&
	    !fwrt->trans->cfg->gen2 &&
	    fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size &&
	    fwrt->fw_paging_db[0].fw_paging_block)
		file_len += fwrt->num_of_paging_blk *
@@ -722,12 +752,14 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
			   sizeof(*dump_info) + sizeof(*dump_smem_cfg);
	}

	if (fwrt->dump.desc)
	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) &&
	    fwrt->dump.desc)
		file_len += sizeof(*dump_data) + sizeof(*dump_trig) +
			    fwrt->dump.desc->len;

	if (!fwrt->fw->n_dbg_mem_tlv)
		file_len += sram_len + sizeof(*dump_mem);
	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM) &&
	    !fwrt->fw->n_dbg_mem_tlv)
		file_len += sizeof(*dump_data) + sram_len + sizeof(*dump_mem);

	dump_file = vzalloc(file_len);
	if (!dump_file) {
@@ -740,23 +772,28 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
	dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
	dump_data = (void *)dump_file->data;

	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) {
		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO);
		dump_data->len = cpu_to_le32(sizeof(*dump_info));
		dump_info = (void *)dump_data->data;
		dump_info->device_family =
		fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000 ?
			fwrt->trans->cfg->device_family ==
			IWL_DEVICE_FAMILY_7000 ?
				cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) :
				cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8);
	dump_info->hw_step = cpu_to_le32(CSR_HW_REV_STEP(fwrt->trans->hw_rev));
		dump_info->hw_step =
			cpu_to_le32(CSR_HW_REV_STEP(fwrt->trans->hw_rev));
		memcpy(dump_info->fw_human_readable, fwrt->fw->human_readable,
		       sizeof(dump_info->fw_human_readable));
		strncpy(dump_info->dev_human_readable, fwrt->trans->cfg->name,
		sizeof(dump_info->dev_human_readable));
			sizeof(dump_info->dev_human_readable) - 1);
		strncpy(dump_info->bus_human_readable, fwrt->dev->bus->name,
		sizeof(dump_info->bus_human_readable));
			sizeof(dump_info->bus_human_readable) - 1);

		dump_data = iwl_fw_error_next_data(dump_data);
	}

	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG)) {
		/* Dump shared memory configuration */
		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_CFG);
		dump_data->len = cpu_to_le32(sizeof(*dump_smem_cfg));
@@ -766,14 +803,16 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
			cpu_to_le32(mem_cfg->num_txfifo_entries);
		for (i = 0; i < MAX_NUM_LMAC; i++) {
			int j;
			u32 *txf_size = mem_cfg->lmac[i].txfifo_size;

			for (j = 0; j < TX_FIFO_MAX_NUM; j++)
				dump_smem_cfg->lmac[i].txfifo_size[j] =
				cpu_to_le32(mem_cfg->lmac[i].txfifo_size[j]);
					cpu_to_le32(txf_size[j]);
			dump_smem_cfg->lmac[i].rxfifo1_size =
				cpu_to_le32(mem_cfg->lmac[i].rxfifo1_size);
		}
	dump_smem_cfg->rxfifo2_size = cpu_to_le32(mem_cfg->rxfifo2_size);
		dump_smem_cfg->rxfifo2_size =
			cpu_to_le32(mem_cfg->rxfifo2_size);
		dump_smem_cfg->internal_txfifo_addr =
			cpu_to_le32(mem_cfg->internal_txfifo_addr);
		for (i = 0; i < TX_FIFO_INTERNAL_MAX_NUM; i++) {
@@ -782,6 +821,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
		}

		dump_data = iwl_fw_error_next_data(dump_data);
	}

	/* We only dump the FIFOs if the FW is in error state */
	if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) {
@@ -790,7 +830,8 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
			iwl_read_radio_regs(fwrt, &dump_data);
	}

	if (fwrt->dump.desc) {
	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) &&
	    fwrt->dump.desc) {
		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO);
		dump_data->len = cpu_to_le32(sizeof(*dump_trig) +
					     fwrt->dump.desc->len);
@@ -805,7 +846,8 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
	if (monitor_dump_only)
		goto dump_trans_data;

	if (!fwrt->fw->n_dbg_mem_tlv) {
	if (!fwrt->fw->n_dbg_mem_tlv &&
	    fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
		dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem));
		dump_mem = (void *)dump_data->data;
@@ -821,6 +863,9 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
		u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs);
		bool success;

		if (!(fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)))
			break;

		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
		dump_data->len = cpu_to_le32(len + sizeof(*dump_mem));
		dump_mem = (void *)dump_data->data;
@@ -854,7 +899,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
			dump_data = iwl_fw_error_next_data(dump_data);
	}

	if (smem_len) {
	if (smem_len && fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
		IWL_DEBUG_INFO(fwrt, "WRT SMEM dump\n");
		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
		dump_data->len = cpu_to_le32(smem_len + sizeof(*dump_mem));
@@ -867,7 +912,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
		dump_data = iwl_fw_error_next_data(dump_data);
	}

	if (sram2_len) {
	if (sram2_len && fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
		IWL_DEBUG_INFO(fwrt, "WRT SRAM dump\n");
		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
		dump_data->len = cpu_to_le32(sram2_len + sizeof(*dump_mem));
@@ -881,7 +926,8 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
	}

	/* Dump fw's virtual image */
	if (!fwrt->trans->cfg->gen2 &&
	if (fwrt->fw->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) &&
	    !fwrt->trans->cfg->gen2 &&
	    fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size &&
	    fwrt->fw_paging_db[0].fw_paging_block) {
		IWL_DEBUG_INFO(fwrt, "WRT paging dump\n");
+3 −0
Original line number Diff line number Diff line
@@ -146,6 +146,9 @@ enum iwl_ucode_tlv_type {
	IWL_UCODE_TLV_FW_GSCAN_CAPA	= 50,
	IWL_UCODE_TLV_FW_MEM_SEG	= 51,
	IWL_UCODE_TLV_IML		= 52,

	/* TLVs 0x1000-0x2000 are for internal driver usage */
	IWL_UCODE_TLV_FW_DBG_DUMP_LST	= 0x1000,
};

struct iwl_ucode_tlv {
+1 −0
Original line number Diff line number Diff line
@@ -299,6 +299,7 @@ struct iwl_fw {
	size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX];
	u8 dbg_dest_reg_num;
	struct iwl_gscan_capabilities gscan_capa;
	u32 dbg_dump_mask;
};

static inline const char *get_fw_dbg_mode_string(int mode)
+13 −0
Original line number Diff line number Diff line
@@ -1043,6 +1043,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
			pieces->dbg_trigger_tlv_len[trigger_id] = tlv_len;
			break;
			}
		case IWL_UCODE_TLV_FW_DBG_DUMP_LST: {
			if (tlv_len != sizeof(u32)) {
				IWL_ERR(drv,
					"dbg lst mask size incorrect, skip\n");
				break;
			}

			drv->fw.dbg_dump_mask =
				le32_to_cpup((__le32 *)tlv_data);
			break;
			}
		case IWL_UCODE_TLV_SEC_RT_USNIFFER:
			*usniffer_images = true;
			iwl_store_ucode_sec(pieces, tlv_data,
@@ -1316,6 +1327,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
	fw->ucode_capa.standard_phy_calibration_size =
			IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE;
	fw->ucode_capa.n_scan_channels = IWL_DEFAULT_SCAN_CHANNELS;
	/* dump all fw memory areas by default */
	fw->dbg_dump_mask = 0xffffffff;

	pieces = kzalloc(sizeof(*pieces), GFP_KERNEL);
	if (!pieces)
+1 −0
Original line number Diff line number Diff line
@@ -771,6 +771,7 @@ struct iwl_trans {
	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;
	u32 dbg_dump_mask;
	u8 dbg_dest_reg_num;

	enum iwl_plat_pm_mode system_pm_mode;
Loading