summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c158
1 files changed, 157 insertions, 1 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
index 125479b5c0d6..869270020763 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
@@ -16,6 +16,7 @@
* @IWL_DBG_TLV_TYPE_HCMD: host command TLV
* @IWL_DBG_TLV_TYPE_REGION: region TLV
* @IWL_DBG_TLV_TYPE_TRIGGER: trigger TLV
+ * @IWL_DBG_TLV_TYPE_CONF_SET: conf set TLV
* @IWL_DBG_TLV_TYPE_NUM: number of debug TLVs
*/
enum iwl_dbg_tlv_type {
@@ -25,6 +26,7 @@ enum iwl_dbg_tlv_type {
IWL_DBG_TLV_TYPE_HCMD,
IWL_DBG_TLV_TYPE_REGION,
IWL_DBG_TLV_TYPE_TRIGGER,
+ IWL_DBG_TLV_TYPE_CONF_SET,
IWL_DBG_TLV_TYPE_NUM,
};
@@ -59,6 +61,7 @@ dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = {
[IWL_DBG_TLV_TYPE_HCMD] = {.min_ver = 1, .max_ver = 1,},
[IWL_DBG_TLV_TYPE_REGION] = {.min_ver = 1, .max_ver = 2,},
[IWL_DBG_TLV_TYPE_TRIGGER] = {.min_ver = 1, .max_ver = 1,},
+ [IWL_DBG_TLV_TYPE_CONF_SET] = {.min_ver = 1, .max_ver = 1,},
};
static int iwl_dbg_tlv_add(const struct iwl_ucode_tlv *tlv,
@@ -260,6 +263,37 @@ static int iwl_dbg_tlv_alloc_trigger(struct iwl_trans *trans,
return ret;
}
+static int iwl_dbg_tlv_config_set(struct iwl_trans *trans,
+ const struct iwl_ucode_tlv *tlv)
+{
+ struct iwl_fw_ini_conf_set_tlv *conf_set = (void *)tlv->data;
+ u32 tp = le32_to_cpu(conf_set->time_point);
+ u32 type = le32_to_cpu(conf_set->set_type);
+
+ if (tp <= IWL_FW_INI_TIME_POINT_INVALID ||
+ tp >= IWL_FW_INI_TIME_POINT_NUM) {
+ IWL_DEBUG_FW(trans,
+ "WRT: Invalid time point %u for config set TLV\n", tp);
+ return -EINVAL;
+ }
+
+ if (type <= IWL_FW_INI_CONFIG_SET_TYPE_INVALID ||
+ type >= IWL_FW_INI_CONFIG_SET_TYPE_MAX_NUM) {
+ IWL_DEBUG_FW(trans,
+ "WRT: Invalid config set type %u for config set TLV\n", type);
+ return -EINVAL;
+ }
+
+ if (type != IWL_FW_INI_CONFIG_SET_TYPE_PERIPH_SCRATCH_HWM ||
+ trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
+ IWL_DEBUG_FW(trans,
+ "WRT: Config set type %u is not supported\n", type);
+ return -EINVAL;
+ }
+
+ return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].config_list);
+}
+
static int (*dbg_tlv_alloc[])(struct iwl_trans *trans,
const struct iwl_ucode_tlv *tlv) = {
[IWL_DBG_TLV_TYPE_DEBUG_INFO] = iwl_dbg_tlv_alloc_debug_info,
@@ -267,6 +301,7 @@ static int (*dbg_tlv_alloc[])(struct iwl_trans *trans,
[IWL_DBG_TLV_TYPE_HCMD] = iwl_dbg_tlv_alloc_hcmd,
[IWL_DBG_TLV_TYPE_REGION] = iwl_dbg_tlv_alloc_region,
[IWL_DBG_TLV_TYPE_TRIGGER] = iwl_dbg_tlv_alloc_trigger,
+ [IWL_DBG_TLV_TYPE_CONF_SET] = iwl_dbg_tlv_config_set,
};
void iwl_dbg_tlv_alloc(struct iwl_trans *trans, const struct iwl_ucode_tlv *tlv,
@@ -399,6 +434,13 @@ void iwl_dbg_tlv_free(struct iwl_trans *trans)
list_del(&tlv_node->list);
kfree(tlv_node);
}
+
+ list_for_each_entry_safe(tlv_node, tlv_node_tmp,
+ &tp->config_list, list) {
+ list_del(&tlv_node->list);
+ kfree(tlv_node);
+ }
+
}
for (i = 0; i < ARRAY_SIZE(trans->dbg.fw_mon_ini); i++)
@@ -466,6 +508,7 @@ void iwl_dbg_tlv_init(struct iwl_trans *trans)
INIT_LIST_HEAD(&tp->trig_list);
INIT_LIST_HEAD(&tp->hcmd_list);
INIT_LIST_HEAD(&tp->active_trig_list);
+ INIT_LIST_HEAD(&tp->config_list);
}
}
@@ -649,6 +692,10 @@ static void iwl_dbg_tlv_apply_buffers(struct iwl_fw_runtime *fwrt)
{
int ret, i;
+ if (fw_has_capa(&fwrt->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT))
+ return;
+
for (i = 0; i < IWL_FW_INI_ALLOCATION_NUM; i++) {
ret = iwl_dbg_tlv_apply_buffer(fwrt, i);
if (ret)
@@ -658,6 +705,87 @@ static void iwl_dbg_tlv_apply_buffers(struct iwl_fw_runtime *fwrt)
}
}
+static int iwl_dbg_tlv_update_dram(struct iwl_fw_runtime *fwrt,
+ enum iwl_fw_ini_allocation_id alloc_id,
+ struct iwl_dram_info *dram_info)
+{
+ struct iwl_fw_mon *fw_mon;
+ u32 remain_frags, num_frags;
+ int j, fw_mon_idx = 0;
+ struct iwl_buf_alloc_cmd *data;
+
+ if (le32_to_cpu(fwrt->trans->dbg.fw_mon_cfg[alloc_id].buf_location) !=
+ IWL_FW_INI_LOCATION_DRAM_PATH) {
+ IWL_DEBUG_FW(fwrt, "DRAM_PATH is not supported alloc_id %u\n", alloc_id);
+ return -1;
+ }
+
+ fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id];
+
+ /* the first fragment of DBGC1 is given to the FW via register
+ * or context info
+ */
+ if (alloc_id == IWL_FW_INI_ALLOCATION_ID_DBGC1)
+ fw_mon_idx++;
+
+ remain_frags = fw_mon->num_frags - fw_mon_idx;
+ if (!remain_frags)
+ return -1;
+
+ num_frags = min_t(u32, remain_frags, BUF_ALLOC_MAX_NUM_FRAGS);
+ data = &dram_info->dram_frags[alloc_id - 1];
+ data->alloc_id = cpu_to_le32(alloc_id);
+ data->num_frags = cpu_to_le32(num_frags);
+ data->buf_location = cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH);
+
+ IWL_DEBUG_FW(fwrt, "WRT: DRAM buffer details alloc_id=%u, num_frags=%u\n",
+ cpu_to_le32(alloc_id), cpu_to_le32(num_frags));
+
+ for (j = 0; j < num_frags; j++) {
+ struct iwl_buf_alloc_frag *frag = &data->frags[j];
+ struct iwl_dram_data *fw_mon_frag = &fw_mon->frags[fw_mon_idx++];
+
+ frag->addr = cpu_to_le64(fw_mon_frag->physical);
+ frag->size = cpu_to_le32(fw_mon_frag->size);
+ IWL_DEBUG_FW(fwrt, "WRT: DRAM fragment details\n");
+ IWL_DEBUG_FW(fwrt, "frag=%u, addr=0x%016llx, size=0x%x)\n",
+ j, cpu_to_le64(fw_mon_frag->physical),
+ cpu_to_le32(fw_mon_frag->size));
+ }
+ return 0;
+}
+
+static void iwl_dbg_tlv_update_drams(struct iwl_fw_runtime *fwrt)
+{
+ int ret, i, dram_alloc = 0;
+ struct iwl_dram_info dram_info;
+ struct iwl_dram_data *frags =
+ &fwrt->trans->dbg.fw_mon_ini[IWL_FW_INI_ALLOCATION_ID_DBGC1].frags[0];
+
+ if (!fw_has_capa(&fwrt->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT))
+ return;
+
+ dram_info.first_word = cpu_to_le32(DRAM_INFO_FIRST_MAGIC_WORD);
+ dram_info.second_word = cpu_to_le32(DRAM_INFO_SECOND_MAGIC_WORD);
+
+ for (i = IWL_FW_INI_ALLOCATION_ID_DBGC1;
+ i <= IWL_FW_INI_ALLOCATION_ID_DBGC3; i++) {
+ ret = iwl_dbg_tlv_update_dram(fwrt, i, &dram_info);
+ if (!ret)
+ dram_alloc++;
+ else
+ IWL_WARN(fwrt,
+ "WRT: Failed to set DRAM buffer for alloc id %d, ret=%d\n",
+ i, ret);
+ }
+ if (dram_alloc) {
+ memcpy(frags->block, &dram_info, sizeof(dram_info));
+ IWL_DEBUG_FW(fwrt, "block data after %016x\n",
+ *((int *)fwrt->trans->dbg.fw_mon_ini[1].frags[0].block));
+ }
+}
+
static void iwl_dbg_tlv_send_hcmds(struct iwl_fw_runtime *fwrt,
struct list_head *hcmd_list)
{
@@ -677,6 +805,31 @@ static void iwl_dbg_tlv_send_hcmds(struct iwl_fw_runtime *fwrt,
}
}
+static void iwl_dbg_tlv_apply_config(struct iwl_fw_runtime *fwrt,
+ struct list_head *config_list)
+{
+ struct iwl_dbg_tlv_node *node;
+
+ list_for_each_entry(node, config_list, list) {
+ struct iwl_fw_ini_conf_set_tlv *config_list = (void *)node->tlv.data;
+ u32 type = le32_to_cpu(config_list->set_type);
+
+ switch (type) {
+ case IWL_FW_INI_CONFIG_SET_TYPE_PERIPH_SCRATCH_HWM: {
+ u32 debug_token_config =
+ le32_to_cpu(config_list->addr_val[0].value);
+
+ IWL_DEBUG_FW(fwrt, "WRT: Setting HWM debug token config: %u\n",
+ debug_token_config);
+ fwrt->trans->dbg.ucode_preset = debug_token_config;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
static void iwl_dbg_tlv_periodic_trig_handler(struct timer_list *t)
{
struct iwl_dbg_tlv_timer_node *timer_node =
@@ -1051,7 +1204,7 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
union iwl_dbg_tlv_tp_data *tp_data,
bool sync)
{
- struct list_head *hcmd_list, *trig_list;
+ struct list_head *hcmd_list, *trig_list, *conf_list;
if (!iwl_trans_dbg_ini_valid(fwrt->trans) ||
tp_id == IWL_FW_INI_TIME_POINT_INVALID ||
@@ -1060,10 +1213,13 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
hcmd_list = &fwrt->trans->dbg.time_point[tp_id].hcmd_list;
trig_list = &fwrt->trans->dbg.time_point[tp_id].active_trig_list;
+ conf_list = &fwrt->trans->dbg.time_point[tp_id].config_list;
switch (tp_id) {
case IWL_FW_INI_TIME_POINT_EARLY:
iwl_dbg_tlv_init_cfg(fwrt);
+ iwl_dbg_tlv_apply_config(fwrt, conf_list);
+ iwl_dbg_tlv_update_drams(fwrt);
iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
break;
case IWL_FW_INI_TIME_POINT_AFTER_ALIVE: