Skip to content

Commit

Permalink
iwlwifi: dbg: dump data according to the new ini TLVs
Browse files Browse the repository at this point in the history
When ini TLVs are loaded, dump data according to the
stored configuration.

Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
  • Loading branch information
Sara Sharon authored and Luca Coelho committed Dec 14, 2018
1 parent 09b0b99 commit 7a14c23
Show file tree
Hide file tree
Showing 9 changed files with 355 additions and 36 deletions.
263 changes: 261 additions & 2 deletions drivers/net/wireless/intel/iwlwifi/fw/dbg.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,28 @@ static void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt,
IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", dump_mem->type);
}

static void iwl_fw_dump_named_mem(struct iwl_fw_runtime *fwrt,
struct iwl_fw_error_dump_data **dump_data,
u32 len, u32 ofs, u8 *name, u8 name_len)
{
struct iwl_fw_error_dump_named_mem *dump_mem;

if (!len)
return;

(*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
(*dump_data)->len = cpu_to_le32(len + sizeof(*dump_mem));
dump_mem = (void *)(*dump_data)->data;
dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_NAMED_MEM);
dump_mem->offset = cpu_to_le32(ofs);
dump_mem->name_len = name_len;
memcpy(dump_mem->name, name, name_len);
iwl_trans_read_mem_bytes(fwrt->trans, ofs, dump_mem->data, len);
*dump_data = iwl_fw_error_next_data(*dump_data);

IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", dump_mem->type);
}

#define ADD_LEN(len, item_len, const_len) \
do {size_t item = item_len; len += (!!item) * const_len + item; } \
while (0)
Expand Down Expand Up @@ -928,6 +950,238 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
return dump_file;
}

static void iwl_dump_prph_ini(struct iwl_trans *trans,
struct iwl_fw_error_dump_data **data,
struct iwl_fw_ini_region_cfg *reg)
{
struct iwl_fw_error_dump_prph *prph;
unsigned long flags;
u32 i, size = le32_to_cpu(reg->num_regions);

IWL_DEBUG_INFO(trans, "WRT PRPH dump\n");

if (!iwl_trans_grab_nic_access(trans, &flags))
return;

for (i = 0; i < size; i++) {
(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH);
(*data)->len = cpu_to_le32(le32_to_cpu(reg->size) +
sizeof(*prph));
prph = (void *)(*data)->data;
prph->prph_start = reg->start_addr[i];
prph->data[0] = cpu_to_le32(iwl_read_prph_no_grab(trans,
le32_to_cpu(prph->prph_start)));
*data = iwl_fw_error_next_data(*data);
}
iwl_trans_release_nic_access(trans, &flags);
}

static void iwl_dump_csr_ini(struct iwl_trans *trans,
struct iwl_fw_error_dump_data **data,
struct iwl_fw_ini_region_cfg *reg)
{
int i, num = le32_to_cpu(reg->num_regions);
u32 size = le32_to_cpu(reg->size);

IWL_DEBUG_INFO(trans, "WRT CSR dump\n");

for (i = 0; i < num; i++) {
u32 add = le32_to_cpu(reg->start_addr[i]);
__le32 *val;
int j;

(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_CSR);
(*data)->len = cpu_to_le32(size);
val = (void *)(*data)->data;

for (j = 0; j < size; j += 4)
*val++ = cpu_to_le32(iwl_trans_read32(trans, j + add));

*data = iwl_fw_error_next_data(*data);
}
}

