File Index
Files and directories
Sign in
FILE

iwl-dbg-tlv.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c C
   1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
   2/*
   3 * Copyright (C) 2018-2025 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
  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 FW
 176	 * is not ready
 177	 */
 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->mac_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 with
 551	 * the requested amount and going down until we can allocate
 552	 * something.  Because of DIV_ROUND_UP(), pages will never go
 553	 * 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->mac_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->mac_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 register
 675	 * or context info
 676	 */
 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 register
 760	 * or context info
 761	 */
 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		else
 821			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		timer_container_of(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 the
 986		 * interval value
 987		 */
 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 int
1132iwl_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 void
1163iwl_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 int
1204iwl_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->mac_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 buffers
1290		 * properly on restart, otherwise garbage may be left there and
1291		 * 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_update_drams(fwrt);
1376		iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
1377		iwl_dbg_tlv_apply_config(fwrt, conf_list);
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_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
1383		iwl_dbg_tlv_apply_config(fwrt, conf_list);
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_tp_trigger(fwrt, sync, trig_list, tp_data,
1394				       iwl_dbg_tlv_check_fw_pkt);
1395		iwl_dbg_tlv_apply_config(fwrt, conf_list);
1396		break;
1397	default:
1398		iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list);
1399		iwl_dbg_tlv_tp_trigger(fwrt, sync, trig_list, tp_data, NULL);
1400		iwl_dbg_tlv_apply_config(fwrt, conf_list);
1401		break;
1402	}
1403}
1404IWL_EXPORT_SYMBOL(_iwl_dbg_tlv_time_point);
~/ Read-only file preview.