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 = ®->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 ®->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, ®_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, ®_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, ¶ms, 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, ¶ms, 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] = ▮ 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