static int iwl_fw_ini_get_trigger_len(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_trigger *trigger)
{
int i, num, size = 0, hdr_len = sizeof(struct iwl_fw_error_dump_data);

if (!trigger || !trigger->num_regions)
return 0;

num = le32_to_cpu(trigger->num_regions);
for (i = 0; i < num; i++) {
u32 reg_id = le32_to_cpu(trigger->data[i]);
struct iwl_fw_ini_region_cfg *reg;
enum iwl_fw_ini_region_type type;
u32 num_entries;

if (WARN_ON(reg_id >= ARRAY_SIZE(fwrt->dump.active_regs)))
continue;

reg = fwrt->dump.active_regs[reg_id].reg;
if (WARN(!reg, "Unassigned region %d\n", reg_id))
continue;

type = le32_to_cpu(reg->region_type);
num_entries = le32_to_cpu(reg->num_regions);

switch (type) {
case IWL_FW_INI_REGION_DEVICE_MEMORY:
size += hdr_len +
sizeof(struct iwl_fw_error_dump_named_mem) +
le32_to_cpu(reg->size);
break;
case IWL_FW_INI_REGION_PERIPHERY_MAC:
case IWL_FW_INI_REGION_PERIPHERY_PHY:
case IWL_FW_INI_REGION_PERIPHERY_AUX:
size += num_entries *
(hdr_len +
sizeof(struct iwl_fw_error_dump_prph) +
sizeof(u32));
break;
case IWL_FW_INI_REGION_TXF:
size += iwl_fw_txf_len(fwrt, &fwrt->smem_cfg);
break;
case IWL_FW_INI_REGION_RXF:
size += iwl_fw_rxf_len(fwrt, &fwrt->smem_cfg);
break;
case IWL_FW_INI_REGION_PAGING:
if (!iwl_fw_dbg_is_paging_enabled(fwrt))
break;
size += fwrt->num_of_paging_blk *
(hdr_len +
sizeof(struct iwl_fw_error_dump_paging) +
PAGING_BLOCK_SIZE);
break;
case IWL_FW_INI_REGION_CSR:
size += num_entries *
(hdr_len + le32_to_cpu(reg->size));
break;
case IWL_FW_INI_REGION_DRAM_BUFFER:
/* Transport takes care of DRAM dumping */
case IWL_FW_INI_REGION_INTERNAL_BUFFER:
case IWL_FW_INI_REGION_DRAM_IMR:
/* Undefined yet */
default:
break;
}
}
return size;
}

static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_trigger *trigger,
struct iwl_fw_error_dump_data **data,
u32 *dump_mask)
{
int i, num = le32_to_cpu(trigger->num_regions);

for (i = 0; i < num; i++) {
u32 reg_id = le32_to_cpu(trigger->data[i]);
enum iwl_fw_ini_region_type type;
struct iwl_fw_ini_region_cfg *reg;

if (reg_id >= ARRAY_SIZE(fwrt->dump.active_regs))
continue;

reg = fwrt->dump.active_regs[reg_id].reg;
/* Don't warn, get_trigger_len already warned */
if (!reg)
continue;

type = le32_to_cpu(reg->region_type);
switch (type) {
case IWL_FW_INI_REGION_DEVICE_MEMORY:
if (WARN_ON(le32_to_cpu(reg->num_regions) > 1))
continue;
iwl_fw_dump_named_mem(fwrt, data,
le32_to_cpu(reg->size),
le32_to_cpu(reg->start_addr[0]),
reg->name,
le32_to_cpu(reg->name_len));
break;
case IWL_FW_INI_REGION_PERIPHERY_MAC:
case IWL_FW_INI_REGION_PERIPHERY_PHY:
case IWL_FW_INI_REGION_PERIPHERY_AUX:
iwl_dump_prph_ini(fwrt->trans, data, reg);
break;
case IWL_FW_INI_REGION_DRAM_BUFFER:
*dump_mask |= IWL_FW_ERROR_DUMP_FW_MONITOR;
break;
case IWL_FW_INI_REGION_PAGING:
if (iwl_fw_dbg_is_paging_enabled(fwrt))
iwl_dump_paging(fwrt, data);
else
*dump_mask |= IWL_FW_ERROR_DUMP_PAGING;
break;
case IWL_FW_INI_REGION_TXF:
iwl_fw_dump_txf(fwrt, data);
break;
case IWL_FW_INI_REGION_RXF:
iwl_fw_dump_rxf(fwrt, data);
break;
case IWL_FW_INI_REGION_CSR:
iwl_dump_csr_ini(fwrt->trans, data, reg);
break;
case IWL_FW_INI_REGION_DRAM_IMR:
case IWL_FW_INI_REGION_INTERNAL_BUFFER:
/* This is undefined yet */
default:
break;
}
}
}

