162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2005-2014, 2018-2023 Intel Corporation
462306a36Sopenharmony_ci * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
562306a36Sopenharmony_ci * Copyright (C) 2015-2017 Intel Deutschland GmbH
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/devcoredump.h>
862306a36Sopenharmony_ci#include "iwl-drv.h"
962306a36Sopenharmony_ci#include "runtime.h"
1062306a36Sopenharmony_ci#include "dbg.h"
1162306a36Sopenharmony_ci#include "debugfs.h"
1262306a36Sopenharmony_ci#include "iwl-io.h"
1362306a36Sopenharmony_ci#include "iwl-prph.h"
1462306a36Sopenharmony_ci#include "iwl-csr.h"
1562306a36Sopenharmony_ci#include "iwl-fh.h"
1662306a36Sopenharmony_ci/**
1762306a36Sopenharmony_ci * struct iwl_fw_dump_ptrs - set of pointers needed for the fw-error-dump
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * @fwrt_ptr: pointer to the buffer coming from fwrt
2062306a36Sopenharmony_ci * @trans_ptr: pointer to struct %iwl_trans_dump_data which contains the
2162306a36Sopenharmony_ci *	transport's data.
2262306a36Sopenharmony_ci * @trans_len: length of the valid data in trans_ptr
2362306a36Sopenharmony_ci * @fwrt_len: length of the valid data in fwrt_ptr
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_cistruct iwl_fw_dump_ptrs {
2662306a36Sopenharmony_ci	struct iwl_trans_dump_data *trans_ptr;
2762306a36Sopenharmony_ci	void *fwrt_ptr;
2862306a36Sopenharmony_ci	u32 fwrt_len;
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define RADIO_REG_MAX_READ 0x2ad
3262306a36Sopenharmony_cistatic void iwl_read_radio_regs(struct iwl_fw_runtime *fwrt,
3362306a36Sopenharmony_ci				struct iwl_fw_error_dump_data **dump_data)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	u8 *pos = (void *)(*dump_data)->data;
3662306a36Sopenharmony_ci	int i;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	IWL_DEBUG_INFO(fwrt, "WRT radio registers dump\n");
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (!iwl_trans_grab_nic_access(fwrt->trans))
4162306a36Sopenharmony_ci		return;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	(*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RADIO_REG);
4462306a36Sopenharmony_ci	(*dump_data)->len = cpu_to_le32(RADIO_REG_MAX_READ);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	for (i = 0; i < RADIO_REG_MAX_READ; i++) {
4762306a36Sopenharmony_ci		u32 rd_cmd = RADIO_RSP_RD_CMD;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci		rd_cmd |= i << RADIO_RSP_ADDR_POS;
5062306a36Sopenharmony_ci		iwl_write_prph_no_grab(fwrt->trans, RSP_RADIO_CMD, rd_cmd);
5162306a36Sopenharmony_ci		*pos = (u8)iwl_read_prph_no_grab(fwrt->trans, RSP_RADIO_RDDAT);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci		pos++;
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	*dump_data = iwl_fw_error_next_data(*dump_data);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	iwl_trans_release_nic_access(fwrt->trans);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic void iwl_fwrt_dump_rxf(struct iwl_fw_runtime *fwrt,
6262306a36Sopenharmony_ci			      struct iwl_fw_error_dump_data **dump_data,
6362306a36Sopenharmony_ci			      int size, u32 offset, int fifo_num)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	struct iwl_fw_error_dump_fifo *fifo_hdr;
6662306a36Sopenharmony_ci	u32 *fifo_data;
6762306a36Sopenharmony_ci	u32 fifo_len;
6862306a36Sopenharmony_ci	int i;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	fifo_hdr = (void *)(*dump_data)->data;
7162306a36Sopenharmony_ci	fifo_data = (void *)fifo_hdr->data;
7262306a36Sopenharmony_ci	fifo_len = size;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/* No need to try to read the data if the length is 0 */
7562306a36Sopenharmony_ci	if (fifo_len == 0)
7662306a36Sopenharmony_ci		return;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* Add a TLV for the RXF */
7962306a36Sopenharmony_ci	(*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF);
8062306a36Sopenharmony_ci	(*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr));
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	fifo_hdr->fifo_num = cpu_to_le32(fifo_num);
8362306a36Sopenharmony_ci	fifo_hdr->available_bytes =
8462306a36Sopenharmony_ci		cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
8562306a36Sopenharmony_ci						RXF_RD_D_SPACE + offset));
8662306a36Sopenharmony_ci	fifo_hdr->wr_ptr =
8762306a36Sopenharmony_ci		cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
8862306a36Sopenharmony_ci						RXF_RD_WR_PTR + offset));
8962306a36Sopenharmony_ci	fifo_hdr->rd_ptr =
9062306a36Sopenharmony_ci		cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
9162306a36Sopenharmony_ci						RXF_RD_RD_PTR + offset));
9262306a36Sopenharmony_ci	fifo_hdr->fence_ptr =
9362306a36Sopenharmony_ci		cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
9462306a36Sopenharmony_ci						RXF_RD_FENCE_PTR + offset));
9562306a36Sopenharmony_ci	fifo_hdr->fence_mode =
9662306a36Sopenharmony_ci		cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
9762306a36Sopenharmony_ci						RXF_SET_FENCE_MODE + offset));
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	/* Lock fence */
10062306a36Sopenharmony_ci	iwl_trans_write_prph(fwrt->trans, RXF_SET_FENCE_MODE + offset, 0x1);
10162306a36Sopenharmony_ci	/* Set fence pointer to the same place like WR pointer */
10262306a36Sopenharmony_ci	iwl_trans_write_prph(fwrt->trans, RXF_LD_WR2FENCE + offset, 0x1);
10362306a36Sopenharmony_ci	/* Set fence offset */
10462306a36Sopenharmony_ci	iwl_trans_write_prph(fwrt->trans,
10562306a36Sopenharmony_ci			     RXF_LD_FENCE_OFFSET_ADDR + offset, 0x0);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/* Read FIFO */
10862306a36Sopenharmony_ci	fifo_len /= sizeof(u32); /* Size in DWORDS */
10962306a36Sopenharmony_ci	for (i = 0; i < fifo_len; i++)
11062306a36Sopenharmony_ci		fifo_data[i] = iwl_trans_read_prph(fwrt->trans,
11162306a36Sopenharmony_ci						 RXF_FIFO_RD_FENCE_INC +
11262306a36Sopenharmony_ci						 offset);
11362306a36Sopenharmony_ci	*dump_data = iwl_fw_error_next_data(*dump_data);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic void iwl_fwrt_dump_txf(struct iwl_fw_runtime *fwrt,
11762306a36Sopenharmony_ci			      struct iwl_fw_error_dump_data **dump_data,
11862306a36Sopenharmony_ci			      int size, u32 offset, int fifo_num)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	struct iwl_fw_error_dump_fifo *fifo_hdr;
12162306a36Sopenharmony_ci	u32 *fifo_data;
12262306a36Sopenharmony_ci	u32 fifo_len;
12362306a36Sopenharmony_ci	int i;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	fifo_hdr = (void *)(*dump_data)->data;
12662306a36Sopenharmony_ci	fifo_data = (void *)fifo_hdr->data;
12762306a36Sopenharmony_ci	fifo_len = size;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* No need to try to read the data if the length is 0 */
13062306a36Sopenharmony_ci	if (fifo_len == 0)
13162306a36Sopenharmony_ci		return;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* Add a TLV for the FIFO */
13462306a36Sopenharmony_ci	(*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXF);
13562306a36Sopenharmony_ci	(*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr));
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	fifo_hdr->fifo_num = cpu_to_le32(fifo_num);
13862306a36Sopenharmony_ci	fifo_hdr->available_bytes =
13962306a36Sopenharmony_ci		cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
14062306a36Sopenharmony_ci						TXF_FIFO_ITEM_CNT + offset));
14162306a36Sopenharmony_ci	fifo_hdr->wr_ptr =
14262306a36Sopenharmony_ci		cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
14362306a36Sopenharmony_ci						TXF_WR_PTR + offset));
14462306a36Sopenharmony_ci	fifo_hdr->rd_ptr =
14562306a36Sopenharmony_ci		cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
14662306a36Sopenharmony_ci						TXF_RD_PTR + offset));
14762306a36Sopenharmony_ci	fifo_hdr->fence_ptr =
14862306a36Sopenharmony_ci		cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
14962306a36Sopenharmony_ci						TXF_FENCE_PTR + offset));
15062306a36Sopenharmony_ci	fifo_hdr->fence_mode =
15162306a36Sopenharmony_ci		cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
15262306a36Sopenharmony_ci						TXF_LOCK_FENCE + offset));
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */
15562306a36Sopenharmony_ci	iwl_trans_write_prph(fwrt->trans, TXF_READ_MODIFY_ADDR + offset,
15662306a36Sopenharmony_ci			     TXF_WR_PTR + offset);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* Dummy-read to advance the read pointer to the head */
15962306a36Sopenharmony_ci	iwl_trans_read_prph(fwrt->trans, TXF_READ_MODIFY_DATA + offset);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* Read FIFO */
16262306a36Sopenharmony_ci	for (i = 0; i < fifo_len / sizeof(u32); i++)
16362306a36Sopenharmony_ci		fifo_data[i] = iwl_trans_read_prph(fwrt->trans,
16462306a36Sopenharmony_ci						  TXF_READ_MODIFY_DATA +
16562306a36Sopenharmony_ci						  offset);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_txf)
16862306a36Sopenharmony_ci		fwrt->sanitize_ops->frob_txf(fwrt->sanitize_ctx,
16962306a36Sopenharmony_ci					     fifo_data, fifo_len);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	*dump_data = iwl_fw_error_next_data(*dump_data);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic void iwl_fw_dump_rxf(struct iwl_fw_runtime *fwrt,
17562306a36Sopenharmony_ci			    struct iwl_fw_error_dump_data **dump_data)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	IWL_DEBUG_INFO(fwrt, "WRT RX FIFO dump\n");
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (!iwl_trans_grab_nic_access(fwrt->trans))
18262306a36Sopenharmony_ci		return;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_RXF)) {
18562306a36Sopenharmony_ci		/* Pull RXF1 */
18662306a36Sopenharmony_ci		iwl_fwrt_dump_rxf(fwrt, dump_data,
18762306a36Sopenharmony_ci				  cfg->lmac[0].rxfifo1_size, 0, 0);
18862306a36Sopenharmony_ci		/* Pull RXF2 */
18962306a36Sopenharmony_ci		iwl_fwrt_dump_rxf(fwrt, dump_data, cfg->rxfifo2_size,
19062306a36Sopenharmony_ci				  RXF_DIFF_FROM_PREV +
19162306a36Sopenharmony_ci				  fwrt->trans->trans_cfg->umac_prph_offset, 1);
19262306a36Sopenharmony_ci		/* Pull LMAC2 RXF1 */
19362306a36Sopenharmony_ci		if (fwrt->smem_cfg.num_lmacs > 1)
19462306a36Sopenharmony_ci			iwl_fwrt_dump_rxf(fwrt, dump_data,
19562306a36Sopenharmony_ci					  cfg->lmac[1].rxfifo1_size,
19662306a36Sopenharmony_ci					  LMAC2_PRPH_OFFSET, 2);
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	iwl_trans_release_nic_access(fwrt->trans);
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic void iwl_fw_dump_txf(struct iwl_fw_runtime *fwrt,
20362306a36Sopenharmony_ci			    struct iwl_fw_error_dump_data **dump_data)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	struct iwl_fw_error_dump_fifo *fifo_hdr;
20662306a36Sopenharmony_ci	struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg;
20762306a36Sopenharmony_ci	u32 *fifo_data;
20862306a36Sopenharmony_ci	u32 fifo_len;
20962306a36Sopenharmony_ci	int i, j;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	IWL_DEBUG_INFO(fwrt, "WRT TX FIFO dump\n");
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (!iwl_trans_grab_nic_access(fwrt->trans))
21462306a36Sopenharmony_ci		return;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_TXF)) {
21762306a36Sopenharmony_ci		/* Pull TXF data from LMAC1 */
21862306a36Sopenharmony_ci		for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) {
21962306a36Sopenharmony_ci			/* Mark the number of TXF we're pulling now */
22062306a36Sopenharmony_ci			iwl_trans_write_prph(fwrt->trans, TXF_LARC_NUM, i);
22162306a36Sopenharmony_ci			iwl_fwrt_dump_txf(fwrt, dump_data,
22262306a36Sopenharmony_ci					  cfg->lmac[0].txfifo_size[i], 0, i);
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		/* Pull TXF data from LMAC2 */
22662306a36Sopenharmony_ci		if (fwrt->smem_cfg.num_lmacs > 1) {
22762306a36Sopenharmony_ci			for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries;
22862306a36Sopenharmony_ci			     i++) {
22962306a36Sopenharmony_ci				/* Mark the number of TXF we're pulling now */
23062306a36Sopenharmony_ci				iwl_trans_write_prph(fwrt->trans,
23162306a36Sopenharmony_ci						     TXF_LARC_NUM +
23262306a36Sopenharmony_ci						     LMAC2_PRPH_OFFSET, i);
23362306a36Sopenharmony_ci				iwl_fwrt_dump_txf(fwrt, dump_data,
23462306a36Sopenharmony_ci						  cfg->lmac[1].txfifo_size[i],
23562306a36Sopenharmony_ci						  LMAC2_PRPH_OFFSET,
23662306a36Sopenharmony_ci						  i + cfg->num_txfifo_entries);
23762306a36Sopenharmony_ci			}
23862306a36Sopenharmony_ci		}
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_INTERNAL_TXF) &&
24262306a36Sopenharmony_ci	    fw_has_capa(&fwrt->fw->ucode_capa,
24362306a36Sopenharmony_ci			IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) {
24462306a36Sopenharmony_ci		/* Pull UMAC internal TXF data from all TXFs */
24562306a36Sopenharmony_ci		for (i = 0;
24662306a36Sopenharmony_ci		     i < ARRAY_SIZE(fwrt->smem_cfg.internal_txfifo_size);
24762306a36Sopenharmony_ci		     i++) {
24862306a36Sopenharmony_ci			fifo_hdr = (void *)(*dump_data)->data;
24962306a36Sopenharmony_ci			fifo_data = (void *)fifo_hdr->data;
25062306a36Sopenharmony_ci			fifo_len = fwrt->smem_cfg.internal_txfifo_size[i];
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci			/* No need to try to read the data if the length is 0 */
25362306a36Sopenharmony_ci			if (fifo_len == 0)
25462306a36Sopenharmony_ci				continue;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci			/* Add a TLV for the internal FIFOs */
25762306a36Sopenharmony_ci			(*dump_data)->type =
25862306a36Sopenharmony_ci				cpu_to_le32(IWL_FW_ERROR_DUMP_INTERNAL_TXF);
25962306a36Sopenharmony_ci			(*dump_data)->len =
26062306a36Sopenharmony_ci				cpu_to_le32(fifo_len + sizeof(*fifo_hdr));
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci			fifo_hdr->fifo_num = cpu_to_le32(i);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci			/* Mark the number of TXF we're pulling now */
26562306a36Sopenharmony_ci			iwl_trans_write_prph(fwrt->trans, TXF_CPU2_NUM, i +
26662306a36Sopenharmony_ci				fwrt->smem_cfg.num_txfifo_entries);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci			fifo_hdr->available_bytes =
26962306a36Sopenharmony_ci				cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
27062306a36Sopenharmony_ci								TXF_CPU2_FIFO_ITEM_CNT));
27162306a36Sopenharmony_ci			fifo_hdr->wr_ptr =
27262306a36Sopenharmony_ci				cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
27362306a36Sopenharmony_ci								TXF_CPU2_WR_PTR));
27462306a36Sopenharmony_ci			fifo_hdr->rd_ptr =
27562306a36Sopenharmony_ci				cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
27662306a36Sopenharmony_ci								TXF_CPU2_RD_PTR));
27762306a36Sopenharmony_ci			fifo_hdr->fence_ptr =
27862306a36Sopenharmony_ci				cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
27962306a36Sopenharmony_ci								TXF_CPU2_FENCE_PTR));
28062306a36Sopenharmony_ci			fifo_hdr->fence_mode =
28162306a36Sopenharmony_ci				cpu_to_le32(iwl_trans_read_prph(fwrt->trans,
28262306a36Sopenharmony_ci								TXF_CPU2_LOCK_FENCE));
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci			/* Set TXF_CPU2_READ_MODIFY_ADDR to TXF_CPU2_WR_PTR */
28562306a36Sopenharmony_ci			iwl_trans_write_prph(fwrt->trans,
28662306a36Sopenharmony_ci					     TXF_CPU2_READ_MODIFY_ADDR,
28762306a36Sopenharmony_ci					     TXF_CPU2_WR_PTR);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci			/* Dummy-read to advance the read pointer to head */
29062306a36Sopenharmony_ci			iwl_trans_read_prph(fwrt->trans,
29162306a36Sopenharmony_ci					    TXF_CPU2_READ_MODIFY_DATA);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci			/* Read FIFO */
29462306a36Sopenharmony_ci			fifo_len /= sizeof(u32); /* Size in DWORDS */
29562306a36Sopenharmony_ci			for (j = 0; j < fifo_len; j++)
29662306a36Sopenharmony_ci				fifo_data[j] =
29762306a36Sopenharmony_ci					iwl_trans_read_prph(fwrt->trans,
29862306a36Sopenharmony_ci							    TXF_CPU2_READ_MODIFY_DATA);
29962306a36Sopenharmony_ci			*dump_data = iwl_fw_error_next_data(*dump_data);
30062306a36Sopenharmony_ci		}
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	iwl_trans_release_nic_access(fwrt->trans);
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistruct iwl_prph_range {
30762306a36Sopenharmony_ci	u32 start, end;
30862306a36Sopenharmony_ci};
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic const struct iwl_prph_range iwl_prph_dump_addr_comm[] = {
31162306a36Sopenharmony_ci	{ .start = 0x00a00000, .end = 0x00a00000 },
31262306a36Sopenharmony_ci	{ .start = 0x00a0000c, .end = 0x00a00024 },
31362306a36Sopenharmony_ci	{ .start = 0x00a0002c, .end = 0x00a0003c },
31462306a36Sopenharmony_ci	{ .start = 0x00a00410, .end = 0x00a00418 },
31562306a36Sopenharmony_ci	{ .start = 0x00a00420, .end = 0x00a00420 },
31662306a36Sopenharmony_ci	{ .start = 0x00a00428, .end = 0x00a00428 },
31762306a36Sopenharmony_ci	{ .start = 0x00a00430, .end = 0x00a0043c },
31862306a36Sopenharmony_ci	{ .start = 0x00a00444, .end = 0x00a00444 },
31962306a36Sopenharmony_ci	{ .start = 0x00a004c0, .end = 0x00a004cc },
32062306a36Sopenharmony_ci	{ .start = 0x00a004d8, .end = 0x00a004d8 },
32162306a36Sopenharmony_ci	{ .start = 0x00a004e0, .end = 0x00a004f0 },
32262306a36Sopenharmony_ci	{ .start = 0x00a00840, .end = 0x00a00840 },
32362306a36Sopenharmony_ci	{ .start = 0x00a00850, .end = 0x00a00858 },
32462306a36Sopenharmony_ci	{ .start = 0x00a01004, .end = 0x00a01008 },
32562306a36Sopenharmony_ci	{ .start = 0x00a01010, .end = 0x00a01010 },
32662306a36Sopenharmony_ci	{ .start = 0x00a01018, .end = 0x00a01018 },
32762306a36Sopenharmony_ci	{ .start = 0x00a01024, .end = 0x00a01024 },
32862306a36Sopenharmony_ci	{ .start = 0x00a0102c, .end = 0x00a01034 },
32962306a36Sopenharmony_ci	{ .start = 0x00a0103c, .end = 0x00a01040 },
33062306a36Sopenharmony_ci	{ .start = 0x00a01048, .end = 0x00a01094 },
33162306a36Sopenharmony_ci	{ .start = 0x00a01c00, .end = 0x00a01c20 },
33262306a36Sopenharmony_ci	{ .start = 0x00a01c58, .end = 0x00a01c58 },
33362306a36Sopenharmony_ci	{ .start = 0x00a01c7c, .end = 0x00a01c7c },
33462306a36Sopenharmony_ci	{ .start = 0x00a01c28, .end = 0x00a01c54 },
33562306a36Sopenharmony_ci	{ .start = 0x00a01c5c, .end = 0x00a01c5c },
33662306a36Sopenharmony_ci	{ .start = 0x00a01c60, .end = 0x00a01cdc },
33762306a36Sopenharmony_ci	{ .start = 0x00a01ce0, .end = 0x00a01d0c },
33862306a36Sopenharmony_ci	{ .start = 0x00a01d18, .end = 0x00a01d20 },
33962306a36Sopenharmony_ci	{ .start = 0x00a01d2c, .end = 0x00a01d30 },
34062306a36Sopenharmony_ci	{ .start = 0x00a01d40, .end = 0x00a01d5c },
34162306a36Sopenharmony_ci	{ .start = 0x00a01d80, .end = 0x00a01d80 },
34262306a36Sopenharmony_ci	{ .start = 0x00a01d98, .end = 0x00a01d9c },
34362306a36Sopenharmony_ci	{ .start = 0x00a01da8, .end = 0x00a01da8 },
34462306a36Sopenharmony_ci	{ .start = 0x00a01db8, .end = 0x00a01df4 },
34562306a36Sopenharmony_ci	{ .start = 0x00a01dc0, .end = 0x00a01dfc },
34662306a36Sopenharmony_ci	{ .start = 0x00a01e00, .end = 0x00a01e2c },
34762306a36Sopenharmony_ci	{ .start = 0x00a01e40, .end = 0x00a01e60 },
34862306a36Sopenharmony_ci	{ .start = 0x00a01e68, .end = 0x00a01e6c },
34962306a36Sopenharmony_ci	{ .start = 0x00a01e74, .end = 0x00a01e74 },
35062306a36Sopenharmony_ci	{ .start = 0x00a01e84, .end = 0x00a01e90 },
35162306a36Sopenharmony_ci	{ .start = 0x00a01e9c, .end = 0x00a01ec4 },
35262306a36Sopenharmony_ci	{ .start = 0x00a01ed0, .end = 0x00a01ee0 },
35362306a36Sopenharmony_ci	{ .start = 0x00a01f00, .end = 0x00a01f1c },
35462306a36Sopenharmony_ci	{ .start = 0x00a01f44, .end = 0x00a01ffc },
35562306a36Sopenharmony_ci	{ .start = 0x00a02000, .end = 0x00a02048 },
35662306a36Sopenharmony_ci	{ .start = 0x00a02068, .end = 0x00a020f0 },
35762306a36Sopenharmony_ci	{ .start = 0x00a02100, .end = 0x00a02118 },
35862306a36Sopenharmony_ci	{ .start = 0x00a02140, .end = 0x00a0214c },
35962306a36Sopenharmony_ci	{ .start = 0x00a02168, .end = 0x00a0218c },
36062306a36Sopenharmony_ci	{ .start = 0x00a021c0, .end = 0x00a021c0 },
36162306a36Sopenharmony_ci	{ .start = 0x00a02400, .end = 0x00a02410 },
36262306a36Sopenharmony_ci	{ .start = 0x00a02418, .end = 0x00a02420 },
36362306a36Sopenharmony_ci	{ .start = 0x00a02428, .end = 0x00a0242c },
36462306a36Sopenharmony_ci	{ .start = 0x00a02434, .end = 0x00a02434 },
36562306a36Sopenharmony_ci	{ .start = 0x00a02440, .end = 0x00a02460 },
36662306a36Sopenharmony_ci	{ .start = 0x00a02468, .end = 0x00a024b0 },
36762306a36Sopenharmony_ci	{ .start = 0x00a024c8, .end = 0x00a024cc },
36862306a36Sopenharmony_ci	{ .start = 0x00a02500, .end = 0x00a02504 },
36962306a36Sopenharmony_ci	{ .start = 0x00a0250c, .end = 0x00a02510 },
37062306a36Sopenharmony_ci	{ .start = 0x00a02540, .end = 0x00a02554 },
37162306a36Sopenharmony_ci	{ .start = 0x00a02580, .end = 0x00a025f4 },
37262306a36Sopenharmony_ci	{ .start = 0x00a02600, .end = 0x00a0260c },
37362306a36Sopenharmony_ci	{ .start = 0x00a02648, .end = 0x00a02650 },
37462306a36Sopenharmony_ci	{ .start = 0x00a02680, .end = 0x00a02680 },
37562306a36Sopenharmony_ci	{ .start = 0x00a026c0, .end = 0x00a026d0 },
37662306a36Sopenharmony_ci	{ .start = 0x00a02700, .end = 0x00a0270c },
37762306a36Sopenharmony_ci	{ .start = 0x00a02804, .end = 0x00a02804 },
37862306a36Sopenharmony_ci	{ .start = 0x00a02818, .end = 0x00a0281c },
37962306a36Sopenharmony_ci	{ .start = 0x00a02c00, .end = 0x00a02db4 },
38062306a36Sopenharmony_ci	{ .start = 0x00a02df4, .end = 0x00a02fb0 },
38162306a36Sopenharmony_ci	{ .start = 0x00a03000, .end = 0x00a03014 },
38262306a36Sopenharmony_ci	{ .start = 0x00a0301c, .end = 0x00a0302c },
38362306a36Sopenharmony_ci	{ .start = 0x00a03034, .end = 0x00a03038 },
38462306a36Sopenharmony_ci	{ .start = 0x00a03040, .end = 0x00a03048 },
38562306a36Sopenharmony_ci	{ .start = 0x00a03060, .end = 0x00a03068 },
38662306a36Sopenharmony_ci	{ .start = 0x00a03070, .end = 0x00a03074 },
38762306a36Sopenharmony_ci	{ .start = 0x00a0307c, .end = 0x00a0307c },
38862306a36Sopenharmony_ci	{ .start = 0x00a03080, .end = 0x00a03084 },
38962306a36Sopenharmony_ci	{ .start = 0x00a0308c, .end = 0x00a03090 },
39062306a36Sopenharmony_ci	{ .start = 0x00a03098, .end = 0x00a03098 },
39162306a36Sopenharmony_ci	{ .start = 0x00a030a0, .end = 0x00a030a0 },
39262306a36Sopenharmony_ci	{ .start = 0x00a030a8, .end = 0x00a030b4 },
39362306a36Sopenharmony_ci	{ .start = 0x00a030bc, .end = 0x00a030bc },
39462306a36Sopenharmony_ci	{ .start = 0x00a030c0, .end = 0x00a0312c },
39562306a36Sopenharmony_ci	{ .start = 0x00a03c00, .end = 0x00a03c5c },
39662306a36Sopenharmony_ci	{ .start = 0x00a04400, .end = 0x00a04454 },
39762306a36Sopenharmony_ci	{ .start = 0x00a04460, .end = 0x00a04474 },
39862306a36Sopenharmony_ci	{ .start = 0x00a044c0, .end = 0x00a044ec },
39962306a36Sopenharmony_ci	{ .start = 0x00a04500, .end = 0x00a04504 },
40062306a36Sopenharmony_ci	{ .start = 0x00a04510, .end = 0x00a04538 },
40162306a36Sopenharmony_ci	{ .start = 0x00a04540, .end = 0x00a04548 },
40262306a36Sopenharmony_ci	{ .start = 0x00a04560, .end = 0x00a0457c },
40362306a36Sopenharmony_ci	{ .start = 0x00a04590, .end = 0x00a04598 },
40462306a36Sopenharmony_ci	{ .start = 0x00a045c0, .end = 0x00a045f4 },
40562306a36Sopenharmony_ci};
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic const struct iwl_prph_range iwl_prph_dump_addr_9000[] = {
40862306a36Sopenharmony_ci	{ .start = 0x00a05c00, .end = 0x00a05c18 },
40962306a36Sopenharmony_ci	{ .start = 0x00a05400, .end = 0x00a056e8 },
41062306a36Sopenharmony_ci	{ .start = 0x00a08000, .end = 0x00a098bc },
41162306a36Sopenharmony_ci	{ .start = 0x00a02400, .end = 0x00a02758 },
41262306a36Sopenharmony_ci	{ .start = 0x00a04764, .end = 0x00a0476c },
41362306a36Sopenharmony_ci	{ .start = 0x00a04770, .end = 0x00a04774 },
41462306a36Sopenharmony_ci	{ .start = 0x00a04620, .end = 0x00a04624 },
41562306a36Sopenharmony_ci};
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic const struct iwl_prph_range iwl_prph_dump_addr_22000[] = {
41862306a36Sopenharmony_ci	{ .start = 0x00a00000, .end = 0x00a00000 },
41962306a36Sopenharmony_ci	{ .start = 0x00a0000c, .end = 0x00a00024 },
42062306a36Sopenharmony_ci	{ .start = 0x00a0002c, .end = 0x00a00034 },
42162306a36Sopenharmony_ci	{ .start = 0x00a0003c, .end = 0x00a0003c },
42262306a36Sopenharmony_ci	{ .start = 0x00a00410, .end = 0x00a00418 },
42362306a36Sopenharmony_ci	{ .start = 0x00a00420, .end = 0x00a00420 },
42462306a36Sopenharmony_ci	{ .start = 0x00a00428, .end = 0x00a00428 },
42562306a36Sopenharmony_ci	{ .start = 0x00a00430, .end = 0x00a0043c },
42662306a36Sopenharmony_ci	{ .start = 0x00a00444, .end = 0x00a00444 },
42762306a36Sopenharmony_ci	{ .start = 0x00a00840, .end = 0x00a00840 },
42862306a36Sopenharmony_ci	{ .start = 0x00a00850, .end = 0x00a00858 },
42962306a36Sopenharmony_ci	{ .start = 0x00a01004, .end = 0x00a01008 },
43062306a36Sopenharmony_ci	{ .start = 0x00a01010, .end = 0x00a01010 },
43162306a36Sopenharmony_ci	{ .start = 0x00a01018, .end = 0x00a01018 },
43262306a36Sopenharmony_ci	{ .start = 0x00a01024, .end = 0x00a01024 },
43362306a36Sopenharmony_ci	{ .start = 0x00a0102c, .end = 0x00a01034 },
43462306a36Sopenharmony_ci	{ .start = 0x00a0103c, .end = 0x00a01040 },
43562306a36Sopenharmony_ci	{ .start = 0x00a01048, .end = 0x00a01050 },
43662306a36Sopenharmony_ci	{ .start = 0x00a01058, .end = 0x00a01058 },
43762306a36Sopenharmony_ci	{ .start = 0x00a01060, .end = 0x00a01070 },
43862306a36Sopenharmony_ci	{ .start = 0x00a0108c, .end = 0x00a0108c },
43962306a36Sopenharmony_ci	{ .start = 0x00a01c20, .end = 0x00a01c28 },
44062306a36Sopenharmony_ci	{ .start = 0x00a01d10, .end = 0x00a01d10 },
44162306a36Sopenharmony_ci	{ .start = 0x00a01e28, .end = 0x00a01e2c },
44262306a36Sopenharmony_ci	{ .start = 0x00a01e60, .end = 0x00a01e60 },
44362306a36Sopenharmony_ci	{ .start = 0x00a01e80, .end = 0x00a01e80 },
44462306a36Sopenharmony_ci	{ .start = 0x00a01ea0, .end = 0x00a01ea0 },
44562306a36Sopenharmony_ci	{ .start = 0x00a02000, .end = 0x00a0201c },
44662306a36Sopenharmony_ci	{ .start = 0x00a02024, .end = 0x00a02024 },
44762306a36Sopenharmony_ci	{ .start = 0x00a02040, .end = 0x00a02048 },
44862306a36Sopenharmony_ci	{ .start = 0x00a020c0, .end = 0x00a020e0 },
44962306a36Sopenharmony_ci	{ .start = 0x00a02400, .end = 0x00a02404 },
45062306a36Sopenharmony_ci	{ .start = 0x00a0240c, .end = 0x00a02414 },
45162306a36Sopenharmony_ci	{ .start = 0x00a0241c, .end = 0x00a0243c },
45262306a36Sopenharmony_ci	{ .start = 0x00a02448, .end = 0x00a024bc },
45362306a36Sopenharmony_ci	{ .start = 0x00a024c4, .end = 0x00a024cc },
45462306a36Sopenharmony_ci	{ .start = 0x00a02508, .end = 0x00a02508 },
45562306a36Sopenharmony_ci	{ .start = 0x00a02510, .end = 0x00a02514 },
45662306a36Sopenharmony_ci	{ .start = 0x00a0251c, .end = 0x00a0251c },
45762306a36Sopenharmony_ci	{ .start = 0x00a0252c, .end = 0x00a0255c },
45862306a36Sopenharmony_ci	{ .start = 0x00a02564, .end = 0x00a025a0 },
45962306a36Sopenharmony_ci	{ .start = 0x00a025a8, .end = 0x00a025b4 },
46062306a36Sopenharmony_ci	{ .start = 0x00a025c0, .end = 0x00a025c0 },
46162306a36Sopenharmony_ci	{ .start = 0x00a025e8, .end = 0x00a025f4 },
46262306a36Sopenharmony_ci	{ .start = 0x00a02c08, .end = 0x00a02c18 },
46362306a36Sopenharmony_ci	{ .start = 0x00a02c2c, .end = 0x00a02c38 },
46462306a36Sopenharmony_ci	{ .start = 0x00a02c68, .end = 0x00a02c78 },
46562306a36Sopenharmony_ci	{ .start = 0x00a03000, .end = 0x00a03000 },
46662306a36Sopenharmony_ci	{ .start = 0x00a03010, .end = 0x00a03014 },
46762306a36Sopenharmony_ci	{ .start = 0x00a0301c, .end = 0x00a0302c },
46862306a36Sopenharmony_ci	{ .start = 0x00a03034, .end = 0x00a03038 },
46962306a36Sopenharmony_ci	{ .start = 0x00a03040, .end = 0x00a03044 },
47062306a36Sopenharmony_ci	{ .start = 0x00a03060, .end = 0x00a03068 },
47162306a36Sopenharmony_ci	{ .start = 0x00a03070, .end = 0x00a03070 },
47262306a36Sopenharmony_ci	{ .start = 0x00a0307c, .end = 0x00a03084 },
47362306a36Sopenharmony_ci	{ .start = 0x00a0308c, .end = 0x00a03090 },
47462306a36Sopenharmony_ci	{ .start = 0x00a03098, .end = 0x00a03098 },
47562306a36Sopenharmony_ci	{ .start = 0x00a030a0, .end = 0x00a030a0 },
47662306a36Sopenharmony_ci	{ .start = 0x00a030a8, .end = 0x00a030b4 },
47762306a36Sopenharmony_ci	{ .start = 0x00a030bc, .end = 0x00a030c0 },
47862306a36Sopenharmony_ci	{ .start = 0x00a030c8, .end = 0x00a030f4 },
47962306a36Sopenharmony_ci	{ .start = 0x00a03100, .end = 0x00a0312c },
48062306a36Sopenharmony_ci	{ .start = 0x00a03c00, .end = 0x00a03c5c },
48162306a36Sopenharmony_ci	{ .start = 0x00a04400, .end = 0x00a04454 },
48262306a36Sopenharmony_ci	{ .start = 0x00a04460, .end = 0x00a04474 },
48362306a36Sopenharmony_ci	{ .start = 0x00a044c0, .end = 0x00a044ec },
48462306a36Sopenharmony_ci	{ .start = 0x00a04500, .end = 0x00a04504 },
48562306a36Sopenharmony_ci	{ .start = 0x00a04510, .end = 0x00a04538 },
48662306a36Sopenharmony_ci	{ .start = 0x00a04540, .end = 0x00a04548 },
48762306a36Sopenharmony_ci	{ .start = 0x00a04560, .end = 0x00a04560 },
48862306a36Sopenharmony_ci	{ .start = 0x00a04570, .end = 0x00a0457c },
48962306a36Sopenharmony_ci	{ .start = 0x00a04590, .end = 0x00a04590 },
49062306a36Sopenharmony_ci	{ .start = 0x00a04598, .end = 0x00a04598 },
49162306a36Sopenharmony_ci	{ .start = 0x00a045c0, .end = 0x00a045f4 },
49262306a36Sopenharmony_ci	{ .start = 0x00a05c18, .end = 0x00a05c1c },
49362306a36Sopenharmony_ci	{ .start = 0x00a0c000, .end = 0x00a0c018 },
49462306a36Sopenharmony_ci	{ .start = 0x00a0c020, .end = 0x00a0c028 },
49562306a36Sopenharmony_ci	{ .start = 0x00a0c038, .end = 0x00a0c094 },
49662306a36Sopenharmony_ci	{ .start = 0x00a0c0c0, .end = 0x00a0c104 },
49762306a36Sopenharmony_ci	{ .start = 0x00a0c10c, .end = 0x00a0c118 },
49862306a36Sopenharmony_ci	{ .start = 0x00a0c150, .end = 0x00a0c174 },
49962306a36Sopenharmony_ci	{ .start = 0x00a0c17c, .end = 0x00a0c188 },
50062306a36Sopenharmony_ci	{ .start = 0x00a0c190, .end = 0x00a0c198 },
50162306a36Sopenharmony_ci	{ .start = 0x00a0c1a0, .end = 0x00a0c1a8 },
50262306a36Sopenharmony_ci	{ .start = 0x00a0c1b0, .end = 0x00a0c1b8 },
50362306a36Sopenharmony_ci};
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic const struct iwl_prph_range iwl_prph_dump_addr_ax210[] = {
50662306a36Sopenharmony_ci	{ .start = 0x00d03c00, .end = 0x00d03c64 },
50762306a36Sopenharmony_ci	{ .start = 0x00d05c18, .end = 0x00d05c1c },
50862306a36Sopenharmony_ci	{ .start = 0x00d0c000, .end = 0x00d0c174 },
50962306a36Sopenharmony_ci};
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic void iwl_read_prph_block(struct iwl_trans *trans, u32 start,
51262306a36Sopenharmony_ci				u32 len_bytes, __le32 *data)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	u32 i;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	for (i = 0; i < len_bytes; i += 4)
51762306a36Sopenharmony_ci		*data++ = cpu_to_le32(iwl_read_prph_no_grab(trans, start + i));
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic void iwl_dump_prph(struct iwl_fw_runtime *fwrt,
52162306a36Sopenharmony_ci			  const struct iwl_prph_range *iwl_prph_dump_addr,
52262306a36Sopenharmony_ci			  u32 range_len, void *ptr)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	struct iwl_fw_error_dump_prph *prph;
52562306a36Sopenharmony_ci	struct iwl_trans *trans = fwrt->trans;
52662306a36Sopenharmony_ci	struct iwl_fw_error_dump_data **data =
52762306a36Sopenharmony_ci		(struct iwl_fw_error_dump_data **)ptr;
52862306a36Sopenharmony_ci	u32 i;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (!data)
53162306a36Sopenharmony_ci		return;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	IWL_DEBUG_INFO(trans, "WRT PRPH dump\n");
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (!iwl_trans_grab_nic_access(trans))
53662306a36Sopenharmony_ci		return;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	for (i = 0; i < range_len; i++) {
53962306a36Sopenharmony_ci		/* The range includes both boundaries */
54062306a36Sopenharmony_ci		int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
54162306a36Sopenharmony_ci			 iwl_prph_dump_addr[i].start + 4;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH);
54462306a36Sopenharmony_ci		(*data)->len = cpu_to_le32(sizeof(*prph) +
54562306a36Sopenharmony_ci					num_bytes_in_chunk);
54662306a36Sopenharmony_ci		prph = (void *)(*data)->data;
54762306a36Sopenharmony_ci		prph->prph_start = cpu_to_le32(iwl_prph_dump_addr[i].start);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		iwl_read_prph_block(trans, iwl_prph_dump_addr[i].start,
55062306a36Sopenharmony_ci				    /* our range is inclusive, hence + 4 */
55162306a36Sopenharmony_ci				    iwl_prph_dump_addr[i].end -
55262306a36Sopenharmony_ci				    iwl_prph_dump_addr[i].start + 4,
55362306a36Sopenharmony_ci				    (void *)prph->data);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		*data = iwl_fw_error_next_data(*data);
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	iwl_trans_release_nic_access(trans);
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci/*
56262306a36Sopenharmony_ci * alloc_sgtable - allocates scallerlist table in the given size,
56362306a36Sopenharmony_ci * fills it with pages and returns it
56462306a36Sopenharmony_ci * @size: the size (in bytes) of the table
56562306a36Sopenharmony_ci*/
56662306a36Sopenharmony_cistatic struct scatterlist *alloc_sgtable(int size)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	int alloc_size, nents, i;
56962306a36Sopenharmony_ci	struct page *new_page;
57062306a36Sopenharmony_ci	struct scatterlist *iter;
57162306a36Sopenharmony_ci	struct scatterlist *table;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	nents = DIV_ROUND_UP(size, PAGE_SIZE);
57462306a36Sopenharmony_ci	table = kcalloc(nents, sizeof(*table), GFP_KERNEL);
57562306a36Sopenharmony_ci	if (!table)
57662306a36Sopenharmony_ci		return NULL;
57762306a36Sopenharmony_ci	sg_init_table(table, nents);
57862306a36Sopenharmony_ci	iter = table;
57962306a36Sopenharmony_ci	for_each_sg(table, iter, sg_nents(table), i) {
58062306a36Sopenharmony_ci		new_page = alloc_page(GFP_KERNEL);
58162306a36Sopenharmony_ci		if (!new_page) {
58262306a36Sopenharmony_ci			/* release all previous allocated pages in the table */
58362306a36Sopenharmony_ci			iter = table;
58462306a36Sopenharmony_ci			for_each_sg(table, iter, sg_nents(table), i) {
58562306a36Sopenharmony_ci				new_page = sg_page(iter);
58662306a36Sopenharmony_ci				if (new_page)
58762306a36Sopenharmony_ci					__free_page(new_page);
58862306a36Sopenharmony_ci			}
58962306a36Sopenharmony_ci			kfree(table);
59062306a36Sopenharmony_ci			return NULL;
59162306a36Sopenharmony_ci		}
59262306a36Sopenharmony_ci		alloc_size = min_t(int, size, PAGE_SIZE);
59362306a36Sopenharmony_ci		size -= PAGE_SIZE;
59462306a36Sopenharmony_ci		sg_set_page(iter, new_page, alloc_size, 0);
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci	return table;
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cistatic void iwl_fw_get_prph_len(struct iwl_fw_runtime *fwrt,
60062306a36Sopenharmony_ci				const struct iwl_prph_range *iwl_prph_dump_addr,
60162306a36Sopenharmony_ci				u32 range_len, void *ptr)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	u32 *prph_len = (u32 *)ptr;
60462306a36Sopenharmony_ci	int i, num_bytes_in_chunk;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	if (!prph_len)
60762306a36Sopenharmony_ci		return;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	for (i = 0; i < range_len; i++) {
61062306a36Sopenharmony_ci		/* The range includes both boundaries */
61162306a36Sopenharmony_ci		num_bytes_in_chunk =
61262306a36Sopenharmony_ci			iwl_prph_dump_addr[i].end -
61362306a36Sopenharmony_ci			iwl_prph_dump_addr[i].start + 4;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci		*prph_len += sizeof(struct iwl_fw_error_dump_data) +
61662306a36Sopenharmony_ci			sizeof(struct iwl_fw_error_dump_prph) +
61762306a36Sopenharmony_ci			num_bytes_in_chunk;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic void iwl_fw_prph_handler(struct iwl_fw_runtime *fwrt, void *ptr,
62262306a36Sopenharmony_ci				void (*handler)(struct iwl_fw_runtime *,
62362306a36Sopenharmony_ci						const struct iwl_prph_range *,
62462306a36Sopenharmony_ci						u32, void *))
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	u32 range_len;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {
62962306a36Sopenharmony_ci		range_len = ARRAY_SIZE(iwl_prph_dump_addr_ax210);
63062306a36Sopenharmony_ci		handler(fwrt, iwl_prph_dump_addr_ax210, range_len, ptr);
63162306a36Sopenharmony_ci	} else if (fwrt->trans->trans_cfg->device_family >=
63262306a36Sopenharmony_ci		   IWL_DEVICE_FAMILY_22000) {
63362306a36Sopenharmony_ci		range_len = ARRAY_SIZE(iwl_prph_dump_addr_22000);
63462306a36Sopenharmony_ci		handler(fwrt, iwl_prph_dump_addr_22000, range_len, ptr);
63562306a36Sopenharmony_ci	} else {
63662306a36Sopenharmony_ci		range_len = ARRAY_SIZE(iwl_prph_dump_addr_comm);
63762306a36Sopenharmony_ci		handler(fwrt, iwl_prph_dump_addr_comm, range_len, ptr);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci		if (fwrt->trans->trans_cfg->mq_rx_supported) {
64062306a36Sopenharmony_ci			range_len = ARRAY_SIZE(iwl_prph_dump_addr_9000);
64162306a36Sopenharmony_ci			handler(fwrt, iwl_prph_dump_addr_9000, range_len, ptr);
64262306a36Sopenharmony_ci		}
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistatic void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt,
64762306a36Sopenharmony_ci			    struct iwl_fw_error_dump_data **dump_data,
64862306a36Sopenharmony_ci			    u32 len, u32 ofs, u32 type)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	struct iwl_fw_error_dump_mem *dump_mem;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	if (!len)
65362306a36Sopenharmony_ci		return;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	(*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
65662306a36Sopenharmony_ci	(*dump_data)->len = cpu_to_le32(len + sizeof(*dump_mem));
65762306a36Sopenharmony_ci	dump_mem = (void *)(*dump_data)->data;
65862306a36Sopenharmony_ci	dump_mem->type = cpu_to_le32(type);
65962306a36Sopenharmony_ci	dump_mem->offset = cpu_to_le32(ofs);
66062306a36Sopenharmony_ci	iwl_trans_read_mem_bytes(fwrt->trans, ofs, dump_mem->data, len);
66162306a36Sopenharmony_ci	*dump_data = iwl_fw_error_next_data(*dump_data);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_mem)
66462306a36Sopenharmony_ci		fwrt->sanitize_ops->frob_mem(fwrt->sanitize_ctx, ofs,
66562306a36Sopenharmony_ci					     dump_mem->data, len);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", dump_mem->type);
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci#define ADD_LEN(len, item_len, const_len) \
67162306a36Sopenharmony_ci	do {size_t item = item_len; len += (!!item) * const_len + item; } \
67262306a36Sopenharmony_ci	while (0)
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic int iwl_fw_rxf_len(struct iwl_fw_runtime *fwrt,
67562306a36Sopenharmony_ci			  struct iwl_fwrt_shared_mem_cfg *mem_cfg)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	size_t hdr_len = sizeof(struct iwl_fw_error_dump_data) +
67862306a36Sopenharmony_ci			 sizeof(struct iwl_fw_error_dump_fifo);
67962306a36Sopenharmony_ci	u32 fifo_len = 0;
68062306a36Sopenharmony_ci	int i;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	if (!iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_RXF))
68362306a36Sopenharmony_ci		return 0;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	/* Count RXF2 size */
68662306a36Sopenharmony_ci	ADD_LEN(fifo_len, mem_cfg->rxfifo2_size, hdr_len);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	/* Count RXF1 sizes */
68962306a36Sopenharmony_ci	if (WARN_ON(mem_cfg->num_lmacs > MAX_NUM_LMAC))
69062306a36Sopenharmony_ci		mem_cfg->num_lmacs = MAX_NUM_LMAC;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	for (i = 0; i < mem_cfg->num_lmacs; i++)
69362306a36Sopenharmony_ci		ADD_LEN(fifo_len, mem_cfg->lmac[i].rxfifo1_size, hdr_len);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	return fifo_len;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic int iwl_fw_txf_len(struct iwl_fw_runtime *fwrt,
69962306a36Sopenharmony_ci			  struct iwl_fwrt_shared_mem_cfg *mem_cfg)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	size_t hdr_len = sizeof(struct iwl_fw_error_dump_data) +
70262306a36Sopenharmony_ci			 sizeof(struct iwl_fw_error_dump_fifo);
70362306a36Sopenharmony_ci	u32 fifo_len = 0;
70462306a36Sopenharmony_ci	int i;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	if (!iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_TXF))
70762306a36Sopenharmony_ci		goto dump_internal_txf;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	/* Count TXF sizes */
71062306a36Sopenharmony_ci	if (WARN_ON(mem_cfg->num_lmacs > MAX_NUM_LMAC))
71162306a36Sopenharmony_ci		mem_cfg->num_lmacs = MAX_NUM_LMAC;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	for (i = 0; i < mem_cfg->num_lmacs; i++) {
71462306a36Sopenharmony_ci		int j;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci		for (j = 0; j < mem_cfg->num_txfifo_entries; j++)
71762306a36Sopenharmony_ci			ADD_LEN(fifo_len, mem_cfg->lmac[i].txfifo_size[j],
71862306a36Sopenharmony_ci				hdr_len);
71962306a36Sopenharmony_ci	}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cidump_internal_txf:
72262306a36Sopenharmony_ci	if (!(iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_INTERNAL_TXF) &&
72362306a36Sopenharmony_ci	      fw_has_capa(&fwrt->fw->ucode_capa,
72462306a36Sopenharmony_ci			  IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)))
72562306a36Sopenharmony_ci		goto out;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mem_cfg->internal_txfifo_size); i++)
72862306a36Sopenharmony_ci		ADD_LEN(fifo_len, mem_cfg->internal_txfifo_size[i], hdr_len);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ciout:
73162306a36Sopenharmony_ci	return fifo_len;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cistatic void iwl_dump_paging(struct iwl_fw_runtime *fwrt,
73562306a36Sopenharmony_ci			    struct iwl_fw_error_dump_data **data)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	int i;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	IWL_DEBUG_INFO(fwrt, "WRT paging dump\n");
74062306a36Sopenharmony_ci	for (i = 1; i < fwrt->num_of_paging_blk + 1; i++) {
74162306a36Sopenharmony_ci		struct iwl_fw_error_dump_paging *paging;
74262306a36Sopenharmony_ci		struct page *pages =
74362306a36Sopenharmony_ci			fwrt->fw_paging_db[i].fw_paging_block;
74462306a36Sopenharmony_ci		dma_addr_t addr = fwrt->fw_paging_db[i].fw_paging_phys;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci		(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING);
74762306a36Sopenharmony_ci		(*data)->len = cpu_to_le32(sizeof(*paging) +
74862306a36Sopenharmony_ci					     PAGING_BLOCK_SIZE);
74962306a36Sopenharmony_ci		paging =  (void *)(*data)->data;
75062306a36Sopenharmony_ci		paging->index = cpu_to_le32(i);
75162306a36Sopenharmony_ci		dma_sync_single_for_cpu(fwrt->trans->dev, addr,
75262306a36Sopenharmony_ci					PAGING_BLOCK_SIZE,
75362306a36Sopenharmony_ci					DMA_BIDIRECTIONAL);
75462306a36Sopenharmony_ci		memcpy(paging->data, page_address(pages),
75562306a36Sopenharmony_ci		       PAGING_BLOCK_SIZE);
75662306a36Sopenharmony_ci		dma_sync_single_for_device(fwrt->trans->dev, addr,
75762306a36Sopenharmony_ci					   PAGING_BLOCK_SIZE,
75862306a36Sopenharmony_ci					   DMA_BIDIRECTIONAL);
75962306a36Sopenharmony_ci		(*data) = iwl_fw_error_next_data(*data);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_mem)
76262306a36Sopenharmony_ci			fwrt->sanitize_ops->frob_mem(fwrt->sanitize_ctx,
76362306a36Sopenharmony_ci						     fwrt->fw_paging_db[i].fw_offs,
76462306a36Sopenharmony_ci						     paging->data,
76562306a36Sopenharmony_ci						     PAGING_BLOCK_SIZE);
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic struct iwl_fw_error_dump_file *
77062306a36Sopenharmony_ciiwl_fw_error_dump_file(struct iwl_fw_runtime *fwrt,
77162306a36Sopenharmony_ci		       struct iwl_fw_dump_ptrs *fw_error_dump,
77262306a36Sopenharmony_ci		       struct iwl_fwrt_dump_data *data)
77362306a36Sopenharmony_ci{
77462306a36Sopenharmony_ci	struct iwl_fw_error_dump_file *dump_file;
77562306a36Sopenharmony_ci	struct iwl_fw_error_dump_data *dump_data;
77662306a36Sopenharmony_ci	struct iwl_fw_error_dump_info *dump_info;
77762306a36Sopenharmony_ci	struct iwl_fw_error_dump_smem_cfg *dump_smem_cfg;
77862306a36Sopenharmony_ci	struct iwl_fw_error_dump_trigger_desc *dump_trig;
77962306a36Sopenharmony_ci	u32 sram_len, sram_ofs;
78062306a36Sopenharmony_ci	const struct iwl_fw_dbg_mem_seg_tlv *fw_mem = fwrt->fw->dbg.mem_tlv;
78162306a36Sopenharmony_ci	struct iwl_fwrt_shared_mem_cfg *mem_cfg = &fwrt->smem_cfg;
78262306a36Sopenharmony_ci	u32 file_len, fifo_len = 0, prph_len = 0, radio_len = 0;
78362306a36Sopenharmony_ci	u32 smem_len = fwrt->fw->dbg.n_mem_tlv ? 0 : fwrt->trans->cfg->smem_len;
78462306a36Sopenharmony_ci	u32 sram2_len = fwrt->fw->dbg.n_mem_tlv ?
78562306a36Sopenharmony_ci				0 : fwrt->trans->cfg->dccm2_len;
78662306a36Sopenharmony_ci	int i;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	/* SRAM - include stack CCM if driver knows the values for it */
78962306a36Sopenharmony_ci	if (!fwrt->trans->cfg->dccm_offset || !fwrt->trans->cfg->dccm_len) {
79062306a36Sopenharmony_ci		const struct fw_img *img;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci		if (fwrt->cur_fw_img >= IWL_UCODE_TYPE_MAX)
79362306a36Sopenharmony_ci			return NULL;
79462306a36Sopenharmony_ci		img = &fwrt->fw->img[fwrt->cur_fw_img];
79562306a36Sopenharmony_ci		sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
79662306a36Sopenharmony_ci		sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
79762306a36Sopenharmony_ci	} else {
79862306a36Sopenharmony_ci		sram_ofs = fwrt->trans->cfg->dccm_offset;
79962306a36Sopenharmony_ci		sram_len = fwrt->trans->cfg->dccm_len;
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	/* reading RXF/TXF sizes */
80362306a36Sopenharmony_ci	if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) {
80462306a36Sopenharmony_ci		fifo_len = iwl_fw_rxf_len(fwrt, mem_cfg);
80562306a36Sopenharmony_ci		fifo_len += iwl_fw_txf_len(fwrt, mem_cfg);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		/* Make room for PRPH registers */
80862306a36Sopenharmony_ci		if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_PRPH))
80962306a36Sopenharmony_ci			iwl_fw_prph_handler(fwrt, &prph_len,
81062306a36Sopenharmony_ci					    iwl_fw_get_prph_len);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci		if (fwrt->trans->trans_cfg->device_family ==
81362306a36Sopenharmony_ci		    IWL_DEVICE_FAMILY_7000 &&
81462306a36Sopenharmony_ci		    iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_RADIO_REG))
81562306a36Sopenharmony_ci			radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ;
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	file_len = sizeof(*dump_file) + fifo_len + prph_len + radio_len;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_DEV_FW_INFO))
82162306a36Sopenharmony_ci		file_len += sizeof(*dump_data) + sizeof(*dump_info);
82262306a36Sopenharmony_ci	if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM_CFG))
82362306a36Sopenharmony_ci		file_len += sizeof(*dump_data) + sizeof(*dump_smem_cfg);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM)) {
82662306a36Sopenharmony_ci		size_t hdr_len = sizeof(*dump_data) +
82762306a36Sopenharmony_ci				 sizeof(struct iwl_fw_error_dump_mem);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci		/* Dump SRAM only if no mem_tlvs */
83062306a36Sopenharmony_ci		if (!fwrt->fw->dbg.n_mem_tlv)
83162306a36Sopenharmony_ci			ADD_LEN(file_len, sram_len, hdr_len);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci		/* Make room for all mem types that exist */
83462306a36Sopenharmony_ci		ADD_LEN(file_len, smem_len, hdr_len);
83562306a36Sopenharmony_ci		ADD_LEN(file_len, sram2_len, hdr_len);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci		for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++)
83862306a36Sopenharmony_ci			ADD_LEN(file_len, le32_to_cpu(fw_mem[i].len), hdr_len);
83962306a36Sopenharmony_ci	}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	/* Make room for fw's virtual image pages, if it exists */
84262306a36Sopenharmony_ci	if (iwl_fw_dbg_is_paging_enabled(fwrt))
84362306a36Sopenharmony_ci		file_len += fwrt->num_of_paging_blk *
84462306a36Sopenharmony_ci			(sizeof(*dump_data) +
84562306a36Sopenharmony_ci			 sizeof(struct iwl_fw_error_dump_paging) +
84662306a36Sopenharmony_ci			 PAGING_BLOCK_SIZE);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (iwl_fw_dbg_is_d3_debug_enabled(fwrt) && fwrt->dump.d3_debug_data) {
84962306a36Sopenharmony_ci		file_len += sizeof(*dump_data) +
85062306a36Sopenharmony_ci			fwrt->trans->cfg->d3_debug_data_length * 2;
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	/* If we only want a monitor dump, reset the file length */
85462306a36Sopenharmony_ci	if (data->monitor_only) {
85562306a36Sopenharmony_ci		file_len = sizeof(*dump_file) + sizeof(*dump_data) * 2 +
85662306a36Sopenharmony_ci			   sizeof(*dump_info) + sizeof(*dump_smem_cfg);
85762306a36Sopenharmony_ci	}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_ERROR_INFO) &&
86062306a36Sopenharmony_ci	    data->desc)
86162306a36Sopenharmony_ci		file_len += sizeof(*dump_data) + sizeof(*dump_trig) +
86262306a36Sopenharmony_ci			data->desc->len;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	dump_file = vzalloc(file_len);
86562306a36Sopenharmony_ci	if (!dump_file)
86662306a36Sopenharmony_ci		return NULL;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	fw_error_dump->fwrt_ptr = dump_file;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
87162306a36Sopenharmony_ci	dump_data = (void *)dump_file->data;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_DEV_FW_INFO)) {
87462306a36Sopenharmony_ci		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO);
87562306a36Sopenharmony_ci		dump_data->len = cpu_to_le32(sizeof(*dump_info));
87662306a36Sopenharmony_ci		dump_info = (void *)dump_data->data;
87762306a36Sopenharmony_ci		dump_info->hw_type =
87862306a36Sopenharmony_ci			cpu_to_le32(CSR_HW_REV_TYPE(fwrt->trans->hw_rev));
87962306a36Sopenharmony_ci		dump_info->hw_step =
88062306a36Sopenharmony_ci			cpu_to_le32(fwrt->trans->hw_rev_step);
88162306a36Sopenharmony_ci		memcpy(dump_info->fw_human_readable, fwrt->fw->human_readable,
88262306a36Sopenharmony_ci		       sizeof(dump_info->fw_human_readable));
88362306a36Sopenharmony_ci		strncpy(dump_info->dev_human_readable, fwrt->trans->name,
88462306a36Sopenharmony_ci			sizeof(dump_info->dev_human_readable) - 1);
88562306a36Sopenharmony_ci		strncpy(dump_info->bus_human_readable, fwrt->dev->bus->name,
88662306a36Sopenharmony_ci			sizeof(dump_info->bus_human_readable) - 1);
88762306a36Sopenharmony_ci		dump_info->num_of_lmacs = fwrt->smem_cfg.num_lmacs;
88862306a36Sopenharmony_ci		dump_info->lmac_err_id[0] =
88962306a36Sopenharmony_ci			cpu_to_le32(fwrt->dump.lmac_err_id[0]);
89062306a36Sopenharmony_ci		if (fwrt->smem_cfg.num_lmacs > 1)
89162306a36Sopenharmony_ci			dump_info->lmac_err_id[1] =
89262306a36Sopenharmony_ci				cpu_to_le32(fwrt->dump.lmac_err_id[1]);
89362306a36Sopenharmony_ci		dump_info->umac_err_id = cpu_to_le32(fwrt->dump.umac_err_id);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		dump_data = iwl_fw_error_next_data(dump_data);
89662306a36Sopenharmony_ci	}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM_CFG)) {
89962306a36Sopenharmony_ci		/* Dump shared memory configuration */
90062306a36Sopenharmony_ci		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_CFG);
90162306a36Sopenharmony_ci		dump_data->len = cpu_to_le32(sizeof(*dump_smem_cfg));
90262306a36Sopenharmony_ci		dump_smem_cfg = (void *)dump_data->data;
90362306a36Sopenharmony_ci		dump_smem_cfg->num_lmacs = cpu_to_le32(mem_cfg->num_lmacs);
90462306a36Sopenharmony_ci		dump_smem_cfg->num_txfifo_entries =
90562306a36Sopenharmony_ci			cpu_to_le32(mem_cfg->num_txfifo_entries);
90662306a36Sopenharmony_ci		for (i = 0; i < MAX_NUM_LMAC; i++) {
90762306a36Sopenharmony_ci			int j;
90862306a36Sopenharmony_ci			u32 *txf_size = mem_cfg->lmac[i].txfifo_size;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci			for (j = 0; j < TX_FIFO_MAX_NUM; j++)
91162306a36Sopenharmony_ci				dump_smem_cfg->lmac[i].txfifo_size[j] =
91262306a36Sopenharmony_ci					cpu_to_le32(txf_size[j]);
91362306a36Sopenharmony_ci			dump_smem_cfg->lmac[i].rxfifo1_size =
91462306a36Sopenharmony_ci				cpu_to_le32(mem_cfg->lmac[i].rxfifo1_size);
91562306a36Sopenharmony_ci		}
91662306a36Sopenharmony_ci		dump_smem_cfg->rxfifo2_size =
91762306a36Sopenharmony_ci			cpu_to_le32(mem_cfg->rxfifo2_size);
91862306a36Sopenharmony_ci		dump_smem_cfg->internal_txfifo_addr =
91962306a36Sopenharmony_ci			cpu_to_le32(mem_cfg->internal_txfifo_addr);
92062306a36Sopenharmony_ci		for (i = 0; i < TX_FIFO_INTERNAL_MAX_NUM; i++) {
92162306a36Sopenharmony_ci			dump_smem_cfg->internal_txfifo_size[i] =
92262306a36Sopenharmony_ci				cpu_to_le32(mem_cfg->internal_txfifo_size[i]);
92362306a36Sopenharmony_ci		}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci		dump_data = iwl_fw_error_next_data(dump_data);
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	/* We only dump the FIFOs if the FW is in error state */
92962306a36Sopenharmony_ci	if (fifo_len) {
93062306a36Sopenharmony_ci		iwl_fw_dump_rxf(fwrt, &dump_data);
93162306a36Sopenharmony_ci		iwl_fw_dump_txf(fwrt, &dump_data);
93262306a36Sopenharmony_ci	}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	if (radio_len)
93562306a36Sopenharmony_ci		iwl_read_radio_regs(fwrt, &dump_data);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_ERROR_INFO) &&
93862306a36Sopenharmony_ci	    data->desc) {
93962306a36Sopenharmony_ci		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO);
94062306a36Sopenharmony_ci		dump_data->len = cpu_to_le32(sizeof(*dump_trig) +
94162306a36Sopenharmony_ci					     data->desc->len);
94262306a36Sopenharmony_ci		dump_trig = (void *)dump_data->data;
94362306a36Sopenharmony_ci		memcpy(dump_trig, &data->desc->trig_desc,
94462306a36Sopenharmony_ci		       sizeof(*dump_trig) + data->desc->len);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci		dump_data = iwl_fw_error_next_data(dump_data);
94762306a36Sopenharmony_ci	}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	/* In case we only want monitor dump, skip to dump trasport data */
95062306a36Sopenharmony_ci	if (data->monitor_only)
95162306a36Sopenharmony_ci		goto out;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM)) {
95462306a36Sopenharmony_ci		const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem =
95562306a36Sopenharmony_ci			fwrt->fw->dbg.mem_tlv;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci		if (!fwrt->fw->dbg.n_mem_tlv)
95862306a36Sopenharmony_ci			iwl_fw_dump_mem(fwrt, &dump_data, sram_len, sram_ofs,
95962306a36Sopenharmony_ci					IWL_FW_ERROR_DUMP_MEM_SRAM);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci		for (i = 0; i < fwrt->fw->dbg.n_mem_tlv; i++) {
96262306a36Sopenharmony_ci			u32 len = le32_to_cpu(fw_dbg_mem[i].len);
96362306a36Sopenharmony_ci			u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci			iwl_fw_dump_mem(fwrt, &dump_data, len, ofs,
96662306a36Sopenharmony_ci					le32_to_cpu(fw_dbg_mem[i].data_type));
96762306a36Sopenharmony_ci		}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		iwl_fw_dump_mem(fwrt, &dump_data, smem_len,
97062306a36Sopenharmony_ci				fwrt->trans->cfg->smem_offset,
97162306a36Sopenharmony_ci				IWL_FW_ERROR_DUMP_MEM_SMEM);
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci		iwl_fw_dump_mem(fwrt, &dump_data, sram2_len,
97462306a36Sopenharmony_ci				fwrt->trans->cfg->dccm2_offset,
97562306a36Sopenharmony_ci				IWL_FW_ERROR_DUMP_MEM_SRAM);
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	if (iwl_fw_dbg_is_d3_debug_enabled(fwrt) && fwrt->dump.d3_debug_data) {
97962306a36Sopenharmony_ci		u32 addr = fwrt->trans->cfg->d3_debug_data_base_addr;
98062306a36Sopenharmony_ci		size_t data_size = fwrt->trans->cfg->d3_debug_data_length;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci		dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA);
98362306a36Sopenharmony_ci		dump_data->len = cpu_to_le32(data_size * 2);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci		memcpy(dump_data->data, fwrt->dump.d3_debug_data, data_size);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		kfree(fwrt->dump.d3_debug_data);
98862306a36Sopenharmony_ci		fwrt->dump.d3_debug_data = NULL;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci		iwl_trans_read_mem_bytes(fwrt->trans, addr,
99162306a36Sopenharmony_ci					 dump_data->data + data_size,
99262306a36Sopenharmony_ci					 data_size);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci		if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_mem)
99562306a36Sopenharmony_ci			fwrt->sanitize_ops->frob_mem(fwrt->sanitize_ctx, addr,
99662306a36Sopenharmony_ci						     dump_data->data + data_size,
99762306a36Sopenharmony_ci						     data_size);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci		dump_data = iwl_fw_error_next_data(dump_data);
100062306a36Sopenharmony_ci	}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	/* Dump fw's virtual image */
100362306a36Sopenharmony_ci	if (iwl_fw_dbg_is_paging_enabled(fwrt))
100462306a36Sopenharmony_ci		iwl_dump_paging(fwrt, &dump_data);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	if (prph_len)
100762306a36Sopenharmony_ci		iwl_fw_prph_handler(fwrt, &dump_data, iwl_dump_prph);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ciout:
101062306a36Sopenharmony_ci	dump_file->file_len = cpu_to_le32(file_len);
101162306a36Sopenharmony_ci	return dump_file;
101262306a36Sopenharmony_ci}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci/**
101562306a36Sopenharmony_ci * struct iwl_dump_ini_region_data - region data
101662306a36Sopenharmony_ci * @reg_tlv: region TLV
101762306a36Sopenharmony_ci * @dump_data: dump data
101862306a36Sopenharmony_ci */
101962306a36Sopenharmony_cistruct iwl_dump_ini_region_data {
102062306a36Sopenharmony_ci	struct iwl_ucode_tlv *reg_tlv;
102162306a36Sopenharmony_ci	struct iwl_fwrt_dump_data *dump_data;
102262306a36Sopenharmony_ci};
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic int
102562306a36Sopenharmony_ciiwl_dump_ini_prph_mac_iter(struct iwl_fw_runtime *fwrt,
102662306a36Sopenharmony_ci			   struct iwl_dump_ini_region_data *reg_data,
102762306a36Sopenharmony_ci			   void *range_ptr, u32 range_len, int idx)
102862306a36Sopenharmony_ci{
102962306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
103062306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
103162306a36Sopenharmony_ci	__le32 *val = range->data;
103262306a36Sopenharmony_ci	u32 prph_val;
103362306a36Sopenharmony_ci	u32 addr = le32_to_cpu(reg->addrs[idx]) +
103462306a36Sopenharmony_ci		   le32_to_cpu(reg->dev_addr.offset);
103562306a36Sopenharmony_ci	int i;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	range->internal_base_addr = cpu_to_le32(addr);
103862306a36Sopenharmony_ci	range->range_data_size = reg->dev_addr.size;
103962306a36Sopenharmony_ci	for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) {
104062306a36Sopenharmony_ci		prph_val = iwl_read_prph(fwrt->trans, addr + i);
104162306a36Sopenharmony_ci		if (iwl_trans_is_hw_error_value(prph_val))
104262306a36Sopenharmony_ci			return -EBUSY;
104362306a36Sopenharmony_ci		*val++ = cpu_to_le32(prph_val);
104462306a36Sopenharmony_ci	}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_cistatic int
105062306a36Sopenharmony_ciiwl_dump_ini_prph_phy_iter(struct iwl_fw_runtime *fwrt,
105162306a36Sopenharmony_ci			   struct iwl_dump_ini_region_data *reg_data,
105262306a36Sopenharmony_ci			   void *range_ptr, u32 range_len, int idx)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
105562306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
105662306a36Sopenharmony_ci	__le32 *val = range->data;
105762306a36Sopenharmony_ci	u32 indirect_wr_addr = WMAL_INDRCT_RD_CMD1;
105862306a36Sopenharmony_ci	u32 indirect_rd_addr = WMAL_MRSPF_1;
105962306a36Sopenharmony_ci	u32 prph_val;
106062306a36Sopenharmony_ci	u32 addr = le32_to_cpu(reg->addrs[idx]);
106162306a36Sopenharmony_ci	u32 dphy_state;
106262306a36Sopenharmony_ci	u32 dphy_addr;
106362306a36Sopenharmony_ci	int i;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	range->internal_base_addr = cpu_to_le32(addr);
106662306a36Sopenharmony_ci	range->range_data_size = reg->dev_addr.size;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	if (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
106962306a36Sopenharmony_ci		indirect_wr_addr = WMAL_INDRCT_CMD1;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	indirect_wr_addr += le32_to_cpu(reg->dev_addr.offset);
107262306a36Sopenharmony_ci	indirect_rd_addr += le32_to_cpu(reg->dev_addr.offset);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (!iwl_trans_grab_nic_access(fwrt->trans))
107562306a36Sopenharmony_ci		return -EBUSY;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	dphy_addr = (reg->dev_addr.offset) ? WFPM_LMAC2_PS_CTL_RW :
107862306a36Sopenharmony_ci					     WFPM_LMAC1_PS_CTL_RW;
107962306a36Sopenharmony_ci	dphy_state = iwl_read_umac_prph_no_grab(fwrt->trans, dphy_addr);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) {
108262306a36Sopenharmony_ci		if (dphy_state == HBUS_TIMEOUT ||
108362306a36Sopenharmony_ci		    (dphy_state & WFPM_PS_CTL_RW_PHYRF_PD_FSM_CURSTATE_MSK) !=
108462306a36Sopenharmony_ci		    WFPM_PHYRF_STATE_ON) {
108562306a36Sopenharmony_ci			*val++ = cpu_to_le32(WFPM_DPHY_OFF);
108662306a36Sopenharmony_ci			continue;
108762306a36Sopenharmony_ci		}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci		iwl_write_prph_no_grab(fwrt->trans, indirect_wr_addr,
109062306a36Sopenharmony_ci				       WMAL_INDRCT_CMD(addr + i));
109162306a36Sopenharmony_ci		prph_val = iwl_read_prph_no_grab(fwrt->trans,
109262306a36Sopenharmony_ci						 indirect_rd_addr);
109362306a36Sopenharmony_ci		*val++ = cpu_to_le32(prph_val);
109462306a36Sopenharmony_ci	}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	iwl_trans_release_nic_access(fwrt->trans);
109762306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_cistatic int iwl_dump_ini_csr_iter(struct iwl_fw_runtime *fwrt,
110162306a36Sopenharmony_ci				 struct iwl_dump_ini_region_data *reg_data,
110262306a36Sopenharmony_ci				 void *range_ptr, u32 range_len, int idx)
110362306a36Sopenharmony_ci{
110462306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
110562306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
110662306a36Sopenharmony_ci	__le32 *val = range->data;
110762306a36Sopenharmony_ci	u32 addr = le32_to_cpu(reg->addrs[idx]) +
110862306a36Sopenharmony_ci		   le32_to_cpu(reg->dev_addr.offset);
110962306a36Sopenharmony_ci	int i;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	range->internal_base_addr = cpu_to_le32(addr);
111262306a36Sopenharmony_ci	range->range_data_size = reg->dev_addr.size;
111362306a36Sopenharmony_ci	for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4)
111462306a36Sopenharmony_ci		*val++ = cpu_to_le32(iwl_trans_read32(fwrt->trans, addr + i));
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cistatic int iwl_dump_ini_config_iter(struct iwl_fw_runtime *fwrt,
112062306a36Sopenharmony_ci				    struct iwl_dump_ini_region_data *reg_data,
112162306a36Sopenharmony_ci				    void *range_ptr, u32 range_len, int idx)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	struct iwl_trans *trans = fwrt->trans;
112462306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
112562306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
112662306a36Sopenharmony_ci	__le32 *val = range->data;
112762306a36Sopenharmony_ci	u32 addr = le32_to_cpu(reg->addrs[idx]) +
112862306a36Sopenharmony_ci		   le32_to_cpu(reg->dev_addr.offset);
112962306a36Sopenharmony_ci	int i;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	/* we shouldn't get here if the trans doesn't have read_config32 */
113262306a36Sopenharmony_ci	if (WARN_ON_ONCE(!trans->ops->read_config32))
113362306a36Sopenharmony_ci		return -EOPNOTSUPP;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	range->internal_base_addr = cpu_to_le32(addr);
113662306a36Sopenharmony_ci	range->range_data_size = reg->dev_addr.size;
113762306a36Sopenharmony_ci	for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) {
113862306a36Sopenharmony_ci		int ret;
113962306a36Sopenharmony_ci		u32 tmp;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci		ret = trans->ops->read_config32(trans, addr + i, &tmp);
114262306a36Sopenharmony_ci		if (ret < 0)
114362306a36Sopenharmony_ci			return ret;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci		*val++ = cpu_to_le32(tmp);
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
114962306a36Sopenharmony_ci}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_cistatic int iwl_dump_ini_dev_mem_iter(struct iwl_fw_runtime *fwrt,
115262306a36Sopenharmony_ci				     struct iwl_dump_ini_region_data *reg_data,
115362306a36Sopenharmony_ci				     void *range_ptr, u32 range_len, int idx)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
115662306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
115762306a36Sopenharmony_ci	u32 addr = le32_to_cpu(reg->addrs[idx]) +
115862306a36Sopenharmony_ci		   le32_to_cpu(reg->dev_addr.offset);
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	range->internal_base_addr = cpu_to_le32(addr);
116162306a36Sopenharmony_ci	range->range_data_size = reg->dev_addr.size;
116262306a36Sopenharmony_ci	iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
116362306a36Sopenharmony_ci				 le32_to_cpu(reg->dev_addr.size));
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	if (reg->sub_type == IWL_FW_INI_REGION_DEVICE_MEMORY_SUBTYPE_HW_SMEM &&
116662306a36Sopenharmony_ci	    fwrt->sanitize_ops && fwrt->sanitize_ops->frob_txf)
116762306a36Sopenharmony_ci		fwrt->sanitize_ops->frob_txf(fwrt->sanitize_ctx,
116862306a36Sopenharmony_ci					     range->data,
116962306a36Sopenharmony_ci					     le32_to_cpu(reg->dev_addr.size));
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
117262306a36Sopenharmony_ci}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_cistatic int _iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt,
117562306a36Sopenharmony_ci				     void *range_ptr, u32 range_len, int idx)
117662306a36Sopenharmony_ci{
117762306a36Sopenharmony_ci	struct page *page = fwrt->fw_paging_db[idx].fw_paging_block;
117862306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
117962306a36Sopenharmony_ci	dma_addr_t addr = fwrt->fw_paging_db[idx].fw_paging_phys;
118062306a36Sopenharmony_ci	u32 page_size = fwrt->fw_paging_db[idx].fw_paging_size;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	range->page_num = cpu_to_le32(idx);
118362306a36Sopenharmony_ci	range->range_data_size = cpu_to_le32(page_size);
118462306a36Sopenharmony_ci	dma_sync_single_for_cpu(fwrt->trans->dev, addr,	page_size,
118562306a36Sopenharmony_ci				DMA_BIDIRECTIONAL);
118662306a36Sopenharmony_ci	memcpy(range->data, page_address(page), page_size);
118762306a36Sopenharmony_ci	dma_sync_single_for_device(fwrt->trans->dev, addr, page_size,
118862306a36Sopenharmony_ci				   DMA_BIDIRECTIONAL);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
119162306a36Sopenharmony_ci}
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_cistatic int iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt,
119462306a36Sopenharmony_ci				    struct iwl_dump_ini_region_data *reg_data,
119562306a36Sopenharmony_ci				    void *range_ptr, u32 range_len, int idx)
119662306a36Sopenharmony_ci{
119762306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range;
119862306a36Sopenharmony_ci	u32 page_size;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	/* all paged index start from 1 to skip CSS section */
120162306a36Sopenharmony_ci	idx++;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	if (!fwrt->trans->trans_cfg->gen2)
120462306a36Sopenharmony_ci		return _iwl_dump_ini_paging_iter(fwrt, range_ptr, range_len, idx);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	range = range_ptr;
120762306a36Sopenharmony_ci	page_size = fwrt->trans->init_dram.paging[idx].size;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	range->page_num = cpu_to_le32(idx);
121062306a36Sopenharmony_ci	range->range_data_size = cpu_to_le32(page_size);
121162306a36Sopenharmony_ci	memcpy(range->data, fwrt->trans->init_dram.paging[idx].block,
121262306a36Sopenharmony_ci	       page_size);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
121562306a36Sopenharmony_ci}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cistatic int
121862306a36Sopenharmony_ciiwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt,
121962306a36Sopenharmony_ci			   struct iwl_dump_ini_region_data *reg_data,
122062306a36Sopenharmony_ci			   void *range_ptr, u32 range_len, int idx)
122162306a36Sopenharmony_ci{
122262306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
122362306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
122462306a36Sopenharmony_ci	struct iwl_dram_data *frag;
122562306a36Sopenharmony_ci	u32 alloc_id = le32_to_cpu(reg->dram_alloc_id);
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	frag = &fwrt->trans->dbg.fw_mon_ini[alloc_id].frags[idx];
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	range->dram_base_addr = cpu_to_le64(frag->physical);
123062306a36Sopenharmony_ci	range->range_data_size = cpu_to_le32(frag->size);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	memcpy(range->data, frag->block, frag->size);
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
123562306a36Sopenharmony_ci}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_cistatic int iwl_dump_ini_mon_smem_iter(struct iwl_fw_runtime *fwrt,
123862306a36Sopenharmony_ci				      struct iwl_dump_ini_region_data *reg_data,
123962306a36Sopenharmony_ci				      void *range_ptr, u32 range_len, int idx)
124062306a36Sopenharmony_ci{
124162306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
124262306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
124362306a36Sopenharmony_ci	u32 addr = le32_to_cpu(reg->internal_buffer.base_addr);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	range->internal_base_addr = cpu_to_le32(addr);
124662306a36Sopenharmony_ci	range->range_data_size = reg->internal_buffer.size;
124762306a36Sopenharmony_ci	iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
124862306a36Sopenharmony_ci				 le32_to_cpu(reg->internal_buffer.size));
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_cistatic bool iwl_ini_txf_iter(struct iwl_fw_runtime *fwrt,
125462306a36Sopenharmony_ci			     struct iwl_dump_ini_region_data *reg_data, int idx)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
125762306a36Sopenharmony_ci	struct iwl_txf_iter_data *iter = &fwrt->dump.txf_iter_data;
125862306a36Sopenharmony_ci	struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg;
125962306a36Sopenharmony_ci	int txf_num = cfg->num_txfifo_entries;
126062306a36Sopenharmony_ci	int int_txf_num = ARRAY_SIZE(cfg->internal_txfifo_size);
126162306a36Sopenharmony_ci	u32 lmac_bitmap = le32_to_cpu(reg->fifos.fid[0]);
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	if (!idx) {
126462306a36Sopenharmony_ci		if (le32_to_cpu(reg->fifos.offset) && cfg->num_lmacs == 1) {
126562306a36Sopenharmony_ci			IWL_ERR(fwrt, "WRT: Invalid lmac offset 0x%x\n",
126662306a36Sopenharmony_ci				le32_to_cpu(reg->fifos.offset));
126762306a36Sopenharmony_ci			return false;
126862306a36Sopenharmony_ci		}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		iter->internal_txf = 0;
127162306a36Sopenharmony_ci		iter->fifo_size = 0;
127262306a36Sopenharmony_ci		iter->fifo = -1;
127362306a36Sopenharmony_ci		if (le32_to_cpu(reg->fifos.offset))
127462306a36Sopenharmony_ci			iter->lmac = 1;
127562306a36Sopenharmony_ci		else
127662306a36Sopenharmony_ci			iter->lmac = 0;
127762306a36Sopenharmony_ci	}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	if (!iter->internal_txf) {
128062306a36Sopenharmony_ci		for (iter->fifo++; iter->fifo < txf_num; iter->fifo++) {
128162306a36Sopenharmony_ci			iter->fifo_size =
128262306a36Sopenharmony_ci				cfg->lmac[iter->lmac].txfifo_size[iter->fifo];
128362306a36Sopenharmony_ci			if (iter->fifo_size && (lmac_bitmap & BIT(iter->fifo)))
128462306a36Sopenharmony_ci				return true;
128562306a36Sopenharmony_ci		}
128662306a36Sopenharmony_ci		iter->fifo--;
128762306a36Sopenharmony_ci	}
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	iter->internal_txf = 1;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	if (!fw_has_capa(&fwrt->fw->ucode_capa,
129262306a36Sopenharmony_ci			 IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG))
129362306a36Sopenharmony_ci		return false;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	for (iter->fifo++; iter->fifo < int_txf_num + txf_num; iter->fifo++) {
129662306a36Sopenharmony_ci		iter->fifo_size =
129762306a36Sopenharmony_ci			cfg->internal_txfifo_size[iter->fifo - txf_num];
129862306a36Sopenharmony_ci		if (iter->fifo_size && (lmac_bitmap & BIT(iter->fifo)))
129962306a36Sopenharmony_ci			return true;
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	return false;
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_cistatic int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt,
130662306a36Sopenharmony_ci				 struct iwl_dump_ini_region_data *reg_data,
130762306a36Sopenharmony_ci				 void *range_ptr, u32 range_len, int idx)
130862306a36Sopenharmony_ci{
130962306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
131062306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
131162306a36Sopenharmony_ci	struct iwl_txf_iter_data *iter = &fwrt->dump.txf_iter_data;
131262306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_register *reg_dump = (void *)range->data;
131362306a36Sopenharmony_ci	u32 offs = le32_to_cpu(reg->fifos.offset), addr;
131462306a36Sopenharmony_ci	u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs);
131562306a36Sopenharmony_ci	u32 registers_size = registers_num * sizeof(*reg_dump);
131662306a36Sopenharmony_ci	__le32 *data;
131762306a36Sopenharmony_ci	int i;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	if (!iwl_ini_txf_iter(fwrt, reg_data, idx))
132062306a36Sopenharmony_ci		return -EIO;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	if (!iwl_trans_grab_nic_access(fwrt->trans))
132362306a36Sopenharmony_ci		return -EBUSY;
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	range->fifo_hdr.fifo_num = cpu_to_le32(iter->fifo);
132662306a36Sopenharmony_ci	range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num);
132762306a36Sopenharmony_ci	range->range_data_size = cpu_to_le32(iter->fifo_size + registers_size);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	iwl_write_prph_no_grab(fwrt->trans, TXF_LARC_NUM + offs, iter->fifo);
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	/*
133262306a36Sopenharmony_ci	 * read txf registers. for each register, write to the dump the
133362306a36Sopenharmony_ci	 * register address and its value
133462306a36Sopenharmony_ci	 */
133562306a36Sopenharmony_ci	for (i = 0; i < registers_num; i++) {
133662306a36Sopenharmony_ci		addr = le32_to_cpu(reg->addrs[i]) + offs;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci		reg_dump->addr = cpu_to_le32(addr);
133962306a36Sopenharmony_ci		reg_dump->data = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans,
134062306a36Sopenharmony_ci								   addr));
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci		reg_dump++;
134362306a36Sopenharmony_ci	}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	if (reg->fifos.hdr_only) {
134662306a36Sopenharmony_ci		range->range_data_size = cpu_to_le32(registers_size);
134762306a36Sopenharmony_ci		goto out;
134862306a36Sopenharmony_ci	}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	/* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */
135162306a36Sopenharmony_ci	iwl_write_prph_no_grab(fwrt->trans, TXF_READ_MODIFY_ADDR + offs,
135262306a36Sopenharmony_ci			       TXF_WR_PTR + offs);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	/* Dummy-read to advance the read pointer to the head */
135562306a36Sopenharmony_ci	iwl_read_prph_no_grab(fwrt->trans, TXF_READ_MODIFY_DATA + offs);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	/* Read FIFO */
135862306a36Sopenharmony_ci	addr = TXF_READ_MODIFY_DATA + offs;
135962306a36Sopenharmony_ci	data = (void *)reg_dump;
136062306a36Sopenharmony_ci	for (i = 0; i < iter->fifo_size; i += sizeof(*data))
136162306a36Sopenharmony_ci		*data++ = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, addr));
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_txf)
136462306a36Sopenharmony_ci		fwrt->sanitize_ops->frob_txf(fwrt->sanitize_ctx,
136562306a36Sopenharmony_ci					     reg_dump, iter->fifo_size);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ciout:
136862306a36Sopenharmony_ci	iwl_trans_release_nic_access(fwrt->trans);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
137162306a36Sopenharmony_ci}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_cistruct iwl_ini_rxf_data {
137462306a36Sopenharmony_ci	u32 fifo_num;
137562306a36Sopenharmony_ci	u32 size;
137662306a36Sopenharmony_ci	u32 offset;
137762306a36Sopenharmony_ci};
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_cistatic void iwl_ini_get_rxf_data(struct iwl_fw_runtime *fwrt,
138062306a36Sopenharmony_ci				 struct iwl_dump_ini_region_data *reg_data,
138162306a36Sopenharmony_ci				 struct iwl_ini_rxf_data *data)
138262306a36Sopenharmony_ci{
138362306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
138462306a36Sopenharmony_ci	u32 fid1 = le32_to_cpu(reg->fifos.fid[0]);
138562306a36Sopenharmony_ci	u32 fid2 = le32_to_cpu(reg->fifos.fid[1]);
138662306a36Sopenharmony_ci	u8 fifo_idx;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	if (!data)
138962306a36Sopenharmony_ci		return;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	memset(data, 0, sizeof(*data));
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	/* make sure only one bit is set in only one fid */
139462306a36Sopenharmony_ci	if (WARN_ONCE(hweight_long(fid1) + hweight_long(fid2) != 1,
139562306a36Sopenharmony_ci		      "fid1=%x, fid2=%x\n", fid1, fid2))
139662306a36Sopenharmony_ci		return;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	if (fid1) {
139962306a36Sopenharmony_ci		fifo_idx = ffs(fid1) - 1;
140062306a36Sopenharmony_ci		if (WARN_ONCE(fifo_idx >= MAX_NUM_LMAC, "fifo_idx=%d\n",
140162306a36Sopenharmony_ci			      fifo_idx))
140262306a36Sopenharmony_ci			return;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci		data->size = fwrt->smem_cfg.lmac[fifo_idx].rxfifo1_size;
140562306a36Sopenharmony_ci		data->fifo_num = fifo_idx;
140662306a36Sopenharmony_ci	} else {
140762306a36Sopenharmony_ci		u8 max_idx;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci		fifo_idx = ffs(fid2) - 1;
141062306a36Sopenharmony_ci		if (iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP,
141162306a36Sopenharmony_ci					    SHARED_MEM_CFG_CMD, 0) <= 3)
141262306a36Sopenharmony_ci			max_idx = 0;
141362306a36Sopenharmony_ci		else
141462306a36Sopenharmony_ci			max_idx = 1;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci		if (WARN_ONCE(fifo_idx > max_idx,
141762306a36Sopenharmony_ci			      "invalid umac fifo idx %d", fifo_idx))
141862306a36Sopenharmony_ci			return;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci		/* use bit 31 to distinguish between umac and lmac rxf while
142162306a36Sopenharmony_ci		 * parsing the dump
142262306a36Sopenharmony_ci		 */
142362306a36Sopenharmony_ci		data->fifo_num = fifo_idx | IWL_RXF_UMAC_BIT;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci		switch (fifo_idx) {
142662306a36Sopenharmony_ci		case 0:
142762306a36Sopenharmony_ci			data->size = fwrt->smem_cfg.rxfifo2_size;
142862306a36Sopenharmony_ci			data->offset = iwl_umac_prph(fwrt->trans,
142962306a36Sopenharmony_ci						     RXF_DIFF_FROM_PREV);
143062306a36Sopenharmony_ci			break;
143162306a36Sopenharmony_ci		case 1:
143262306a36Sopenharmony_ci			data->size = fwrt->smem_cfg.rxfifo2_control_size;
143362306a36Sopenharmony_ci			data->offset = iwl_umac_prph(fwrt->trans,
143462306a36Sopenharmony_ci						     RXF2C_DIFF_FROM_PREV);
143562306a36Sopenharmony_ci			break;
143662306a36Sopenharmony_ci		}
143762306a36Sopenharmony_ci	}
143862306a36Sopenharmony_ci}
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_cistatic int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt,
144162306a36Sopenharmony_ci				 struct iwl_dump_ini_region_data *reg_data,
144262306a36Sopenharmony_ci				 void *range_ptr, u32 range_len, int idx)
144362306a36Sopenharmony_ci{
144462306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
144562306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
144662306a36Sopenharmony_ci	struct iwl_ini_rxf_data rxf_data;
144762306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_register *reg_dump = (void *)range->data;
144862306a36Sopenharmony_ci	u32 offs = le32_to_cpu(reg->fifos.offset), addr;
144962306a36Sopenharmony_ci	u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs);
145062306a36Sopenharmony_ci	u32 registers_size = registers_num * sizeof(*reg_dump);
145162306a36Sopenharmony_ci	__le32 *data;
145262306a36Sopenharmony_ci	int i;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	iwl_ini_get_rxf_data(fwrt, reg_data, &rxf_data);
145562306a36Sopenharmony_ci	if (!rxf_data.size)
145662306a36Sopenharmony_ci		return -EIO;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	if (!iwl_trans_grab_nic_access(fwrt->trans))
145962306a36Sopenharmony_ci		return -EBUSY;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	range->fifo_hdr.fifo_num = cpu_to_le32(rxf_data.fifo_num);
146262306a36Sopenharmony_ci	range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num);
146362306a36Sopenharmony_ci	range->range_data_size = cpu_to_le32(rxf_data.size + registers_size);
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	/*
146662306a36Sopenharmony_ci	 * read rxf registers. for each register, write to the dump the
146762306a36Sopenharmony_ci	 * register address and its value
146862306a36Sopenharmony_ci	 */
146962306a36Sopenharmony_ci	for (i = 0; i < registers_num; i++) {
147062306a36Sopenharmony_ci		addr = le32_to_cpu(reg->addrs[i]) + offs;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci		reg_dump->addr = cpu_to_le32(addr);
147362306a36Sopenharmony_ci		reg_dump->data = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans,
147462306a36Sopenharmony_ci								   addr));
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci		reg_dump++;
147762306a36Sopenharmony_ci	}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	if (reg->fifos.hdr_only) {
148062306a36Sopenharmony_ci		range->range_data_size = cpu_to_le32(registers_size);
148162306a36Sopenharmony_ci		goto out;
148262306a36Sopenharmony_ci	}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	offs = rxf_data.offset;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	/* Lock fence */
148762306a36Sopenharmony_ci	iwl_write_prph_no_grab(fwrt->trans, RXF_SET_FENCE_MODE + offs, 0x1);
148862306a36Sopenharmony_ci	/* Set fence pointer to the same place like WR pointer */
148962306a36Sopenharmony_ci	iwl_write_prph_no_grab(fwrt->trans, RXF_LD_WR2FENCE + offs, 0x1);
149062306a36Sopenharmony_ci	/* Set fence offset */
149162306a36Sopenharmony_ci	iwl_write_prph_no_grab(fwrt->trans, RXF_LD_FENCE_OFFSET_ADDR + offs,
149262306a36Sopenharmony_ci			       0x0);
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	/* Read FIFO */
149562306a36Sopenharmony_ci	addr =  RXF_FIFO_RD_FENCE_INC + offs;
149662306a36Sopenharmony_ci	data = (void *)reg_dump;
149762306a36Sopenharmony_ci	for (i = 0; i < rxf_data.size; i += sizeof(*data))
149862306a36Sopenharmony_ci		*data++ = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, addr));
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ciout:
150162306a36Sopenharmony_ci	iwl_trans_release_nic_access(fwrt->trans);
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
150462306a36Sopenharmony_ci}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_cistatic int
150762306a36Sopenharmony_ciiwl_dump_ini_err_table_iter(struct iwl_fw_runtime *fwrt,
150862306a36Sopenharmony_ci			    struct iwl_dump_ini_region_data *reg_data,
150962306a36Sopenharmony_ci			    void *range_ptr, u32 range_len, int idx)
151062306a36Sopenharmony_ci{
151162306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
151262306a36Sopenharmony_ci	struct iwl_fw_ini_region_err_table *err_table = &reg->err_table;
151362306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
151462306a36Sopenharmony_ci	u32 addr = le32_to_cpu(err_table->base_addr) +
151562306a36Sopenharmony_ci		   le32_to_cpu(err_table->offset);
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	range->internal_base_addr = cpu_to_le32(addr);
151862306a36Sopenharmony_ci	range->range_data_size = err_table->size;
151962306a36Sopenharmony_ci	iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
152062306a36Sopenharmony_ci				 le32_to_cpu(err_table->size));
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
152362306a36Sopenharmony_ci}
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_cistatic int
152662306a36Sopenharmony_ciiwl_dump_ini_special_mem_iter(struct iwl_fw_runtime *fwrt,
152762306a36Sopenharmony_ci			      struct iwl_dump_ini_region_data *reg_data,
152862306a36Sopenharmony_ci			      void *range_ptr, u32 range_len, int idx)
152962306a36Sopenharmony_ci{
153062306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
153162306a36Sopenharmony_ci	struct iwl_fw_ini_region_special_device_memory *special_mem =
153262306a36Sopenharmony_ci		&reg->special_mem;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
153562306a36Sopenharmony_ci	u32 addr = le32_to_cpu(special_mem->base_addr) +
153662306a36Sopenharmony_ci		   le32_to_cpu(special_mem->offset);
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	range->internal_base_addr = cpu_to_le32(addr);
153962306a36Sopenharmony_ci	range->range_data_size = special_mem->size;
154062306a36Sopenharmony_ci	iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data,
154162306a36Sopenharmony_ci				 le32_to_cpu(special_mem->size));
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_cistatic int
154762306a36Sopenharmony_ciiwl_dump_ini_dbgi_sram_iter(struct iwl_fw_runtime *fwrt,
154862306a36Sopenharmony_ci			    struct iwl_dump_ini_region_data *reg_data,
154962306a36Sopenharmony_ci			    void *range_ptr, u32 range_len, int idx)
155062306a36Sopenharmony_ci{
155162306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
155262306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
155362306a36Sopenharmony_ci	__le32 *val = range->data;
155462306a36Sopenharmony_ci	u32 prph_data;
155562306a36Sopenharmony_ci	int i;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	if (!iwl_trans_grab_nic_access(fwrt->trans))
155862306a36Sopenharmony_ci		return -EBUSY;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	range->range_data_size = reg->dev_addr.size;
156162306a36Sopenharmony_ci	for (i = 0; i < (le32_to_cpu(reg->dev_addr.size) / 4); i++) {
156262306a36Sopenharmony_ci		prph_data = iwl_read_prph_no_grab(fwrt->trans, (i % 2) ?
156362306a36Sopenharmony_ci					  DBGI_SRAM_TARGET_ACCESS_RDATA_MSB :
156462306a36Sopenharmony_ci					  DBGI_SRAM_TARGET_ACCESS_RDATA_LSB);
156562306a36Sopenharmony_ci		if (iwl_trans_is_hw_error_value(prph_data)) {
156662306a36Sopenharmony_ci			iwl_trans_release_nic_access(fwrt->trans);
156762306a36Sopenharmony_ci			return -EBUSY;
156862306a36Sopenharmony_ci		}
156962306a36Sopenharmony_ci		*val++ = cpu_to_le32(prph_data);
157062306a36Sopenharmony_ci	}
157162306a36Sopenharmony_ci	iwl_trans_release_nic_access(fwrt->trans);
157262306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
157362306a36Sopenharmony_ci}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_cistatic int iwl_dump_ini_fw_pkt_iter(struct iwl_fw_runtime *fwrt,
157662306a36Sopenharmony_ci				    struct iwl_dump_ini_region_data *reg_data,
157762306a36Sopenharmony_ci				    void *range_ptr, u32 range_len, int idx)
157862306a36Sopenharmony_ci{
157962306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
158062306a36Sopenharmony_ci	struct iwl_rx_packet *pkt = reg_data->dump_data->fw_pkt;
158162306a36Sopenharmony_ci	u32 pkt_len;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	if (!pkt)
158462306a36Sopenharmony_ci		return -EIO;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	pkt_len = iwl_rx_packet_payload_len(pkt);
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	memcpy(&range->fw_pkt_hdr, &pkt->hdr, sizeof(range->fw_pkt_hdr));
158962306a36Sopenharmony_ci	range->range_data_size = cpu_to_le32(pkt_len);
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	memcpy(range->data, pkt->data, pkt_len);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
159462306a36Sopenharmony_ci}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_cistatic int iwl_dump_ini_imr_iter(struct iwl_fw_runtime *fwrt,
159762306a36Sopenharmony_ci				 struct iwl_dump_ini_region_data *reg_data,
159862306a36Sopenharmony_ci				 void *range_ptr, u32 range_len, int idx)
159962306a36Sopenharmony_ci{
160062306a36Sopenharmony_ci	/* read the IMR memory and DMA it to SRAM */
160162306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_range *range = range_ptr;
160262306a36Sopenharmony_ci	u64 imr_curr_addr = fwrt->trans->dbg.imr_data.imr_curr_addr;
160362306a36Sopenharmony_ci	u32 imr_rem_bytes = fwrt->trans->dbg.imr_data.imr2sram_remainbyte;
160462306a36Sopenharmony_ci	u32 sram_addr = fwrt->trans->dbg.imr_data.sram_addr;
160562306a36Sopenharmony_ci	u32 sram_size = fwrt->trans->dbg.imr_data.sram_size;
160662306a36Sopenharmony_ci	u32 size_to_dump = (imr_rem_bytes > sram_size) ? sram_size : imr_rem_bytes;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	range->range_data_size = cpu_to_le32(size_to_dump);
160962306a36Sopenharmony_ci	if (iwl_trans_write_imr_mem(fwrt->trans, sram_addr,
161062306a36Sopenharmony_ci				    imr_curr_addr, size_to_dump)) {
161162306a36Sopenharmony_ci		IWL_ERR(fwrt, "WRT_DEBUG: IMR Memory transfer failed\n");
161262306a36Sopenharmony_ci		return -1;
161362306a36Sopenharmony_ci	}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	fwrt->trans->dbg.imr_data.imr_curr_addr = imr_curr_addr + size_to_dump;
161662306a36Sopenharmony_ci	fwrt->trans->dbg.imr_data.imr2sram_remainbyte -= size_to_dump;
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	iwl_trans_read_mem_bytes(fwrt->trans, sram_addr, range->data,
161962306a36Sopenharmony_ci				 size_to_dump);
162062306a36Sopenharmony_ci	return sizeof(*range) + le32_to_cpu(range->range_data_size);
162162306a36Sopenharmony_ci}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_cistatic void *
162462306a36Sopenharmony_ciiwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt,
162562306a36Sopenharmony_ci			     struct iwl_dump_ini_region_data *reg_data,
162662306a36Sopenharmony_ci			     void *data, u32 data_len)
162762306a36Sopenharmony_ci{
162862306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump *dump = data;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	return dump->data;
163362306a36Sopenharmony_ci}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci/**
163662306a36Sopenharmony_ci * mask_apply_and_normalize - applies mask on val and normalize the result
163762306a36Sopenharmony_ci *
163862306a36Sopenharmony_ci * The normalization is based on the first set bit in the mask
163962306a36Sopenharmony_ci *
164062306a36Sopenharmony_ci * @val: value
164162306a36Sopenharmony_ci * @mask: mask to apply and to normalize with
164262306a36Sopenharmony_ci */
164362306a36Sopenharmony_cistatic u32 mask_apply_and_normalize(u32 val, u32 mask)
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	return (val & mask) >> (ffs(mask) - 1);
164662306a36Sopenharmony_ci}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_cistatic __le32 iwl_get_mon_reg(struct iwl_fw_runtime *fwrt, u32 alloc_id,
164962306a36Sopenharmony_ci			      const struct iwl_fw_mon_reg *reg_info)
165062306a36Sopenharmony_ci{
165162306a36Sopenharmony_ci	u32 val, offs;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	/* The header addresses of DBGCi is calculate as follows:
165462306a36Sopenharmony_ci	 * DBGC1 address + (0x100 * i)
165562306a36Sopenharmony_ci	 */
165662306a36Sopenharmony_ci	offs = (alloc_id - IWL_FW_INI_ALLOCATION_ID_DBGC1) * 0x100;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	if (!reg_info || !reg_info->addr || !reg_info->mask)
165962306a36Sopenharmony_ci		return 0;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	val = iwl_read_prph_no_grab(fwrt->trans, reg_info->addr + offs);
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	return cpu_to_le32(mask_apply_and_normalize(val, reg_info->mask));
166462306a36Sopenharmony_ci}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_cistatic void *
166762306a36Sopenharmony_ciiwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, u32 alloc_id,
166862306a36Sopenharmony_ci			     struct iwl_fw_ini_monitor_dump *data,
166962306a36Sopenharmony_ci			     const struct iwl_fw_mon_regs *addrs)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci	if (!iwl_trans_grab_nic_access(fwrt->trans)) {
167262306a36Sopenharmony_ci		IWL_ERR(fwrt, "Failed to get monitor header\n");
167362306a36Sopenharmony_ci		return NULL;
167462306a36Sopenharmony_ci	}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	data->write_ptr = iwl_get_mon_reg(fwrt, alloc_id,
167762306a36Sopenharmony_ci					  &addrs->write_ptr);
167862306a36Sopenharmony_ci	if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {
167962306a36Sopenharmony_ci		u32 wrt_ptr = le32_to_cpu(data->write_ptr);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci		data->write_ptr = cpu_to_le32(wrt_ptr >> 2);
168262306a36Sopenharmony_ci	}
168362306a36Sopenharmony_ci	data->cycle_cnt = iwl_get_mon_reg(fwrt, alloc_id,
168462306a36Sopenharmony_ci					  &addrs->cycle_cnt);
168562306a36Sopenharmony_ci	data->cur_frag = iwl_get_mon_reg(fwrt, alloc_id,
168662306a36Sopenharmony_ci					 &addrs->cur_frag);
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	iwl_trans_release_nic_access(fwrt->trans);
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	data->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	return data->data;
169362306a36Sopenharmony_ci}
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_cistatic void *
169662306a36Sopenharmony_ciiwl_dump_ini_mon_dram_fill_header(struct iwl_fw_runtime *fwrt,
169762306a36Sopenharmony_ci				  struct iwl_dump_ini_region_data *reg_data,
169862306a36Sopenharmony_ci				  void *data, u32 data_len)
169962306a36Sopenharmony_ci{
170062306a36Sopenharmony_ci	struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data;
170162306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
170262306a36Sopenharmony_ci	u32 alloc_id = le32_to_cpu(reg->dram_alloc_id);
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	return iwl_dump_ini_mon_fill_header(fwrt, alloc_id, mon_dump,
170562306a36Sopenharmony_ci					    &fwrt->trans->cfg->mon_dram_regs);
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_cistatic void *
170962306a36Sopenharmony_ciiwl_dump_ini_mon_smem_fill_header(struct iwl_fw_runtime *fwrt,
171062306a36Sopenharmony_ci				  struct iwl_dump_ini_region_data *reg_data,
171162306a36Sopenharmony_ci				  void *data, u32 data_len)
171262306a36Sopenharmony_ci{
171362306a36Sopenharmony_ci	struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data;
171462306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
171562306a36Sopenharmony_ci	u32 alloc_id = le32_to_cpu(reg->internal_buffer.alloc_id);
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	return iwl_dump_ini_mon_fill_header(fwrt, alloc_id, mon_dump,
171862306a36Sopenharmony_ci					    &fwrt->trans->cfg->mon_smem_regs);
171962306a36Sopenharmony_ci}
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_cistatic void *
172262306a36Sopenharmony_ciiwl_dump_ini_mon_dbgi_fill_header(struct iwl_fw_runtime *fwrt,
172362306a36Sopenharmony_ci				  struct iwl_dump_ini_region_data *reg_data,
172462306a36Sopenharmony_ci				  void *data, u32 data_len)
172562306a36Sopenharmony_ci{
172662306a36Sopenharmony_ci	struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	return iwl_dump_ini_mon_fill_header(fwrt,
172962306a36Sopenharmony_ci					    /* no offset calculation later */
173062306a36Sopenharmony_ci					    IWL_FW_INI_ALLOCATION_ID_DBGC1,
173162306a36Sopenharmony_ci					    mon_dump,
173262306a36Sopenharmony_ci					    &fwrt->trans->cfg->mon_dbgi_regs);
173362306a36Sopenharmony_ci}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_cistatic void *
173662306a36Sopenharmony_ciiwl_dump_ini_err_table_fill_header(struct iwl_fw_runtime *fwrt,
173762306a36Sopenharmony_ci				   struct iwl_dump_ini_region_data *reg_data,
173862306a36Sopenharmony_ci				   void *data, u32 data_len)
173962306a36Sopenharmony_ci{
174062306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
174162306a36Sopenharmony_ci	struct iwl_fw_ini_err_table_dump *dump = data;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
174462306a36Sopenharmony_ci	dump->version = reg->err_table.version;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	return dump->data;
174762306a36Sopenharmony_ci}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_cistatic void *
175062306a36Sopenharmony_ciiwl_dump_ini_special_mem_fill_header(struct iwl_fw_runtime *fwrt,
175162306a36Sopenharmony_ci				     struct iwl_dump_ini_region_data *reg_data,
175262306a36Sopenharmony_ci				     void *data, u32 data_len)
175362306a36Sopenharmony_ci{
175462306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
175562306a36Sopenharmony_ci	struct iwl_fw_ini_special_device_memory *dump = data;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
175862306a36Sopenharmony_ci	dump->type = reg->special_mem.type;
175962306a36Sopenharmony_ci	dump->version = reg->special_mem.version;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	return dump->data;
176262306a36Sopenharmony_ci}
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_cistatic void *
176562306a36Sopenharmony_ciiwl_dump_ini_imr_fill_header(struct iwl_fw_runtime *fwrt,
176662306a36Sopenharmony_ci			     struct iwl_dump_ini_region_data *reg_data,
176762306a36Sopenharmony_ci			     void *data, u32 data_len)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump *dump = data;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER);
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	return dump->data;
177462306a36Sopenharmony_ci}
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_cistatic u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt,
177762306a36Sopenharmony_ci				   struct iwl_dump_ini_region_data *reg_data)
177862306a36Sopenharmony_ci{
177962306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	return iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs);
178262306a36Sopenharmony_ci}
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_cistatic u32 iwl_dump_ini_paging_ranges(struct iwl_fw_runtime *fwrt,
178562306a36Sopenharmony_ci				      struct iwl_dump_ini_region_data *reg_data)
178662306a36Sopenharmony_ci{
178762306a36Sopenharmony_ci	if (fwrt->trans->trans_cfg->gen2) {
178862306a36Sopenharmony_ci		if (fwrt->trans->init_dram.paging_cnt)
178962306a36Sopenharmony_ci			return fwrt->trans->init_dram.paging_cnt - 1;
179062306a36Sopenharmony_ci		else
179162306a36Sopenharmony_ci			return 0;
179262306a36Sopenharmony_ci	}
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	return fwrt->num_of_paging_blk;
179562306a36Sopenharmony_ci}
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_cistatic u32
179862306a36Sopenharmony_ciiwl_dump_ini_mon_dram_ranges(struct iwl_fw_runtime *fwrt,
179962306a36Sopenharmony_ci			     struct iwl_dump_ini_region_data *reg_data)
180062306a36Sopenharmony_ci{
180162306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
180262306a36Sopenharmony_ci	struct iwl_fw_mon *fw_mon;
180362306a36Sopenharmony_ci	u32 ranges = 0, alloc_id = le32_to_cpu(reg->dram_alloc_id);
180462306a36Sopenharmony_ci	int i;
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id];
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	for (i = 0; i < fw_mon->num_frags; i++) {
180962306a36Sopenharmony_ci		if (!fw_mon->frags[i].size)
181062306a36Sopenharmony_ci			break;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci		ranges++;
181362306a36Sopenharmony_ci	}
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	return ranges;
181662306a36Sopenharmony_ci}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_cistatic u32 iwl_dump_ini_txf_ranges(struct iwl_fw_runtime *fwrt,
181962306a36Sopenharmony_ci				   struct iwl_dump_ini_region_data *reg_data)
182062306a36Sopenharmony_ci{
182162306a36Sopenharmony_ci	u32 num_of_fifos = 0;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	while (iwl_ini_txf_iter(fwrt, reg_data, num_of_fifos))
182462306a36Sopenharmony_ci		num_of_fifos++;
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	return num_of_fifos;
182762306a36Sopenharmony_ci}
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_cistatic u32 iwl_dump_ini_single_range(struct iwl_fw_runtime *fwrt,
183062306a36Sopenharmony_ci				     struct iwl_dump_ini_region_data *reg_data)
183162306a36Sopenharmony_ci{
183262306a36Sopenharmony_ci	return 1;
183362306a36Sopenharmony_ci}
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_cistatic u32 iwl_dump_ini_imr_ranges(struct iwl_fw_runtime *fwrt,
183662306a36Sopenharmony_ci				   struct iwl_dump_ini_region_data *reg_data)
183762306a36Sopenharmony_ci{
183862306a36Sopenharmony_ci	/* range is total number of pages need to copied from
183962306a36Sopenharmony_ci	 *IMR memory to SRAM and later from SRAM to DRAM
184062306a36Sopenharmony_ci	 */
184162306a36Sopenharmony_ci	u32 imr_enable = fwrt->trans->dbg.imr_data.imr_enable;
184262306a36Sopenharmony_ci	u32 imr_size = fwrt->trans->dbg.imr_data.imr_size;
184362306a36Sopenharmony_ci	u32 sram_size = fwrt->trans->dbg.imr_data.sram_size;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	if (imr_enable == 0 || imr_size == 0 || sram_size == 0) {
184662306a36Sopenharmony_ci		IWL_DEBUG_INFO(fwrt,
184762306a36Sopenharmony_ci			       "WRT: Invalid imr data enable: %d, imr_size: %d, sram_size: %d\n",
184862306a36Sopenharmony_ci			       imr_enable, imr_size, sram_size);
184962306a36Sopenharmony_ci		return 0;
185062306a36Sopenharmony_ci	}
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	return((imr_size % sram_size) ? (imr_size / sram_size + 1) : (imr_size / sram_size));
185362306a36Sopenharmony_ci}
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_cistatic u32 iwl_dump_ini_mem_get_size(struct iwl_fw_runtime *fwrt,
185662306a36Sopenharmony_ci				     struct iwl_dump_ini_region_data *reg_data)
185762306a36Sopenharmony_ci{
185862306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
185962306a36Sopenharmony_ci	u32 size = le32_to_cpu(reg->dev_addr.size);
186062306a36Sopenharmony_ci	u32 ranges = iwl_dump_ini_mem_ranges(fwrt, reg_data);
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	if (!size || !ranges)
186362306a36Sopenharmony_ci		return 0;
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	return sizeof(struct iwl_fw_ini_error_dump) + ranges *
186662306a36Sopenharmony_ci		(size + sizeof(struct iwl_fw_ini_error_dump_range));
186762306a36Sopenharmony_ci}
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_cistatic u32
187062306a36Sopenharmony_ciiwl_dump_ini_paging_get_size(struct iwl_fw_runtime *fwrt,
187162306a36Sopenharmony_ci			     struct iwl_dump_ini_region_data *reg_data)
187262306a36Sopenharmony_ci{
187362306a36Sopenharmony_ci	int i;
187462306a36Sopenharmony_ci	u32 range_header_len = sizeof(struct iwl_fw_ini_error_dump_range);
187562306a36Sopenharmony_ci	u32 size = sizeof(struct iwl_fw_ini_error_dump);
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	/* start from 1 to skip CSS section */
187862306a36Sopenharmony_ci	for (i = 1; i <= iwl_dump_ini_paging_ranges(fwrt, reg_data); i++) {
187962306a36Sopenharmony_ci		size += range_header_len;
188062306a36Sopenharmony_ci		if (fwrt->trans->trans_cfg->gen2)
188162306a36Sopenharmony_ci			size += fwrt->trans->init_dram.paging[i].size;
188262306a36Sopenharmony_ci		else
188362306a36Sopenharmony_ci			size += fwrt->fw_paging_db[i].fw_paging_size;
188462306a36Sopenharmony_ci	}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	return size;
188762306a36Sopenharmony_ci}
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_cistatic u32
189062306a36Sopenharmony_ciiwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt,
189162306a36Sopenharmony_ci			       struct iwl_dump_ini_region_data *reg_data)
189262306a36Sopenharmony_ci{
189362306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
189462306a36Sopenharmony_ci	struct iwl_fw_mon *fw_mon;
189562306a36Sopenharmony_ci	u32 size = 0, alloc_id = le32_to_cpu(reg->dram_alloc_id);
189662306a36Sopenharmony_ci	int i;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id];
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	for (i = 0; i < fw_mon->num_frags; i++) {
190162306a36Sopenharmony_ci		struct iwl_dram_data *frag = &fw_mon->frags[i];
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci		if (!frag->size)
190462306a36Sopenharmony_ci			break;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci		size += sizeof(struct iwl_fw_ini_error_dump_range) + frag->size;
190762306a36Sopenharmony_ci	}
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	if (size)
191062306a36Sopenharmony_ci		size += sizeof(struct iwl_fw_ini_monitor_dump);
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	return size;
191362306a36Sopenharmony_ci}
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_cistatic u32
191662306a36Sopenharmony_ciiwl_dump_ini_mon_smem_get_size(struct iwl_fw_runtime *fwrt,
191762306a36Sopenharmony_ci			       struct iwl_dump_ini_region_data *reg_data)
191862306a36Sopenharmony_ci{
191962306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
192062306a36Sopenharmony_ci	u32 size;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	size = le32_to_cpu(reg->internal_buffer.size);
192362306a36Sopenharmony_ci	if (!size)
192462306a36Sopenharmony_ci		return 0;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	size += sizeof(struct iwl_fw_ini_monitor_dump) +
192762306a36Sopenharmony_ci		sizeof(struct iwl_fw_ini_error_dump_range);
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	return size;
193062306a36Sopenharmony_ci}
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_cistatic u32 iwl_dump_ini_mon_dbgi_get_size(struct iwl_fw_runtime *fwrt,
193362306a36Sopenharmony_ci					  struct iwl_dump_ini_region_data *reg_data)
193462306a36Sopenharmony_ci{
193562306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
193662306a36Sopenharmony_ci	u32 size = le32_to_cpu(reg->dev_addr.size);
193762306a36Sopenharmony_ci	u32 ranges = iwl_dump_ini_mem_ranges(fwrt, reg_data);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	if (!size || !ranges)
194062306a36Sopenharmony_ci		return 0;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	return sizeof(struct iwl_fw_ini_monitor_dump) + ranges *
194362306a36Sopenharmony_ci		(size + sizeof(struct iwl_fw_ini_error_dump_range));
194462306a36Sopenharmony_ci}
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_cistatic u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt,
194762306a36Sopenharmony_ci				     struct iwl_dump_ini_region_data *reg_data)
194862306a36Sopenharmony_ci{
194962306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
195062306a36Sopenharmony_ci	struct iwl_txf_iter_data *iter = &fwrt->dump.txf_iter_data;
195162306a36Sopenharmony_ci	u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs);
195262306a36Sopenharmony_ci	u32 size = 0;
195362306a36Sopenharmony_ci	u32 fifo_hdr = sizeof(struct iwl_fw_ini_error_dump_range) +
195462306a36Sopenharmony_ci		       registers_num *
195562306a36Sopenharmony_ci		       sizeof(struct iwl_fw_ini_error_dump_register);
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	while (iwl_ini_txf_iter(fwrt, reg_data, size)) {
195862306a36Sopenharmony_ci		size += fifo_hdr;
195962306a36Sopenharmony_ci		if (!reg->fifos.hdr_only)
196062306a36Sopenharmony_ci			size += iter->fifo_size;
196162306a36Sopenharmony_ci	}
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	if (!size)
196462306a36Sopenharmony_ci		return 0;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	return size + sizeof(struct iwl_fw_ini_error_dump);
196762306a36Sopenharmony_ci}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_cistatic u32 iwl_dump_ini_rxf_get_size(struct iwl_fw_runtime *fwrt,
197062306a36Sopenharmony_ci				     struct iwl_dump_ini_region_data *reg_data)
197162306a36Sopenharmony_ci{
197262306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
197362306a36Sopenharmony_ci	struct iwl_ini_rxf_data rx_data;
197462306a36Sopenharmony_ci	u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs);
197562306a36Sopenharmony_ci	u32 size = sizeof(struct iwl_fw_ini_error_dump) +
197662306a36Sopenharmony_ci		sizeof(struct iwl_fw_ini_error_dump_range) +
197762306a36Sopenharmony_ci		registers_num * sizeof(struct iwl_fw_ini_error_dump_register);
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	if (reg->fifos.hdr_only)
198062306a36Sopenharmony_ci		return size;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	iwl_ini_get_rxf_data(fwrt, reg_data, &rx_data);
198362306a36Sopenharmony_ci	size += rx_data.size;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	return size;
198662306a36Sopenharmony_ci}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_cistatic u32
198962306a36Sopenharmony_ciiwl_dump_ini_err_table_get_size(struct iwl_fw_runtime *fwrt,
199062306a36Sopenharmony_ci				struct iwl_dump_ini_region_data *reg_data)
199162306a36Sopenharmony_ci{
199262306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
199362306a36Sopenharmony_ci	u32 size = le32_to_cpu(reg->err_table.size);
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	if (size)
199662306a36Sopenharmony_ci		size += sizeof(struct iwl_fw_ini_err_table_dump) +
199762306a36Sopenharmony_ci			sizeof(struct iwl_fw_ini_error_dump_range);
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	return size;
200062306a36Sopenharmony_ci}
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_cistatic u32
200362306a36Sopenharmony_ciiwl_dump_ini_special_mem_get_size(struct iwl_fw_runtime *fwrt,
200462306a36Sopenharmony_ci				  struct iwl_dump_ini_region_data *reg_data)
200562306a36Sopenharmony_ci{
200662306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
200762306a36Sopenharmony_ci	u32 size = le32_to_cpu(reg->special_mem.size);
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	if (size)
201062306a36Sopenharmony_ci		size += sizeof(struct iwl_fw_ini_special_device_memory) +
201162306a36Sopenharmony_ci			sizeof(struct iwl_fw_ini_error_dump_range);
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	return size;
201462306a36Sopenharmony_ci}
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_cistatic u32
201762306a36Sopenharmony_ciiwl_dump_ini_fw_pkt_get_size(struct iwl_fw_runtime *fwrt,
201862306a36Sopenharmony_ci			     struct iwl_dump_ini_region_data *reg_data)
201962306a36Sopenharmony_ci{
202062306a36Sopenharmony_ci	u32 size = 0;
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	if (!reg_data->dump_data->fw_pkt)
202362306a36Sopenharmony_ci		return 0;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	size += iwl_rx_packet_payload_len(reg_data->dump_data->fw_pkt);
202662306a36Sopenharmony_ci	if (size)
202762306a36Sopenharmony_ci		size += sizeof(struct iwl_fw_ini_error_dump) +
202862306a36Sopenharmony_ci			sizeof(struct iwl_fw_ini_error_dump_range);
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	return size;
203162306a36Sopenharmony_ci}
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_cistatic u32
203462306a36Sopenharmony_ciiwl_dump_ini_imr_get_size(struct iwl_fw_runtime *fwrt,
203562306a36Sopenharmony_ci			  struct iwl_dump_ini_region_data *reg_data)
203662306a36Sopenharmony_ci{
203762306a36Sopenharmony_ci	u32 ranges = 0;
203862306a36Sopenharmony_ci	u32 imr_enable = fwrt->trans->dbg.imr_data.imr_enable;
203962306a36Sopenharmony_ci	u32 imr_size = fwrt->trans->dbg.imr_data.imr_size;
204062306a36Sopenharmony_ci	u32 sram_size = fwrt->trans->dbg.imr_data.sram_size;
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	if (imr_enable == 0 || imr_size == 0 || sram_size == 0) {
204362306a36Sopenharmony_ci		IWL_DEBUG_INFO(fwrt,
204462306a36Sopenharmony_ci			       "WRT: Invalid imr data enable: %d, imr_size: %d, sram_size: %d\n",
204562306a36Sopenharmony_ci			       imr_enable, imr_size, sram_size);
204662306a36Sopenharmony_ci		return 0;
204762306a36Sopenharmony_ci	}
204862306a36Sopenharmony_ci	ranges = iwl_dump_ini_imr_ranges(fwrt, reg_data);
204962306a36Sopenharmony_ci	if (!ranges) {
205062306a36Sopenharmony_ci		IWL_ERR(fwrt, "WRT: ranges :=%d\n", ranges);
205162306a36Sopenharmony_ci		return 0;
205262306a36Sopenharmony_ci	}
205362306a36Sopenharmony_ci	imr_size += sizeof(struct iwl_fw_ini_error_dump) +
205462306a36Sopenharmony_ci		ranges * sizeof(struct iwl_fw_ini_error_dump_range);
205562306a36Sopenharmony_ci	return imr_size;
205662306a36Sopenharmony_ci}
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci/**
205962306a36Sopenharmony_ci * struct iwl_dump_ini_mem_ops - ini memory dump operations
206062306a36Sopenharmony_ci * @get_num_of_ranges: returns the number of memory ranges in the region.
206162306a36Sopenharmony_ci * @get_size: returns the total size of the region.
206262306a36Sopenharmony_ci * @fill_mem_hdr: fills region type specific headers and returns pointer to
206362306a36Sopenharmony_ci *	the first range or NULL if failed to fill headers.
206462306a36Sopenharmony_ci * @fill_range: copies a given memory range into the dump.
206562306a36Sopenharmony_ci *	Returns the size of the range or negative error value otherwise.
206662306a36Sopenharmony_ci */
206762306a36Sopenharmony_cistruct iwl_dump_ini_mem_ops {
206862306a36Sopenharmony_ci	u32 (*get_num_of_ranges)(struct iwl_fw_runtime *fwrt,
206962306a36Sopenharmony_ci				 struct iwl_dump_ini_region_data *reg_data);
207062306a36Sopenharmony_ci	u32 (*get_size)(struct iwl_fw_runtime *fwrt,
207162306a36Sopenharmony_ci			struct iwl_dump_ini_region_data *reg_data);
207262306a36Sopenharmony_ci	void *(*fill_mem_hdr)(struct iwl_fw_runtime *fwrt,
207362306a36Sopenharmony_ci			      struct iwl_dump_ini_region_data *reg_data,
207462306a36Sopenharmony_ci			      void *data, u32 data_len);
207562306a36Sopenharmony_ci	int (*fill_range)(struct iwl_fw_runtime *fwrt,
207662306a36Sopenharmony_ci			  struct iwl_dump_ini_region_data *reg_data,
207762306a36Sopenharmony_ci			  void *range, u32 range_len, int idx);
207862306a36Sopenharmony_ci};
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci/**
208162306a36Sopenharmony_ci * iwl_dump_ini_mem
208262306a36Sopenharmony_ci *
208362306a36Sopenharmony_ci * Creates a dump tlv and copy a memory region into it.
208462306a36Sopenharmony_ci * Returns the size of the current dump tlv or 0 if failed
208562306a36Sopenharmony_ci *
208662306a36Sopenharmony_ci * @fwrt: fw runtime struct
208762306a36Sopenharmony_ci * @list: list to add the dump tlv to
208862306a36Sopenharmony_ci * @reg_data: memory region
208962306a36Sopenharmony_ci * @ops: memory dump operations
209062306a36Sopenharmony_ci */
209162306a36Sopenharmony_cistatic u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list,
209262306a36Sopenharmony_ci			    struct iwl_dump_ini_region_data *reg_data,
209362306a36Sopenharmony_ci			    const struct iwl_dump_ini_mem_ops *ops)
209462306a36Sopenharmony_ci{
209562306a36Sopenharmony_ci	struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
209662306a36Sopenharmony_ci	struct iwl_fw_ini_dump_entry *entry;
209762306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_data *tlv;
209862306a36Sopenharmony_ci	struct iwl_fw_ini_error_dump_header *header;
209962306a36Sopenharmony_ci	u32 type = reg->type;
210062306a36Sopenharmony_ci	u32 id = le32_get_bits(reg->id, IWL_FW_INI_REGION_ID_MASK);
210162306a36Sopenharmony_ci	u32 num_of_ranges, i, size;
210262306a36Sopenharmony_ci	u8 *range;
210362306a36Sopenharmony_ci	u32 free_size;
210462306a36Sopenharmony_ci	u64 header_size;
210562306a36Sopenharmony_ci	u32 dump_policy = IWL_FW_INI_DUMP_VERBOSE;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	IWL_DEBUG_FW(fwrt, "WRT: Collecting region: dump type=%d, id=%d, type=%d\n",
210862306a36Sopenharmony_ci		     dump_policy, id, type);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	if (le32_to_cpu(reg->hdr.version) >= 2) {
211162306a36Sopenharmony_ci		u32 dp = le32_get_bits(reg->id,
211262306a36Sopenharmony_ci				       IWL_FW_INI_REGION_DUMP_POLICY_MASK);
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci		if (dump_policy == IWL_FW_INI_DUMP_VERBOSE &&
211562306a36Sopenharmony_ci		    !(dp & IWL_FW_INI_DEBUG_DUMP_POLICY_NO_LIMIT)) {
211662306a36Sopenharmony_ci			IWL_DEBUG_FW(fwrt,
211762306a36Sopenharmony_ci				     "WRT: no dump - type %d and policy mismatch=%d\n",
211862306a36Sopenharmony_ci				     dump_policy, dp);
211962306a36Sopenharmony_ci			return 0;
212062306a36Sopenharmony_ci		} else if (dump_policy == IWL_FW_INI_DUMP_MEDIUM &&
212162306a36Sopenharmony_ci			   !(dp & IWL_FW_IWL_DEBUG_DUMP_POLICY_MAX_LIMIT_5MB)) {
212262306a36Sopenharmony_ci			IWL_DEBUG_FW(fwrt,
212362306a36Sopenharmony_ci				     "WRT: no dump - type %d and policy mismatch=%d\n",
212462306a36Sopenharmony_ci				     dump_policy, dp);
212562306a36Sopenharmony_ci			return 0;
212662306a36Sopenharmony_ci		} else if (dump_policy == IWL_FW_INI_DUMP_BRIEF &&
212762306a36Sopenharmony_ci			   !(dp & IWL_FW_INI_DEBUG_DUMP_POLICY_MAX_LIMIT_600KB)) {
212862306a36Sopenharmony_ci			IWL_DEBUG_FW(fwrt,
212962306a36Sopenharmony_ci				     "WRT: no dump - type %d and policy mismatch=%d\n",
213062306a36Sopenharmony_ci				     dump_policy, dp);
213162306a36Sopenharmony_ci			return 0;
213262306a36Sopenharmony_ci		}
213362306a36Sopenharmony_ci	}
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	if (!ops->get_num_of_ranges || !ops->get_size || !ops->fill_mem_hdr ||
213662306a36Sopenharmony_ci	    !ops->fill_range) {
213762306a36Sopenharmony_ci		IWL_DEBUG_FW(fwrt, "WRT: no ops for collecting data\n");
213862306a36Sopenharmony_ci		return 0;
213962306a36Sopenharmony_ci	}
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	size = ops->get_size(fwrt, reg_data);
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	if (size < sizeof(*header)) {
214462306a36Sopenharmony_ci		IWL_DEBUG_FW(fwrt, "WRT: size didn't include space for header\n");
214562306a36Sopenharmony_ci		return 0;
214662306a36Sopenharmony_ci	}
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	entry = vzalloc(sizeof(*entry) + sizeof(*tlv) + size);
214962306a36Sopenharmony_ci	if (!entry)
215062306a36Sopenharmony_ci		return 0;
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	entry->size = sizeof(*tlv) + size;
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	tlv = (void *)entry->data;
215562306a36Sopenharmony_ci	tlv->type = reg->type;
215662306a36Sopenharmony_ci	tlv->sub_type = reg->sub_type;
215762306a36Sopenharmony_ci	tlv->sub_type_ver = reg->sub_type_ver;
215862306a36Sopenharmony_ci	tlv->reserved = reg->reserved;
215962306a36Sopenharmony_ci	tlv->len = cpu_to_le32(size);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	num_of_ranges = ops->get_num_of_ranges(fwrt, reg_data);
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	header = (void *)tlv->data;
216462306a36Sopenharmony_ci	header->region_id = cpu_to_le32(id);
216562306a36Sopenharmony_ci	header->num_of_ranges = cpu_to_le32(num_of_ranges);
216662306a36Sopenharmony_ci	header->name_len = cpu_to_le32(IWL_FW_INI_MAX_NAME);
216762306a36Sopenharmony_ci	memcpy(header->name, reg->name, IWL_FW_INI_MAX_NAME);
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	free_size = size;
217062306a36Sopenharmony_ci	range = ops->fill_mem_hdr(fwrt, reg_data, header, free_size);
217162306a36Sopenharmony_ci	if (!range) {
217262306a36Sopenharmony_ci		IWL_ERR(fwrt,
217362306a36Sopenharmony_ci			"WRT: Failed to fill region header: id=%d, type=%d\n",
217462306a36Sopenharmony_ci			id, type);
217562306a36Sopenharmony_ci		goto out_err;
217662306a36Sopenharmony_ci	}
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci	header_size = range - (u8 *)header;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	if (WARN(header_size > free_size,
218162306a36Sopenharmony_ci		 "header size %llu > free_size %d",
218262306a36Sopenharmony_ci		 header_size, free_size)) {
218362306a36Sopenharmony_ci		IWL_ERR(fwrt,
218462306a36Sopenharmony_ci			"WRT: fill_mem_hdr used more than given free_size\n");
218562306a36Sopenharmony_ci		goto out_err;
218662306a36Sopenharmony_ci	}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	free_size -= header_size;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	for (i = 0; i < num_of_ranges; i++) {
219162306a36Sopenharmony_ci		int range_size = ops->fill_range(fwrt, reg_data, range,
219262306a36Sopenharmony_ci						 free_size, i);
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci		if (range_size < 0) {
219562306a36Sopenharmony_ci			IWL_ERR(fwrt,
219662306a36Sopenharmony_ci				"WRT: Failed to dump region: id=%d, type=%d\n",
219762306a36Sopenharmony_ci				id, type);
219862306a36Sopenharmony_ci			goto out_err;
219962306a36Sopenharmony_ci		}
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci		if (WARN(range_size > free_size, "range_size %d > free_size %d",
220262306a36Sopenharmony_ci			 range_size, free_size)) {
220362306a36Sopenharmony_ci			IWL_ERR(fwrt,
220462306a36Sopenharmony_ci				"WRT: fill_raged used more than given free_size\n");
220562306a36Sopenharmony_ci			goto out_err;
220662306a36Sopenharmony_ci		}
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci		free_size -= range_size;
220962306a36Sopenharmony_ci		range = range + range_size;
221062306a36Sopenharmony_ci	}
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	list_add_tail(&entry->list, list);
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	return entry->size;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ciout_err:
221762306a36Sopenharmony_ci	vfree(entry);
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	return 0;
222062306a36Sopenharmony_ci}
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_cistatic u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt,
222362306a36Sopenharmony_ci			     struct iwl_fw_ini_trigger_tlv *trigger,
222462306a36Sopenharmony_ci			     struct list_head *list)
222562306a36Sopenharmony_ci{
222662306a36Sopenharmony_ci	struct iwl_fw_ini_dump_entry *entry;
222762306a36Sopenharmony_ci	struct iwl_fw_error_dump_data *tlv;
222862306a36Sopenharmony_ci	struct iwl_fw_ini_dump_info *dump;
222962306a36Sopenharmony_ci	struct iwl_dbg_tlv_node *node;
223062306a36Sopenharmony_ci	struct iwl_fw_ini_dump_cfg_name *cfg_name;
223162306a36Sopenharmony_ci	u32 size = sizeof(*tlv) + sizeof(*dump);
223262306a36Sopenharmony_ci	u32 num_of_cfg_names = 0;
223362306a36Sopenharmony_ci	u32 hw_type;
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci	list_for_each_entry(node, &fwrt->trans->dbg.debug_info_tlv_list, list) {
223662306a36Sopenharmony_ci		size += sizeof(*cfg_name);
223762306a36Sopenharmony_ci		num_of_cfg_names++;
223862306a36Sopenharmony_ci	}
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	entry = vzalloc(sizeof(*entry) + size);
224162306a36Sopenharmony_ci	if (!entry)
224262306a36Sopenharmony_ci		return 0;
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	entry->size = size;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	tlv = (void *)entry->data;
224762306a36Sopenharmony_ci	tlv->type = cpu_to_le32(IWL_INI_DUMP_INFO_TYPE);
224862306a36Sopenharmony_ci	tlv->len = cpu_to_le32(size - sizeof(*tlv));
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	dump = (void *)tlv->data;
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	dump->version = cpu_to_le32(IWL_INI_DUMP_VER);
225362306a36Sopenharmony_ci	dump->time_point = trigger->time_point;
225462306a36Sopenharmony_ci	dump->trigger_reason = trigger->trigger_reason;
225562306a36Sopenharmony_ci	dump->external_cfg_state =
225662306a36Sopenharmony_ci		cpu_to_le32(fwrt->trans->dbg.external_ini_cfg);
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	dump->ver_type = cpu_to_le32(fwrt->dump.fw_ver.type);
225962306a36Sopenharmony_ci	dump->ver_subtype = cpu_to_le32(fwrt->dump.fw_ver.subtype);
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	dump->hw_step = cpu_to_le32(fwrt->trans->hw_rev_step);
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	/*
226462306a36Sopenharmony_ci	 * Several HWs all have type == 0x42, so we'll override this value
226562306a36Sopenharmony_ci	 * according to the detected HW
226662306a36Sopenharmony_ci	 */
226762306a36Sopenharmony_ci	hw_type = CSR_HW_REV_TYPE(fwrt->trans->hw_rev);
226862306a36Sopenharmony_ci	if (hw_type == IWL_AX210_HW_TYPE) {
226962306a36Sopenharmony_ci		u32 prph_val = iwl_read_umac_prph(fwrt->trans, WFPM_OTP_CFG1_ADDR);
227062306a36Sopenharmony_ci		u32 is_jacket = !!(prph_val & WFPM_OTP_CFG1_IS_JACKET_BIT);
227162306a36Sopenharmony_ci		u32 is_cdb = !!(prph_val & WFPM_OTP_CFG1_IS_CDB_BIT);
227262306a36Sopenharmony_ci		u32 masked_bits = is_jacket | (is_cdb << 1);
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci		/*
227562306a36Sopenharmony_ci		 * The HW type depends on certain bits in this case, so add
227662306a36Sopenharmony_ci		 * these bits to the HW type. We won't have collisions since we
227762306a36Sopenharmony_ci		 * add these bits after the highest possible bit in the mask.
227862306a36Sopenharmony_ci		 */
227962306a36Sopenharmony_ci		hw_type |= masked_bits << IWL_AX210_HW_TYPE_ADDITION_SHIFT;
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci	dump->hw_type = cpu_to_le32(hw_type);
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	dump->rf_id_flavor =
228462306a36Sopenharmony_ci		cpu_to_le32(CSR_HW_RFID_FLAVOR(fwrt->trans->hw_rf_id));
228562306a36Sopenharmony_ci	dump->rf_id_dash = cpu_to_le32(CSR_HW_RFID_DASH(fwrt->trans->hw_rf_id));
228662306a36Sopenharmony_ci	dump->rf_id_step = cpu_to_le32(CSR_HW_RFID_STEP(fwrt->trans->hw_rf_id));
228762306a36Sopenharmony_ci	dump->rf_id_type = cpu_to_le32(CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id));
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci	dump->lmac_major = cpu_to_le32(fwrt->dump.fw_ver.lmac_major);
229062306a36Sopenharmony_ci	dump->lmac_minor = cpu_to_le32(fwrt->dump.fw_ver.lmac_minor);
229162306a36Sopenharmony_ci	dump->umac_major = cpu_to_le32(fwrt->dump.fw_ver.umac_major);
229262306a36Sopenharmony_ci	dump->umac_minor = cpu_to_le32(fwrt->dump.fw_ver.umac_minor);
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	dump->fw_mon_mode = cpu_to_le32(fwrt->trans->dbg.ini_dest);
229562306a36Sopenharmony_ci	dump->regions_mask = trigger->regions_mask &
229662306a36Sopenharmony_ci			     ~cpu_to_le64(fwrt->trans->dbg.unsupported_region_msk);
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	dump->build_tag_len = cpu_to_le32(sizeof(dump->build_tag));
229962306a36Sopenharmony_ci	memcpy(dump->build_tag, fwrt->fw->human_readable,
230062306a36Sopenharmony_ci	       sizeof(dump->build_tag));
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	cfg_name = dump->cfg_names;
230362306a36Sopenharmony_ci	dump->num_of_cfg_names = cpu_to_le32(num_of_cfg_names);
230462306a36Sopenharmony_ci	list_for_each_entry(node, &fwrt->trans->dbg.debug_info_tlv_list, list) {
230562306a36Sopenharmony_ci		struct iwl_fw_ini_debug_info_tlv *debug_info =
230662306a36Sopenharmony_ci			(void *)node->tlv.data;
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci		cfg_name->image_type = debug_info->image_type;
230962306a36Sopenharmony_ci		cfg_name->cfg_name_len =
231062306a36Sopenharmony_ci			cpu_to_le32(IWL_FW_INI_MAX_CFG_NAME);
231162306a36Sopenharmony_ci		memcpy(cfg_name->cfg_name, debug_info->debug_cfg_name,
231262306a36Sopenharmony_ci		       sizeof(cfg_name->cfg_name));
231362306a36Sopenharmony_ci		cfg_name++;
231462306a36Sopenharmony_ci	}
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	/* add dump info TLV to the beginning of the list since it needs to be
231762306a36Sopenharmony_ci	 * the first TLV in the dump
231862306a36Sopenharmony_ci	 */
231962306a36Sopenharmony_ci	list_add(&entry->list, list);
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	return entry->size;
232262306a36Sopenharmony_ci}
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_cistatic u32 iwl_dump_ini_file_name_info(struct iwl_fw_runtime *fwrt,
232562306a36Sopenharmony_ci				       struct list_head *list)
232662306a36Sopenharmony_ci{
232762306a36Sopenharmony_ci	struct iwl_fw_ini_dump_entry *entry;
232862306a36Sopenharmony_ci	struct iwl_dump_file_name_info *tlv;
232962306a36Sopenharmony_ci	u32 len = strnlen(fwrt->trans->dbg.dump_file_name_ext,
233062306a36Sopenharmony_ci			  IWL_FW_INI_MAX_NAME);
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	if (!fwrt->trans->dbg.dump_file_name_ext_valid)
233362306a36Sopenharmony_ci		return 0;
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	entry = vzalloc(sizeof(*entry) + sizeof(*tlv) + len);
233662306a36Sopenharmony_ci	if (!entry)
233762306a36Sopenharmony_ci		return 0;
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	entry->size = sizeof(*tlv) + len;
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	tlv = (void *)entry->data;
234262306a36Sopenharmony_ci	tlv->type = cpu_to_le32(IWL_INI_DUMP_NAME_TYPE);
234362306a36Sopenharmony_ci	tlv->len = cpu_to_le32(len);
234462306a36Sopenharmony_ci	memcpy(tlv->data, fwrt->trans->dbg.dump_file_name_ext, len);
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	/* add the dump file name extension tlv to the list */
234762306a36Sopenharmony_ci	list_add_tail(&entry->list, list);
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci	fwrt->trans->dbg.dump_file_name_ext_valid = false;
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	return entry->size;
235262306a36Sopenharmony_ci}
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_cistatic const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = {
235562306a36Sopenharmony_ci	[IWL_FW_INI_REGION_INVALID] = {},
235662306a36Sopenharmony_ci	[IWL_FW_INI_REGION_INTERNAL_BUFFER] = {
235762306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_single_range,
235862306a36Sopenharmony_ci		.get_size = iwl_dump_ini_mon_smem_get_size,
235962306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_mon_smem_fill_header,
236062306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_mon_smem_iter,
236162306a36Sopenharmony_ci	},
236262306a36Sopenharmony_ci	[IWL_FW_INI_REGION_DRAM_BUFFER] = {
236362306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_mon_dram_ranges,
236462306a36Sopenharmony_ci		.get_size = iwl_dump_ini_mon_dram_get_size,
236562306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_mon_dram_fill_header,
236662306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_mon_dram_iter,
236762306a36Sopenharmony_ci	},
236862306a36Sopenharmony_ci	[IWL_FW_INI_REGION_TXF] = {
236962306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_txf_ranges,
237062306a36Sopenharmony_ci		.get_size = iwl_dump_ini_txf_get_size,
237162306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
237262306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_txf_iter,
237362306a36Sopenharmony_ci	},
237462306a36Sopenharmony_ci	[IWL_FW_INI_REGION_RXF] = {
237562306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_single_range,
237662306a36Sopenharmony_ci		.get_size = iwl_dump_ini_rxf_get_size,
237762306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
237862306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_rxf_iter,
237962306a36Sopenharmony_ci	},
238062306a36Sopenharmony_ci	[IWL_FW_INI_REGION_LMAC_ERROR_TABLE] = {
238162306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_single_range,
238262306a36Sopenharmony_ci		.get_size = iwl_dump_ini_err_table_get_size,
238362306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_err_table_fill_header,
238462306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_err_table_iter,
238562306a36Sopenharmony_ci	},
238662306a36Sopenharmony_ci	[IWL_FW_INI_REGION_UMAC_ERROR_TABLE] = {
238762306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_single_range,
238862306a36Sopenharmony_ci		.get_size = iwl_dump_ini_err_table_get_size,
238962306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_err_table_fill_header,
239062306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_err_table_iter,
239162306a36Sopenharmony_ci	},
239262306a36Sopenharmony_ci	[IWL_FW_INI_REGION_RSP_OR_NOTIF] = {
239362306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_single_range,
239462306a36Sopenharmony_ci		.get_size = iwl_dump_ini_fw_pkt_get_size,
239562306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
239662306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_fw_pkt_iter,
239762306a36Sopenharmony_ci	},
239862306a36Sopenharmony_ci	[IWL_FW_INI_REGION_DEVICE_MEMORY] = {
239962306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_mem_ranges,
240062306a36Sopenharmony_ci		.get_size = iwl_dump_ini_mem_get_size,
240162306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
240262306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_dev_mem_iter,
240362306a36Sopenharmony_ci	},
240462306a36Sopenharmony_ci	[IWL_FW_INI_REGION_PERIPHERY_MAC] = {
240562306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_mem_ranges,
240662306a36Sopenharmony_ci		.get_size = iwl_dump_ini_mem_get_size,
240762306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
240862306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_prph_mac_iter,
240962306a36Sopenharmony_ci	},
241062306a36Sopenharmony_ci	[IWL_FW_INI_REGION_PERIPHERY_PHY] = {
241162306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_mem_ranges,
241262306a36Sopenharmony_ci		.get_size = iwl_dump_ini_mem_get_size,
241362306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
241462306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_prph_phy_iter,
241562306a36Sopenharmony_ci	},
241662306a36Sopenharmony_ci	[IWL_FW_INI_REGION_PERIPHERY_AUX] = {},
241762306a36Sopenharmony_ci	[IWL_FW_INI_REGION_PAGING] = {
241862306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
241962306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_paging_ranges,
242062306a36Sopenharmony_ci		.get_size = iwl_dump_ini_paging_get_size,
242162306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_paging_iter,
242262306a36Sopenharmony_ci	},
242362306a36Sopenharmony_ci	[IWL_FW_INI_REGION_CSR] = {
242462306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_mem_ranges,
242562306a36Sopenharmony_ci		.get_size = iwl_dump_ini_mem_get_size,
242662306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
242762306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_csr_iter,
242862306a36Sopenharmony_ci	},
242962306a36Sopenharmony_ci	[IWL_FW_INI_REGION_DRAM_IMR] = {
243062306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_imr_ranges,
243162306a36Sopenharmony_ci		.get_size = iwl_dump_ini_imr_get_size,
243262306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_imr_fill_header,
243362306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_imr_iter,
243462306a36Sopenharmony_ci	},
243562306a36Sopenharmony_ci	[IWL_FW_INI_REGION_PCI_IOSF_CONFIG] = {
243662306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_mem_ranges,
243762306a36Sopenharmony_ci		.get_size = iwl_dump_ini_mem_get_size,
243862306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_mem_fill_header,
243962306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_config_iter,
244062306a36Sopenharmony_ci	},
244162306a36Sopenharmony_ci	[IWL_FW_INI_REGION_SPECIAL_DEVICE_MEMORY] = {
244262306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_single_range,
244362306a36Sopenharmony_ci		.get_size = iwl_dump_ini_special_mem_get_size,
244462306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_special_mem_fill_header,
244562306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_special_mem_iter,
244662306a36Sopenharmony_ci	},
244762306a36Sopenharmony_ci	[IWL_FW_INI_REGION_DBGI_SRAM] = {
244862306a36Sopenharmony_ci		.get_num_of_ranges = iwl_dump_ini_mem_ranges,
244962306a36Sopenharmony_ci		.get_size = iwl_dump_ini_mon_dbgi_get_size,
245062306a36Sopenharmony_ci		.fill_mem_hdr = iwl_dump_ini_mon_dbgi_fill_header,
245162306a36Sopenharmony_ci		.fill_range = iwl_dump_ini_dbgi_sram_iter,
245262306a36Sopenharmony_ci	},
245362306a36Sopenharmony_ci};
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_cistatic u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt,
245662306a36Sopenharmony_ci				struct iwl_fwrt_dump_data *dump_data,
245762306a36Sopenharmony_ci				struct list_head *list)
245862306a36Sopenharmony_ci{
245962306a36Sopenharmony_ci	struct iwl_fw_ini_trigger_tlv *trigger = dump_data->trig;
246062306a36Sopenharmony_ci	enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trigger->time_point);
246162306a36Sopenharmony_ci	struct iwl_dump_ini_region_data reg_data = {
246262306a36Sopenharmony_ci		.dump_data = dump_data,
246362306a36Sopenharmony_ci	};
246462306a36Sopenharmony_ci	struct iwl_dump_ini_region_data imr_reg_data = {
246562306a36Sopenharmony_ci		.dump_data = dump_data,
246662306a36Sopenharmony_ci	};
246762306a36Sopenharmony_ci	int i;
246862306a36Sopenharmony_ci	u32 size = 0;
246962306a36Sopenharmony_ci	u64 regions_mask = le64_to_cpu(trigger->regions_mask) &
247062306a36Sopenharmony_ci			   ~(fwrt->trans->dbg.unsupported_region_msk);
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(trigger->regions_mask) != sizeof(regions_mask));
247362306a36Sopenharmony_ci	BUILD_BUG_ON((sizeof(trigger->regions_mask) * BITS_PER_BYTE) <
247462306a36Sopenharmony_ci		     ARRAY_SIZE(fwrt->trans->dbg.active_regions));
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(fwrt->trans->dbg.active_regions); i++) {
247762306a36Sopenharmony_ci		u32 reg_type;
247862306a36Sopenharmony_ci		struct iwl_fw_ini_region_tlv *reg;
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci		if (!(BIT_ULL(i) & regions_mask))
248162306a36Sopenharmony_ci			continue;
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci		reg_data.reg_tlv = fwrt->trans->dbg.active_regions[i];
248462306a36Sopenharmony_ci		if (!reg_data.reg_tlv) {
248562306a36Sopenharmony_ci			IWL_WARN(fwrt,
248662306a36Sopenharmony_ci				 "WRT: Unassigned region id %d, skipping\n", i);
248762306a36Sopenharmony_ci			continue;
248862306a36Sopenharmony_ci		}
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci		reg = (void *)reg_data.reg_tlv->data;
249162306a36Sopenharmony_ci		reg_type = reg->type;
249262306a36Sopenharmony_ci		if (reg_type >= ARRAY_SIZE(iwl_dump_ini_region_ops))
249362306a36Sopenharmony_ci			continue;
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci		if (reg_type == IWL_FW_INI_REGION_PERIPHERY_PHY &&
249662306a36Sopenharmony_ci		    tp_id != IWL_FW_INI_TIME_POINT_FW_ASSERT) {
249762306a36Sopenharmony_ci			IWL_WARN(fwrt,
249862306a36Sopenharmony_ci				 "WRT: trying to collect phy prph at time point: %d, skipping\n",
249962306a36Sopenharmony_ci				 tp_id);
250062306a36Sopenharmony_ci			continue;
250162306a36Sopenharmony_ci		}
250262306a36Sopenharmony_ci		/*
250362306a36Sopenharmony_ci		 * DRAM_IMR can be collected only for FW/HW error timepoint
250462306a36Sopenharmony_ci		 * when fw is not alive. In addition, it must be collected
250562306a36Sopenharmony_ci		 * lastly as it overwrites SRAM that can possibly contain
250662306a36Sopenharmony_ci		 * debug data which also need to be collected.
250762306a36Sopenharmony_ci		 */
250862306a36Sopenharmony_ci		if (reg_type == IWL_FW_INI_REGION_DRAM_IMR) {
250962306a36Sopenharmony_ci			if (tp_id == IWL_FW_INI_TIME_POINT_FW_ASSERT ||
251062306a36Sopenharmony_ci			    tp_id == IWL_FW_INI_TIME_POINT_FW_HW_ERROR)
251162306a36Sopenharmony_ci				imr_reg_data.reg_tlv = fwrt->trans->dbg.active_regions[i];
251262306a36Sopenharmony_ci			else
251362306a36Sopenharmony_ci				IWL_INFO(fwrt,
251462306a36Sopenharmony_ci					 "WRT: trying to collect DRAM_IMR at time point: %d, skipping\n",
251562306a36Sopenharmony_ci					 tp_id);
251662306a36Sopenharmony_ci		/* continue to next region */
251762306a36Sopenharmony_ci			continue;
251862306a36Sopenharmony_ci		}
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci		size += iwl_dump_ini_mem(fwrt, list, &reg_data,
252262306a36Sopenharmony_ci					 &iwl_dump_ini_region_ops[reg_type]);
252362306a36Sopenharmony_ci	}
252462306a36Sopenharmony_ci	/* collect DRAM_IMR region in the last */
252562306a36Sopenharmony_ci	if (imr_reg_data.reg_tlv)
252662306a36Sopenharmony_ci		size += iwl_dump_ini_mem(fwrt, list, &reg_data,
252762306a36Sopenharmony_ci					 &iwl_dump_ini_region_ops[IWL_FW_INI_REGION_DRAM_IMR]);
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	if (size) {
253062306a36Sopenharmony_ci		size += iwl_dump_ini_file_name_info(fwrt, list);
253162306a36Sopenharmony_ci		size += iwl_dump_ini_info(fwrt, trigger, list);
253262306a36Sopenharmony_ci	}
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	return size;
253562306a36Sopenharmony_ci}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_cistatic bool iwl_fw_ini_trigger_on(struct iwl_fw_runtime *fwrt,
253862306a36Sopenharmony_ci				  struct iwl_fw_ini_trigger_tlv *trig)
253962306a36Sopenharmony_ci{
254062306a36Sopenharmony_ci	enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trig->time_point);
254162306a36Sopenharmony_ci	u32 usec = le32_to_cpu(trig->ignore_consec);
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	if (!iwl_trans_dbg_ini_valid(fwrt->trans) ||
254462306a36Sopenharmony_ci	    tp_id == IWL_FW_INI_TIME_POINT_INVALID ||
254562306a36Sopenharmony_ci	    tp_id >= IWL_FW_INI_TIME_POINT_NUM ||
254662306a36Sopenharmony_ci	    iwl_fw_dbg_no_trig_window(fwrt, tp_id, usec))
254762306a36Sopenharmony_ci		return false;
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci	return true;
255062306a36Sopenharmony_ci}
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_cistatic u32 iwl_dump_ini_file_gen(struct iwl_fw_runtime *fwrt,
255362306a36Sopenharmony_ci				 struct iwl_fwrt_dump_data *dump_data,
255462306a36Sopenharmony_ci				 struct list_head *list)
255562306a36Sopenharmony_ci{
255662306a36Sopenharmony_ci	struct iwl_fw_ini_trigger_tlv *trigger = dump_data->trig;
255762306a36Sopenharmony_ci	struct iwl_fw_ini_dump_entry *entry;
255862306a36Sopenharmony_ci	struct iwl_fw_ini_dump_file_hdr *hdr;
255962306a36Sopenharmony_ci	u32 size;
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	if (!trigger || !iwl_fw_ini_trigger_on(fwrt, trigger) ||
256262306a36Sopenharmony_ci	    !le64_to_cpu(trigger->regions_mask))
256362306a36Sopenharmony_ci		return 0;
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci	entry = vzalloc(sizeof(*entry) + sizeof(*hdr));
256662306a36Sopenharmony_ci	if (!entry)
256762306a36Sopenharmony_ci		return 0;
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	entry->size = sizeof(*hdr);
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	size = iwl_dump_ini_trigger(fwrt, dump_data, list);
257262306a36Sopenharmony_ci	if (!size) {
257362306a36Sopenharmony_ci		vfree(entry);
257462306a36Sopenharmony_ci		return 0;
257562306a36Sopenharmony_ci	}
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	hdr = (void *)entry->data;
257862306a36Sopenharmony_ci	hdr->barker = cpu_to_le32(IWL_FW_INI_ERROR_DUMP_BARKER);
257962306a36Sopenharmony_ci	hdr->file_len = cpu_to_le32(size + entry->size);
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	list_add(&entry->list, list);
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	return le32_to_cpu(hdr->file_len);
258462306a36Sopenharmony_ci}
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_cistatic inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt,
258762306a36Sopenharmony_ci					 const struct iwl_fw_dump_desc *desc)
258862306a36Sopenharmony_ci{
258962306a36Sopenharmony_ci	if (desc && desc != &iwl_dump_desc_assert)
259062306a36Sopenharmony_ci		kfree(desc);
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci	fwrt->dump.lmac_err_id[0] = 0;
259362306a36Sopenharmony_ci	if (fwrt->smem_cfg.num_lmacs > 1)
259462306a36Sopenharmony_ci		fwrt->dump.lmac_err_id[1] = 0;
259562306a36Sopenharmony_ci	fwrt->dump.umac_err_id = 0;
259662306a36Sopenharmony_ci}
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_cistatic void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
259962306a36Sopenharmony_ci			      struct iwl_fwrt_dump_data *dump_data)
260062306a36Sopenharmony_ci{
260162306a36Sopenharmony_ci	struct iwl_fw_dump_ptrs fw_error_dump = {};
260262306a36Sopenharmony_ci	struct iwl_fw_error_dump_file *dump_file;
260362306a36Sopenharmony_ci	struct scatterlist *sg_dump_data;
260462306a36Sopenharmony_ci	u32 file_len;
260562306a36Sopenharmony_ci	u32 dump_mask = fwrt->fw->dbg.dump_mask;
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	dump_file = iwl_fw_error_dump_file(fwrt, &fw_error_dump, dump_data);
260862306a36Sopenharmony_ci	if (!dump_file)
260962306a36Sopenharmony_ci		return;
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci	if (dump_data->monitor_only)
261262306a36Sopenharmony_ci		dump_mask &= BIT(IWL_FW_ERROR_DUMP_FW_MONITOR);
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	fw_error_dump.trans_ptr = iwl_trans_dump_data(fwrt->trans, dump_mask,
261562306a36Sopenharmony_ci						      fwrt->sanitize_ops,
261662306a36Sopenharmony_ci						      fwrt->sanitize_ctx);
261762306a36Sopenharmony_ci	file_len = le32_to_cpu(dump_file->file_len);
261862306a36Sopenharmony_ci	fw_error_dump.fwrt_len = file_len;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	if (fw_error_dump.trans_ptr) {
262162306a36Sopenharmony_ci		file_len += fw_error_dump.trans_ptr->len;
262262306a36Sopenharmony_ci		dump_file->file_len = cpu_to_le32(file_len);
262362306a36Sopenharmony_ci	}
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	sg_dump_data = alloc_sgtable(file_len);
262662306a36Sopenharmony_ci	if (sg_dump_data) {
262762306a36Sopenharmony_ci		sg_pcopy_from_buffer(sg_dump_data,
262862306a36Sopenharmony_ci				     sg_nents(sg_dump_data),
262962306a36Sopenharmony_ci				     fw_error_dump.fwrt_ptr,
263062306a36Sopenharmony_ci				     fw_error_dump.fwrt_len, 0);
263162306a36Sopenharmony_ci		if (fw_error_dump.trans_ptr)
263262306a36Sopenharmony_ci			sg_pcopy_from_buffer(sg_dump_data,
263362306a36Sopenharmony_ci					     sg_nents(sg_dump_data),
263462306a36Sopenharmony_ci					     fw_error_dump.trans_ptr->data,
263562306a36Sopenharmony_ci					     fw_error_dump.trans_ptr->len,
263662306a36Sopenharmony_ci					     fw_error_dump.fwrt_len);
263762306a36Sopenharmony_ci		dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len,
263862306a36Sopenharmony_ci			       GFP_KERNEL);
263962306a36Sopenharmony_ci	}
264062306a36Sopenharmony_ci	vfree(fw_error_dump.fwrt_ptr);
264162306a36Sopenharmony_ci	vfree(fw_error_dump.trans_ptr);
264262306a36Sopenharmony_ci}
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_cistatic void iwl_dump_ini_list_free(struct list_head *list)
264562306a36Sopenharmony_ci{
264662306a36Sopenharmony_ci	while (!list_empty(list)) {
264762306a36Sopenharmony_ci		struct iwl_fw_ini_dump_entry *entry =
264862306a36Sopenharmony_ci			list_entry(list->next, typeof(*entry), list);
264962306a36Sopenharmony_ci
265062306a36Sopenharmony_ci		list_del(&entry->list);
265162306a36Sopenharmony_ci		vfree(entry);
265262306a36Sopenharmony_ci	}
265362306a36Sopenharmony_ci}
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_cistatic void iwl_fw_error_dump_data_free(struct iwl_fwrt_dump_data *dump_data)
265662306a36Sopenharmony_ci{
265762306a36Sopenharmony_ci	dump_data->trig = NULL;
265862306a36Sopenharmony_ci	kfree(dump_data->fw_pkt);
265962306a36Sopenharmony_ci	dump_data->fw_pkt = NULL;
266062306a36Sopenharmony_ci}
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_cistatic void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt,
266362306a36Sopenharmony_ci				  struct iwl_fwrt_dump_data *dump_data)
266462306a36Sopenharmony_ci{
266562306a36Sopenharmony_ci	LIST_HEAD(dump_list);
266662306a36Sopenharmony_ci	struct scatterlist *sg_dump_data;
266762306a36Sopenharmony_ci	u32 file_len = iwl_dump_ini_file_gen(fwrt, dump_data, &dump_list);
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci	if (!file_len)
267062306a36Sopenharmony_ci		return;
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	sg_dump_data = alloc_sgtable(file_len);
267362306a36Sopenharmony_ci	if (sg_dump_data) {
267462306a36Sopenharmony_ci		struct iwl_fw_ini_dump_entry *entry;
267562306a36Sopenharmony_ci		int sg_entries = sg_nents(sg_dump_data);
267662306a36Sopenharmony_ci		u32 offs = 0;
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_ci		list_for_each_entry(entry, &dump_list, list) {
267962306a36Sopenharmony_ci			sg_pcopy_from_buffer(sg_dump_data, sg_entries,
268062306a36Sopenharmony_ci					     entry->data, entry->size, offs);
268162306a36Sopenharmony_ci			offs += entry->size;
268262306a36Sopenharmony_ci		}
268362306a36Sopenharmony_ci		dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len,
268462306a36Sopenharmony_ci			       GFP_KERNEL);
268562306a36Sopenharmony_ci	}
268662306a36Sopenharmony_ci	iwl_dump_ini_list_free(&dump_list);
268762306a36Sopenharmony_ci}
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ciconst struct iwl_fw_dump_desc iwl_dump_desc_assert = {
269062306a36Sopenharmony_ci	.trig_desc = {
269162306a36Sopenharmony_ci		.type = cpu_to_le32(FW_DBG_TRIGGER_FW_ASSERT),
269262306a36Sopenharmony_ci	},
269362306a36Sopenharmony_ci};
269462306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_dump_desc_assert);
269562306a36Sopenharmony_ci
269662306a36Sopenharmony_ciint iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
269762306a36Sopenharmony_ci			    const struct iwl_fw_dump_desc *desc,
269862306a36Sopenharmony_ci			    bool monitor_only,
269962306a36Sopenharmony_ci			    unsigned int delay)
270062306a36Sopenharmony_ci{
270162306a36Sopenharmony_ci	struct iwl_fwrt_wk_data *wk_data;
270262306a36Sopenharmony_ci	unsigned long idx;
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci	if (iwl_trans_dbg_ini_valid(fwrt->trans)) {
270562306a36Sopenharmony_ci		iwl_fw_free_dump_desc(fwrt, desc);
270662306a36Sopenharmony_ci		return 0;
270762306a36Sopenharmony_ci	}
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci	/*
271062306a36Sopenharmony_ci	 * Check there is an available worker.
271162306a36Sopenharmony_ci	 * ffz return value is undefined if no zero exists,
271262306a36Sopenharmony_ci	 * so check against ~0UL first.
271362306a36Sopenharmony_ci	 */
271462306a36Sopenharmony_ci	if (fwrt->dump.active_wks == ~0UL)
271562306a36Sopenharmony_ci		return -EBUSY;
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci	idx = ffz(fwrt->dump.active_wks);
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	if (idx >= IWL_FW_RUNTIME_DUMP_WK_NUM ||
272062306a36Sopenharmony_ci	    test_and_set_bit(fwrt->dump.wks[idx].idx, &fwrt->dump.active_wks))
272162306a36Sopenharmony_ci		return -EBUSY;
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	wk_data = &fwrt->dump.wks[idx];
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci	if (WARN_ON(wk_data->dump_data.desc))
272662306a36Sopenharmony_ci		iwl_fw_free_dump_desc(fwrt, wk_data->dump_data.desc);
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_ci	wk_data->dump_data.desc = desc;
272962306a36Sopenharmony_ci	wk_data->dump_data.monitor_only = monitor_only;
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci	IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n",
273262306a36Sopenharmony_ci		 le32_to_cpu(desc->trig_desc.type));
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	schedule_delayed_work(&wk_data->wk, usecs_to_jiffies(delay));
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci	return 0;
273762306a36Sopenharmony_ci}
273862306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_desc);
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ciint iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt,
274162306a36Sopenharmony_ci			     enum iwl_fw_dbg_trigger trig_type)
274262306a36Sopenharmony_ci{
274362306a36Sopenharmony_ci	if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status))
274462306a36Sopenharmony_ci		return -EIO;
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci	if (iwl_trans_dbg_ini_valid(fwrt->trans)) {
274762306a36Sopenharmony_ci		if (trig_type != FW_DBG_TRIGGER_ALIVE_TIMEOUT &&
274862306a36Sopenharmony_ci		    trig_type != FW_DBG_TRIGGER_DRIVER)
274962306a36Sopenharmony_ci			return -EIO;
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci		iwl_dbg_tlv_time_point(fwrt,
275262306a36Sopenharmony_ci				       IWL_FW_INI_TIME_POINT_HOST_ALIVE_TIMEOUT,
275362306a36Sopenharmony_ci				       NULL);
275462306a36Sopenharmony_ci	} else {
275562306a36Sopenharmony_ci		struct iwl_fw_dump_desc *iwl_dump_error_desc;
275662306a36Sopenharmony_ci		int ret;
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci		iwl_dump_error_desc =
275962306a36Sopenharmony_ci			kmalloc(sizeof(*iwl_dump_error_desc), GFP_KERNEL);
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci		if (!iwl_dump_error_desc)
276262306a36Sopenharmony_ci			return -ENOMEM;
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci		iwl_dump_error_desc->trig_desc.type = cpu_to_le32(trig_type);
276562306a36Sopenharmony_ci		iwl_dump_error_desc->len = 0;
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_ci		ret = iwl_fw_dbg_collect_desc(fwrt, iwl_dump_error_desc,
276862306a36Sopenharmony_ci					      false, 0);
276962306a36Sopenharmony_ci		if (ret) {
277062306a36Sopenharmony_ci			kfree(iwl_dump_error_desc);
277162306a36Sopenharmony_ci			return ret;
277262306a36Sopenharmony_ci		}
277362306a36Sopenharmony_ci	}
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci	iwl_trans_sync_nmi(fwrt->trans);
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci	return 0;
277862306a36Sopenharmony_ci}
277962306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_fw_dbg_error_collect);
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ciint iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
278262306a36Sopenharmony_ci		       enum iwl_fw_dbg_trigger trig,
278362306a36Sopenharmony_ci		       const char *str, size_t len,
278462306a36Sopenharmony_ci		       struct iwl_fw_dbg_trigger_tlv *trigger)
278562306a36Sopenharmony_ci{
278662306a36Sopenharmony_ci	struct iwl_fw_dump_desc *desc;
278762306a36Sopenharmony_ci	unsigned int delay = 0;
278862306a36Sopenharmony_ci	bool monitor_only = false;
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	if (trigger) {
279162306a36Sopenharmony_ci		u16 occurrences = le16_to_cpu(trigger->occurrences) - 1;
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci		if (!le16_to_cpu(trigger->occurrences))
279462306a36Sopenharmony_ci			return 0;
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ci		if (trigger->flags & IWL_FW_DBG_FORCE_RESTART) {
279762306a36Sopenharmony_ci			IWL_WARN(fwrt, "Force restart: trigger %d fired.\n",
279862306a36Sopenharmony_ci				 trig);
279962306a36Sopenharmony_ci			iwl_force_nmi(fwrt->trans);
280062306a36Sopenharmony_ci			return 0;
280162306a36Sopenharmony_ci		}
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci		trigger->occurrences = cpu_to_le16(occurrences);
280462306a36Sopenharmony_ci		monitor_only = trigger->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY;
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci		/* convert msec to usec */
280762306a36Sopenharmony_ci		delay = le32_to_cpu(trigger->stop_delay) * USEC_PER_MSEC;
280862306a36Sopenharmony_ci	}
280962306a36Sopenharmony_ci
281062306a36Sopenharmony_ci	desc = kzalloc(struct_size(desc, trig_desc.data, len), GFP_ATOMIC);
281162306a36Sopenharmony_ci	if (!desc)
281262306a36Sopenharmony_ci		return -ENOMEM;
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci	desc->len = len;
281662306a36Sopenharmony_ci	desc->trig_desc.type = cpu_to_le32(trig);
281762306a36Sopenharmony_ci	memcpy(desc->trig_desc.data, str, len);
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_ci	return iwl_fw_dbg_collect_desc(fwrt, desc, monitor_only, delay);
282062306a36Sopenharmony_ci}
282162306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_fw_dbg_collect);
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ciint iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
282462306a36Sopenharmony_ci			    struct iwl_fw_dbg_trigger_tlv *trigger,
282562306a36Sopenharmony_ci			    const char *fmt, ...)
282662306a36Sopenharmony_ci{
282762306a36Sopenharmony_ci	int ret, len = 0;
282862306a36Sopenharmony_ci	char buf[64];
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci	if (iwl_trans_dbg_ini_valid(fwrt->trans))
283162306a36Sopenharmony_ci		return 0;
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci	if (fmt) {
283462306a36Sopenharmony_ci		va_list ap;
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci		buf[sizeof(buf) - 1] = '\0';
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci		va_start(ap, fmt);
283962306a36Sopenharmony_ci		vsnprintf(buf, sizeof(buf), fmt, ap);
284062306a36Sopenharmony_ci		va_end(ap);
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci		/* check for truncation */
284362306a36Sopenharmony_ci		if (WARN_ON_ONCE(buf[sizeof(buf) - 1]))
284462306a36Sopenharmony_ci			buf[sizeof(buf) - 1] = '\0';
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci		len = strlen(buf) + 1;
284762306a36Sopenharmony_ci	}
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_ci	ret = iwl_fw_dbg_collect(fwrt, le32_to_cpu(trigger->id), buf, len,
285062306a36Sopenharmony_ci				 trigger);
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci	if (ret)
285362306a36Sopenharmony_ci		return ret;
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	return 0;
285662306a36Sopenharmony_ci}
285762306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_trig);
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ciint iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id)
286062306a36Sopenharmony_ci{
286162306a36Sopenharmony_ci	u8 *ptr;
286262306a36Sopenharmony_ci	int ret;
286362306a36Sopenharmony_ci	int i;
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	if (WARN_ONCE(conf_id >= ARRAY_SIZE(fwrt->fw->dbg.conf_tlv),
286662306a36Sopenharmony_ci		      "Invalid configuration %d\n", conf_id))
286762306a36Sopenharmony_ci		return -EINVAL;
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	/* EARLY START - firmware's configuration is hard coded */
287062306a36Sopenharmony_ci	if ((!fwrt->fw->dbg.conf_tlv[conf_id] ||
287162306a36Sopenharmony_ci	     !fwrt->fw->dbg.conf_tlv[conf_id]->num_of_hcmds) &&
287262306a36Sopenharmony_ci	    conf_id == FW_DBG_START_FROM_ALIVE)
287362306a36Sopenharmony_ci		return 0;
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_ci	if (!fwrt->fw->dbg.conf_tlv[conf_id])
287662306a36Sopenharmony_ci		return -EINVAL;
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci	if (fwrt->dump.conf != FW_DBG_INVALID)
287962306a36Sopenharmony_ci		IWL_INFO(fwrt, "FW already configured (%d) - re-configuring\n",
288062306a36Sopenharmony_ci			 fwrt->dump.conf);
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci	/* Send all HCMDs for configuring the FW debug */
288362306a36Sopenharmony_ci	ptr = (void *)&fwrt->fw->dbg.conf_tlv[conf_id]->hcmd;
288462306a36Sopenharmony_ci	for (i = 0; i < fwrt->fw->dbg.conf_tlv[conf_id]->num_of_hcmds; i++) {
288562306a36Sopenharmony_ci		struct iwl_fw_dbg_conf_hcmd *cmd = (void *)ptr;
288662306a36Sopenharmony_ci		struct iwl_host_cmd hcmd = {
288762306a36Sopenharmony_ci			.id = cmd->id,
288862306a36Sopenharmony_ci			.len = { le16_to_cpu(cmd->len), },
288962306a36Sopenharmony_ci			.data = { cmd->data, },
289062306a36Sopenharmony_ci		};
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci		ret = iwl_trans_send_cmd(fwrt->trans, &hcmd);
289362306a36Sopenharmony_ci		if (ret)
289462306a36Sopenharmony_ci			return ret;
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_ci		ptr += sizeof(*cmd);
289762306a36Sopenharmony_ci		ptr += le16_to_cpu(cmd->len);
289862306a36Sopenharmony_ci	}
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci	fwrt->dump.conf = conf_id;
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci	return 0;
290362306a36Sopenharmony_ci}
290462306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_fw_start_dbg_conf);
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_civoid iwl_send_dbg_dump_complete_cmd(struct iwl_fw_runtime *fwrt,
290762306a36Sopenharmony_ci				    u32 timepoint,
290862306a36Sopenharmony_ci				    u32 timepoint_data)
290962306a36Sopenharmony_ci{
291062306a36Sopenharmony_ci	struct iwl_dbg_dump_complete_cmd hcmd_data;
291162306a36Sopenharmony_ci	struct iwl_host_cmd hcmd = {
291262306a36Sopenharmony_ci		.id = WIDE_ID(DEBUG_GROUP, FW_DUMP_COMPLETE_CMD),
291362306a36Sopenharmony_ci		.data[0] = &hcmd_data,
291462306a36Sopenharmony_ci		.len[0] = sizeof(hcmd_data),
291562306a36Sopenharmony_ci	};
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status))
291862306a36Sopenharmony_ci		return;
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci	if (fw_has_capa(&fwrt->fw->ucode_capa,
292162306a36Sopenharmony_ci			IWL_UCODE_TLV_CAPA_DUMP_COMPLETE_SUPPORT)) {
292262306a36Sopenharmony_ci		hcmd_data.tp = cpu_to_le32(timepoint);
292362306a36Sopenharmony_ci		hcmd_data.tp_data = cpu_to_le32(timepoint_data);
292462306a36Sopenharmony_ci		iwl_trans_send_cmd(fwrt->trans, &hcmd);
292562306a36Sopenharmony_ci	}
292662306a36Sopenharmony_ci}
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci/* this function assumes dump_start was called beforehand and dump_end will be
292962306a36Sopenharmony_ci * called afterwards
293062306a36Sopenharmony_ci */
293162306a36Sopenharmony_cistatic void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx)
293262306a36Sopenharmony_ci{
293362306a36Sopenharmony_ci	struct iwl_fw_dbg_params params = {0};
293462306a36Sopenharmony_ci	struct iwl_fwrt_dump_data *dump_data =
293562306a36Sopenharmony_ci		&fwrt->dump.wks[wk_idx].dump_data;
293662306a36Sopenharmony_ci	u32 policy;
293762306a36Sopenharmony_ci	u32 time_point;
293862306a36Sopenharmony_ci	if (!test_bit(wk_idx, &fwrt->dump.active_wks))
293962306a36Sopenharmony_ci		return;
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci	if (!dump_data->trig) {
294262306a36Sopenharmony_ci		IWL_ERR(fwrt, "dump trigger data is not set\n");
294362306a36Sopenharmony_ci		goto out;
294462306a36Sopenharmony_ci	}
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci	if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status)) {
294762306a36Sopenharmony_ci		IWL_ERR(fwrt, "Device is not enabled - cannot dump error\n");
294862306a36Sopenharmony_ci		goto out;
294962306a36Sopenharmony_ci	}
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_ci	/* there's no point in fw dump if the bus is dead */
295262306a36Sopenharmony_ci	if (test_bit(STATUS_TRANS_DEAD, &fwrt->trans->status)) {
295362306a36Sopenharmony_ci		IWL_ERR(fwrt, "Skip fw error dump since bus is dead\n");
295462306a36Sopenharmony_ci		goto out;
295562306a36Sopenharmony_ci	}
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci	iwl_fw_dbg_stop_restart_recording(fwrt, &params, true);
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ci	IWL_DEBUG_FW_INFO(fwrt, "WRT: Data collection start\n");
296062306a36Sopenharmony_ci	if (iwl_trans_dbg_ini_valid(fwrt->trans))
296162306a36Sopenharmony_ci		iwl_fw_error_ini_dump(fwrt, &fwrt->dump.wks[wk_idx].dump_data);
296262306a36Sopenharmony_ci	else
296362306a36Sopenharmony_ci		iwl_fw_error_dump(fwrt, &fwrt->dump.wks[wk_idx].dump_data);
296462306a36Sopenharmony_ci	IWL_DEBUG_FW_INFO(fwrt, "WRT: Data collection done\n");
296562306a36Sopenharmony_ci
296662306a36Sopenharmony_ci	iwl_fw_dbg_stop_restart_recording(fwrt, &params, false);
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci	policy = le32_to_cpu(dump_data->trig->apply_policy);
296962306a36Sopenharmony_ci	time_point = le32_to_cpu(dump_data->trig->time_point);
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci	if (policy & IWL_FW_INI_APPLY_POLICY_DUMP_COMPLETE_CMD) {
297262306a36Sopenharmony_ci		IWL_DEBUG_FW_INFO(fwrt, "WRT: sending dump complete\n");
297362306a36Sopenharmony_ci		iwl_send_dbg_dump_complete_cmd(fwrt, time_point, 0);
297462306a36Sopenharmony_ci	}
297562306a36Sopenharmony_ci	if (fwrt->trans->dbg.last_tp_resetfw == IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY)
297662306a36Sopenharmony_ci		iwl_force_nmi(fwrt->trans);
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ciout:
297962306a36Sopenharmony_ci	if (iwl_trans_dbg_ini_valid(fwrt->trans)) {
298062306a36Sopenharmony_ci		iwl_fw_error_dump_data_free(dump_data);
298162306a36Sopenharmony_ci	} else {
298262306a36Sopenharmony_ci		iwl_fw_free_dump_desc(fwrt, dump_data->desc);
298362306a36Sopenharmony_ci		dump_data->desc = NULL;
298462306a36Sopenharmony_ci	}
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_ci	clear_bit(wk_idx, &fwrt->dump.active_wks);
298762306a36Sopenharmony_ci}
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_ciint iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt,
299062306a36Sopenharmony_ci			   struct iwl_fwrt_dump_data *dump_data,
299162306a36Sopenharmony_ci			   bool sync)
299262306a36Sopenharmony_ci{
299362306a36Sopenharmony_ci	struct iwl_fw_ini_trigger_tlv *trig = dump_data->trig;
299462306a36Sopenharmony_ci	enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trig->time_point);
299562306a36Sopenharmony_ci	u32 occur, delay;
299662306a36Sopenharmony_ci	unsigned long idx;
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci	if (!iwl_fw_ini_trigger_on(fwrt, trig)) {
299962306a36Sopenharmony_ci		IWL_WARN(fwrt, "WRT: Trigger %d is not active, aborting dump\n",
300062306a36Sopenharmony_ci			 tp_id);
300162306a36Sopenharmony_ci		return -EINVAL;
300262306a36Sopenharmony_ci	}
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	delay = le32_to_cpu(trig->dump_delay);
300562306a36Sopenharmony_ci	occur = le32_to_cpu(trig->occurrences);
300662306a36Sopenharmony_ci	if (!occur)
300762306a36Sopenharmony_ci		return 0;
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci	trig->occurrences = cpu_to_le32(--occur);
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci	/* Check there is an available worker.
301262306a36Sopenharmony_ci	 * ffz return value is undefined if no zero exists,
301362306a36Sopenharmony_ci	 * so check against ~0UL first.
301462306a36Sopenharmony_ci	 */
301562306a36Sopenharmony_ci	if (fwrt->dump.active_wks == ~0UL)
301662306a36Sopenharmony_ci		return -EBUSY;
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci	idx = ffz(fwrt->dump.active_wks);
301962306a36Sopenharmony_ci
302062306a36Sopenharmony_ci	if (idx >= IWL_FW_RUNTIME_DUMP_WK_NUM ||
302162306a36Sopenharmony_ci	    test_and_set_bit(fwrt->dump.wks[idx].idx, &fwrt->dump.active_wks))
302262306a36Sopenharmony_ci		return -EBUSY;
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci	fwrt->dump.wks[idx].dump_data = *dump_data;
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci	if (sync)
302762306a36Sopenharmony_ci		delay = 0;
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci	IWL_WARN(fwrt,
303062306a36Sopenharmony_ci		 "WRT: Collecting data: ini trigger %d fired (delay=%dms).\n",
303162306a36Sopenharmony_ci		 tp_id, (u32)(delay / USEC_PER_MSEC));
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci	if (sync)
303462306a36Sopenharmony_ci		iwl_fw_dbg_collect_sync(fwrt, idx);
303562306a36Sopenharmony_ci	else
303662306a36Sopenharmony_ci		schedule_delayed_work(&fwrt->dump.wks[idx].wk, usecs_to_jiffies(delay));
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_ci	return 0;
303962306a36Sopenharmony_ci}
304062306a36Sopenharmony_ci
304162306a36Sopenharmony_civoid iwl_fw_error_dump_wk(struct work_struct *work)
304262306a36Sopenharmony_ci{
304362306a36Sopenharmony_ci	struct iwl_fwrt_wk_data *wks =
304462306a36Sopenharmony_ci		container_of(work, typeof(*wks), wk.work);
304562306a36Sopenharmony_ci	struct iwl_fw_runtime *fwrt =
304662306a36Sopenharmony_ci		container_of(wks, typeof(*fwrt), dump.wks[wks->idx]);
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci	/* assumes the op mode mutex is locked in dump_start since
304962306a36Sopenharmony_ci	 * iwl_fw_dbg_collect_sync can't run in parallel
305062306a36Sopenharmony_ci	 */
305162306a36Sopenharmony_ci	if (fwrt->ops && fwrt->ops->dump_start)
305262306a36Sopenharmony_ci		fwrt->ops->dump_start(fwrt->ops_ctx);
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ci	iwl_fw_dbg_collect_sync(fwrt, wks->idx);
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci	if (fwrt->ops && fwrt->ops->dump_end)
305762306a36Sopenharmony_ci		fwrt->ops->dump_end(fwrt->ops_ctx);
305862306a36Sopenharmony_ci}
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_civoid iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt)
306162306a36Sopenharmony_ci{
306262306a36Sopenharmony_ci	const struct iwl_cfg *cfg = fwrt->trans->cfg;
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	if (!iwl_fw_dbg_is_d3_debug_enabled(fwrt))
306562306a36Sopenharmony_ci		return;
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_ci	if (!fwrt->dump.d3_debug_data) {
306862306a36Sopenharmony_ci		fwrt->dump.d3_debug_data = kmalloc(cfg->d3_debug_data_length,
306962306a36Sopenharmony_ci						   GFP_KERNEL);
307062306a36Sopenharmony_ci		if (!fwrt->dump.d3_debug_data) {
307162306a36Sopenharmony_ci			IWL_ERR(fwrt,
307262306a36Sopenharmony_ci				"failed to allocate memory for D3 debug data\n");
307362306a36Sopenharmony_ci			return;
307462306a36Sopenharmony_ci		}
307562306a36Sopenharmony_ci	}
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_ci	/* if the buffer holds previous debug data it is overwritten */
307862306a36Sopenharmony_ci	iwl_trans_read_mem_bytes(fwrt->trans, cfg->d3_debug_data_base_addr,
307962306a36Sopenharmony_ci				 fwrt->dump.d3_debug_data,
308062306a36Sopenharmony_ci				 cfg->d3_debug_data_length);
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_mem)
308362306a36Sopenharmony_ci		fwrt->sanitize_ops->frob_mem(fwrt->sanitize_ctx,
308462306a36Sopenharmony_ci					     cfg->d3_debug_data_base_addr,
308562306a36Sopenharmony_ci					     fwrt->dump.d3_debug_data,
308662306a36Sopenharmony_ci					     cfg->d3_debug_data_length);
308762306a36Sopenharmony_ci}
308862306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_fw_dbg_read_d3_debug_data);
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_civoid iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt)
309162306a36Sopenharmony_ci{
309262306a36Sopenharmony_ci	int i;
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci	iwl_dbg_tlv_del_timers(fwrt->trans);
309562306a36Sopenharmony_ci	for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++)
309662306a36Sopenharmony_ci		iwl_fw_dbg_collect_sync(fwrt, i);
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	iwl_fw_dbg_stop_restart_recording(fwrt, NULL, true);
309962306a36Sopenharmony_ci}
310062306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_fw_dbg_stop_sync);
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_cistatic int iwl_fw_dbg_suspend_resume_hcmd(struct iwl_trans *trans, bool suspend)
310362306a36Sopenharmony_ci{
310462306a36Sopenharmony_ci	struct iwl_dbg_suspend_resume_cmd cmd = {
310562306a36Sopenharmony_ci		.operation = suspend ?
310662306a36Sopenharmony_ci			cpu_to_le32(DBGC_SUSPEND_CMD) :
310762306a36Sopenharmony_ci			cpu_to_le32(DBGC_RESUME_CMD),
310862306a36Sopenharmony_ci	};
310962306a36Sopenharmony_ci	struct iwl_host_cmd hcmd = {
311062306a36Sopenharmony_ci		.id = WIDE_ID(DEBUG_GROUP, DBGC_SUSPEND_RESUME),
311162306a36Sopenharmony_ci		.data[0] = &cmd,
311262306a36Sopenharmony_ci		.len[0] = sizeof(cmd),
311362306a36Sopenharmony_ci	};
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci	return iwl_trans_send_cmd(trans, &hcmd);
311662306a36Sopenharmony_ci}
311762306a36Sopenharmony_ci
311862306a36Sopenharmony_cistatic void iwl_fw_dbg_stop_recording(struct iwl_trans *trans,
311962306a36Sopenharmony_ci				      struct iwl_fw_dbg_params *params)
312062306a36Sopenharmony_ci{
312162306a36Sopenharmony_ci	if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_7000) {
312262306a36Sopenharmony_ci		iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100);
312362306a36Sopenharmony_ci		return;
312462306a36Sopenharmony_ci	}
312562306a36Sopenharmony_ci
312662306a36Sopenharmony_ci	if (params) {
312762306a36Sopenharmony_ci		params->in_sample = iwl_read_umac_prph(trans, DBGC_IN_SAMPLE);
312862306a36Sopenharmony_ci		params->out_ctrl = iwl_read_umac_prph(trans, DBGC_OUT_CTRL);
312962306a36Sopenharmony_ci	}
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	iwl_write_umac_prph(trans, DBGC_IN_SAMPLE, 0);
313262306a36Sopenharmony_ci	/* wait for the DBGC to finish writing the internal buffer to DRAM to
313362306a36Sopenharmony_ci	 * avoid halting the HW while writing
313462306a36Sopenharmony_ci	 */
313562306a36Sopenharmony_ci	usleep_range(700, 1000);
313662306a36Sopenharmony_ci	iwl_write_umac_prph(trans, DBGC_OUT_CTRL, 0);
313762306a36Sopenharmony_ci}
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_cistatic int iwl_fw_dbg_restart_recording(struct iwl_trans *trans,
314062306a36Sopenharmony_ci					struct iwl_fw_dbg_params *params)
314162306a36Sopenharmony_ci{
314262306a36Sopenharmony_ci	if (!params)
314362306a36Sopenharmony_ci		return -EIO;
314462306a36Sopenharmony_ci
314562306a36Sopenharmony_ci	if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_7000) {
314662306a36Sopenharmony_ci		iwl_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100);
314762306a36Sopenharmony_ci		iwl_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1);
314862306a36Sopenharmony_ci		iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1);
314962306a36Sopenharmony_ci	} else {
315062306a36Sopenharmony_ci		iwl_write_umac_prph(trans, DBGC_IN_SAMPLE, params->in_sample);
315162306a36Sopenharmony_ci		iwl_write_umac_prph(trans, DBGC_OUT_CTRL, params->out_ctrl);
315262306a36Sopenharmony_ci	}
315362306a36Sopenharmony_ci
315462306a36Sopenharmony_ci	return 0;
315562306a36Sopenharmony_ci}
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ciint iwl_fw_send_timestamp_marker_cmd(struct iwl_fw_runtime *fwrt)
315862306a36Sopenharmony_ci{
315962306a36Sopenharmony_ci	struct iwl_mvm_marker marker = {
316062306a36Sopenharmony_ci		.dw_len = sizeof(struct iwl_mvm_marker) / 4,
316162306a36Sopenharmony_ci		.marker_id = MARKER_ID_SYNC_CLOCK,
316262306a36Sopenharmony_ci	};
316362306a36Sopenharmony_ci	struct iwl_host_cmd hcmd = {
316462306a36Sopenharmony_ci		.flags = CMD_ASYNC,
316562306a36Sopenharmony_ci		.id = WIDE_ID(LONG_GROUP, MARKER_CMD),
316662306a36Sopenharmony_ci		.dataflags = {},
316762306a36Sopenharmony_ci	};
316862306a36Sopenharmony_ci	struct iwl_mvm_marker_rsp *resp;
316962306a36Sopenharmony_ci	int cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
317062306a36Sopenharmony_ci					    WIDE_ID(LONG_GROUP, MARKER_CMD),
317162306a36Sopenharmony_ci					    IWL_FW_CMD_VER_UNKNOWN);
317262306a36Sopenharmony_ci	int ret;
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci	if (cmd_ver == 1) {
317562306a36Sopenharmony_ci		/* the real timestamp is taken from the ftrace clock
317662306a36Sopenharmony_ci		 * this is for finding the match between fw and kernel logs
317762306a36Sopenharmony_ci		 */
317862306a36Sopenharmony_ci		marker.timestamp = cpu_to_le64(fwrt->timestamp.seq++);
317962306a36Sopenharmony_ci	} else if (cmd_ver == 2) {
318062306a36Sopenharmony_ci		marker.timestamp = cpu_to_le64(ktime_get_boottime_ns());
318162306a36Sopenharmony_ci	} else {
318262306a36Sopenharmony_ci		IWL_DEBUG_INFO(fwrt,
318362306a36Sopenharmony_ci			       "Invalid version of Marker CMD. Ver = %d\n",
318462306a36Sopenharmony_ci			       cmd_ver);
318562306a36Sopenharmony_ci		return -EINVAL;
318662306a36Sopenharmony_ci	}
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci	hcmd.data[0] = &marker;
318962306a36Sopenharmony_ci	hcmd.len[0] = sizeof(marker);
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_ci	ret = iwl_trans_send_cmd(fwrt->trans, &hcmd);
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ci	if (cmd_ver > 1 && hcmd.resp_pkt) {
319462306a36Sopenharmony_ci		resp = (void *)hcmd.resp_pkt->data;
319562306a36Sopenharmony_ci		IWL_DEBUG_INFO(fwrt, "FW GP2 time: %u\n",
319662306a36Sopenharmony_ci			       le32_to_cpu(resp->gp2));
319762306a36Sopenharmony_ci	}
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci	return ret;
320062306a36Sopenharmony_ci}
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_civoid iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
320362306a36Sopenharmony_ci				       struct iwl_fw_dbg_params *params,
320462306a36Sopenharmony_ci				       bool stop)
320562306a36Sopenharmony_ci{
320662306a36Sopenharmony_ci	int ret __maybe_unused = 0;
320762306a36Sopenharmony_ci
320862306a36Sopenharmony_ci	if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status))
320962306a36Sopenharmony_ci		return;
321062306a36Sopenharmony_ci
321162306a36Sopenharmony_ci	if (fw_has_capa(&fwrt->fw->ucode_capa,
321262306a36Sopenharmony_ci			IWL_UCODE_TLV_CAPA_DBG_SUSPEND_RESUME_CMD_SUPP)) {
321362306a36Sopenharmony_ci		if (stop)
321462306a36Sopenharmony_ci			iwl_fw_send_timestamp_marker_cmd(fwrt);
321562306a36Sopenharmony_ci		ret = iwl_fw_dbg_suspend_resume_hcmd(fwrt->trans, stop);
321662306a36Sopenharmony_ci	} else if (stop) {
321762306a36Sopenharmony_ci		iwl_fw_dbg_stop_recording(fwrt->trans, params);
321862306a36Sopenharmony_ci	} else {
321962306a36Sopenharmony_ci		ret = iwl_fw_dbg_restart_recording(fwrt->trans, params);
322062306a36Sopenharmony_ci	}
322162306a36Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS
322262306a36Sopenharmony_ci	if (!ret) {
322362306a36Sopenharmony_ci		if (stop)
322462306a36Sopenharmony_ci			fwrt->trans->dbg.rec_on = false;
322562306a36Sopenharmony_ci		else
322662306a36Sopenharmony_ci			iwl_fw_set_dbg_rec_on(fwrt);
322762306a36Sopenharmony_ci	}
322862306a36Sopenharmony_ci#endif
322962306a36Sopenharmony_ci}
323062306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_fw_dbg_stop_restart_recording);
3231