File Index
Files and directories
Sign in
FILE

debugfs.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c C
   1// SPDX-License-Identifier: BSD-3-Clause-Clear
   2/* Copyright (C) 2020 MediaTek Inc. */
   3
   4#include <linux/relay.h>
   5#include "mt7915.h"
   6#include "eeprom.h"
   7#include "mcu.h"
   8#include "mac.h"
   9
  10#define FW_BIN_LOG_MAGIC	0x44e98caf
  11
  12/** global debugfs **/
  13
  14struct hw_queue_map {
  15	const char *name;
  16	u8 index;
  17	u8 pid;
  18	u8 qid;
  19};
  20
  21static int
  22mt7915_implicit_txbf_set(void *data, u64 val)
  23{
  24	struct mt7915_dev *dev = data;
  25
  26	/* The existing connected stations shall reconnect to apply
  27	 * new implicit txbf configuration.
  28	 */
  29	dev->ibf = !!val;
  30
  31	return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE);
  32}
  33
  34static int
  35mt7915_implicit_txbf_get(void *data, u64 *val)
  36{
  37	struct mt7915_dev *dev = data;
  38
  39	*val = dev->ibf;
  40
  41	return 0;
  42}
  43
  44DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7915_implicit_txbf_get,
  45			 mt7915_implicit_txbf_set, "%lld\n");
  46
  47/* test knob of system error recovery */
  48static ssize_t
  49mt7915_sys_recovery_set(struct file *file, const char __user *user_buf,
  50			size_t count, loff_t *ppos)
  51{
  52	struct mt7915_phy *phy = file->private_data;
  53	struct mt7915_dev *dev = phy->dev;
  54	bool band = phy->mt76->band_idx;
  55	char buf[16];
  56	int ret = 0;
  57	u16 val;
  58
  59	if (count >= sizeof(buf))
  60		return -EINVAL;
  61
  62	if (copy_from_user(buf, user_buf, count))
  63		return -EFAULT;
  64
  65	if (count && buf[count - 1] == '\n')
  66		buf[count - 1] = '\0';
  67	else
  68		buf[count] = '\0';
  69
  70	if (kstrtou16(buf, 0, &val))
  71		return -EINVAL;
  72
  73	switch (val) {
  74	/*
  75	 * 0: grab firmware current SER state.
  76	 * 1: trigger & enable system error L1 recovery.
  77	 * 2: trigger & enable system error L2 recovery.
  78	 * 3: trigger & enable system error L3 rx abort.
  79	 * 4: trigger & enable system error L3 tx abort
  80	 * 5: trigger & enable system error L3 tx disable.
  81	 * 6: trigger & enable system error L3 bf recovery.
  82	 * 7: trigger & enable system error full recovery.
  83	 * 8: trigger firmware crash.
  84	 */
  85	case SER_QUERY:
  86		ret = mt7915_mcu_set_ser(dev, 0, 0, band);
  87		break;
  88	case SER_SET_RECOVER_L1:
  89	case SER_SET_RECOVER_L2:
  90	case SER_SET_RECOVER_L3_RX_ABORT:
  91	case SER_SET_RECOVER_L3_TX_ABORT:
  92	case SER_SET_RECOVER_L3_TX_DISABLE:
  93	case SER_SET_RECOVER_L3_BF:
  94		ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), band);
  95		if (ret)
  96			return ret;
  97
  98		ret = mt7915_mcu_set_ser(dev, SER_RECOVER, val, band);
  99		break;
 100
 101	/* enable full chip reset */
 102	case SER_SET_RECOVER_FULL:
 103		mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
 104		ret = mt7915_mcu_set_ser(dev, 1, 3, band);
 105		if (ret)
 106			return ret;
 107
 108		dev->recovery.state |= MT_MCU_CMD_WDT_MASK;
 109		mt7915_reset(dev);
 110		break;
 111
 112	/* WARNING: trigger firmware crash */
 113	case SER_SET_SYSTEM_ASSERT:
 114		mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR, BIT(18));
 115		mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_SOFT_ADDR, BIT(18));
 116		break;
 117	default:
 118		break;
 119	}
 120
 121	return ret ? ret : count;
 122}
 123
 124static ssize_t
 125mt7915_sys_recovery_get(struct file *file, char __user *user_buf,
 126			size_t count, loff_t *ppos)
 127{
 128	struct mt7915_phy *phy = file->private_data;
 129	struct mt7915_dev *dev = phy->dev;
 130	char *buff;
 131	int desc = 0;
 132	ssize_t ret;
 133	static const size_t bufsz = 1024;
 134
 135	buff = kmalloc(bufsz, GFP_KERNEL);
 136	if (!buff)
 137		return -ENOMEM;
 138
 139	/* HELP */
 140	desc += scnprintf(buff + desc, bufsz - desc,
 141			  "Please echo the correct value ...\n");
 142	desc += scnprintf(buff + desc, bufsz - desc,
 143			  "0: grab firmware transient SER state\n");
 144	desc += scnprintf(buff + desc, bufsz - desc,
 145			  "1: trigger system error L1 recovery\n");
 146	desc += scnprintf(buff + desc, bufsz - desc,
 147			  "2: trigger system error L2 recovery\n");
 148	desc += scnprintf(buff + desc, bufsz - desc,
 149			  "3: trigger system error L3 rx abort\n");
 150	desc += scnprintf(buff + desc, bufsz - desc,
 151			  "4: trigger system error L3 tx abort\n");
 152	desc += scnprintf(buff + desc, bufsz - desc,
 153			  "5: trigger system error L3 tx disable\n");
 154	desc += scnprintf(buff + desc, bufsz - desc,
 155			  "6: trigger system error L3 bf recovery\n");
 156	desc += scnprintf(buff + desc, bufsz - desc,
 157			  "7: trigger system error full recovery\n");
 158	desc += scnprintf(buff + desc, bufsz - desc,
 159			  "8: trigger firmware crash\n");
 160
 161	/* SER statistics */
 162	desc += scnprintf(buff + desc, bufsz - desc,
 163			  "\nlet's dump firmware SER statistics...\n");
 164	desc += scnprintf(buff + desc, bufsz - desc,
 165			  "::E  R , SER_STATUS        = 0x%08x\n",
 166			  mt76_rr(dev, MT_SWDEF_SER_STATS));
 167	desc += scnprintf(buff + desc, bufsz - desc,
 168			  "::E  R , SER_PLE_ERR       = 0x%08x\n",
 169			  mt76_rr(dev, MT_SWDEF_PLE_STATS));
 170	desc += scnprintf(buff + desc, bufsz - desc,
 171			  "::E  R , SER_PLE_ERR_1     = 0x%08x\n",
 172			  mt76_rr(dev, MT_SWDEF_PLE1_STATS));
 173	desc += scnprintf(buff + desc, bufsz - desc,
 174			  "::E  R , SER_PLE_ERR_AMSDU = 0x%08x\n",
 175			  mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATS));
 176	desc += scnprintf(buff + desc, bufsz - desc,
 177			  "::E  R , SER_PSE_ERR       = 0x%08x\n",
 178			  mt76_rr(dev, MT_SWDEF_PSE_STATS));
 179	desc += scnprintf(buff + desc, bufsz - desc,
 180			  "::E  R , SER_PSE_ERR_1     = 0x%08x\n",
 181			  mt76_rr(dev, MT_SWDEF_PSE1_STATS));
 182	desc += scnprintf(buff + desc, bufsz - desc,
 183			  "::E  R , SER_LMAC_WISR6_B0 = 0x%08x\n",
 184			  mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATS));
 185	desc += scnprintf(buff + desc, bufsz - desc,
 186			  "::E  R , SER_LMAC_WISR6_B1 = 0x%08x\n",
 187			  mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATS));
 188	desc += scnprintf(buff + desc, bufsz - desc,
 189			  "::E  R , SER_LMAC_WISR7_B0 = 0x%08x\n",
 190			  mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATS));
 191	desc += scnprintf(buff + desc, bufsz - desc,
 192			  "::E  R , SER_LMAC_WISR7_B1 = 0x%08x\n",
 193			  mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS));
 194	desc += scnprintf(buff + desc, bufsz - desc,
 195			  "\nSYS_RESET_COUNT: WM %d, WA %d\n",
 196			  dev->recovery.wm_reset_count,
 197			  dev->recovery.wa_reset_count);
 198
 199	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
 200	kfree(buff);
 201	return ret;
 202}
 203
 204static const struct file_operations mt7915_sys_recovery_ops = {
 205	.write = mt7915_sys_recovery_set,
 206	.read = mt7915_sys_recovery_get,
 207	.open = simple_open,
 208	.llseek = default_llseek,
 209};
 210
 211static int
 212mt7915_radar_trigger(void *data, u64 val)
 213{
 214#define RADAR_MAIN_CHAIN	1
 215#define RADAR_BACKGROUND	2
 216	struct mt7915_phy *phy = data;
 217	struct mt7915_dev *dev = phy->dev;
 218	int rdd_idx;
 219
 220	if (!val || val > RADAR_BACKGROUND)
 221		return -EINVAL;
 222
 223	if (val == RADAR_BACKGROUND && !dev->rdd2_phy) {
 224		dev_err(dev->mt76.dev, "Background radar is not enabled\n");
 225		return -EINVAL;
 226	}
 227
 228	rdd_idx = mt7915_get_rdd_idx(phy, val == RADAR_BACKGROUND);
 229	if (rdd_idx < 0) {
 230		dev_err(dev->mt76.dev, "No RDD found\n");
 231		return -EINVAL;
 232	}
 233
 234	return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_RADAR_EMULATE,
 235				       rdd_idx, 0, 0);
 236}
 237
 238DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,
 239			 mt7915_radar_trigger, "%lld\n");
 240
 241static int
 242mt7915_muru_debug_set(void *data, u64 val)
 243{
 244	struct mt7915_dev *dev = data;
 245
 246	dev->muru_debug = val;
 247	mt7915_mcu_muru_debug_set(dev, dev->muru_debug);
 248
 249	return 0;
 250}
 251
 252static int
 253mt7915_muru_debug_get(void *data, u64 *val)
 254{
 255	struct mt7915_dev *dev = data;
 256
 257	*val = dev->muru_debug;
 258
 259	return 0;
 260}
 261
 262DEFINE_DEBUGFS_ATTRIBUTE(fops_muru_debug, mt7915_muru_debug_get,
 263			 mt7915_muru_debug_set, "%lld\n");
 264
 265static int mt7915_muru_stats_show(struct seq_file *file, void *data)
 266{
 267	struct mt7915_phy *phy = file->private;
 268	struct mt7915_dev *dev = phy->dev;
 269	static const char * const dl_non_he_type[] = {
 270		"CCK", "OFDM", "HT MIX", "HT GF",
 271		"VHT SU", "VHT 2MU", "VHT 3MU", "VHT 4MU"
 272	};
 273	static const char * const dl_he_type[] = {
 274		"HE SU", "HE EXT", "HE 2MU", "HE 3MU", "HE 4MU",
 275		"HE 2RU", "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU",
 276		"HE >16RU"
 277	};
 278	static const char * const ul_he_type[] = {
 279		"HE 2MU", "HE 3MU", "HE 4MU", "HE SU", "HE 2RU",
 280		"HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU", "HE >16RU"
 281	};
 282	int ret, i;
 283	u64 total_ppdu_cnt, sub_total_cnt;
 284
 285	if (!dev->muru_debug) {
 286		seq_puts(file, "Please enable muru_debug first.\n");
 287		return 0;
 288	}
 289
 290	mutex_lock(&dev->mt76.mutex);
 291
 292	ret = mt7915_mcu_muru_debug_get(phy);
 293	if (ret)
 294		goto exit;
 295
 296	/* Non-HE Downlink*/
 297	seq_puts(file, "[Non-HE]\nDownlink\nData Type:  ");
 298
 299	for (i = 0; i < 5; i++)
 300		seq_printf(file, "%8s | ", dl_non_he_type[i]);
 301
 302	seq_puts(file, "\nTotal Count:");
 303	seq_printf(file, "%8u | %8u | %8u | %8u | %8u | ",
 304		   phy->mib.dl_cck_cnt,
 305		   phy->mib.dl_ofdm_cnt,
 306		   phy->mib.dl_htmix_cnt,
 307		   phy->mib.dl_htgf_cnt,
 308		   phy->mib.dl_vht_su_cnt);
 309
 310	seq_puts(file, "\nDownlink MU-MIMO\nData Type:  ");
 311
 312	for (i = 5; i < 8; i++)
 313		seq_printf(file, "%8s | ", dl_non_he_type[i]);
 314
 315	seq_puts(file, "\nTotal Count:");
 316	seq_printf(file, "%8u | %8u | %8u | ",
 317		   phy->mib.dl_vht_2mu_cnt,
 318		   phy->mib.dl_vht_3mu_cnt,
 319		   phy->mib.dl_vht_4mu_cnt);
 320
 321	sub_total_cnt = (u64)phy->mib.dl_vht_2mu_cnt +
 322			     phy->mib.dl_vht_3mu_cnt +
 323			     phy->mib.dl_vht_4mu_cnt;
 324
 325	seq_printf(file, "\nTotal non-HE MU-MIMO DL PPDU count: %lld",
 326		   sub_total_cnt);
 327
 328	total_ppdu_cnt = sub_total_cnt +
 329			 phy->mib.dl_cck_cnt +
 330			 phy->mib.dl_ofdm_cnt +
 331			 phy->mib.dl_htmix_cnt +
 332			 phy->mib.dl_htgf_cnt +
 333			 phy->mib.dl_vht_su_cnt;
 334
 335	seq_printf(file, "\nAll non-HE DL PPDU count: %lld", total_ppdu_cnt);
 336
 337	/* HE Downlink */
 338	seq_puts(file, "\n\n[HE]\nDownlink\nData Type:  ");
 339
 340	for (i = 0; i < 2; i++)
 341		seq_printf(file, "%8s | ", dl_he_type[i]);
 342
 343	seq_puts(file, "\nTotal Count:");
 344	seq_printf(file, "%8u | %8u | ",
 345		   phy->mib.dl_he_su_cnt, phy->mib.dl_he_ext_su_cnt);
 346
 347	seq_puts(file, "\nDownlink MU-MIMO\nData Type:  ");
 348
 349	for (i = 2; i < 5; i++)
 350		seq_printf(file, "%8s | ", dl_he_type[i]);
 351
 352	seq_puts(file, "\nTotal Count:");
 353	seq_printf(file, "%8u | %8u | %8u | ",
 354		   phy->mib.dl_he_2mu_cnt, phy->mib.dl_he_3mu_cnt,
 355		   phy->mib.dl_he_4mu_cnt);
 356
 357	seq_puts(file, "\nDownlink OFDMA\nData Type:  ");
 358
 359	for (i = 5; i < 11; i++)
 360		seq_printf(file, "%8s | ", dl_he_type[i]);
 361
 362	seq_puts(file, "\nTotal Count:");
 363	seq_printf(file, "%8u | %8u | %8u | %8u | %9u | %8u | ",
 364		   phy->mib.dl_he_2ru_cnt,
 365		   phy->mib.dl_he_3ru_cnt,
 366		   phy->mib.dl_he_4ru_cnt,
 367		   phy->mib.dl_he_5to8ru_cnt,
 368		   phy->mib.dl_he_9to16ru_cnt,
 369		   phy->mib.dl_he_gtr16ru_cnt);
 370
 371	sub_total_cnt = (u64)phy->mib.dl_he_2mu_cnt +
 372			     phy->mib.dl_he_3mu_cnt +
 373			     phy->mib.dl_he_4mu_cnt;
 374	total_ppdu_cnt = sub_total_cnt;
 375
 376	seq_printf(file, "\nTotal HE MU-MIMO DL PPDU count: %lld",
 377		   sub_total_cnt);
 378
 379	sub_total_cnt = (u64)phy->mib.dl_he_2ru_cnt +
 380			     phy->mib.dl_he_3ru_cnt +
 381			     phy->mib.dl_he_4ru_cnt +
 382			     phy->mib.dl_he_5to8ru_cnt +
 383			     phy->mib.dl_he_9to16ru_cnt +
 384			     phy->mib.dl_he_gtr16ru_cnt;
 385	total_ppdu_cnt += sub_total_cnt;
 386
 387	seq_printf(file, "\nTotal HE OFDMA DL PPDU count: %lld",
 388		   sub_total_cnt);
 389
 390	total_ppdu_cnt += (u64)phy->mib.dl_he_su_cnt +
 391			       phy->mib.dl_he_ext_su_cnt;
 392
 393	seq_printf(file, "\nAll HE DL PPDU count: %lld", total_ppdu_cnt);
 394
 395	/* HE Uplink */
 396	seq_puts(file, "\n\nUplink");
 397	seq_puts(file, "\nTrigger-based Uplink MU-MIMO\nData Type:  ");
 398
 399	for (i = 0; i < 3; i++)
 400		seq_printf(file, "%8s | ", ul_he_type[i]);
 401
 402	seq_puts(file, "\nTotal Count:");
 403	seq_printf(file, "%8u | %8u | %8u | ",
 404		   phy->mib.ul_hetrig_2mu_cnt,
 405		   phy->mib.ul_hetrig_3mu_cnt,
 406		   phy->mib.ul_hetrig_4mu_cnt);
 407
 408	seq_puts(file, "\nTrigger-based Uplink OFDMA\nData Type:  ");
 409
 410	for (i = 3; i < 10; i++)
 411		seq_printf(file, "%8s | ", ul_he_type[i]);
 412
 413	seq_puts(file, "\nTotal Count:");
 414	seq_printf(file, "%8u | %8u | %8u | %8u | %8u | %9u |  %7u | ",
 415		   phy->mib.ul_hetrig_su_cnt,
 416		   phy->mib.ul_hetrig_2ru_cnt,
 417		   phy->mib.ul_hetrig_3ru_cnt,
 418		   phy->mib.ul_hetrig_4ru_cnt,
 419		   phy->mib.ul_hetrig_5to8ru_cnt,
 420		   phy->mib.ul_hetrig_9to16ru_cnt,
 421		   phy->mib.ul_hetrig_gtr16ru_cnt);
 422
 423	sub_total_cnt = (u64)phy->mib.ul_hetrig_2mu_cnt +
 424			     phy->mib.ul_hetrig_3mu_cnt +
 425			     phy->mib.ul_hetrig_4mu_cnt;
 426	total_ppdu_cnt = sub_total_cnt;
 427
 428	seq_printf(file, "\nTotal HE MU-MIMO UL TB PPDU count: %lld",
 429		   sub_total_cnt);
 430
 431	sub_total_cnt = (u64)phy->mib.ul_hetrig_2ru_cnt +
 432			     phy->mib.ul_hetrig_3ru_cnt +
 433			     phy->mib.ul_hetrig_4ru_cnt +
 434			     phy->mib.ul_hetrig_5to8ru_cnt +
 435			     phy->mib.ul_hetrig_9to16ru_cnt +
 436			     phy->mib.ul_hetrig_gtr16ru_cnt;
 437	total_ppdu_cnt += sub_total_cnt;
 438
 439	seq_printf(file, "\nTotal HE OFDMA UL TB PPDU count: %lld",
 440		   sub_total_cnt);
 441
 442	total_ppdu_cnt += phy->mib.ul_hetrig_su_cnt;
 443
 444	seq_printf(file, "\nAll HE UL TB PPDU count: %lld\n", total_ppdu_cnt);
 445
 446exit:
 447	mutex_unlock(&dev->mt76.mutex);
 448
 449	return ret;
 450}
 451DEFINE_SHOW_ATTRIBUTE(mt7915_muru_stats);
 452
 453static int
 454mt7915_rdd_monitor(struct seq_file *s, void *data)
 455{
 456	struct mt7915_dev *dev = dev_get_drvdata(s->private);
 457	struct cfg80211_chan_def *chandef = &dev->rdd2_chandef;
 458	const char *bw;
 459	int ret = 0;
 460
 461	mutex_lock(&dev->mt76.mutex);
 462
 463	if (!mt7915_eeprom_has_background_radar(dev)) {
 464		seq_puts(s, "no background radar capability\n");
 465		goto out;
 466	}
 467
 468	if (!cfg80211_chandef_valid(chandef)) {
 469		ret = -EINVAL;
 470		goto out;
 471	}
 472
 473	if (!dev->rdd2_phy) {
 474		seq_puts(s, "not running\n");
 475		goto out;
 476	}
 477
 478	switch (chandef->width) {
 479	case NL80211_CHAN_WIDTH_40:
 480		bw = "40";
 481		break;
 482	case NL80211_CHAN_WIDTH_80:
 483		bw = "80";
 484		break;
 485	case NL80211_CHAN_WIDTH_160:
 486		bw = "160";
 487		break;
 488	case NL80211_CHAN_WIDTH_80P80:
 489		bw = "80P80";
 490		break;
 491	default:
 492		bw = "20";
 493		break;
 494	}
 495
 496	seq_printf(s, "channel %d (%d MHz) width %s MHz center1: %d MHz\n",
 497		   chandef->chan->hw_value, chandef->chan->center_freq,
 498		   bw, chandef->center_freq1);
 499out:
 500	mutex_unlock(&dev->mt76.mutex);
 501
 502	return ret;
 503}
 504
 505static int
 506mt7915_fw_debug_wm_set(void *data, u64 val)
 507{
 508	struct mt7915_dev *dev = data;
 509	enum {
 510		DEBUG_TXCMD = 62,
 511		DEBUG_CMD_RPT_TX,
 512		DEBUG_CMD_RPT_TRIG,
 513		DEBUG_SPL,
 514		DEBUG_RPT_RX,
 515	} debug;
 516	bool tx, rx, en;
 517	int ret;
 518
 519	dev->fw.debug_wm = val ? MCU_FW_LOG_TO_HOST : 0;
 520
 521	if (dev->fw.debug_bin)
 522		val = 16;
 523	else
 524		val = dev->fw.debug_wm;
 525
 526	tx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(1));
 527	rx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(2));
 528	en = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(0));
 529
 530	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, val);
 531	if (ret)
 532		goto out;
 533
 534	for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) {
 535		if (debug == DEBUG_RPT_RX)
 536			val = en && rx;
 537		else
 538			val = en && tx;
 539
 540		ret = mt7915_mcu_fw_dbg_ctrl(dev, debug, val);
 541		if (ret)
 542			goto out;
 543	}
 544
 545	/* WM CPU info record control */
 546	mt76_clear(dev, MT_CPU_UTIL_CTRL, BIT(0));
 547	mt76_wr(dev, MT_DIC_CMD_REG_CMD, BIT(2) | BIT(13) |
 548		(dev->fw.debug_wm ? 0 : BIT(0)));
 549	mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR, BIT(5));
 550	mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR, BIT(5));
 551
 552out:
 553	if (ret)
 554		dev->fw.debug_wm = 0;
 555
 556	return ret;
 557}
 558
 559static int
 560mt7915_fw_debug_wm_get(void *data, u64 *val)
 561{
 562	struct mt7915_dev *dev = data;
 563
 564	*val = dev->fw.debug_wm;
 565
 566	return 0;
 567}
 568
 569DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wm, mt7915_fw_debug_wm_get,
 570			 mt7915_fw_debug_wm_set, "%lld\n");
 571
 572static int
 573mt7915_fw_debug_wa_set(void *data, u64 val)
 574{
 575	struct mt7915_dev *dev = data;
 576	int ret;
 577
 578	dev->fw.debug_wa = val ? MCU_FW_LOG_TO_HOST : 0;
 579
 580	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, dev->fw.debug_wa);
 581	if (ret)
 582		goto out;
 583
 584	ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
 585				MCU_WA_PARAM_PDMA_RX, !!dev->fw.debug_wa, 0);
 586out:
 587	if (ret)
 588		dev->fw.debug_wa = 0;
 589
 590	return ret;
 591}
 592
 593static int
 594mt7915_fw_debug_wa_get(void *data, u64 *val)
 595{
 596	struct mt7915_dev *dev = data;
 597
 598	*val = dev->fw.debug_wa;
 599
 600	return 0;
 601}
 602
 603DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7915_fw_debug_wa_get,
 604			 mt7915_fw_debug_wa_set, "%lld\n");
 605
 606static struct dentry *
 607create_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode,
 608		   struct rchan_buf *buf, int *is_global)
 609{
 610	struct dentry *f;
 611
 612	f = debugfs_create_file("fwlog_data", mode, parent, buf,
 613				&relay_file_operations);
 614	if (IS_ERR(f))
 615		return NULL;
 616
 617	*is_global = 1;
 618
 619	return f;
 620}
 621
 622static int
 623remove_buf_file_cb(struct dentry *f)
 624{
 625	debugfs_remove(f);
 626
 627	return 0;
 628}
 629
 630static int
 631mt7915_fw_debug_bin_set(void *data, u64 val)
 632{
 633	static struct rchan_callbacks relay_cb = {
 634		.create_buf_file = create_buf_file_cb,
 635		.remove_buf_file = remove_buf_file_cb,
 636	};
 637	struct mt7915_dev *dev = data;
 638
 639	if (!dev->relay_fwlog)
 640		dev->relay_fwlog = relay_open("fwlog_data", dev->debugfs_dir,
 641					    1500, 512, &relay_cb, NULL);
 642	if (!dev->relay_fwlog)
 643		return -ENOMEM;
 644
 645	dev->fw.debug_bin = val;
 646
 647	relay_reset(dev->relay_fwlog);
 648
 649	return mt7915_fw_debug_wm_set(dev, dev->fw.debug_wm);
 650}
 651
 652static int
 653mt7915_fw_debug_bin_get(void *data, u64 *val)
 654{
 655	struct mt7915_dev *dev = data;
 656
 657	*val = dev->fw.debug_bin;
 658
 659	return 0;
 660}
 661
 662DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7915_fw_debug_bin_get,
 663			 mt7915_fw_debug_bin_set, "%lld\n");
 664
 665static int
 666mt7915_fw_util_wm_show(struct seq_file *file, void *data)
 667{
 668	struct mt7915_dev *dev = file->private;
 669
 670	seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WM_MCU_PC));
 671
 672	if (dev->fw.debug_wm) {
 673		seq_printf(file, "Busy: %u%%  Peak busy: %u%%\n",
 674			   mt76_rr(dev, MT_CPU_UTIL_BUSY_PCT),
 675			   mt76_rr(dev, MT_CPU_UTIL_PEAK_BUSY_PCT));
 676		seq_printf(file, "Idle count: %u  Peak idle count: %u\n",
 677			   mt76_rr(dev, MT_CPU_UTIL_IDLE_CNT),
 678			   mt76_rr(dev, MT_CPU_UTIL_PEAK_IDLE_CNT));
 679	}
 680
 681	return 0;
 682}
 683
 684DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wm);
 685
 686static int
 687mt7915_fw_util_wa_show(struct seq_file *file, void *data)
 688{
 689	struct mt7915_dev *dev = file->private;
 690
 691	seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WA_MCU_PC));
 692
 693	if (dev->fw.debug_wa)
 694		return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(QUERY),
 695					 MCU_WA_PARAM_CPU_UTIL, 0, 0);
 696
 697	return 0;
 698}
 699
 700DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wa);
 701
 702static void
 703mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,
 704			   struct seq_file *file)
 705{
 706	struct mt7915_dev *dev = phy->dev;
 707	bool ext_phy = phy != &dev->phy;
 708	int bound[15], range[4], i;
 709	u8 band = phy->mt76->band_idx;
 710
 711	/* Tx ampdu stat */
 712	for (i = 0; i < ARRAY_SIZE(range); i++)
 713		range[i] = mt76_rr(dev, MT_MIB_ARNG(band, i));
 714
 715	for (i = 0; i < ARRAY_SIZE(bound); i++)
 716		bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1;
 717
 718	seq_printf(file, "\nPhy %d, Phy band %d\n", ext_phy, band);
 719
 720	seq_printf(file, "Length: %8d | ", bound[0]);
 721	for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
 722		seq_printf(file, "%3d -%3d | ",
 723			   bound[i] + 1, bound[i + 1]);
 724
 725	seq_puts(file, "\nCount:  ");
 726	for (i = 0; i < ARRAY_SIZE(bound); i++)
 727		seq_printf(file, "%8d | ", phy->mt76->aggr_stats[i]);
 728	seq_puts(file, "\n");
 729
 730	seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);
 731}
 732
 733static void
 734mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)
 735{
 736	struct mt76_mib_stats *mib = &phy->mib;
 737	static const char * const bw[] = {
 738		"BW20", "BW40", "BW80", "BW160"
 739	};
 740
 741	/* Tx Beamformer monitor */
 742	seq_puts(s, "\nTx Beamformer applied PPDU counts: ");
 743
 744	seq_printf(s, "iBF: %d, eBF: %d\n",
 745		   mib->tx_bf_ibf_ppdu_cnt,
 746		   mib->tx_bf_ebf_ppdu_cnt);
 747
 748	/* Tx Beamformer Rx feedback monitor */
 749	seq_puts(s, "Tx Beamformer Rx feedback statistics: ");
 750
 751	seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ",
 752		   mib->tx_bf_rx_fb_all_cnt,
 753		   mib->tx_bf_rx_fb_he_cnt,
 754		   mib->tx_bf_rx_fb_vht_cnt,
 755		   mib->tx_bf_rx_fb_ht_cnt);
 756
 757	seq_printf(s, "%s, NC: %d, NR: %d\n",
 758		   bw[mib->tx_bf_rx_fb_bw],
 759		   mib->tx_bf_rx_fb_nc_cnt,
 760		   mib->tx_bf_rx_fb_nr_cnt);
 761
 762	/* Tx Beamformee Rx NDPA & Tx feedback report */
 763	seq_printf(s, "Tx Beamformee successful feedback frames: %d\n",
 764		   mib->tx_bf_fb_cpl_cnt);
 765	seq_printf(s, "Tx Beamformee feedback triggered counts: %d\n",
 766		   mib->tx_bf_fb_trig_cnt);
 767
 768	/* Tx SU & MU counters */
 769	seq_printf(s, "Tx multi-user Beamforming counts: %d\n",
 770		   mib->tx_bf_cnt);
 771	seq_printf(s, "Tx multi-user MPDU counts: %d\n", mib->tx_mu_mpdu_cnt);
 772	seq_printf(s, "Tx multi-user successful MPDU counts: %d\n",
 773		   mib->tx_mu_acked_mpdu_cnt);
 774	seq_printf(s, "Tx single-user successful MPDU counts: %d\n",
 775		   mib->tx_su_acked_mpdu_cnt);
 776
 777	seq_puts(s, "\n");
 778}
 779
 780static int
 781mt7915_tx_stats_show(struct seq_file *file, void *data)
 782{
 783	struct mt7915_phy *phy = file->private;
 784	struct mt7915_dev *dev = phy->dev;
 785	struct mt76_mib_stats *mib = &phy->mib;
 786	int i;
 787
 788	mutex_lock(&dev->mt76.mutex);
 789
 790	mt7915_ampdu_stat_read_phy(phy, file);
 791	mt7915_mac_update_stats(phy);
 792	mt7915_txbf_stat_read_phy(phy, file);
 793
 794	/* Tx amsdu info */
 795	seq_puts(file, "Tx MSDU statistics:\n");
 796	for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
 797		seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ",
 798			   i + 1, mib->tx_amsdu[i]);
 799		if (mib->tx_amsdu_cnt)
 800			seq_printf(file, "(%3d%%)\n",
 801				   mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt);
 802		else
 803			seq_puts(file, "\n");
 804	}
 805
 806	mutex_unlock(&dev->mt76.mutex);
 807
 808	return 0;
 809}
 810
 811DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats);
 812
 813static void
 814mt7915_hw_queue_read(struct seq_file *s, u32 size,
 815		     const struct hw_queue_map *map)
 816{
 817	struct mt7915_phy *phy = s->private;
 818	struct mt7915_dev *dev = phy->dev;
 819	u32 i, val;
 820
 821	val = mt76_rr(dev, MT_FL_Q_EMPTY);
 822	for (i = 0; i < size; i++) {
 823		u32 ctrl, head, tail, queued;
 824
 825		if (val & BIT(map[i].index))
 826			continue;
 827
 828		ctrl = BIT(31) | (map[i].pid << 10) | ((u32)map[i].qid << 24);
 829		mt76_wr(dev, MT_FL_Q0_CTRL, ctrl);
 830
 831		head = mt76_get_field(dev, MT_FL_Q2_CTRL,
 832				      GENMASK(11, 0));
 833		tail = mt76_get_field(dev, MT_FL_Q2_CTRL,
 834				      GENMASK(27, 16));
 835		queued = mt76_get_field(dev, MT_FL_Q3_CTRL,
 836					GENMASK(11, 0));
 837
 838		seq_printf(s, "\t%s: ", map[i].name);
 839		seq_printf(s, "queued:0x%03x head:0x%03x tail:0x%03x\n",
 840			   queued, head, tail);
 841	}
 842}
 843
 844static void
 845mt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
 846{
 847	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
 848	struct mt7915_dev *dev = msta->vif->phy->dev;
 849	struct seq_file *s = data;
 850	u8 ac;
 851
 852	for (ac = 0; ac < 4; ac++) {
 853		u32 qlen, ctrl, val;
 854		u32 idx = msta->wcid.idx >> 5;
 855		u8 offs = msta->wcid.idx & GENMASK(4, 0);
 856
 857		ctrl = BIT(31) | BIT(11) | (ac << 24);
 858		val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx));
 859
 860		if (val & BIT(offs))
 861			continue;
 862
 863		mt76_wr(dev, MT_FL_Q0_CTRL, ctrl | msta->wcid.idx);
 864		qlen = mt76_get_field(dev, MT_FL_Q3_CTRL,
 865				      GENMASK(11, 0));
 866		seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n",
 867			   sta->addr, msta->wcid.idx,
 868			   msta->vif->mt76.wmm_idx, ac, qlen);
 869	}
 870}
 871
 872static int
 873mt7915_hw_queues_show(struct seq_file *file, void *data)
 874{
 875	struct mt7915_phy *phy = file->private;
 876	struct mt7915_dev *dev = phy->dev;
 877	static const struct hw_queue_map ple_queue_map[] = {
 878		{ "CPU_Q0",  0,  1, MT_CTX0	      },
 879		{ "CPU_Q1",  1,  1, MT_CTX0 + 1	      },
 880		{ "CPU_Q2",  2,  1, MT_CTX0 + 2	      },
 881		{ "CPU_Q3",  3,  1, MT_CTX0 + 3	      },
 882		{ "ALTX_Q0", 8,  2, MT_LMAC_ALTX0     },
 883		{ "BMC_Q0",  9,  2, MT_LMAC_BMC0      },
 884		{ "BCN_Q0",  10, 2, MT_LMAC_BCN0      },
 885		{ "PSMP_Q0", 11, 2, MT_LMAC_PSMP0     },
 886		{ "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 },
 887		{ "BMC_Q1",  13, 2, MT_LMAC_BMC0  + 4 },
 888		{ "BCN_Q1",  14, 2, MT_LMAC_BCN0  + 4 },
 889		{ "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 },
 890	};
 891	static const struct hw_queue_map pse_queue_map[] = {
 892		{ "CPU Q0",  0,  1, MT_CTX0	      },
 893		{ "CPU Q1",  1,  1, MT_CTX0 + 1	      },
 894		{ "CPU Q2",  2,  1, MT_CTX0 + 2	      },
 895		{ "CPU Q3",  3,  1, MT_CTX0 + 3	      },
 896		{ "HIF_Q0",  8,  0, MT_HIF0	      },
 897		{ "HIF_Q1",  9,  0, MT_HIF0 + 1	      },
 898		{ "HIF_Q2",  10, 0, MT_HIF0 + 2	      },
 899		{ "HIF_Q3",  11, 0, MT_HIF0 + 3	      },
 900		{ "HIF_Q4",  12, 0, MT_HIF0 + 4	      },
 901		{ "HIF_Q5",  13, 0, MT_HIF0 + 5	      },
 902		{ "LMAC_Q",  16, 2, 0		      },
 903		{ "MDP_TXQ", 17, 2, 1		      },
 904		{ "MDP_RXQ", 18, 2, 2		      },
 905		{ "SEC_TXQ", 19, 2, 3		      },
 906		{ "SEC_RXQ", 20, 2, 4		      },
 907	};
 908	u32 val, head, tail;
 909
 910	/* ple queue */
 911	val = mt76_rr(dev, MT_PLE_FREEPG_CNT);
 912	head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0));
 913	tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16));
 914	seq_puts(file, "PLE page info:\n");
 915	seq_printf(file,
 916		   "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n",
 917		   val, head, tail);
 918
 919	val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP);
 920	head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0));
 921	tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16));
 922	seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n",
 923		   val, head, tail);
 924
 925	seq_puts(file, "PLE non-empty queue info:\n");
 926	mt7915_hw_queue_read(file, ARRAY_SIZE(ple_queue_map),
 927			     &ple_queue_map[0]);
 928
 929	/* iterate per-sta ple queue */
 930	ieee80211_iterate_stations_atomic(phy->mt76->hw,
 931					  mt7915_sta_hw_queue_read, file);
 932	/* pse queue */
 933	seq_puts(file, "PSE non-empty queue info:\n");
 934	mt7915_hw_queue_read(file, ARRAY_SIZE(pse_queue_map),
 935			     &pse_queue_map[0]);
 936
 937	return 0;
 938}
 939
 940DEFINE_SHOW_ATTRIBUTE(mt7915_hw_queues);
 941
 942static int
 943mt7915_xmit_queues_show(struct seq_file *file, void *data)
 944{
 945	struct mt7915_phy *phy = file->private;
 946	struct mt7915_dev *dev = phy->dev;
 947	struct {
 948		struct mt76_queue *q;
 949		char *queue;
 950	} queue_map[] = {
 951		{ phy->mt76->q_tx[MT_TXQ_BE],	 "   MAIN"  },
 952		{ dev->mt76.q_mcu[MT_MCUQ_WM],	 "  MCUWM"  },
 953		{ dev->mt76.q_mcu[MT_MCUQ_WA],	 "  MCUWA"  },
 954		{ dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" },
 955	};
 956	int i;
 957
 958	seq_puts(file, "     queue | hw-queued |      head |      tail |\n");
 959	for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
 960		struct mt76_queue *q = queue_map[i].q;
 961
 962		if (!q)
 963			continue;
 964
 965		seq_printf(file, "   %s | %9d | %9d | %9d |\n",
 966			   queue_map[i].queue, q->queued, q->head,
 967			   q->tail);
 968	}
 969
 970	return 0;
 971}
 972
 973DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues);
 974
 975#define mt7915_txpower_puts(rate)						\
 976({										\
 977	len += scnprintf(buf + len, sz - len, "%-16s:", #rate " (TMAC)");	\
 978	for (i = 0; i < mt7915_sku_group_len[SKU_##rate]; i++, offs++)		\
 979		len += scnprintf(buf + len, sz - len, " %6d", txpwr[offs]);	\
 980	len += scnprintf(buf + len, sz - len, "\n");				\
 981})
 982
 983#define mt7915_txpower_sets(rate, pwr, flag)			\
 984({								\
 985	offs += len;						\
 986	len = mt7915_sku_group_len[rate];			\
 987	if (mode == flag) {					\
 988		for (i = 0; i < len; i++)			\
 989			req.txpower_sku[offs + i] = pwr;	\
 990	}							\
 991})
 992
 993static ssize_t
 994mt7915_rate_txpower_get(struct file *file, char __user *user_buf,
 995			size_t count, loff_t *ppos)
 996{
 997	struct mt7915_phy *phy = file->private_data;
 998	struct mt7915_dev *dev = phy->dev;
 999	s8 txpwr[MT7915_SKU_RATE_NUM];
1000	static const size_t sz = 2048;
1001	u8 band = phy->mt76->band_idx;
1002	int i, offs = 0, len = 0;
1003	ssize_t ret;
1004	char *buf;
1005	u32 reg;
1006
1007	buf = kzalloc(sz, GFP_KERNEL);
1008	if (!buf)
1009		return -ENOMEM;
1010
1011	ret = mt7915_mcu_get_txpower_sku(phy, txpwr, sizeof(txpwr), TX_POWER_INFO_RATE);
1012	if (ret)
1013		goto out;
1014
1015	/* Txpower propagation path: TMAC -> TXV -> BBP */
1016	len += scnprintf(buf + len, sz - len,
1017			 "\nPhy%d Tx power table (channel %d)\n",
1018			 phy != &dev->phy, phy->mt76->chandef.chan->hw_value);
1019	len += scnprintf(buf + len, sz - len, "%-16s  %6s %6s %6s %6s\n",
1020			 " ", "1m", "2m", "5m", "11m");
1021	mt7915_txpower_puts(CCK);
1022
1023	len += scnprintf(buf + len, sz - len,
1024			 "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s\n",
1025			 " ", "6m", "9m", "12m", "18m", "24m", "36m", "48m",
1026			 "54m");
1027	mt7915_txpower_puts(OFDM);
1028
1029	len += scnprintf(buf + len, sz - len,
1030			 "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s\n",
1031			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4",
1032			 "mcs5", "mcs6", "mcs7");
1033	mt7915_txpower_puts(HT_BW20);
1034
1035	len += scnprintf(buf + len, sz - len,
1036			 "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
1037			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
1038			 "mcs6", "mcs7", "mcs32");
1039	mt7915_txpower_puts(HT_BW40);
1040
1041	len += scnprintf(buf + len, sz - len,
1042			 "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
1043			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
1044			 "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11");
1045	mt7915_txpower_puts(VHT_BW20);
1046	mt7915_txpower_puts(VHT_BW40);
1047	mt7915_txpower_puts(VHT_BW80);
1048	mt7915_txpower_puts(VHT_BW160);
1049	mt7915_txpower_puts(HE_RU26);
1050	mt7915_txpower_puts(HE_RU52);
1051	mt7915_txpower_puts(HE_RU106);
1052	mt7915_txpower_puts(HE_RU242);
1053	mt7915_txpower_puts(HE_RU484);
1054	mt7915_txpower_puts(HE_RU996);
1055	mt7915_txpower_puts(HE_RU2x996);
1056
1057	reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_TPC_CTRL_STAT(band) :
1058	      MT_WF_PHY_TPC_CTRL_STAT_MT7916(band);
1059
1060	len += scnprintf(buf + len, sz - len, "\nTx power (bbp)  : %6ld\n",
1061			 mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER));
1062
1063	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1064
1065out:
1066	kfree(buf);
1067	return ret;
1068}
1069
1070static ssize_t
1071mt7915_rate_txpower_set(struct file *file, const char __user *user_buf,
1072			size_t count, loff_t *ppos)
1073{
1074	int i, ret, pwr, pwr160 = 0, pwr80 = 0, pwr40 = 0, pwr20 = 0;
1075	struct mt7915_phy *phy = file->private_data;
1076	struct mt7915_dev *dev = phy->dev;
1077	struct mt76_phy *mphy = phy->mt76;
1078	struct mt7915_mcu_txpower_sku req = {
1079		.format_id = TX_POWER_LIMIT_TABLE,
1080		.band_idx = phy->mt76->band_idx,
1081	};
1082	char buf[100];
1083	enum mac80211_rx_encoding mode;
1084	u32 offs = 0, len = 0;
1085
1086	if (count >= sizeof(buf))
1087		return -EINVAL;
1088
1089	if (copy_from_user(buf, user_buf, count))
1090		return -EFAULT;
1091
1092	if (count && buf[count - 1] == '\n')
1093		buf[count - 1] = '\0';
1094	else
1095		buf[count] = '\0';
1096
1097	if (sscanf(buf, "%u %u %u %u %u",
1098		   &mode, &pwr160, &pwr80, &pwr40, &pwr20) != 5) {
1099		dev_warn(dev->mt76.dev,
1100			 "per bandwidth power limit: Mode BW160 BW80 BW40 BW20");
1101		return -EINVAL;
1102	}
1103
1104	if (mode > RX_ENC_HE)
1105		return -EINVAL;
1106
1107	if (pwr160)
1108		pwr160 = mt76_get_power_bound(mphy, pwr160);
1109	if (pwr80)
1110		pwr80 = mt76_get_power_bound(mphy, pwr80);
1111	if (pwr40)
1112		pwr40 = mt76_get_power_bound(mphy, pwr40);
1113	if (pwr20)
1114		pwr20 = mt76_get_power_bound(mphy, pwr20);
1115
1116	if (pwr160 < 0 || pwr80 < 0 || pwr40 < 0 || pwr20 < 0)
1117		return -EINVAL;
1118
1119	mutex_lock(&dev->mt76.mutex);
1120	ret = mt7915_mcu_get_txpower_sku(phy, req.txpower_sku,
1121					 sizeof(req.txpower_sku), TX_POWER_INFO_RATE);
1122	if (ret)
1123		goto out;
1124
1125	mt7915_txpower_sets(SKU_CCK, pwr20, RX_ENC_LEGACY);
1126	mt7915_txpower_sets(SKU_OFDM, pwr20, RX_ENC_LEGACY);
1127	if (mode == RX_ENC_LEGACY)
1128		goto skip;
1129
1130	mt7915_txpower_sets(SKU_HT_BW20, pwr20, RX_ENC_HT);
1131	mt7915_txpower_sets(SKU_HT_BW40, pwr40, RX_ENC_HT);
1132	if (mode == RX_ENC_HT)
1133		goto skip;
1134
1135	mt7915_txpower_sets(SKU_VHT_BW20, pwr20, RX_ENC_VHT);
1136	mt7915_txpower_sets(SKU_VHT_BW40, pwr40, RX_ENC_VHT);
1137	mt7915_txpower_sets(SKU_VHT_BW80, pwr80, RX_ENC_VHT);
1138	mt7915_txpower_sets(SKU_VHT_BW160, pwr160, RX_ENC_VHT);
1139	if (mode == RX_ENC_VHT)
1140		goto skip;
1141
1142	mt7915_txpower_sets(SKU_HE_RU26, pwr20, RX_ENC_HE + 1);
1143	mt7915_txpower_sets(SKU_HE_RU52, pwr20, RX_ENC_HE + 1);
1144	mt7915_txpower_sets(SKU_HE_RU106, pwr20, RX_ENC_HE + 1);
1145	mt7915_txpower_sets(SKU_HE_RU242, pwr20, RX_ENC_HE);
1146	mt7915_txpower_sets(SKU_HE_RU484, pwr40, RX_ENC_HE);
1147	mt7915_txpower_sets(SKU_HE_RU996, pwr80, RX_ENC_HE);
1148	mt7915_txpower_sets(SKU_HE_RU2x996, pwr160, RX_ENC_HE);
1149skip:
1150	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),
1151				&req, sizeof(req), true);
1152	if (ret)
1153		goto out;
1154
1155	pwr = max3(pwr80, pwr40, pwr20);
1156	mphy->txpower_cur = max3(mphy->txpower_cur, pwr160, pwr);
1157out:
1158	mutex_unlock(&dev->mt76.mutex);
1159
1160	return ret ? ret : count;
1161}
1162
1163static const struct file_operations mt7915_txpower_fops = {
1164	.write = mt7915_rate_txpower_set,
1165	.read = mt7915_rate_txpower_get,
1166	.open = simple_open,
1167	.owner = THIS_MODULE,
1168	.llseek = default_llseek,
1169};
1170
1171static int
1172mt7915_path_txpower_show(struct seq_file *file)
1173{
1174	struct mt7915_phy *phy = file->private;
1175	s8 txpower[MT7915_SKU_PATH_NUM], *buf = txpower;
1176	int ret;
1177
1178#define PATH_POWER_SHOW(_name, _len, _skip) do {			\
1179		size_t __len = (_len);					\
1180		if (_skip) {						\
1181			buf -= 1;					\
1182			*buf = 0;					\
1183		}							\
1184		mt76_seq_puts_array(file, _name, buf, __len);		\
1185		buf += __len;						\
1186	} while (0)
1187
1188	seq_printf(file, "\n%*c", 18, ' ');
1189	seq_puts(file, "1T1S/2T1S/3T1S/4T1S/2T2S/3T2S/4T2S/3T3S/4T3S/4T4S\n");
1190	ret = mt7915_mcu_get_txpower_sku(phy, txpower, sizeof(txpower),
1191					 TX_POWER_INFO_PATH);
1192	if (ret)
1193		return ret;
1194
1195	PATH_POWER_SHOW("CCK", 4, 0);
1196	PATH_POWER_SHOW("OFDM", 4, 0);
1197	PATH_POWER_SHOW("BF-OFDM", 4, 1);
1198
1199	PATH_POWER_SHOW("HT/VHT20", 10, 0);
1200	PATH_POWER_SHOW("BF-HT/VHT20", 10, 1);
1201	PATH_POWER_SHOW("HT/VHT40", 10, 0);
1202	PATH_POWER_SHOW("BF-HT/VHT40", 10, 1);
1203
1204	PATH_POWER_SHOW("BW20/RU242", 10, 0);
1205	PATH_POWER_SHOW("BF-BW20/RU242", 10, 1);
1206	PATH_POWER_SHOW("BW40/RU484", 10, 0);
1207	PATH_POWER_SHOW("BF-BW40/RU484", 10, 1);
1208	PATH_POWER_SHOW("BW80/RU996", 10, 0);
1209	PATH_POWER_SHOW("BF-BW80/RU996", 10, 1);
1210	PATH_POWER_SHOW("BW160/RU2x996", 10, 0);
1211	PATH_POWER_SHOW("BF-BW160/RU2x996", 10, 1);
1212	PATH_POWER_SHOW("RU26", 10, 0);
1213	PATH_POWER_SHOW("BF-RU26", 10, 0);
1214	PATH_POWER_SHOW("RU52", 10, 0);
1215	PATH_POWER_SHOW("BF-RU52", 10, 0);
1216	PATH_POWER_SHOW("RU106", 10, 0);
1217	PATH_POWER_SHOW("BF-RU106", 10, 0);
1218#undef PATH_POWER_SHOW
1219
1220	return 0;
1221}
1222
1223static int
1224mt7915_txpower_path_show(struct seq_file *file, void *data)
1225{
1226	struct mt7915_phy *phy = file->private;
1227
1228	seq_printf(file, "\nBand %d\n", phy != &phy->dev->phy);
1229
1230	return mt7915_path_txpower_show(file);
1231}
1232
1233DEFINE_SHOW_ATTRIBUTE(mt7915_txpower_path);
1234
1235static int
1236mt7915_twt_stats(struct seq_file *s, void *data)
1237{
1238	struct mt7915_dev *dev = dev_get_drvdata(s->private);
1239	struct mt7915_twt_flow *iter;
1240
1241	rcu_read_lock();
1242
1243	seq_puts(s, "     wcid |       id |    flags |      exp | mantissa");
1244	seq_puts(s, " | duration |            tsf |\n");
1245	list_for_each_entry_rcu(iter, &dev->twt_list, list)
1246		seq_printf(s,
1247			"%9d | %8d | %5c%c%c%c | %8d | %8d | %8d | %14lld |\n",
1248			iter->wcid, iter->id,
1249			iter->sched ? 's' : 'u',
1250			iter->protection ? 'p' : '-',
1251			iter->trigger ? 't' : '-',
1252			iter->flowtype ? '-' : 'a',
1253			iter->exp, iter->mantissa,
1254			iter->duration, iter->tsf);
1255
1256	rcu_read_unlock();
1257
1258	return 0;
1259}
1260
1261/* The index of RF registers use the generic regidx, combined with two parts:
1262 * WF selection [31:24] and offset [23:0].
1263 */
1264static int
1265mt7915_rf_regval_get(void *data, u64 *val)
1266{
1267	struct mt7915_dev *dev = data;
1268	u32 regval;
1269	int ret;
1270
1271	ret = mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &regval, false);
1272	if (ret)
1273		return ret;
1274
1275	*val = regval;
1276
1277	return 0;
1278}
1279
1280static int
1281mt7915_rf_regval_set(void *data, u64 val)
1282{
1283	struct mt7915_dev *dev = data;
1284	u32 val32 = val;
1285
1286	return mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &val32, true);
1287}
1288
1289DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7915_rf_regval_get,
1290			 mt7915_rf_regval_set, "0x%08llx\n");
1291
1292int mt7915_init_debugfs(struct mt7915_phy *phy)
1293{
1294	struct mt7915_dev *dev = phy->dev;
1295	bool ext_phy = phy != &dev->phy;
1296	struct dentry *dir;
1297
1298	dir = mt76_register_debugfs_fops(phy->mt76, NULL);
1299	if (!dir)
1300		return -ENOMEM;
1301	debugfs_create_file("muru_debug", 0600, dir, dev, &fops_muru_debug);
1302	debugfs_create_file("muru_stats", 0400, dir, phy,
1303			    &mt7915_muru_stats_fops);
1304	debugfs_create_file("hw-queues", 0400, dir, phy,
1305			    &mt7915_hw_queues_fops);
1306	debugfs_create_file("xmit-queues", 0400, dir, phy,
1307			    &mt7915_xmit_queues_fops);
1308	debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops);
1309	debugfs_create_file("sys_recovery", 0600, dir, phy,
1310			    &mt7915_sys_recovery_ops);
1311	debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm);
1312	debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa);
1313	debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin);
1314	debugfs_create_file("fw_util_wm", 0400, dir, dev,
1315			    &mt7915_fw_util_wm_fops);
1316	debugfs_create_file("fw_util_wa", 0400, dir, dev,
1317			    &mt7915_fw_util_wa_fops);
1318	debugfs_create_file("implicit_txbf", 0600, dir, dev,
1319			    &fops_implicit_txbf);
1320	debugfs_create_file("txpower_sku", 0400, dir, phy,
1321			    &mt7915_txpower_fops);
1322	debugfs_create_file("txpower_path", 0400, dir, phy,
1323			    &mt7915_txpower_path_fops);
1324	debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,
1325				    mt7915_twt_stats);
1326	debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
1327
1328	if (!dev->dbdc_support || phy->mt76->band_idx) {
1329		debugfs_create_u32("dfs_hw_pattern", 0400, dir,
1330				   &dev->hw_pattern);
1331		debugfs_create_file("radar_trigger", 0200, dir, phy,
1332				    &fops_radar_trigger);
1333		debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir,
1334					    mt7915_rdd_monitor);
1335	}
1336
1337	if (!ext_phy)
1338		dev->debugfs_dir = dir;
1339
1340	return 0;
1341}
1342
1343static void
1344mt7915_debugfs_write_fwlog(struct mt7915_dev *dev, const void *hdr, int hdrlen,
1345			 const void *data, int len)
1346{
1347	static DEFINE_SPINLOCK(lock);
1348	unsigned long flags;
1349	void *dest;
1350
1351	spin_lock_irqsave(&lock, flags);
1352	dest = relay_reserve(dev->relay_fwlog, hdrlen + len + 4);
1353	if (dest) {
1354		*(u32 *)dest = hdrlen + len;
1355		dest += 4;
1356
1357		if (hdrlen) {
1358			memcpy(dest, hdr, hdrlen);
1359			dest += hdrlen;
1360		}
1361
1362		memcpy(dest, data, len);
1363		relay_flush(dev->relay_fwlog);
1364	}
1365	spin_unlock_irqrestore(&lock, flags);
1366}
1367
1368void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len)
1369{
1370	struct {
1371		__le32 magic;
1372		__le32 timestamp;
1373		__le16 msg_type;
1374		__le16 len;
1375	} hdr = {
1376		.magic = cpu_to_le32(FW_BIN_LOG_MAGIC),
1377		.msg_type = cpu_to_le16(PKT_TYPE_RX_FW_MONITOR),
1378	};
1379
1380	if (!dev->relay_fwlog)
1381		return;
1382
1383	hdr.timestamp = cpu_to_le32(mt76_rr(dev, MT_LPON_FRCR(0)));
1384	hdr.len = *(__le16 *)data;
1385	mt7915_debugfs_write_fwlog(dev, &hdr, sizeof(hdr), data, len);
1386}
1387
1388bool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len)
1389{
1390	if (get_unaligned_le32(data) != FW_BIN_LOG_MAGIC)
1391		return false;
1392
1393	if (dev->relay_fwlog)
1394		mt7915_debugfs_write_fwlog(dev, NULL, 0, data, len);
1395
1396	return true;
1397}
1398
1399#ifdef CONFIG_MAC80211_DEBUGFS
1400/** per-station debugfs **/
1401
1402static ssize_t mt7915_sta_fixed_rate_set(struct file *file,
1403					 const char __user *user_buf,
1404					 size_t count, loff_t *ppos)
1405{
1406	struct ieee80211_sta *sta = file->private_data;
1407	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
1408	struct mt7915_dev *dev = msta->vif->phy->dev;
1409	struct ieee80211_vif *vif;
1410	struct sta_phy phy = {};
1411	char buf[100];
1412	int ret;
1413	u32 field;
1414	u8 i, gi, he_ltf;
1415
1416	if (count >= sizeof(buf))
1417		return -EINVAL;
1418
1419	if (copy_from_user(buf, user_buf, count))
1420		return -EFAULT;
1421
1422	if (count && buf[count - 1] == '\n')
1423		buf[count - 1] = '\0';
1424	else
1425		buf[count] = '\0';
1426
1427	/* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 9
1428	 * bw - bw20: 0, bw40: 1, bw80: 2, bw160: 3
1429	 * nss - vht: 1~4, he: 1~4, others: ignore
1430	 * mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~2
1431	 * gi - (ht/vht) lgi: 0, sgi: 1; (he) 0.8us: 0, 1.6us: 1, 3.2us: 2
1432	 * ldpc - off: 0, on: 1
1433	 * stbc - off: 0, on: 1
1434	 * he_ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2
1435	 */
1436	if (sscanf(buf, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu",
1437		   &phy.type, &phy.bw, &phy.nss, &phy.mcs, &gi,
1438		   &phy.ldpc, &phy.stbc, &he_ltf) != 8) {
1439		dev_warn(dev->mt76.dev,
1440			 "format: Mode BW NSS MCS (HE)GI LDPC STBC HE_LTF\n");
1441		field = RATE_PARAM_AUTO;
1442		goto out;
1443	}
1444
1445	phy.ldpc = (phy.bw || phy.ldpc) * GENMASK(2, 0);
1446	for (i = 0; i <= phy.bw; i++) {
1447		phy.sgi |= gi << (i << sta->deflink.he_cap.has_he);
1448		phy.he_ltf |= he_ltf << (i << sta->deflink.he_cap.has_he);
1449	}
1450	field = RATE_PARAM_FIXED;
1451
1452out:
1453	vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
1454	ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, field);
1455	if (ret)
1456		return -EFAULT;
1457
1458	return count;
1459}
1460
1461static const struct file_operations fops_fixed_rate = {
1462	.write = mt7915_sta_fixed_rate_set,
1463	.open = simple_open,
1464	.owner = THIS_MODULE,
1465	.llseek = default_llseek,
1466};
1467
1468static int
1469mt7915_queues_show(struct seq_file *s, void *data)
1470{
1471	struct ieee80211_sta *sta = s->private;
1472
1473	mt7915_sta_hw_queue_read(s, sta);
1474
1475	return 0;
1476}
1477
1478DEFINE_SHOW_ATTRIBUTE(mt7915_queues);
1479
1480void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1481			    struct ieee80211_sta *sta, struct dentry *dir)
1482{
1483	debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate);
1484	debugfs_create_file("hw-queues", 0400, dir, sta, &mt7915_queues_fops);
1485}
1486
1487#endif
~/ Read-only file preview.