cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

iwl-dbg-tlv.c (38476B)


      1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
      2/*
      3 * Copyright (C) 2018-2022 Intel Corporation
      4 */
      5#include <linux/firmware.h>
      6#include "iwl-drv.h"
      7#include "iwl-trans.h"
      8#include "iwl-dbg-tlv.h"
      9#include "fw/dbg.h"
     10#include "fw/runtime.h"
     11
     12/**
     13 * enum iwl_dbg_tlv_type - debug TLV types
     14 * @IWL_DBG_TLV_TYPE_DEBUG_INFO: debug info TLV
     15 * @IWL_DBG_TLV_TYPE_BUF_ALLOC: buffer allocation TLV
     16 * @IWL_DBG_TLV_TYPE_HCMD: host command TLV
     17 * @IWL_DBG_TLV_TYPE_REGION: region TLV
     18 * @IWL_DBG_TLV_TYPE_TRIGGER: trigger TLV
     19 * @IWL_DBG_TLV_TYPE_CONF_SET: conf set TLV
     20 * @IWL_DBG_TLV_TYPE_NUM: number of debug TLVs
     21 */
     22enum iwl_dbg_tlv_type {
     23	IWL_DBG_TLV_TYPE_DEBUG_INFO =
     24		IWL_UCODE_TLV_TYPE_DEBUG_INFO - IWL_UCODE_TLV_DEBUG_BASE,
     25	IWL_DBG_TLV_TYPE_BUF_ALLOC,
     26	IWL_DBG_TLV_TYPE_HCMD,
     27	IWL_DBG_TLV_TYPE_REGION,
     28	IWL_DBG_TLV_TYPE_TRIGGER,
     29	IWL_DBG_TLV_TYPE_CONF_SET,
     30	IWL_DBG_TLV_TYPE_NUM,
     31};
     32
     33/**
     34 * struct iwl_dbg_tlv_ver_data -  debug TLV version struct
     35 * @min_ver: min version supported
     36 * @max_ver: max version supported
     37 */
     38struct iwl_dbg_tlv_ver_data {
     39	int min_ver;
     40	int max_ver;
     41};
     42
     43/**
     44 * struct iwl_dbg_tlv_timer_node - timer node struct
     45 * @list: list of &struct iwl_dbg_tlv_timer_node
     46 * @timer: timer
     47 * @fwrt: &struct iwl_fw_runtime
     48 * @tlv: TLV attach to the timer node
     49 */
     50struct iwl_dbg_tlv_timer_node {
     51	struct list_head list;
     52	struct timer_list timer;
     53	struct iwl_fw_runtime *fwrt;
     54	struct iwl_ucode_tlv *tlv;
     55};
     56
     57static const struct iwl_dbg_tlv_ver_data
     58dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = {
     59	[IWL_DBG_TLV_TYPE_DEBUG_INFO]	= {.min_ver = 1, .max_ver = 1,},
     60	[IWL_DBG_TLV_TYPE_BUF_ALLOC]	= {.min_ver = 1, .max_ver = 1,},
     61	[IWL_DBG_TLV_TYPE_HCMD]		= {.min_ver = 1, .max_ver = 1,},
     62	[IWL_DBG_TLV_TYPE_REGION]	= {.min_ver = 1, .max_ver = 3,},
     63	[IWL_DBG_TLV_TYPE_TRIGGER]	= {.min_ver = 1, .max_ver = 1,},
     64	[IWL_DBG_TLV_TYPE_CONF_SET]	= {.min_ver = 1, .max_ver = 1,},
     65};
     66
     67static int iwl_dbg_tlv_add(const struct iwl_ucode_tlv *tlv,
     68			   struct list_head *list)
     69{
     70	u32 len = le32_to_cpu(tlv->length);
     71	struct iwl_dbg_tlv_node *node;
     72
     73	node = kzalloc(sizeof(*node) + len, GFP_KERNEL);
     74	if (!node)
     75		return -ENOMEM;
     76
     77	memcpy(&node->tlv, tlv, sizeof(node->tlv));
     78	memcpy(node->tlv.data, tlv->data, len);
     79	list_add_tail(&node->list, list);
     80
     81	return 0;
     82}
     83
     84static bool iwl_dbg_tlv_ver_support(const struct iwl_ucode_tlv *tlv)
     85{
     86	const struct iwl_fw_ini_header *hdr = (const void *)&tlv->data[0];
     87	u32 type = le32_to_cpu(tlv->type);
     88	u32 tlv_idx = type - IWL_UCODE_TLV_DEBUG_BASE;
     89	u32 ver = le32_to_cpu(hdr->version);
     90
     91	if (ver < dbg_ver_table[tlv_idx].min_ver ||
     92	    ver > dbg_ver_table[tlv_idx].max_ver)
     93		return false;
     94
     95	return true;
     96}
     97
     98static int iwl_dbg_tlv_alloc_debug_info(struct iwl_trans *trans,
     99					const struct iwl_ucode_tlv *tlv)
    100{
    101	const struct iwl_fw_ini_debug_info_tlv *debug_info = (const void *)tlv->data;
    102
    103	if (le32_to_cpu(tlv->length) != sizeof(*debug_info))
    104		return -EINVAL;
    105
    106	IWL_DEBUG_FW(trans, "WRT: Loading debug cfg: %s\n",
    107		     debug_info->debug_cfg_name);
    108
    109	return iwl_dbg_tlv_add(tlv, &trans->dbg.debug_info_tlv_list);
    110}
    111
    112static int iwl_dbg_tlv_alloc_buf_alloc(struct iwl_trans *trans,
    113				       const struct iwl_ucode_tlv *tlv)
    114{
    115	const struct iwl_fw_ini_allocation_tlv *alloc = (const void *)tlv->data;
    116	u32 buf_location;
    117	u32 alloc_id;
    118
    119	if (le32_to_cpu(tlv->length) != sizeof(*alloc))
    120		return -EINVAL;
    121
    122	buf_location = le32_to_cpu(alloc->buf_location);
    123	alloc_id = le32_to_cpu(alloc->alloc_id);
    124
    125	if (buf_location == IWL_FW_INI_LOCATION_INVALID ||
    126	    buf_location >= IWL_FW_INI_LOCATION_NUM)
    127		goto err;
    128
    129	if (alloc_id == IWL_FW_INI_ALLOCATION_INVALID ||
    130	    alloc_id >= IWL_FW_INI_ALLOCATION_NUM)
    131		goto err;
    132
    133	if (buf_location == IWL_FW_INI_LOCATION_NPK_PATH &&
    134	    alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1)
    135		goto err;
    136
    137	if (buf_location == IWL_FW_INI_LOCATION_SRAM_PATH &&
    138	    alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1)
    139		goto err;
    140
    141	trans->dbg.fw_mon_cfg[alloc_id] = *alloc;
    142
    143	return 0;
    144err:
    145	IWL_ERR(trans,
    146		"WRT: Invalid allocation id %u and/or location id %u for allocation TLV\n",
    147		alloc_id, buf_location);
    148	return -EINVAL;
    149}
    150
    151static int iwl_dbg_tlv_alloc_hcmd(struct iwl_trans *trans,
    152				  const struct iwl_ucode_tlv *tlv)
    153{
    154	const struct iwl_fw_ini_hcmd_tlv *hcmd = (const void *)tlv->data;
    155	u32 tp = le32_to_cpu(hcmd->time_point);
    156
    157	if (le32_to_cpu(tlv->length) <= sizeof(*hcmd))
    158		return -EINVAL;
    159
    160	/* Host commands can not be sent in early time point since the FW
    161	 * is not ready
    162	 */
    163	if (tp == IWL_FW_INI_TIME_POINT_INVALID ||
    164	    tp >= IWL_FW_INI_TIME_POINT_NUM ||
    165	    tp == IWL_FW_INI_TIME_POINT_EARLY) {
    166		IWL_ERR(trans,
    167			"WRT: Invalid time point %u for host command TLV\n",
    168			tp);
    169		return -EINVAL;
    170	}
    171
    172	return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].hcmd_list);
    173}
    174
    175static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans,
    176				    const struct iwl_ucode_tlv *tlv)
    177{
    178	const struct iwl_fw_ini_region_tlv *reg = (const void *)tlv->data;
    179	struct iwl_ucode_tlv **active_reg;
    180	u32 id = le32_to_cpu(reg->id);
    181	u8 type = reg->type;
    182	u32 tlv_len = sizeof(*tlv) + le32_to_cpu(tlv->length);
    183
    184	/*
    185	 * The higher part of the ID from version 2 is debug policy.
    186	 * The id will be only lsb 16 bits, so mask it out.
    187	 */
    188	if (le32_to_cpu(reg->hdr.version) >= 2)
    189		id &= IWL_FW_INI_REGION_ID_MASK;
    190
    191	if (le32_to_cpu(tlv->length) < sizeof(*reg))
    192		return -EINVAL;
    193
    194	/* for safe use of a string from FW, limit it to IWL_FW_INI_MAX_NAME */
    195	IWL_DEBUG_FW(trans, "WRT: parsing region: %.*s\n",
    196		     IWL_FW_INI_MAX_NAME, reg->name);
    197
    198	if (id >= IWL_FW_INI_MAX_REGION_ID) {
    199		IWL_ERR(trans, "WRT: Invalid region id %u\n", id);
    200		return -EINVAL;
    201	}
    202
    203	if (type <= IWL_FW_INI_REGION_INVALID ||
    204	    type >= IWL_FW_INI_REGION_NUM) {
    205		IWL_ERR(trans, "WRT: Invalid region type %u\n", type);
    206		return -EINVAL;
    207	}
    208
    209	if (type == IWL_FW_INI_REGION_PCI_IOSF_CONFIG &&
    210	    !trans->ops->read_config32) {
    211		IWL_ERR(trans, "WRT: Unsupported region type %u\n", type);
    212		return -EOPNOTSUPP;
    213	}
    214
    215	if (type == IWL_FW_INI_REGION_INTERNAL_BUFFER) {
    216		trans->dbg.imr_data.sram_addr =
    217			le32_to_cpu(reg->internal_buffer.base_addr);
    218		trans->dbg.imr_data.sram_size =
    219			le32_to_cpu(reg->internal_buffer.size);
    220	}
    221
    222
    223	active_reg = &trans->dbg.active_regions[id];
    224	if (*active_reg) {
    225		IWL_WARN(trans, "WRT: Overriding region id %u\n", id);
    226
    227		kfree(*active_reg);
    228	}
    229
    230	*active_reg = kmemdup(tlv, tlv_len, GFP_KERNEL);
    231	if (!*active_reg)
    232		return -ENOMEM;
    233
    234	IWL_DEBUG_FW(trans, "WRT: Enabling region id %u type %u\n", id, type);
    235
    236	return 0;
    237}
    238
    239static int iwl_dbg_tlv_alloc_trigger(struct iwl_trans *trans,
    240				     const struct iwl_ucode_tlv *tlv)
    241{
    242	const struct iwl_fw_ini_trigger_tlv *trig = (const void *)tlv->data;
    243	struct iwl_fw_ini_trigger_tlv *dup_trig;
    244	u32 tp = le32_to_cpu(trig->time_point);
    245	u32 rf = le32_to_cpu(trig->reset_fw);
    246	struct iwl_ucode_tlv *dup = NULL;
    247	int ret;
    248
    249	if (le32_to_cpu(tlv->length) < sizeof(*trig))
    250		return -EINVAL;
    251
    252	if (tp <= IWL_FW_INI_TIME_POINT_INVALID ||
    253	    tp >= IWL_FW_INI_TIME_POINT_NUM) {
    254		IWL_ERR(trans,
    255			"WRT: Invalid time point %u for trigger TLV\n",
    256			tp);
    257		return -EINVAL;
    258	}
    259
    260	IWL_DEBUG_FW(trans,
    261		     "WRT: time point %u for trigger TLV with reset_fw %u\n",
    262		     tp, rf);
    263	trans->dbg.last_tp_resetfw = 0xFF;
    264	if (!le32_to_cpu(trig->occurrences)) {
    265		dup = kmemdup(tlv, sizeof(*tlv) + le32_to_cpu(tlv->length),
    266				GFP_KERNEL);
    267		if (!dup)
    268			return -ENOMEM;
    269		dup_trig = (void *)dup->data;
    270		dup_trig->occurrences = cpu_to_le32(-1);
    271		tlv = dup;
    272	}
    273
    274	ret = iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].trig_list);
    275	kfree(dup);
    276
    277	return ret;
    278}
    279
    280static int iwl_dbg_tlv_config_set(struct iwl_trans *trans,
    281				  const struct iwl_ucode_tlv *tlv)
    282{
    283	const struct iwl_fw_ini_conf_set_tlv *conf_set = (const void *)tlv->data;
    284	u32 tp = le32_to_cpu(conf_set->time_point);
    285	u32 type = le32_to_cpu(conf_set->set_type);
    286
    287	if (tp <= IWL_FW_INI_TIME_POINT_INVALID ||
    288	    tp >= IWL_FW_INI_TIME_POINT_NUM) {
    289		IWL_DEBUG_FW(trans,
    290			     "WRT: Invalid time point %u for config set TLV\n", tp);
    291		return -EINVAL;
    292	}
    293
    294	if (type <= IWL_FW_INI_CONFIG_SET_TYPE_INVALID ||
    295	    type >= IWL_FW_INI_CONFIG_SET_TYPE_MAX_NUM) {
    296		IWL_DEBUG_FW(trans,
    297			     "WRT: Invalid config set type %u for config set TLV\n", type);
    298		return -EINVAL;
    299	}
    300
    301	return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].config_list);
    302}
    303
    304static int (*dbg_tlv_alloc[])(struct iwl_trans *trans,
    305			      const struct iwl_ucode_tlv *tlv) = {
    306	[IWL_DBG_TLV_TYPE_DEBUG_INFO]	= iwl_dbg_tlv_alloc_debug_info,
    307	[IWL_DBG_TLV_TYPE_BUF_ALLOC]	= iwl_dbg_tlv_alloc_buf_alloc,
    308	[IWL_DBG_TLV_TYPE_HCMD]		= iwl_dbg_tlv_alloc_hcmd,
    309	[IWL_DBG_TLV_TYPE_REGION]	= iwl_dbg_tlv_alloc_region,
    310	[IWL_DBG_TLV_TYPE_TRIGGER]	= iwl_dbg_tlv_alloc_trigger,
    311	[IWL_DBG_TLV_TYPE_CONF_SET]	= iwl_dbg_tlv_config_set,
    312};
    313
    314void iwl_dbg_tlv_alloc(struct iwl_trans *trans, const struct iwl_ucode_tlv *tlv,
    315		       bool ext)
    316{
    317	enum iwl_ini_cfg_state *cfg_state = ext ?
    318		&trans->dbg.external_ini_cfg : &trans->dbg.internal_ini_cfg;
    319	const struct iwl_fw_ini_header *hdr = (const void *)&tlv->data[0];
    320	u32 type;
    321	u32 tlv_idx;
    322	u32 domain;
    323	int ret;
    324
    325	if (le32_to_cpu(tlv->length) < sizeof(*hdr))
    326		return;
    327
    328	type = le32_to_cpu(tlv->type);
    329	tlv_idx = type - IWL_UCODE_TLV_DEBUG_BASE;
    330	domain = le32_to_cpu(hdr->domain);
    331
    332	if (domain != IWL_FW_INI_DOMAIN_ALWAYS_ON &&
    333	    !(domain & trans->dbg.domains_bitmap)) {
    334		IWL_DEBUG_FW(trans,
    335			     "WRT: Skipping TLV with disabled domain 0x%0x (0x%0x)\n",
    336			     domain, trans->dbg.domains_bitmap);
    337		return;
    338	}
    339
    340	if (tlv_idx >= ARRAY_SIZE(dbg_tlv_alloc) || !dbg_tlv_alloc[tlv_idx]) {
    341		IWL_ERR(trans, "WRT: Unsupported TLV type 0x%x\n", type);
    342		goto out_err;
    343	}
    344
    345	if (!iwl_dbg_tlv_ver_support(tlv)) {
    346		IWL_ERR(trans, "WRT: Unsupported TLV 0x%x version %u\n", type,
    347			le32_to_cpu(hdr->version));
    348		goto out_err;
    349	}
    350
    351	ret = dbg_tlv_alloc[tlv_idx](trans, tlv);
    352	if (ret) {
    353		IWL_ERR(trans,
    354			"WRT: Failed to allocate TLV 0x%x, ret %d, (ext=%d)\n",
    355			type, ret, ext);
    356		goto out_err;
    357	}
    358
    359	if (*cfg_state == IWL_INI_CFG_STATE_NOT_LOADED)
    360		*cfg_state = IWL_INI_CFG_STATE_LOADED;
    361
    362	return;
    363
    364out_err:
    365	*cfg_state = IWL_INI_CFG_STATE_CORRUPTED;
    366}
    367
    368void iwl_dbg_tlv_del_timers(struct iwl_trans *trans)
    369{
    370	struct list_head *timer_list = &trans->dbg.periodic_trig_list;
    371	struct iwl_dbg_tlv_timer_node *node, *tmp;
    372
    373	list_for_each_entry_safe(node, tmp, timer_list, list) {
    374		del_timer_sync(&node->timer);
    375		list_del(&node->list);
    376		kfree(node);
    377	}
    378}
    379IWL_EXPORT_SYMBOL(iwl_dbg_tlv_del_timers);
    380
    381static void iwl_dbg_tlv_fragments_free(struct iwl_trans *trans,
    382				       enum iwl_fw_ini_allocation_id alloc_id)
    383{
    384	struct iwl_fw_mon *fw_mon;
    385	int i;
    386
    387	if (alloc_id <= IWL_FW_INI_ALLOCATION_INVALID ||
    388	    alloc_id >= IWL_FW_INI_ALLOCATION_NUM)
    389		return;
    390
    391	fw_mon = &trans->dbg.fw_mon_ini[alloc_id];
    392
    393	for (i = 0; i < fw_mon->num_frags; i++) {
    394		struct iwl_dram_data *frag = &fw_mon->frags[i];
    395
    396		dma_free_coherent(trans->dev, frag->size, frag->block,
    397				  frag->physical);
    398
    399		frag->physical = 0;
    400		frag->block = NULL;
    401		frag->size = 0;
    402	}
    403
    404	kfree(fw_mon->frags);
    405	fw_mon->frags = NULL;
    406	fw_mon->num_frags = 0;
    407}
    408
    409void iwl_dbg_tlv_free(struct iwl_trans *trans)
    410{
    411	struct iwl_dbg_tlv_node *tlv_node, *tlv_node_tmp;
    412	int i;
    413
    414	iwl_dbg_tlv_del_timers(trans);
    415
    416	for (i = 0; i < ARRAY_SIZE(trans->dbg.active_regions); i++) {
    417		struct iwl_ucode_tlv **active_reg =
    418			&trans->dbg.active_regions[i];
    419
    420		kfree(*active_reg);
    421		*active_reg = NULL;
    422	}
    423
    424	list_for_each_entry_safe(tlv_node, tlv_node_tmp,
    425				 &trans->dbg.debug_info_tlv_list, list) {
    426		list_del(&tlv_node->list);
    427		kfree(tlv_node);
    428	}
    429
    430	for (i = 0; i < ARRAY_SIZE(trans->dbg.time_point); i++) {
    431		struct iwl_dbg_tlv_time_point_data *tp =
    432			&trans->dbg.time_point[i];
    433
    434		list_for_each_entry_safe(tlv_node, tlv_node_tmp, &tp->trig_list,
    435					 list) {
    436			list_del(&tlv_node->list);
    437			kfree(tlv_node);
    438		}
    439
    440		list_for_each_entry_safe(tlv_node, tlv_node_tmp, &tp->hcmd_list,
    441					 list) {
    442			list_del(&tlv_node->list);
    443			kfree(tlv_node);
    444		}
    445
    446		list_for_each_entry_safe(tlv_node, tlv_node_tmp,
    447					 &tp->active_trig_list, list) {
    448			list_del(&tlv_node->list);
    449			kfree(tlv_node);
    450		}
    451
    452		list_for_each_entry_safe(tlv_node, tlv_node_tmp,
    453					 &tp->config_list, list) {
    454			list_del(&tlv_node->list);
    455			kfree(tlv_node);
    456		}
    457
    458	}
    459
    460	for (i = 0; i < ARRAY_SIZE(trans->dbg.fw_mon_ini); i++)
    461		iwl_dbg_tlv_fragments_free(trans, i);
    462}
    463
    464static int iwl_dbg_tlv_parse_bin(struct iwl_trans *trans, const u8 *data,
    465				 size_t len)
    466{
    467	const struct iwl_ucode_tlv *tlv;
    468	u32 tlv_len;
    469
    470	while (len >= sizeof(*tlv)) {
    471		len -= sizeof(*tlv);
    472		tlv = (const void *)data;
    473
    474		tlv_len = le32_to_cpu(tlv->length);
    475
    476		if (len < tlv_len) {
    477			IWL_ERR(trans, "invalid TLV len: %zd/%u\n",
    478				len, tlv_len);
    479			return -EINVAL;
    480		}
    481		len -= ALIGN(tlv_len, 4);
    482		data += sizeof(*tlv) + ALIGN(tlv_len, 4);
    483
    484		iwl_dbg_tlv_alloc(trans, tlv, true);
    485	}
    486
    487	return 0;
    488}
    489
    490void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans)
    491{
    492	const struct firmware *fw;
    493	const char *yoyo_bin = "iwl-debug-yoyo.bin";
    494	int res;
    495
    496	if (!iwlwifi_mod_params.enable_ini ||
    497	    trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_8000)
    498		return;
    499
    500	res = firmware_request_nowarn(&fw, yoyo_bin, dev);
    501	IWL_DEBUG_FW(trans, "%s %s\n", res ? "didn't load" : "loaded", yoyo_bin);
    502
    503	if (res)
    504		return;
    505
    506	iwl_dbg_tlv_parse_bin(trans, fw->data, fw->size);
    507
    508	release_firmware(fw);
    509}
    510
    511void iwl_dbg_tlv_init(struct iwl_trans *trans)
    512{
    513	int i;
    514
    515	INIT_LIST_HEAD(&trans->dbg.debug_info_tlv_list);
    516	INIT_LIST_HEAD(&trans->dbg.periodic_trig_list);
    517
    518	for (i = 0; i < ARRAY_SIZE(trans->dbg.time_point); i++) {
    519		struct iwl_dbg_tlv_time_point_data *tp =
    520			&trans->dbg.time_point[i];
    521
    522		INIT_LIST_HEAD(&tp->trig_list);
    523		INIT_LIST_HEAD(&tp->hcmd_list);
    524		INIT_LIST_HEAD(&tp->active_trig_list);
    525		INIT_LIST_HEAD(&tp->config_list);
    526	}
    527}
    528
    529static int iwl_dbg_tlv_alloc_fragment(struct iwl_fw_runtime *fwrt,
    530				      struct iwl_dram_data *frag, u32 pages)
    531{
    532	void *block = NULL;
    533	dma_addr_t physical;
    534
    535	if (!frag || frag->size || !pages)
    536		return -EIO;
    537
    538	/*
    539	 * We try to allocate as many pages as we can, starting with
    540	 * the requested amount and going down until we can allocate
    541	 * something.  Because of DIV_ROUND_UP(), pages will never go
    542	 * down to 0 and stop the loop, so stop when pages reaches 1,
    543	 * which is too small anyway.
    544	 */
    545	while (pages > 1) {
    546		block = dma_alloc_coherent(fwrt->dev, pages * PAGE_SIZE,
    547					   &physical,
    548					   GFP_KERNEL | __GFP_NOWARN);
    549		if (block)
    550			break;
    551
    552		IWL_WARN(fwrt, "WRT: Failed to allocate fragment size %lu\n",
    553			 pages * PAGE_SIZE);
    554
    555		pages = DIV_ROUND_UP(pages, 2);
    556	}
    557
    558	if (!block)
    559		return -ENOMEM;
    560
    561	frag->physical = physical;
    562	frag->block = block;
    563	frag->size = pages * PAGE_SIZE;
    564
    565	return pages;
    566}
    567
    568static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt,
    569				       enum iwl_fw_ini_allocation_id alloc_id)
    570{
    571	struct iwl_fw_mon *fw_mon;
    572	struct iwl_fw_ini_allocation_tlv *fw_mon_cfg;
    573	u32 num_frags, remain_pages, frag_pages;
    574	int i;
    575
    576	if (alloc_id < IWL_FW_INI_ALLOCATION_INVALID ||
    577	    alloc_id >= IWL_FW_INI_ALLOCATION_NUM)
    578		return -EIO;
    579
    580	fw_mon_cfg = &fwrt->trans->dbg.fw_mon_cfg[alloc_id];
    581	fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id];
    582
    583	if (fw_mon->num_frags ||
    584	    fw_mon_cfg->buf_location !=
    585	    cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH))
    586		return 0;
    587
    588	num_frags = le32_to_cpu(fw_mon_cfg->max_frags_num);
    589	if (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
    590		if (alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1)
    591			return -EIO;
    592		num_frags = 1;
    593	}
    594
    595	remain_pages = DIV_ROUND_UP(le32_to_cpu(fw_mon_cfg->req_size),
    596				    PAGE_SIZE);
    597	num_frags = min_t(u32, num_frags, BUF_ALLOC_MAX_NUM_FRAGS);
    598	num_frags = min_t(u32, num_frags, remain_pages);
    599	frag_pages = DIV_ROUND_UP(remain_pages, num_frags);
    600
    601	fw_mon->frags = kcalloc(num_frags, sizeof(*fw_mon->frags), GFP_KERNEL);
    602	if (!fw_mon->frags)
    603		return -ENOMEM;
    604
    605	for (i = 0; i < num_frags; i++) {
    606		int pages = min_t(u32, frag_pages, remain_pages);
    607
    608		IWL_DEBUG_FW(fwrt,
    609			     "WRT: Allocating DRAM buffer (alloc_id=%u, fragment=%u, size=0x%lx)\n",
    610			     alloc_id, i, pages * PAGE_SIZE);
    611
    612		pages = iwl_dbg_tlv_alloc_fragment(fwrt, &fw_mon->frags[i],
    613						   pages);
    614		if (pages < 0) {
    615			u32 alloc_size = le32_to_cpu(fw_mon_cfg->req_size) -
    616				(remain_pages * PAGE_SIZE);
    617
    618			if (alloc_size < le32_to_cpu(fw_mon_cfg->min_size)) {
    619				iwl_dbg_tlv_fragments_free(fwrt->trans,
    620							   alloc_id);
    621				return pages;
    622			}
    623			break;
    624		}
    625
    626		remain_pages -= pages;
    627		fw_mon->num_frags++;
    628	}
    629
    630	return 0;
    631}
    632
    633static int iwl_dbg_tlv_apply_buffer(struct iwl_fw_runtime *fwrt,
    634				    enum iwl_fw_ini_allocation_id alloc_id)
    635{
    636	struct iwl_fw_mon *fw_mon;
    637	u32 remain_frags, num_commands;
    638	int i, fw_mon_idx = 0;
    639
    640	if (!fw_has_capa(&fwrt->fw->ucode_capa,
    641			 IWL_UCODE_TLV_CAPA_DBG_BUF_ALLOC_CMD_SUPP))
    642		return 0;
    643
    644	if (alloc_id < IWL_FW_INI_ALLOCATION_INVALID ||
    645	    alloc_id >= IWL_FW_INI_ALLOCATION_NUM)
    646		return -EIO;
    647
    648	if (le32_to_cpu(fwrt->trans->dbg.fw_mon_cfg[alloc_id].buf_location) !=
    649	    IWL_FW_INI_LOCATION_DRAM_PATH)
    650		return 0;
    651
    652	fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id];
    653
    654	/* the first fragment of DBGC1 is given to the FW via register
    655	 * or context info
    656	 */
    657	if (alloc_id == IWL_FW_INI_ALLOCATION_ID_DBGC1)
    658		fw_mon_idx++;
    659
    660	remain_frags = fw_mon->num_frags - fw_mon_idx;
    661	if (!remain_frags)
    662		return 0;
    663
    664	num_commands = DIV_ROUND_UP(remain_frags, BUF_ALLOC_MAX_NUM_FRAGS);
    665
    666	IWL_DEBUG_FW(fwrt, "WRT: Applying DRAM destination (alloc_id=%u)\n",
    667		     alloc_id);
    668
    669	for (i = 0; i < num_commands; i++) {
    670		u32 num_frags = min_t(u32, remain_frags,
    671				      BUF_ALLOC_MAX_NUM_FRAGS);
    672		struct iwl_buf_alloc_cmd data = {
    673			.alloc_id = cpu_to_le32(alloc_id),
    674			.num_frags = cpu_to_le32(num_frags),
    675			.buf_location =
    676				cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH),
    677		};
    678		struct iwl_host_cmd hcmd = {
    679			.id = WIDE_ID(DEBUG_GROUP, BUFFER_ALLOCATION),
    680			.data[0] = &data,
    681			.len[0] = sizeof(data),
    682			.flags = CMD_SEND_IN_RFKILL,
    683		};
    684		int ret, j;
    685
    686		for (j = 0; j < num_frags; j++) {
    687			struct iwl_buf_alloc_frag *frag = &data.frags[j];
    688			struct iwl_dram_data *fw_mon_frag =
    689				&fw_mon->frags[fw_mon_idx++];
    690
    691			frag->addr = cpu_to_le64(fw_mon_frag->physical);
    692			frag->size = cpu_to_le32(fw_mon_frag->size);
    693		}
    694		ret = iwl_trans_send_cmd(fwrt->trans, &hcmd);
    695		if (ret)
    696			return ret;
    697
    698		remain_frags -= num_frags;
    699	}
    700
    701	return 0;
    702}
    703
    704static void iwl_dbg_tlv_apply_buffers(struct iwl_fw_runtime *fwrt)
    705{
    706	int ret, i;
    707
    708	if (fw_has_capa(&fwrt->fw->ucode_capa,
    709			IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT))
    710		return;
    711
    712	for (i = 0; i < IWL_FW_INI_ALLOCATION_NUM; i++) {
    713		ret = iwl_dbg_tlv_apply_buffer(fwrt, i);
    714		if (ret)
    715			IWL_WARN(fwrt,
    716				 "WRT: Failed to apply DRAM buffer for allocation id %d, ret=%d\n",
    717				 i, ret);
    718	}
    719}
    720
    721static int iwl_dbg_tlv_update_dram(struct iwl_fw_runtime *fwrt,
    722				   enum iwl_fw_ini_allocation_id alloc_id,
    723				   struct iwl_dram_info *dram_info)
    724{
    725	struct iwl_fw_mon *fw_mon;
    726	u32 remain_frags, num_frags;
    727	int j, fw_mon_idx = 0;
    728	struct iwl_buf_alloc_cmd *data;
    729
    730	if (le32_to_cpu(fwrt->trans->dbg.fw_mon_cfg[alloc_id].buf_location) !=
    731			IWL_FW_INI_LOCATION_DRAM_PATH) {
    732		IWL_DEBUG_FW(fwrt, "DRAM_PATH is not supported alloc_id %u\n", alloc_id);
    733		return -1;
    734	}
    735
    736	fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id];
    737
    738	/* the first fragment of DBGC1 is given to the FW via register
    739	 * or context info
    740	 */
    741	if (alloc_id == IWL_FW_INI_ALLOCATION_ID_DBGC1)
    742		fw_mon_idx++;
    743
    744	remain_frags = fw_mon->num_frags - fw_mon_idx;
    745	if (!remain_frags)
    746		return -1;
    747
    748	num_frags = min_t(u32, remain_frags, BUF_ALLOC_MAX_NUM_FRAGS);
    749	data = &dram_info->dram_frags[alloc_id - 1];
    750	data->alloc_id = cpu_to_le32(alloc_id);
    751	data->num_frags = cpu_to_le32(num_frags);
    752	data->buf_location = cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH);
    753
    754	IWL_DEBUG_FW(fwrt, "WRT: DRAM buffer details alloc_id=%u, num_frags=%u\n",
    755		     cpu_to_le32(alloc_id), cpu_to_le32(num_frags));
    756
    757	for (j = 0; j < num_frags; j++) {
    758		struct iwl_buf_alloc_frag *frag = &data->frags[j];
    759		struct iwl_dram_data *fw_mon_frag = &fw_mon->frags[fw_mon_idx++];
    760
    761		frag->addr = cpu_to_le64(fw_mon_frag->physical);
    762		frag->size = cpu_to_le32(fw_mon_frag->size);
    763		IWL_DEBUG_FW(fwrt, "WRT: DRAM fragment details\n");
    764		IWL_DEBUG_FW(fwrt, "frag=%u, addr=0x%016llx, size=0x%x)\n",
    765			     j, cpu_to_le64(fw_mon_frag->physical),
    766			     cpu_to_le32(fw_mon_frag->size));
    767	}
    768	return 0;
    769}
    770
    771static void iwl_dbg_tlv_update_drams(struct iwl_fw_runtime *fwrt)
    772{
    773	int ret, i;
    774	bool dram_alloc = false;
    775	struct iwl_dram_data *frags =
    776		&fwrt->trans->dbg.fw_mon_ini[IWL_FW_INI_ALLOCATION_ID_DBGC1].frags[0];
    777	struct iwl_dram_info *dram_info;
    778
    779	if (!frags || !frags->block)
    780		return;
    781
    782	dram_info = frags->block;
    783
    784	if (!fw_has_capa(&fwrt->fw->ucode_capa,
    785			 IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT))
    786		return;
    787
    788	dram_info->first_word = cpu_to_le32(DRAM_INFO_FIRST_MAGIC_WORD);
    789	dram_info->second_word = cpu_to_le32(DRAM_INFO_SECOND_MAGIC_WORD);
    790
    791	for (i = IWL_FW_INI_ALLOCATION_ID_DBGC1;
    792	     i <= IWL_FW_INI_ALLOCATION_ID_DBGC3; i++) {
    793		ret = iwl_dbg_tlv_update_dram(fwrt, i, dram_info);
    794		if (!ret)
    795			dram_alloc = true;
    796		else
    797			IWL_WARN(fwrt,
    798				 "WRT: Failed to set DRAM buffer for alloc id %d, ret=%d\n",
    799				 i, ret);
    800	}
    801
    802	if (dram_alloc)
    803		IWL_DEBUG_FW(fwrt, "block data after  %08x\n",
    804			     dram_info->first_word);
    805	else
    806		memset(frags->block, 0, sizeof(*dram_info));
    807}
    808
    809static void iwl_dbg_tlv_send_hcmds(struct iwl_fw_runtime *fwrt,
    810				   struct list_head *hcmd_list)
    811{
    812	struct iwl_dbg_tlv_node *node;
    813
    814	list_for_each_entry(node, hcmd_list, list) {
    815		struct iwl_fw_ini_hcmd_tlv *hcmd = (void *)node->tlv.data;
    816		struct iwl_fw_ini_hcmd *hcmd_data = &hcmd->hcmd;
    817		u16 hcmd_len = le32_to_cpu(node->tlv.length) - sizeof(*hcmd);
    818		struct iwl_host_cmd cmd = {
    819			.id = WIDE_ID(hcmd_data->group, hcmd_data->id),
    820			.len = { hcmd_len, },
    821			.data = { hcmd_data->data, },
    822		};
    823
    824		iwl_trans_send_cmd(fwrt->trans, &cmd);
    825	}
    826}
    827
    828static void iwl_dbg_tlv_apply_config(struct iwl_fw_runtime *fwrt,
    829				     struct list_head *conf_list)
    830{
    831	struct iwl_dbg_tlv_node *node;
    832
    833	list_for_each_entry(node, conf_list, list) {
    834		struct iwl_fw_ini_conf_set_tlv *config_list = (void *)node->tlv.data;
    835		u32 count, address, value;
    836		u32 len = (le32_to_cpu(node->tlv.length) - sizeof(*config_list)) / 8;
    837		u32 type = le32_to_cpu(config_list->set_type);
    838		u32 offset = le32_to_cpu(config_list->addr_offset);
    839
    840		switch (type) {
    841		case IWL_FW_INI_CONFIG_SET_TYPE_DEVICE_PERIPHERY_MAC: {
    842			if (!iwl_trans_grab_nic_access(fwrt->trans)) {
    843				IWL_DEBUG_FW(fwrt, "WRT: failed to get nic access\n");
    844				IWL_DEBUG_FW(fwrt, "WRT: skipping MAC PERIPHERY config\n");
    845				continue;
    846			}
    847			IWL_DEBUG_FW(fwrt, "WRT:  MAC PERIPHERY config len: len %u\n", len);
    848			for (count = 0; count < len; count++) {
    849				address = le32_to_cpu(config_list->addr_val[count].address);
    850				value = le32_to_cpu(config_list->addr_val[count].value);
    851				iwl_trans_write_prph(fwrt->trans, address + offset, value);
    852			}
    853			iwl_trans_release_nic_access(fwrt->trans);
    854		break;
    855		}
    856		case IWL_FW_INI_CONFIG_SET_TYPE_DEVICE_MEMORY: {
    857			for (count = 0; count < len; count++) {
    858				address = le32_to_cpu(config_list->addr_val[count].address);
    859				value = le32_to_cpu(config_list->addr_val[count].value);
    860				iwl_trans_write_mem32(fwrt->trans, address + offset, value);
    861				IWL_DEBUG_FW(fwrt, "WRT: DEV_MEM: count %u, add: %u val: %u\n",
    862					     count, address, value);
    863			}
    864		break;
    865		}
    866		case IWL_FW_INI_CONFIG_SET_TYPE_CSR: {
    867			for (count = 0; count < len; count++) {
    868				address = le32_to_cpu(config_list->addr_val[count].address);
    869				value = le32_to_cpu(config_list->addr_val[count].value);
    870				iwl_write32(fwrt->trans, address + offset, value);
    871				IWL_DEBUG_FW(fwrt, "WRT: CSR: count %u, add: %u val: %u\n",
    872					     count, address, value);
    873			}
    874		break;
    875		}
    876		case IWL_FW_INI_CONFIG_SET_TYPE_DBGC_DRAM_ADDR: {
    877			struct iwl_dbgc1_info dram_info = {};
    878			struct iwl_dram_data *frags = &fwrt->trans->dbg.fw_mon_ini[1].frags[0];
    879			__le64 dram_base_addr;
    880			__le32 dram_size;
    881			u64 dram_addr;
    882			u32 ret;
    883
    884			if (!frags)
    885				break;
    886
    887			dram_base_addr = cpu_to_le64(frags->physical);
    888			dram_size = cpu_to_le32(frags->size);
    889			dram_addr = le64_to_cpu(dram_base_addr);
    890
    891			IWL_DEBUG_FW(fwrt, "WRT: dram_base_addr 0x%016llx, dram_size 0x%x\n",
    892				     dram_base_addr, dram_size);
    893			IWL_DEBUG_FW(fwrt, "WRT: config_list->addr_offset: %u\n",
    894				     le32_to_cpu(config_list->addr_offset));
    895			for (count = 0; count < len; count++) {
    896				address = le32_to_cpu(config_list->addr_val[count].address);
    897				dram_info.dbgc1_add_lsb =
    898					cpu_to_le32((dram_addr & 0x00000000FFFFFFFFULL) + 0x400);
    899				dram_info.dbgc1_add_msb =
    900					cpu_to_le32((dram_addr & 0xFFFFFFFF00000000ULL) >> 32);
    901				dram_info.dbgc1_size = cpu_to_le32(le32_to_cpu(dram_size) - 0x400);
    902				ret = iwl_trans_write_mem(fwrt->trans,
    903							  address + offset, &dram_info, 4);
    904				if (ret) {
    905					IWL_ERR(fwrt, "Failed to write dram_info to HW_SMEM\n");
    906					break;
    907				}
    908			}
    909			break;
    910		}
    911		case IWL_FW_INI_CONFIG_SET_TYPE_PERIPH_SCRATCH_HWM: {
    912			u32 debug_token_config =
    913				le32_to_cpu(config_list->addr_val[0].value);
    914
    915			IWL_DEBUG_FW(fwrt, "WRT: Setting HWM debug token config: %u\n",
    916				     debug_token_config);
    917			fwrt->trans->dbg.ucode_preset = debug_token_config;
    918			break;
    919		}
    920		default:
    921			break;
    922		}
    923	}
    924}
    925
    926static void iwl_dbg_tlv_periodic_trig_handler(struct timer_list *t)
    927{
    928	struct iwl_dbg_tlv_timer_node *timer_node =
    929		from_timer(timer_node, t, timer);
    930	struct iwl_fwrt_dump_data dump_data = {
    931		.trig = (void *)timer_node->tlv->data,
    932	};
    933	int ret;
    934
    935	ret = iwl_fw_dbg_ini_collect(timer_node->fwrt, &dump_data, false);
    936	if (!ret || ret == -EBUSY) {
    937		u32 occur = le32_to_cpu(dump_data.trig->occurrences);
    938		u32 collect_interval = le32_to_cpu(dump_data.trig->data[0]);
    939
    940		if (!occur)
    941			return;
    942
    943		mod_timer(t, jiffies + msecs_to_jiffies(collect_interval));
    944	}
    945}
    946
    947static void iwl_dbg_tlv_set_periodic_trigs(struct iwl_fw_runtime *fwrt)
    948{
    949	struct iwl_dbg_tlv_node *node;
    950	struct list_head *trig_list =
    951		&fwrt->trans->dbg.time_point[IWL_FW_INI_TIME_POINT_PERIODIC].active_trig_list;
    952
    953	list_for_each_entry(node, trig_list, list) {
    954		struct iwl_fw_ini_trigger_tlv *trig = (void *)node->tlv.data;
    955		struct iwl_dbg_tlv_timer_node *timer_node;
    956		u32 occur = le32_to_cpu(trig->occurrences), collect_interval;
    957		u32 min_interval = 100;
    958
    959		if (!occur)
    960			continue;
    961
    962		/* make sure there is at least one dword of data for the
    963		 * interval value
    964		 */
    965		if (le32_to_cpu(node->tlv.length) <
    966		    sizeof(*trig) + sizeof(__le32)) {
    967			IWL_ERR(fwrt,
    968				"WRT: Invalid periodic trigger data was not given\n");
    969			continue;
    970		}
    971
    972		if (le32_to_cpu(trig->data[0]) < min_interval) {
    973			IWL_WARN(fwrt,
    974				 "WRT: Override min interval from %u to %u msec\n",
    975				 le32_to_cpu(trig->data[0]), min_interval);
    976			trig->data[0] = cpu_to_le32(min_interval);
    977		}
    978
    979		collect_interval = le32_to_cpu(trig->data[0]);
    980
    981		timer_node = kzalloc(sizeof(*timer_node), GFP_KERNEL);
    982		if (!timer_node) {
    983			IWL_ERR(fwrt,
    984				"WRT: Failed to allocate periodic trigger\n");
    985			continue;
    986		}
    987
    988		timer_node->fwrt = fwrt;
    989		timer_node->tlv = &node->tlv;
    990		timer_setup(&timer_node->timer,
    991			    iwl_dbg_tlv_periodic_trig_handler, 0);
    992
    993		list_add_tail(&timer_node->list,
    994			      &fwrt->trans->dbg.periodic_trig_list);
    995
    996		IWL_DEBUG_FW(fwrt, "WRT: Enabling periodic trigger\n");
    997
    998		mod_timer(&timer_node->timer,
    999			  jiffies + msecs_to_jiffies(collect_interval));
   1000	}
   1001}
   1002
   1003static bool is_trig_data_contained(const struct iwl_ucode_tlv *new,
   1004				   const struct iwl_ucode_tlv *old)
   1005{
   1006	const struct iwl_fw_ini_trigger_tlv *new_trig = (const void *)new->data;
   1007	const struct iwl_fw_ini_trigger_tlv *old_trig = (const void *)old->data;
   1008	const __le32 *new_data = new_trig->data, *old_data = old_trig->data;
   1009	u32 new_dwords_num = iwl_tlv_array_len(new, new_trig, data);
   1010	u32 old_dwords_num = iwl_tlv_array_len(old, old_trig, data);
   1011	int i, j;
   1012
   1013	for (i = 0; i < new_dwords_num; i++) {
   1014		bool match = false;
   1015
   1016		for (j = 0; j < old_dwords_num; j++) {
   1017			if (new_data[i] == old_data[j]) {
   1018				match = true;
   1019				break;
   1020			}
   1021		}
   1022		if (!match)
   1023			return false;
   1024	}
   1025
   1026	return true;
   1027}
   1028
   1029static int iwl_dbg_tlv_override_trig_node(struct iwl_fw_runtime *fwrt,
   1030					  struct iwl_ucode_tlv *trig_tlv,
   1031					  struct iwl_dbg_tlv_node *node)
   1032{
   1033	struct iwl_ucode_tlv *node_tlv = &node->tlv;
   1034	struct iwl_fw_ini_trigger_tlv *node_trig = (void *)node_tlv->data;
   1035	struct iwl_fw_ini_trigger_tlv *trig = (void *)trig_tlv->data;
   1036	u32 policy = le32_to_cpu(trig->apply_policy);
   1037	u32 size = le32_to_cpu(trig_tlv->length);
   1038	u32 trig_data_len = size - sizeof(*trig);
   1039	u32 offset = 0;
   1040
   1041	if (!(policy & IWL_FW_INI_APPLY_POLICY_OVERRIDE_DATA)) {
   1042		u32 data_len = le32_to_cpu(node_tlv->length) -
   1043			sizeof(*node_trig);
   1044
   1045		IWL_DEBUG_FW(fwrt,
   1046			     "WRT: Appending trigger data (time point %u)\n",
   1047			     le32_to_cpu(trig->time_point));
   1048
   1049		offset += data_len;
   1050		size += data_len;
   1051	} else {
   1052		IWL_DEBUG_FW(fwrt,
   1053			     "WRT: Overriding trigger data (time point %u)\n",
   1054			     le32_to_cpu(trig->time_point));
   1055	}
   1056
   1057	if (size != le32_to_cpu(node_tlv->length)) {
   1058		struct list_head *prev = node->list.prev;
   1059		struct iwl_dbg_tlv_node *tmp;
   1060
   1061		list_del(&node->list);
   1062
   1063		tmp = krealloc(node, sizeof(*node) + size, GFP_KERNEL);
   1064		if (!tmp) {
   1065			IWL_WARN(fwrt,
   1066				 "WRT: No memory to override trigger (time point %u)\n",
   1067				 le32_to_cpu(trig->time_point));
   1068
   1069			list_add(&node->list, prev);
   1070
   1071			return -ENOMEM;
   1072		}
   1073
   1074		list_add(&tmp->list, prev);
   1075		node_tlv = &tmp->tlv;
   1076		node_trig = (void *)node_tlv->data;
   1077	}
   1078
   1079	memcpy(node_trig->data + offset, trig->data, trig_data_len);
   1080	node_tlv->length = cpu_to_le32(size);
   1081
   1082	if (policy & IWL_FW_INI_APPLY_POLICY_OVERRIDE_CFG) {
   1083		IWL_DEBUG_FW(fwrt,
   1084			     "WRT: Overriding trigger configuration (time point %u)\n",
   1085			     le32_to_cpu(trig->time_point));
   1086
   1087		/* the first 11 dwords are configuration related */
   1088		memcpy(node_trig, trig, sizeof(__le32) * 11);
   1089	}
   1090
   1091	if (policy & IWL_FW_INI_APPLY_POLICY_OVERRIDE_REGIONS) {
   1092		IWL_DEBUG_FW(fwrt,
   1093			     "WRT: Overriding trigger regions (time point %u)\n",
   1094			     le32_to_cpu(trig->time_point));
   1095
   1096		node_trig->regions_mask = trig->regions_mask;
   1097	} else {
   1098		IWL_DEBUG_FW(fwrt,
   1099			     "WRT: Appending trigger regions (time point %u)\n",
   1100			     le32_to_cpu(trig->time_point));
   1101
   1102		node_trig->regions_mask |= trig->regions_mask;
   1103	}
   1104
   1105	return 0;
   1106}
   1107
   1108static int
   1109iwl_dbg_tlv_add_active_trigger(struct iwl_fw_runtime *fwrt,
   1110			       struct list_head *trig_list,
   1111			       struct iwl_ucode_tlv *trig_tlv)
   1112{
   1113	struct iwl_fw_ini_trigger_tlv *trig = (void *)trig_tlv->data;
   1114	struct iwl_dbg_tlv_node *node, *match = NULL;
   1115	u32 policy = le32_to_cpu(trig->apply_policy);
   1116
   1117	list_for_each_entry(node, trig_list, list) {
   1118		if (!(policy & IWL_FW_INI_APPLY_POLICY_MATCH_TIME_POINT))
   1119			break;
   1120
   1121		if (!(policy & IWL_FW_INI_APPLY_POLICY_MATCH_DATA) ||
   1122		    is_trig_data_contained(trig_tlv, &node->tlv)) {
   1123			match = node;
   1124			break;
   1125		}
   1126	}
   1127
   1128	if (!match) {
   1129		IWL_DEBUG_FW(fwrt, "WRT: Enabling trigger (time point %u)\n",
   1130			     le32_to_cpu(trig->time_point));
   1131		return iwl_dbg_tlv_add(trig_tlv, trig_list);
   1132	}
   1133
   1134	return iwl_dbg_tlv_override_trig_node(fwrt, trig_tlv, match);
   1135}
   1136
   1137static void
   1138iwl_dbg_tlv_gen_active_trig_list(struct iwl_fw_runtime *fwrt,
   1139				 struct iwl_dbg_tlv_time_point_data *tp)
   1140{
   1141	struct iwl_dbg_tlv_node *node;
   1142	struct list_head *trig_list = &tp->trig_list;
   1143	struct list_head *active_trig_list = &tp->active_trig_list;
   1144
   1145	list_for_each_entry(node, trig_list, list) {
   1146		struct iwl_ucode_tlv *tlv = &node->tlv;
   1147
   1148		iwl_dbg_tlv_add_active_trigger(fwrt, active_trig_list, tlv);
   1149	}
   1150}
   1151
   1152static bool iwl_dbg_tlv_check_fw_pkt(struct iwl_fw_runtime *fwrt,
   1153				     struct iwl_fwrt_dump_data *dump_data,
   1154				     union iwl_dbg_tlv_tp_data *tp_data,
   1155				     u32 trig_data)
   1156{
   1157	struct iwl_rx_packet *pkt = tp_data->fw_pkt;
   1158	struct iwl_cmd_header *wanted_hdr = (void *)&trig_data;
   1159
   1160	if (pkt && (pkt->hdr.cmd == wanted_hdr->cmd &&
   1161		    pkt->hdr.group_id == wanted_hdr->group_id)) {
   1162		struct iwl_rx_packet *fw_pkt =
   1163			kmemdup(pkt,
   1164				sizeof(*pkt) + iwl_rx_packet_payload_len(pkt),
   1165				GFP_ATOMIC);
   1166
   1167		if (!fw_pkt)
   1168			return false;
   1169
   1170		dump_data->fw_pkt = fw_pkt;
   1171
   1172		return true;
   1173	}
   1174
   1175	return false;
   1176}
   1177
   1178static int
   1179iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync,
   1180		       struct list_head *active_trig_list,
   1181		       union iwl_dbg_tlv_tp_data *tp_data,
   1182		       bool (*data_check)(struct iwl_fw_runtime *fwrt,
   1183					  struct iwl_fwrt_dump_data *dump_data,
   1184					  union iwl_dbg_tlv_tp_data *tp_data,
   1185					  u32 trig_data))
   1186{
   1187	struct iwl_dbg_tlv_node *node;
   1188
   1189	list_for_each_entry(node, active_trig_list, list) {
   1190		struct iwl_fwrt_dump_data dump_data = {
   1191			.trig = (void *)node->tlv.data,
   1192		};
   1193		u32 num_data = iwl_tlv_array_len(&node->tlv, dump_data.trig,
   1194						 data);
   1195		int ret, i;
   1196		u32 tp = le32_to_cpu(dump_data.trig->time_point);
   1197
   1198
   1199		if (!num_data) {
   1200			ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data, sync);
   1201			if (ret)
   1202				return ret;
   1203		}
   1204
   1205		for (i = 0; i < num_data; i++) {
   1206			if (!data_check ||
   1207			    data_check(fwrt, &dump_data, tp_data,
   1208				       le32_to_cpu(dump_data.trig->data[i]))) {
   1209				ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data, sync);
   1210				if (ret)
   1211					return ret;
   1212
   1213				break;
   1214			}
   1215		}
   1216
   1217		fwrt->trans->dbg.restart_required = FALSE;
   1218		IWL_DEBUG_INFO(fwrt, "WRT: tp %d, reset_fw %d\n",
   1219			       tp, dump_data.trig->reset_fw);
   1220		IWL_DEBUG_INFO(fwrt, "WRT: restart_required %d, last_tp_resetfw %d\n",
   1221			       fwrt->trans->dbg.restart_required,
   1222			       fwrt->trans->dbg.last_tp_resetfw);
   1223
   1224		if (fwrt->trans->trans_cfg->device_family ==
   1225		    IWL_DEVICE_FAMILY_9000) {
   1226			fwrt->trans->dbg.restart_required = TRUE;
   1227		} else if (tp == IWL_FW_INI_TIME_POINT_FW_ASSERT &&
   1228			   fwrt->trans->dbg.last_tp_resetfw ==
   1229			   IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY) {
   1230			fwrt->trans->dbg.restart_required = FALSE;
   1231			fwrt->trans->dbg.last_tp_resetfw = 0xFF;
   1232			IWL_DEBUG_FW(fwrt, "WRT: FW_ASSERT due to reset_fw_mode-no restart\n");
   1233		} else if (le32_to_cpu(dump_data.trig->reset_fw) ==
   1234			   IWL_FW_INI_RESET_FW_MODE_STOP_AND_RELOAD_FW) {
   1235			IWL_DEBUG_INFO(fwrt, "WRT: stop and reload firmware\n");
   1236			fwrt->trans->dbg.restart_required = TRUE;
   1237		} else if (le32_to_cpu(dump_data.trig->reset_fw) ==
   1238			   IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY) {
   1239			IWL_DEBUG_INFO(fwrt, "WRT: stop only and no reload firmware\n");
   1240			fwrt->trans->dbg.restart_required = FALSE;
   1241			fwrt->trans->dbg.last_tp_resetfw =
   1242				le32_to_cpu(dump_data.trig->reset_fw);
   1243		} else if (le32_to_cpu(dump_data.trig->reset_fw) ==
   1244			   IWL_FW_INI_RESET_FW_MODE_NOTHING) {
   1245			IWL_DEBUG_INFO(fwrt,
   1246				       "WRT: nothing need to be done after debug collection\n");
   1247		} else {
   1248			IWL_ERR(fwrt, "WRT: wrong resetfw %d\n",
   1249				le32_to_cpu(dump_data.trig->reset_fw));
   1250		}
   1251	}
   1252	return 0;
   1253}
   1254
   1255static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt)
   1256{
   1257	enum iwl_fw_ini_buffer_location *ini_dest = &fwrt->trans->dbg.ini_dest;
   1258	int ret, i;
   1259	u32 failed_alloc = 0;
   1260
   1261	if (*ini_dest != IWL_FW_INI_LOCATION_INVALID)
   1262		return;
   1263
   1264	IWL_DEBUG_FW(fwrt,
   1265		     "WRT: Generating active triggers list, domain 0x%x\n",
   1266		     fwrt->trans->dbg.domains_bitmap);
   1267
   1268	for (i = 0; i < ARRAY_SIZE(fwrt->trans->dbg.time_point); i++) {
   1269		struct iwl_dbg_tlv_time_point_data *tp =
   1270			&fwrt->trans->dbg.time_point[i];
   1271
   1272		iwl_dbg_tlv_gen_active_trig_list(fwrt, tp);
   1273	}
   1274
   1275	*ini_dest = IWL_FW_INI_LOCATION_INVALID;
   1276	for (i = 0; i < IWL_FW_INI_ALLOCATION_NUM; i++) {
   1277		struct iwl_fw_ini_allocation_tlv *fw_mon_cfg =
   1278			&fwrt->trans->dbg.fw_mon_cfg[i];
   1279		u32 dest = le32_to_cpu(fw_mon_cfg->buf_location);
   1280
   1281		if (dest == IWL_FW_INI_LOCATION_INVALID) {
   1282			failed_alloc |= BIT(i);
   1283			continue;
   1284		}
   1285
   1286		if (*ini_dest == IWL_FW_INI_LOCATION_INVALID)
   1287			*ini_dest = dest;
   1288
   1289		if (dest != *ini_dest)
   1290			continue;
   1291
   1292		ret = iwl_dbg_tlv_alloc_fragments(fwrt, i);
   1293
   1294		if (ret) {
   1295			IWL_WARN(fwrt,
   1296				 "WRT: Failed to allocate DRAM buffer for allocation id %d, ret=%d\n",
   1297				 i, ret);
   1298			failed_alloc |= BIT(i);
   1299		}
   1300	}
   1301
   1302	if (!failed_alloc)
   1303		return;
   1304
   1305	for (i = 0; i < ARRAY_SIZE(fwrt->trans->dbg.active_regions) && failed_alloc; i++) {
   1306		struct iwl_fw_ini_region_tlv *reg;
   1307		struct iwl_ucode_tlv **active_reg =
   1308			&fwrt->trans->dbg.active_regions[i];
   1309		u32 reg_type;
   1310
   1311		if (!*active_reg) {
   1312			fwrt->trans->dbg.unsupported_region_msk |= BIT(i);
   1313			continue;
   1314		}
   1315
   1316		reg = (void *)(*active_reg)->data;
   1317		reg_type = reg->type;
   1318
   1319		if (reg_type != IWL_FW_INI_REGION_DRAM_BUFFER ||
   1320		    !(BIT(le32_to_cpu(reg->dram_alloc_id)) & failed_alloc))
   1321			continue;
   1322
   1323		IWL_DEBUG_FW(fwrt,
   1324			     "WRT: removing allocation id %d from region id %d\n",
   1325			     le32_to_cpu(reg->dram_alloc_id), i);
   1326
   1327		failed_alloc &= ~le32_to_cpu(reg->dram_alloc_id);
   1328		fwrt->trans->dbg.unsupported_region_msk |= BIT(i);
   1329
   1330		kfree(*active_reg);
   1331		*active_reg = NULL;
   1332	}
   1333}
   1334
   1335void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
   1336			     enum iwl_fw_ini_time_point tp_id,
   1337			     union iwl_dbg_tlv_tp_data *tp_data,
   1338			     bool sync)
   1339{
   1340	struct list_head *hcmd_list, *trig_list, *conf_list;
   1341
   1342	if (!iwl_trans_dbg_ini_valid(fwrt->trans) ||
   1343	    tp_id == IWL_FW_INI_TIME_POINT_INVALID ||
   1344	    tp_id >= IWL_FW_INI_TIME_POINT_NUM)
   1345		return;
   1346
   1347	hcmd_list = &fwrt->trans->dbg.time_point[tp_id].hcmd_list;
   1348	trig_list = &fwrt->trans->dbg.time_point[tp_id].active_trig_list;
   1349	conf_list = &fwrt->trans->dbg.time_point[tp_id].config_list;
   1350
   1351	switch (tp_id) {
   1352	case IWL_FW_INI_TIME_POINT_EARLY:
   1353		iwl_dbg_tlv_init_cfg(fwrt);
   1354		iwl_dbg_tlv_apply_config(fwrt, conf_list);
   1355		iwl_dbg_tlv_update_drams(fwrt);
   1356		iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
   1357		break;
   1358	case IWL_FW_INI_TIME_POINT_AFTER_ALIVE:
   1359		iwl_dbg_tlv_apply_buffers(fwrt);
   1360		iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
   1361		iwl_dbg_tlv_apply_config(fwrt, conf_list);
   1362		iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
   1363		break;
   1364	case IWL_FW_INI_TIME_POINT_PERIODIC:
   1365		iwl_dbg_tlv_set_periodic_trigs(fwrt);
   1366		iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
   1367		break;
   1368	case IWL_FW_INI_TIME_POINT_FW_RSP_OR_NOTIF:
   1369	case IWL_FW_INI_TIME_POINT_MISSED_BEACONS:
   1370	case IWL_FW_INI_TIME_POINT_FW_DHC_NOTIFICATION:
   1371		iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
   1372		iwl_dbg_tlv_apply_config(fwrt, conf_list);
   1373		iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data,
   1374				       iwl_dbg_tlv_check_fw_pkt);
   1375		break;
   1376	default:
   1377		iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
   1378		iwl_dbg_tlv_apply_config(fwrt, conf_list);
   1379		iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
   1380		break;
   1381	}
   1382}
   1383IWL_EXPORT_SYMBOL(_iwl_dbg_tlv_time_point);