Commit 5bdaa0ef authored by Johannes Berg's avatar Johannes Berg Committed by Luca Coelho

iwlwifi: allow memory debug TLV to specify the memory type

Due to some new features and changes, the firmware file will now
specify what type of memory to dump, in upper 8 bits of the type
field of the TLV. Parse it (types we don't understand are errors)
and teach the code to dump periphery memory.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 1110f8e3
...@@ -1020,6 +1020,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, ...@@ -1020,6 +1020,18 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
IWL_DEBUG_INFO(drv, "Found debug memory segment: %u\n", IWL_DEBUG_INFO(drv, "Found debug memory segment: %u\n",
dbg_mem->data_type); dbg_mem->data_type);
switch (type & FW_DBG_MEM_TYPE_MASK) {
case FW_DBG_MEM_TYPE_REGULAR:
case FW_DBG_MEM_TYPE_PRPH:
/* we know how to handle these */
break;
default:
IWL_ERR(drv,
"Found debug memory segment with invalid type: 0x%x\n",
type);
return -EINVAL;
}
size = sizeof(*pieces->dbg_mem_tlv) * size = sizeof(*pieces->dbg_mem_tlv) *
(pieces->n_dbg_mem_tlv + 1); (pieces->n_dbg_mem_tlv + 1);
n = krealloc(pieces->dbg_mem_tlv, size, GFP_KERNEL); n = krealloc(pieces->dbg_mem_tlv, size, GFP_KERNEL);
......
...@@ -488,10 +488,23 @@ enum iwl_fw_dbg_monitor_mode { ...@@ -488,10 +488,23 @@ enum iwl_fw_dbg_monitor_mode {
MIPI_MODE = 3, MIPI_MODE = 3,
}; };
/**
* enum iwl_fw_mem_seg_type - memory segment type
* @FW_DBG_MEM_TYPE_MASK: mask for the type indication
* @FW_DBG_MEM_TYPE_REGULAR: regular memory
* @FW_DBG_MEM_TYPE_PRPH: periphery memory (requires special reading)
*/
enum iwl_fw_mem_seg_type {
FW_DBG_MEM_TYPE_MASK = 0xff000000,
FW_DBG_MEM_TYPE_REGULAR = 0x00000000,
FW_DBG_MEM_TYPE_PRPH = 0x01000000,
};
/** /**
* struct iwl_fw_dbg_mem_seg_tlv - configures the debug data memory segments * struct iwl_fw_dbg_mem_seg_tlv - configures the debug data memory segments
* *
* @data_type: the memory segment type to record * @data_type: the memory segment type to record, see &enum iwl_fw_mem_seg_type
* for what we care about
* @ofs: the memory segment offset * @ofs: the memory segment offset
* @len: the memory segment length, in bytes * @len: the memory segment length, in bytes
* *
......
...@@ -406,6 +406,30 @@ static const struct iwl_prph_range iwl_prph_dump_addr_9000[] = { ...@@ -406,6 +406,30 @@ static const struct iwl_prph_range iwl_prph_dump_addr_9000[] = {
{ .start = 0x00a02400, .end = 0x00a02758 }, { .start = 0x00a02400, .end = 0x00a02758 },
}; };
static void _iwl_read_prph_block(struct iwl_trans *trans, u32 start,
u32 len_bytes, __le32 *data)
{
u32 i;
for (i = 0; i < len_bytes; i += 4)
*data++ = cpu_to_le32(iwl_read_prph_no_grab(trans, start + i));
}
static bool iwl_read_prph_block(struct iwl_trans *trans, u32 start,
u32 len_bytes, __le32 *data)
{
unsigned long flags;
bool success = false;
if (iwl_trans_grab_nic_access(trans, &flags)) {
success = true;
_iwl_read_prph_block(trans, start, len_bytes, data);
iwl_trans_release_nic_access(trans, &flags);
}
return success;
}
static void iwl_dump_prph(struct iwl_trans *trans, static void iwl_dump_prph(struct iwl_trans *trans,
struct iwl_fw_error_dump_data **data, struct iwl_fw_error_dump_data **data,
const struct iwl_prph_range *iwl_prph_dump_addr, const struct iwl_prph_range *iwl_prph_dump_addr,
...@@ -422,21 +446,18 @@ static void iwl_dump_prph(struct iwl_trans *trans, ...@@ -422,21 +446,18 @@ static void iwl_dump_prph(struct iwl_trans *trans,
/* The range includes both boundaries */ /* The range includes both boundaries */
int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
iwl_prph_dump_addr[i].start + 4; iwl_prph_dump_addr[i].start + 4;
int reg;
__le32 *val;
(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH); (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH);
(*data)->len = cpu_to_le32(sizeof(*prph) + (*data)->len = cpu_to_le32(sizeof(*prph) +
num_bytes_in_chunk); num_bytes_in_chunk);
prph = (void *)(*data)->data; prph = (void *)(*data)->data;
prph->prph_start = cpu_to_le32(iwl_prph_dump_addr[i].start); prph->prph_start = cpu_to_le32(iwl_prph_dump_addr[i].start);
val = (void *)prph->data;
for (reg = iwl_prph_dump_addr[i].start; _iwl_read_prph_block(trans, iwl_prph_dump_addr[i].start,
reg <= iwl_prph_dump_addr[i].end; /* our range is inclusive, hence + 4 */
reg += 4) iwl_prph_dump_addr[i].end -
*val++ = cpu_to_le32(iwl_read_prph_no_grab(trans, iwl_prph_dump_addr[i].start + 4,
reg)); (void *)prph->data);
*data = iwl_fw_error_next_data(*data); *data = iwl_fw_error_next_data(*data);
} }
...@@ -716,16 +737,36 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -716,16 +737,36 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
for (i = 0; i < mvm->fw->n_dbg_mem_tlv; i++) { for (i = 0; i < mvm->fw->n_dbg_mem_tlv; i++) {
u32 len = le32_to_cpu(fw_dbg_mem[i].len); u32 len = le32_to_cpu(fw_dbg_mem[i].len);
u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs); u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs);
bool success;
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
dump_data->len = cpu_to_le32(len + sizeof(*dump_mem)); dump_data->len = cpu_to_le32(len + sizeof(*dump_mem));
dump_mem = (void *)dump_data->data; dump_mem = (void *)dump_data->data;
dump_mem->type = fw_dbg_mem[i].data_type; dump_mem->type = fw_dbg_mem[i].data_type;
dump_mem->offset = cpu_to_le32(ofs); dump_mem->offset = cpu_to_le32(ofs);
iwl_trans_read_mem_bytes(mvm->trans, ofs,
dump_mem->data, switch (dump_mem->type & cpu_to_le32(FW_DBG_MEM_TYPE_MASK)) {
len); case cpu_to_le32(FW_DBG_MEM_TYPE_REGULAR):
dump_data = iwl_fw_error_next_data(dump_data); iwl_trans_read_mem_bytes(mvm->trans, ofs,
dump_mem->data,
len);
success = true;
break;
case cpu_to_le32(FW_DBG_MEM_TYPE_PRPH):
success = iwl_read_prph_block(mvm->trans, ofs, len,
(void *)dump_mem->data);
break;
default:
/*
* shouldn't get here, we ignored this kind
* of TLV earlier during the TLV parsing?!
*/
WARN_ON(1);
success = false;
}
if (success)
dump_data = iwl_fw_error_next_data(dump_data);
} }
if (smem_len) { if (smem_len) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment