brintos

brintos / linux-shallow public Read only

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