Commit 00eacde4 authored by Shahar S Matityahu's avatar Shahar S Matityahu Committed by Luca Coelho

iwlwifi: dbg_ini: separate cfg and dump flows to different modules

separate configuration flows and dump collection flows.
make ini configuration flows be in iwl-dbg-tlv.c and dump related flows
in dbg.c to better reflect their logical difference.
Signed-off-by: default avatarShahar S Matityahu <shahar.s.matityahu@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent dd36a507
...@@ -2438,435 +2438,6 @@ void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt) ...@@ -2438,435 +2438,6 @@ void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt)
} }
IWL_EXPORT_SYMBOL(iwl_fw_dbg_read_d3_debug_data); IWL_EXPORT_SYMBOL(iwl_fw_dbg_read_d3_debug_data);
static void iwl_fw_dbg_info_apply(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_debug_info_tlv *dbg_info,
bool ext, enum iwl_fw_ini_apply_point pnt)
{
u32 img_name_len = le32_to_cpu(dbg_info->img_name_len);
u32 dbg_cfg_name_len = le32_to_cpu(dbg_info->dbg_cfg_name_len);
if (img_name_len != IWL_FW_INI_MAX_IMG_NAME_LEN) {
IWL_WARN(fwrt,
"WRT: ext=%d. Invalid image name length %d, expected %d\n",
ext, img_name_len,
IWL_FW_INI_MAX_IMG_NAME_LEN);
return;
}
if (dbg_cfg_name_len != IWL_FW_INI_MAX_DBG_CFG_NAME_LEN) {
IWL_WARN(fwrt,
"WRT: ext=%d. Invalid debug cfg name length %d, expected %d\n",
ext, dbg_cfg_name_len,
IWL_FW_INI_MAX_DBG_CFG_NAME_LEN);
return;
}
if (ext) {
memcpy(fwrt->dump.external_dbg_cfg_name, dbg_info->dbg_cfg_name,
sizeof(fwrt->dump.external_dbg_cfg_name));
} else {
memcpy(fwrt->dump.img_name, dbg_info->img_name,
sizeof(fwrt->dump.img_name));
memcpy(fwrt->dump.internal_dbg_cfg_name, dbg_info->dbg_cfg_name,
sizeof(fwrt->dump.internal_dbg_cfg_name));
}
}
static void
iwl_fw_dbg_buffer_allocation(struct iwl_fw_runtime *fwrt, u32 size)
{
struct iwl_trans *trans = fwrt->trans;
void *virtual_addr = NULL;
dma_addr_t phys_addr;
if (WARN_ON_ONCE(trans->dbg.num_blocks ==
ARRAY_SIZE(trans->dbg.fw_mon)))
return;
virtual_addr =
dma_alloc_coherent(fwrt->trans->dev, size, &phys_addr,
GFP_KERNEL | __GFP_NOWARN);
/* TODO: alloc fragments if needed */
if (!virtual_addr)
IWL_ERR(fwrt, "Failed to allocate debug memory\n");
IWL_DEBUG_FW(trans,
"Allocated DRAM buffer[%d], size=0x%x\n",
trans->dbg.num_blocks, size);
trans->dbg.fw_mon[trans->dbg.num_blocks].block = virtual_addr;
trans->dbg.fw_mon[trans->dbg.num_blocks].physical = phys_addr;
trans->dbg.fw_mon[trans->dbg.num_blocks].size = size;
trans->dbg.num_blocks++;
}
static void iwl_fw_dbg_buffer_apply(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_allocation_tlv *alloc,
enum iwl_fw_ini_apply_point pnt)
{
struct iwl_trans *trans = fwrt->trans;
struct iwl_ldbg_config_cmd ldbg_cmd = {
.type = cpu_to_le32(BUFFER_ALLOCATION),
};
struct iwl_buffer_allocation_cmd *cmd = &ldbg_cmd.buffer_allocation;
struct iwl_host_cmd hcmd = {
.id = LDBG_CONFIG_CMD,
.flags = CMD_ASYNC,
.data[0] = &ldbg_cmd,
.len[0] = sizeof(ldbg_cmd),
};
int block_idx = trans->dbg.num_blocks;
u32 buf_location = le32_to_cpu(alloc->buffer_location);
u32 alloc_id = le32_to_cpu(alloc->allocation_id);
if (alloc_id <= IWL_FW_INI_ALLOCATION_INVALID ||
alloc_id >= IWL_FW_INI_ALLOCATION_NUM) {
IWL_ERR(fwrt, "WRT: Invalid allocation id %d\n", alloc_id);
return;
}
if (fwrt->trans->dbg.ini_dest == IWL_FW_INI_LOCATION_INVALID)
fwrt->trans->dbg.ini_dest = buf_location;
if (buf_location != fwrt->trans->dbg.ini_dest) {
WARN(fwrt,
"WRT: attempt to override buffer location on apply point %d\n",
pnt);
return;
}
if (buf_location == IWL_FW_INI_LOCATION_SRAM_PATH) {
IWL_DEBUG_FW(trans, "WRT: Applying SMEM buffer destination\n");
/* set sram monitor by enabling bit 7 */
iwl_set_bit(fwrt->trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM);
return;
}
if (buf_location != IWL_FW_INI_LOCATION_DRAM_PATH)
return;
if (!(BIT(alloc_id) & fwrt->trans->dbg.is_alloc)) {
iwl_fw_dbg_buffer_allocation(fwrt, le32_to_cpu(alloc->size));
if (block_idx == trans->dbg.num_blocks)
return;
fwrt->trans->dbg.is_alloc |= BIT(alloc_id);
}
/* First block is assigned via registers / context info */
if (trans->dbg.num_blocks == 1)
return;
IWL_DEBUG_FW(trans,
"WRT: Applying DRAM buffer[%d] destination\n", block_idx);
cmd->num_frags = cpu_to_le32(1);
cmd->fragments[0].address =
cpu_to_le64(trans->dbg.fw_mon[block_idx].physical);
cmd->fragments[0].size = alloc->size;
cmd->allocation_id = alloc->allocation_id;
cmd->buffer_location = alloc->buffer_location;
iwl_trans_send_cmd(trans, &hcmd);
}
static void iwl_fw_dbg_send_hcmd(struct iwl_fw_runtime *fwrt,
struct iwl_ucode_tlv *tlv)
{
struct iwl_fw_ini_hcmd_tlv *hcmd_tlv = (void *)&tlv->data[0];
struct iwl_fw_ini_hcmd *data = &hcmd_tlv->hcmd;
u16 len = le32_to_cpu(tlv->length) - sizeof(*hcmd_tlv);
struct iwl_host_cmd hcmd = {
.id = WIDE_ID(data->group, data->id),
.len = { len, },
.data = { data->data, },
};
/* currently the driver supports always on domain only */
if (le32_to_cpu(hcmd_tlv->domain) != IWL_FW_INI_DBG_DOMAIN_ALWAYS_ON)
return;
IWL_DEBUG_FW(fwrt, "WRT: Sending host command id=0x%x, group=0x%x\n",
data->id, data->group);
iwl_trans_send_cmd(fwrt->trans, &hcmd);
}
static void iwl_fw_dbg_update_regions(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_region_tlv *tlv,
enum iwl_fw_ini_apply_point pnt)
{
void *iter = (void *)tlv->region_config;
int i, size = le32_to_cpu(tlv->num_regions);
const char *err_st =
"WRT: Invalid region %s %d for apply point %d\n";
for (i = 0; i < size; i++) {
struct iwl_fw_ini_region_cfg *reg = iter, **active;
int id = le32_to_cpu(reg->region_id);
u32 type = le32_to_cpu(reg->region_type);
if (WARN(id >= ARRAY_SIZE(fwrt->dump.active_regs), err_st, "id",
id, pnt))
break;
if (WARN(type == 0 || type >= IWL_FW_INI_REGION_NUM, err_st,
"type", type, pnt))
break;
active = &fwrt->dump.active_regs[id];
if (*active)
IWL_WARN(fwrt->trans, "WRT: Region id %d override\n",
id);
IWL_DEBUG_FW(fwrt, "WRT: Activating region id %d\n", id);
*active = reg;
if (type == IWL_FW_INI_REGION_TXF ||
type == IWL_FW_INI_REGION_RXF)
iter += le32_to_cpu(reg->fifos.num_of_registers) *
sizeof(__le32);
else if (type == IWL_FW_INI_REGION_DEVICE_MEMORY ||
type == IWL_FW_INI_REGION_PERIPHERY_MAC ||
type == IWL_FW_INI_REGION_PERIPHERY_PHY ||
type == IWL_FW_INI_REGION_PERIPHERY_AUX ||
type == IWL_FW_INI_REGION_INTERNAL_BUFFER ||
type == IWL_FW_INI_REGION_PAGING ||
type == IWL_FW_INI_REGION_CSR ||
type == IWL_FW_INI_REGION_LMAC_ERROR_TABLE ||
type == IWL_FW_INI_REGION_UMAC_ERROR_TABLE)
iter += le32_to_cpu(reg->internal.num_of_ranges) *
sizeof(__le32);
iter += sizeof(*reg);
}
}
static int iwl_fw_dbg_trig_realloc(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_active_triggers *active,
u32 id, int size)
{
void *ptr;
if (size <= active->size)
return 0;
ptr = krealloc(active->trig, size, GFP_KERNEL);
if (!ptr) {
IWL_ERR(fwrt, "WRT: Failed to allocate memory for trigger %d\n",
id);
return -ENOMEM;
}
active->trig = ptr;
active->size = size;
return 0;
}
static void iwl_fw_dbg_update_triggers(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_trigger_tlv *tlv,
enum iwl_fw_ini_apply_point apply_point)
{
int i, size = le32_to_cpu(tlv->num_triggers);
void *iter = (void *)tlv->trigger_config;
for (i = 0; i < size; i++) {
struct iwl_fw_ini_trigger *trig = iter;
struct iwl_fw_ini_active_triggers *active;
int id = le32_to_cpu(trig->trigger_id);
u32 trig_regs_size = le32_to_cpu(trig->num_regions) *
sizeof(__le32);
if (WARN(id >= ARRAY_SIZE(fwrt->dump.active_trigs),
"WRT: Invalid trigger id %d for apply point %d\n", id,
apply_point))
break;
active = &fwrt->dump.active_trigs[id];
if (!active->active) {
size_t trig_size = sizeof(*trig) + trig_regs_size;
IWL_DEBUG_FW(fwrt, "WRT: Activating trigger %d\n", id);
if (iwl_fw_dbg_trig_realloc(fwrt, active, id,
trig_size))
goto next;
memcpy(active->trig, trig, trig_size);
} else {
u32 conf_override =
!(le32_to_cpu(trig->override_trig) & 0xff);
u32 region_override =
!(le32_to_cpu(trig->override_trig) & 0xff00);
u32 offset = 0;
u32 active_regs =
le32_to_cpu(active->trig->num_regions);
u32 new_regs = le32_to_cpu(trig->num_regions);
int mem_to_add = trig_regs_size;
if (region_override) {
IWL_DEBUG_FW(fwrt,
"WRT: Trigger %d regions override\n",
id);
mem_to_add -= active_regs * sizeof(__le32);
} else {
IWL_DEBUG_FW(fwrt,
"WRT: Trigger %d regions appending\n",
id);
offset += active_regs;
new_regs += active_regs;
}
if (iwl_fw_dbg_trig_realloc(fwrt, active, id,
active->size + mem_to_add))
goto next;
if (conf_override) {
IWL_DEBUG_FW(fwrt,
"WRT: Trigger %d configuration override\n",
id);
memcpy(active->trig, trig, sizeof(*trig));
}
memcpy(active->trig->data + offset, trig->data,
trig_regs_size);
active->trig->num_regions = cpu_to_le32(new_regs);
}
/* Since zero means infinity - just set to -1 */
if (!le32_to_cpu(active->trig->occurrences))
active->trig->occurrences = cpu_to_le32(-1);
active->active = true;
if (id == IWL_FW_TRIGGER_ID_PERIODIC_TRIGGER) {
u32 collect_interval = le32_to_cpu(trig->trigger_data);
/* the minimum allowed interval is 50ms */
if (collect_interval < 50) {
collect_interval = 50;
trig->trigger_data =
cpu_to_le32(collect_interval);
}
mod_timer(&fwrt->dump.periodic_trig,
jiffies + msecs_to_jiffies(collect_interval));
}
next:
iter += sizeof(*trig) + trig_regs_size;
}
}
static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
struct iwl_apply_point_data *data,
enum iwl_fw_ini_apply_point pnt,
bool ext)
{
struct iwl_apply_point_data *iter;
if (!data->list.next)
return;
list_for_each_entry(iter, &data->list, list) {
struct iwl_ucode_tlv *tlv = &iter->tlv;
void *ini_tlv = (void *)tlv->data;
u32 type = le32_to_cpu(tlv->type);
switch (type) {
case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
iwl_fw_dbg_info_apply(fwrt, ini_tlv, ext, pnt);
break;
case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
if (pnt != IWL_FW_INI_APPLY_EARLY) {
IWL_ERR(fwrt,
"WRT: ext=%d. Invalid apply point %d for buffer allocation\n",
ext, pnt);
break;
}
iwl_fw_dbg_buffer_apply(fwrt, ini_tlv, pnt);
break;
case IWL_UCODE_TLV_TYPE_HCMD:
if (pnt < IWL_FW_INI_APPLY_AFTER_ALIVE) {
IWL_ERR(fwrt,
"WRT: ext=%d. Invalid apply point %d for host command\n",
ext, pnt);
break;
}
iwl_fw_dbg_send_hcmd(fwrt, tlv);
break;
case IWL_UCODE_TLV_TYPE_REGIONS:
iwl_fw_dbg_update_regions(fwrt, ini_tlv, pnt);
break;
case IWL_UCODE_TLV_TYPE_TRIGGERS:
iwl_fw_dbg_update_triggers(fwrt, ini_tlv, pnt);
break;
default:
WARN_ONCE(1, "WRT: Invalid TLV 0x%x for apply point\n",
type);
break;
}
}
}
static void iwl_fw_dbg_ini_reset_cfg(struct iwl_fw_runtime *fwrt)
{
int i;
for (i = 0; i < IWL_FW_INI_MAX_REGION_ID; i++)
fwrt->dump.active_regs[i] = NULL;
/* disable the triggers, used in recovery flow */
for (i = 0; i < IWL_FW_TRIGGER_ID_NUM; i++)
fwrt->dump.active_trigs[i].active = false;
memset(fwrt->dump.img_name, 0,
sizeof(fwrt->dump.img_name));
memset(fwrt->dump.internal_dbg_cfg_name, 0,
sizeof(fwrt->dump.internal_dbg_cfg_name));
memset(fwrt->dump.external_dbg_cfg_name, 0,
sizeof(fwrt->dump.external_dbg_cfg_name));
fwrt->trans->dbg.ini_dest = IWL_FW_INI_LOCATION_INVALID;
}
void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
enum iwl_fw_ini_apply_point apply_point)
{
void *data;
if (apply_point == IWL_FW_INI_APPLY_EARLY)
iwl_fw_dbg_ini_reset_cfg(fwrt);
if (fwrt->trans->dbg.internal_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED) {
IWL_DEBUG_FW(fwrt,
"WRT: Enabling internal configuration apply point %d\n",
apply_point);
data = &fwrt->trans->dbg.apply_points[apply_point];
_iwl_fw_dbg_apply_point(fwrt, data, apply_point, false);
}
if (fwrt->trans->dbg.external_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED) {
IWL_DEBUG_FW(fwrt,
"WRT: Enabling external configuration apply point %d\n",
apply_point);
data = &fwrt->trans->dbg.apply_points_ext[apply_point];
_iwl_fw_dbg_apply_point(fwrt, data, apply_point, true);
}
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_apply_point);
void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt) void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt)
{ {
int i; int i;
......
...@@ -368,9 +368,6 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {} ...@@ -368,9 +368,6 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}
#endif /* CONFIG_IWLWIFI_DEBUGFS */ #endif /* CONFIG_IWLWIFI_DEBUGFS */
void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
enum iwl_fw_ini_apply_point apply_point);
void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt); void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt);
static inline void iwl_fw_lmac1_set_alive_err_table(struct iwl_trans *trans, static inline void iwl_fw_lmac1_set_alive_err_table(struct iwl_trans *trans,
......
...@@ -64,7 +64,6 @@ ...@@ -64,7 +64,6 @@
#include "iwl-trans.h" #include "iwl-trans.h"
#include "img.h" #include "img.h"
#include "fw/api/debug.h" #include "fw/api/debug.h"
#include "fw/api/dbg-tlv.h"
#include "fw/api/paging.h" #include "fw/api/paging.h"
#include "iwl-eeprom-parse.h" #include "iwl-eeprom-parse.h"
......
...@@ -60,8 +60,11 @@ ...@@ -60,8 +60,11 @@
*****************************************************************************/ *****************************************************************************/
#include <linux/firmware.h> #include <linux/firmware.h>
#include "iwl-drv.h"
#include "iwl-trans.h" #include "iwl-trans.h"
#include "iwl-dbg-tlv.h" #include "iwl-dbg-tlv.h"
#include "fw/dbg.h"
#include "fw/runtime.h"
/** /**
* enum iwl_dbg_tlv_type - debug TLV types * enum iwl_dbg_tlv_type - debug TLV types
...@@ -254,3 +257,429 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans) ...@@ -254,3 +257,429 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans)
release_firmware(fw); release_firmware(fw);
} }
static void
iwl_dbg_tlv_apply_debug_info(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_debug_info_tlv *dbg_info,
bool ext, enum iwl_fw_ini_apply_point pnt)
{
u32 img_name_len = le32_to_cpu(dbg_info->img_name_len);
u32 dbg_cfg_name_len = le32_to_cpu(dbg_info->dbg_cfg_name_len);
const char err_str[] =
"WRT: Invalid %s name length %d, expected %d\n";
if (img_name_len != IWL_FW_INI_MAX_IMG_NAME_LEN) {
IWL_WARN(fwrt, err_str, "image", img_name_len,
IWL_FW_INI_MAX_IMG_NAME_LEN);
return;
}
if (dbg_cfg_name_len != IWL_FW_INI_MAX_DBG_CFG_NAME_LEN) {
IWL_WARN(fwrt, err_str, "debug cfg", dbg_cfg_name_len,
IWL_FW_INI_MAX_DBG_CFG_NAME_LEN);
return;
}
if (ext) {
memcpy(fwrt->dump.external_dbg_cfg_name, dbg_info->dbg_cfg_name,
sizeof(fwrt->dump.external_dbg_cfg_name));
} else {
memcpy(fwrt->dump.img_name, dbg_info->img_name,
sizeof(fwrt->dump.img_name));
memcpy(fwrt->dump.internal_dbg_cfg_name, dbg_info->dbg_cfg_name,
sizeof(fwrt->dump.internal_dbg_cfg_name));
}
}
static void iwl_dbg_tlv_alloc_buffer(struct iwl_fw_runtime *fwrt, u32 size)
{
struct iwl_trans *trans = fwrt->trans;
void *virtual_addr = NULL;
dma_addr_t phys_addr;
if (WARN_ON_ONCE(trans->dbg.num_blocks ==
ARRAY_SIZE(trans->dbg.fw_mon)))
return;
virtual_addr =
dma_alloc_coherent(fwrt->trans->dev, size, &phys_addr,
GFP_KERNEL | __GFP_NOWARN);
/* TODO: alloc fragments if needed */
if (!virtual_addr)
IWL_ERR(fwrt, "Failed to allocate debug memory\n");
IWL_DEBUG_FW(trans,
"Allocated DRAM buffer[%d], size=0x%x\n",
trans->dbg.num_blocks, size);
trans->dbg.fw_mon[trans->dbg.num_blocks].block = virtual_addr;
trans->dbg.fw_mon[trans->dbg.num_blocks].physical = phys_addr;
trans->dbg.fw_mon[trans->dbg.num_blocks].size = size;
trans->dbg.num_blocks++;
}
static void iwl_dbg_tlv_apply_buffer(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_allocation_tlv *alloc,
enum iwl_fw_ini_apply_point pnt)
{
struct iwl_trans *trans = fwrt->trans;
struct iwl_ldbg_config_cmd ldbg_cmd = {
.type = cpu_to_le32(BUFFER_ALLOCATION),
};
struct iwl_buffer_allocation_cmd *cmd = &ldbg_cmd.buffer_allocation;
struct iwl_host_cmd hcmd = {
.id = LDBG_CONFIG_CMD,
.flags = CMD_ASYNC,
.data[0] = &ldbg_cmd,
.len[0] = sizeof(ldbg_cmd),
};
int block_idx = trans->dbg.num_blocks;
u32 buf_location = le32_to_cpu(alloc->buffer_location);
u32 alloc_id = le32_to_cpu(alloc->allocation_id);
if (alloc_id <= IWL_FW_INI_ALLOCATION_INVALID ||
alloc_id >= IWL_FW_INI_ALLOCATION_NUM) {
IWL_ERR(fwrt, "WRT: Invalid allocation id %d\n", alloc_id);
return;
}
if (fwrt->trans->dbg.ini_dest == IWL_FW_INI_LOCATION_INVALID)
fwrt->trans->dbg.ini_dest = buf_location;
if (buf_location != fwrt->trans->dbg.ini_dest) {
WARN(fwrt,
"WRT: attempt to override buffer location on apply point %d\n",
pnt);
return;
}
if (buf_location == IWL_FW_INI_LOCATION_SRAM_PATH) {
IWL_DEBUG_FW(trans, "WRT: Applying SMEM buffer destination\n");
/* set sram monitor by enabling bit 7 */
iwl_set_bit(fwrt->trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM);
return;
}
if (buf_location != IWL_FW_INI_LOCATION_DRAM_PATH)
return;
if (!(BIT(alloc_id) & fwrt->trans->dbg.is_alloc)) {
iwl_dbg_tlv_alloc_buffer(fwrt, le32_to_cpu(alloc->size));
if (block_idx == trans->dbg.num_blocks)
return;
fwrt->trans->dbg.is_alloc |= BIT(alloc_id);
}
/* First block is assigned via registers / context info */
if (trans->dbg.num_blocks == 1)
return;
IWL_DEBUG_FW(trans,
"WRT: Applying DRAM buffer[%d] destination\n", block_idx);
cmd->num_frags = cpu_to_le32(1);
cmd->fragments[0].address =
cpu_to_le64(trans->dbg.fw_mon[block_idx].physical);
cmd->fragments[0].size = alloc->size;
cmd->allocation_id = alloc->allocation_id;
cmd->buffer_location = alloc->buffer_location;
iwl_trans_send_cmd(trans, &hcmd);
}
static void iwl_dbg_tlv_apply_hcmd(struct iwl_fw_runtime *fwrt,
struct iwl_ucode_tlv *tlv)
{
struct iwl_fw_ini_hcmd_tlv *hcmd_tlv = (void *)&tlv->data[0];
struct iwl_fw_ini_hcmd *data = &hcmd_tlv->hcmd;
u16 len = le32_to_cpu(tlv->length) - sizeof(*hcmd_tlv);
struct iwl_host_cmd hcmd = {
.id = WIDE_ID(data->group, data->id),
.len = { len, },
.data = { data->data, },
};
/* currently the driver supports always on domain only */
if (le32_to_cpu(hcmd_tlv->domain) != IWL_FW_INI_DBG_DOMAIN_ALWAYS_ON)
return;
IWL_DEBUG_FW(fwrt, "WRT: Sending host command id=0x%x, group=0x%x\n",
data->id, data->group);
iwl_trans_send_cmd(fwrt->trans, &hcmd);
}
static void iwl_dbg_tlv_apply_region(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_region_tlv *tlv,
enum iwl_fw_ini_apply_point pnt)
{
void *iter = (void *)tlv->region_config;
int i, size = le32_to_cpu(tlv->num_regions);
const char *err_st =
"WRT: Invalid region %s %d for apply point %d\n";
for (i = 0; i < size; i++) {
struct iwl_fw_ini_region_cfg *reg = iter, **active;
int id = le32_to_cpu(reg->region_id);
u32 type = le32_to_cpu(reg->region_type);
if (WARN(id >= ARRAY_SIZE(fwrt->dump.active_regs), err_st, "id",
id, pnt))
break;
if (WARN(type == 0 || type >= IWL_FW_INI_REGION_NUM, err_st,
"type", type, pnt))
break;
active = &fwrt->dump.active_regs[id];
if (*active)
IWL_WARN(fwrt->trans, "WRT: Region id %d override\n",
id);
IWL_DEBUG_FW(fwrt, "WRT: Activating region id %d\n", id);
*active = reg;
if (type == IWL_FW_INI_REGION_TXF ||
type == IWL_FW_INI_REGION_RXF)
iter += le32_to_cpu(reg->fifos.num_of_registers) *
sizeof(__le32);
else if (type == IWL_FW_INI_REGION_DEVICE_MEMORY ||
type == IWL_FW_INI_REGION_PERIPHERY_MAC ||
type == IWL_FW_INI_REGION_PERIPHERY_PHY ||
type == IWL_FW_INI_REGION_PERIPHERY_AUX ||
type == IWL_FW_INI_REGION_INTERNAL_BUFFER ||
type == IWL_FW_INI_REGION_PAGING ||
type == IWL_FW_INI_REGION_CSR ||
type == IWL_FW_INI_REGION_LMAC_ERROR_TABLE ||
type == IWL_FW_INI_REGION_UMAC_ERROR_TABLE)
iter += le32_to_cpu(reg->internal.num_of_ranges) *
sizeof(__le32);
iter += sizeof(*reg);
}
}
static int iwl_dbg_tlv_trig_realloc(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_active_triggers *active,
u32 id, int size)
{
void *ptr;
if (size <= active->size)
return 0;
ptr = krealloc(active->trig, size, GFP_KERNEL);
if (!ptr) {
IWL_ERR(fwrt, "WRT: Failed to allocate memory for trigger %d\n",
id);
return -ENOMEM;
}
active->trig = ptr;
active->size = size;
return 0;
}
static void iwl_dbg_tlv_apply_trigger(struct iwl_fw_runtime *fwrt,
struct iwl_fw_ini_trigger_tlv *tlv,
enum iwl_fw_ini_apply_point apply_point)
{
int i, size = le32_to_cpu(tlv->num_triggers);
void *iter = (void *)tlv->trigger_config;
for (i = 0; i < size; i++) {
struct iwl_fw_ini_trigger *trig = iter;
struct iwl_fw_ini_active_triggers *active;
int id = le32_to_cpu(trig->trigger_id);
u32 trig_regs_size = le32_to_cpu(trig->num_regions) *
sizeof(__le32);
if (WARN(id >= ARRAY_SIZE(fwrt->dump.active_trigs),
"WRT: Invalid trigger id %d for apply point %d\n", id,
apply_point))
break;
active = &fwrt->dump.active_trigs[id];
if (!active->active) {
size_t trig_size = sizeof(*trig) + trig_regs_size;
IWL_DEBUG_FW(fwrt, "WRT: Activating trigger %d\n", id);
if (iwl_dbg_tlv_trig_realloc(fwrt, active, id,
trig_size))
goto next;
memcpy(active->trig, trig, trig_size);
} else {
u32 conf_override =
!(le32_to_cpu(trig->override_trig) & 0xff);
u32 region_override =
!(le32_to_cpu(trig->override_trig) & 0xff00);
u32 offset = 0;
u32 active_regs =
le32_to_cpu(active->trig->num_regions);
u32 new_regs = le32_to_cpu(trig->num_regions);
int mem_to_add = trig_regs_size;
if (region_override) {
IWL_DEBUG_FW(fwrt,
"WRT: Trigger %d regions override\n",
id);
mem_to_add -= active_regs * sizeof(__le32);
} else {
IWL_DEBUG_FW(fwrt,
"WRT: Trigger %d regions appending\n",
id);
offset += active_regs;
new_regs += active_regs;
}
if (iwl_dbg_tlv_trig_realloc(fwrt, active, id,
active->size + mem_to_add))
goto next;
if (conf_override) {
IWL_DEBUG_FW(fwrt,
"WRT: Trigger %d configuration override\n",
id);
memcpy(active->trig, trig, sizeof(*trig));
}
memcpy(active->trig->data + offset, trig->data,
trig_regs_size);
active->trig->num_regions = cpu_to_le32(new_regs);
}
/* Since zero means infinity - just set to -1 */
if (!le32_to_cpu(active->trig->occurrences))
active->trig->occurrences = cpu_to_le32(-1);
active->active = true;
if (id == IWL_FW_TRIGGER_ID_PERIODIC_TRIGGER) {
u32 collect_interval = le32_to_cpu(trig->trigger_data);
/* the minimum allowed interval is 50ms */
if (collect_interval < 50) {
collect_interval = 50;
trig->trigger_data =
cpu_to_le32(collect_interval);
}
mod_timer(&fwrt->dump.periodic_trig,
jiffies + msecs_to_jiffies(collect_interval));
}
next:
iter += sizeof(*trig) + trig_regs_size;
}
}
static void _iwl_dbg_tlv_apply_point(struct iwl_fw_runtime *fwrt,
struct iwl_apply_point_data *data,
enum iwl_fw_ini_apply_point pnt,
bool ext)
{
struct iwl_apply_point_data *iter;
if (!data->list.next)
return;
list_for_each_entry(iter, &data->list, list) {
struct iwl_ucode_tlv *tlv = &iter->tlv;
void *ini_tlv = (void *)tlv->data;
u32 type = le32_to_cpu(tlv->type);
const char invalid_ap_str[] =
"WRT: Invalid apply point %d for %s\n";
switch (type) {
case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
iwl_dbg_tlv_apply_debug_info(fwrt, ini_tlv, ext, pnt);
break;
case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
if (pnt != IWL_FW_INI_APPLY_EARLY) {
IWL_ERR(fwrt, invalid_ap_str, pnt,
"buffer allocation");
break;
}
iwl_dbg_tlv_apply_buffer(fwrt, ini_tlv, pnt);
break;
case IWL_UCODE_TLV_TYPE_HCMD:
if (pnt < IWL_FW_INI_APPLY_AFTER_ALIVE) {
IWL_ERR(fwrt, invalid_ap_str, pnt,
"host command");
break;
}
iwl_dbg_tlv_apply_hcmd(fwrt, tlv);
break;
case IWL_UCODE_TLV_TYPE_REGIONS:
iwl_dbg_tlv_apply_region(fwrt, ini_tlv, pnt);
break;
case IWL_UCODE_TLV_TYPE_TRIGGERS:
iwl_dbg_tlv_apply_trigger(fwrt, ini_tlv, pnt);
break;
default:
WARN_ONCE(1, "WRT: Invalid TLV 0x%x for apply point\n",
type);
break;
}
}
}
static void iwl_dbg_tlv_reset_cfg(struct iwl_fw_runtime *fwrt)
{
int i;
for (i = 0; i < IWL_FW_INI_MAX_REGION_ID; i++)
fwrt->dump.active_regs[i] = NULL;
/* disable the triggers, used in recovery flow */
for (i = 0; i < IWL_FW_TRIGGER_ID_NUM; i++)
fwrt->dump.active_trigs[i].active = false;
memset(fwrt->dump.img_name, 0,
sizeof(fwrt->dump.img_name));
memset(fwrt->dump.internal_dbg_cfg_name, 0,
sizeof(fwrt->dump.internal_dbg_cfg_name));
memset(fwrt->dump.external_dbg_cfg_name, 0,
sizeof(fwrt->dump.external_dbg_cfg_name));
fwrt->trans->dbg.ini_dest = IWL_FW_INI_LOCATION_INVALID;
}
void iwl_dbg_tlv_apply_point(struct iwl_fw_runtime *fwrt,
enum iwl_fw_ini_apply_point apply_point)
{
void *data;
if (apply_point == IWL_FW_INI_APPLY_EARLY)
iwl_dbg_tlv_reset_cfg(fwrt);
if (fwrt->trans->dbg.internal_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED) {
IWL_DEBUG_FW(fwrt,
"WRT: Enabling internal configuration apply point %d\n",
apply_point);
data = &fwrt->trans->dbg.apply_points[apply_point];
_iwl_dbg_tlv_apply_point(fwrt, data, apply_point, false);
}
if (fwrt->trans->dbg.external_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED) {
IWL_DEBUG_FW(fwrt,
"WRT: Enabling external configuration apply point %d\n",
apply_point);
data = &fwrt->trans->dbg.apply_points_ext[apply_point];
_iwl_dbg_tlv_apply_point(fwrt, data, apply_point, true);
}
}
IWL_EXPORT_SYMBOL(iwl_dbg_tlv_apply_point);
...@@ -75,9 +75,13 @@ struct iwl_apply_point_data { ...@@ -75,9 +75,13 @@ struct iwl_apply_point_data {
}; };
struct iwl_trans; struct iwl_trans;
struct iwl_fw_runtime;
void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans); void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans);
void iwl_dbg_tlv_free(struct iwl_trans *trans); void iwl_dbg_tlv_free(struct iwl_trans *trans);
void iwl_dbg_tlv_alloc(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv, void iwl_dbg_tlv_alloc(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv,
bool ext); bool ext);
void iwl_dbg_tlv_apply_point(struct iwl_fw_runtime *fwrt,
enum iwl_fw_ini_apply_point apply_point);
#endif /* __iwl_dbg_tlv_h__*/ #endif /* __iwl_dbg_tlv_h__*/
...@@ -430,7 +430,7 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -430,7 +430,7 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
iwl_wait_init_complete, iwl_wait_init_complete,
NULL); NULL);
iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_EARLY); iwl_dbg_tlv_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_EARLY);
/* Will also start the device */ /* Will also start the device */
ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR);
...@@ -438,7 +438,7 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -438,7 +438,7 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret);
goto error; goto error;
} }
iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_AFTER_ALIVE); iwl_dbg_tlv_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_AFTER_ALIVE);
/* Send init config command to mark that we are sending NVM access /* Send init config command to mark that we are sending NVM access
* commands * commands
...@@ -1263,7 +1263,7 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) ...@@ -1263,7 +1263,7 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm)
if (ret) if (ret)
return ret; return ret;
iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_EARLY); iwl_dbg_tlv_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_EARLY);
mvm->rfkill_safe_init_done = false; mvm->rfkill_safe_init_done = false;
ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR);
...@@ -1272,7 +1272,7 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) ...@@ -1272,7 +1272,7 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm)
mvm->rfkill_safe_init_done = true; mvm->rfkill_safe_init_done = true;
iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_AFTER_ALIVE); iwl_dbg_tlv_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_AFTER_ALIVE);
return iwl_init_paging(&mvm->fwrt, mvm->fwrt.cur_fw_img); return iwl_init_paging(&mvm->fwrt, mvm->fwrt.cur_fw_img);
} }
......
...@@ -1447,7 +1447,7 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, ...@@ -1447,7 +1447,7 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
rx_missed_bcon >= stop_trig_missed_bcon) rx_missed_bcon >= stop_trig_missed_bcon)
iwl_fw_dbg_collect_trig(&mvm->fwrt, trigger, NULL); iwl_fw_dbg_collect_trig(&mvm->fwrt, trigger, NULL);
iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_MISSED_BEACONS); iwl_dbg_tlv_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_MISSED_BEACONS);
out: out:
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -1106,7 +1106,7 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm) ...@@ -1106,7 +1106,7 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
} }
ret = iwl_mvm_up(mvm); ret = iwl_mvm_up(mvm);
iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_POST_INIT); iwl_dbg_tlv_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_POST_INIT);
if (ret && test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { if (ret && test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
/* Something went wrong - we need to finish some cleanup /* Something went wrong - we need to finish some cleanup
......
...@@ -1940,7 +1940,7 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, ...@@ -1940,7 +1940,7 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
mvm->scan_uid_status[uid] = 0; mvm->scan_uid_status[uid] = 0;
iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_SCAN_COMPLETE); iwl_dbg_tlv_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_SCAN_COMPLETE);
} }
void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
......
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