static struct iwl_fw_error_dump_file *
_iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt,
struct iwl_fw_dump_ptrs *fw_error_dump,
u32 *dump_mask)
{
int size, id = le32_to_cpu(fwrt->dump.desc->trig_desc.type);
struct iwl_fw_error_dump_data *dump_data;
struct iwl_fw_error_dump_file *dump_file;
struct iwl_fw_ini_trigger *trigger, *ext;

if (id == FW_DBG_TRIGGER_FW_ASSERT)
id = IWL_FW_TRIGGER_ID_FW_ASSERT;
else if (id == FW_DBG_TRIGGER_USER)
id = IWL_FW_TRIGGER_ID_USER_TRIGGER;
else if (id < FW_DBG_TRIGGER_MAX)
return NULL;

if (WARN_ON(id >= ARRAY_SIZE(fwrt->dump.active_trigs)))
return NULL;

trigger = fwrt->dump.active_trigs[id].conf;
ext = fwrt->dump.active_trigs[id].conf_ext;

size = sizeof(*dump_file);
size += iwl_fw_ini_get_trigger_len(fwrt, trigger);
size += iwl_fw_ini_get_trigger_len(fwrt, ext);

if (!size)
return NULL;

dump_file = vzalloc(size);
if (!dump_file)
return NULL;

fw_error_dump->fwrt_ptr = dump_file;

dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
dump_data = (void *)dump_file->data;
dump_file->file_len = cpu_to_le32(size);

*dump_mask = 0;
if (trigger)
iwl_fw_ini_dump_trigger(fwrt, trigger, &dump_data, dump_mask);
if (ext)
iwl_fw_ini_dump_trigger(fwrt, ext, &dump_data, dump_mask);

return dump_file;
}

void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
{
struct iwl_fw_dump_ptrs *fw_error_dump;
Expand All @@ -948,13 +1202,18 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
if (!fw_error_dump)
goto out;

dump_file = _iwl_fw_error_dump(fwrt, fw_error_dump);
if (fwrt->trans->ini_valid)
dump_file = _iwl_fw_error_ini_dump(fwrt, fw_error_dump,
&dump_mask);
else
dump_file = _iwl_fw_error_dump(fwrt, fw_error_dump);

if (!dump_file) {
kfree(fw_error_dump);
goto out;
}

if (fwrt->dump.monitor_only)
if (!fwrt->trans->ini_valid && fwrt->dump.monitor_only)
dump_mask &= IWL_FW_ERROR_DUMP_FW_MONITOR;

fw_error_dump->trans_ptr = iwl_trans_dump_data(fwrt->trans, dump_mask);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/intel/iwlwifi/fw/dbg.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work);

static inline bool iwl_fw_dbg_type_on(struct iwl_fw_runtime *fwrt, u32 type)
{
return (fwrt->fw->dbg.dump_mask & BIT(type));
return (fwrt->fw->dbg.dump_mask & BIT(type) || fwrt->trans->ini_valid);
}

static inline bool iwl_fw_dbg_is_d3_debug_enabled(struct iwl_fw_runtime *fwrt)
Expand Down
17 changes: 17 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ struct iwl_fw_error_dump_prph {
enum iwl_fw_error_dump_mem_type {
IWL_FW_ERROR_DUMP_MEM_SRAM,
IWL_FW_ERROR_DUMP_MEM_SMEM,
IWL_FW_ERROR_DUMP_MEM_NAMED_MEM = 10,
};

/**
Expand All @@ -263,6 +264,22 @@ struct iwl_fw_error_dump_mem {
u8 data[];
};

/**
* struct iwl_fw_error_dump_named_mem - chunk of memory
* @type: &enum iwl_fw_error_dump_mem_type
* @offset: the offset from which the memory was read
* @name_len: name length
* @name: file name
* @data: the content of the memory
*/
struct iwl_fw_error_dump_named_mem {
__le32 type;
__le32 offset;
u8 name_len;
u8 name[32];
u8 data[];
};

/**
* struct iwl_fw_error_dump_rb - content of an Receive Buffer
* @index: the index of the Receive Buffer in the Rx queue
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/iwl-prph.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,12 @@
#define MON_BUFF_END_ADDR (0xa03c40)
#define MON_BUFF_WRPTR (0xa03c44)
#define MON_BUFF_CYCLE_CNT (0xa03c48)
/* FW monitor family 8000 and on */
#define MON_BUFF_BASE_ADDR_VER2 (0xa03c3c)
#define MON_BUFF_END_ADDR_VER2 (0xa03c20)
#define MON_BUFF_WRPTR_VER2 (0xa03c24)
#define MON_BUFF_CYCLE_CNT_VER2 (0xa03c28)
#define MON_BUFF_SHIFT_VER2 (0x8)

#define MON_DMARB_RD_CTL_ADDR (0xa03c60)
#define MON_DMARB_RD_DATA_ADDR (0xa03c5c)
Expand Down
12 changes: 7 additions & 5 deletions drivers/net/wireless/intel/iwlwifi/mvm/fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1050,11 +1050,13 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
if (ret)
IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");

mvm->fwrt.dump.conf = FW_DBG_INVALID;
/* if we have a destination, assume EARLY START */
if (mvm->fw->dbg.dest_tlv)
mvm->fwrt.dump.conf = FW_DBG_START_FROM_ALIVE;
iwl_fw_start_dbg_conf(&mvm->fwrt, FW_DBG_START_FROM_ALIVE);
if (!mvm->trans->ini_valid) {
mvm->fwrt.dump.conf = FW_DBG_INVALID;
/* if we have a destination, assume EARLY START */
if (mvm->fw->dbg.dest_tlv)
mvm->fwrt.dump.conf = FW_DBG_START_FROM_ALIVE;
iwl_fw_start_dbg_conf(&mvm->fwrt, FW_DBG_START_FROM_ALIVE);
}

ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
if (ret)
Expand Down
13 changes: 8 additions & 5 deletions drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,14 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
cpu_to_le64(trans_pcie->rxq->bd_dma);

/* Configure debug, for integration */
iwl_pcie_alloc_fw_monitor(trans, 0);
prph_sc_ctrl->hwm_cfg.hwm_base_addr =
cpu_to_le64(trans->fw_mon[0].physical);
prph_sc_ctrl->hwm_cfg.hwm_size =
cpu_to_le32(trans->fw_mon[0].size);
if (!trans->ini_valid)
iwl_pcie_alloc_fw_monitor(trans, 0);
if (trans->num_blocks) {
prph_sc_ctrl->hwm_cfg.hwm_base_addr =
cpu_to_le64(trans->fw_mon[0].physical);
prph_sc_ctrl->hwm_cfg.hwm_size =
cpu_to_le32(trans->fw_mon[0].size);
}

/* allocate ucode sections in dram and set addresses */
ret = iwl_pcie_init_fw_sec(trans, fw, &prph_scratch->dram);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
iwl_enable_interrupts(trans);

/* Configure debug, if exists */
if (trans->dbg_dest_tlv)
if (iwl_pcie_dbg_on(trans))
iwl_pcie_apply_destination(trans);

/* kick FW self load */
Expand Down
Loading

0 comments on commit 7a14c23

Please sign in to comment.