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: Shahar S Matityahu <shahar.s.matityahu@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
}
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)
{
int i;
#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);
static inline void iwl_fw_lmac1_set_alive_err_table(struct iwl_trans *trans,
#include "iwl-trans.h"
#include "img.h"
#include "fw/api/debug.h"
-#include "fw/api/dbg-tlv.h"
#include "fw/api/paging.h"
#include "iwl-eeprom-parse.h"
*****************************************************************************/
#include <linux/firmware.h>
+#include "iwl-drv.h"
#include "iwl-trans.h"
#include "iwl-dbg-tlv.h"
+#include "fw/dbg.h"
+#include "fw/runtime.h"
/**
* enum iwl_dbg_tlv_type - debug TLV types
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);
};
struct iwl_trans;
+struct iwl_fw_runtime;
+
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_alloc(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv,
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__*/
iwl_wait_init_complete,
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 */
ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR);
IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret);
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
* commands
if (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;
ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR);
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);
}
rx_missed_bcon >= stop_trig_missed_bcon)
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:
rcu_read_unlock();
}
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)) {
/* Something went wrong - we need to finish some cleanup
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,