brintos

brintos / linux-shallow public Read only

0
0
Text · 36.3 KiB · 5780138 Raw
1401 lines · c
1// SPDX-License-Identifier: ISC2/* 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	0x44e98caf11 12/** global debugfs **/13 14struct hw_queue_map {15	const char *name;16	u8 index;17	u8 pid;18	u8 qid;19};20 21static int22mt7915_implicit_txbf_set(void *data, u64 val)23{24	struct mt7915_dev *dev = data;25 26	/* The existing connected stations shall reconnect to apply27	 * new implicit txbf configuration.28	 */29	dev->ibf = !!val;30 31	return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE);32}33 34static int35mt7915_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_t49mt7915_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	else68		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 abort80	 * 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_t125mt7915_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 int212mt7915_radar_trigger(void *data, u64 val)213{214	struct mt7915_dev *dev = data;215 216	if (val > MT_RX_SEL2)217		return -EINVAL;218 219	return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_RADAR_EMULATE,220				       val, 0, 0);221}222 223DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,224			 mt7915_radar_trigger, "%lld\n");225 226static int227mt7915_muru_debug_set(void *data, u64 val)228{229	struct mt7915_dev *dev = data;230 231	dev->muru_debug = val;232	mt7915_mcu_muru_debug_set(dev, dev->muru_debug);233 234	return 0;235}236 237static int238mt7915_muru_debug_get(void *data, u64 *val)239{240	struct mt7915_dev *dev = data;241 242	*val = dev->muru_debug;243 244	return 0;245}246 247DEFINE_DEBUGFS_ATTRIBUTE(fops_muru_debug, mt7915_muru_debug_get,248			 mt7915_muru_debug_set, "%lld\n");249 250static int mt7915_muru_stats_show(struct seq_file *file, void *data)251{252	struct mt7915_phy *phy = file->private;253	struct mt7915_dev *dev = phy->dev;254	static const char * const dl_non_he_type[] = {255		"CCK", "OFDM", "HT MIX", "HT GF",256		"VHT SU", "VHT 2MU", "VHT 3MU", "VHT 4MU"257	};258	static const char * const dl_he_type[] = {259		"HE SU", "HE EXT", "HE 2MU", "HE 3MU", "HE 4MU",260		"HE 2RU", "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU",261		"HE >16RU"262	};263	static const char * const ul_he_type[] = {264		"HE 2MU", "HE 3MU", "HE 4MU", "HE SU", "HE 2RU",265		"HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU", "HE >16RU"266	};267	int ret, i;268	u64 total_ppdu_cnt, sub_total_cnt;269 270	if (!dev->muru_debug) {271		seq_puts(file, "Please enable muru_debug first.\n");272		return 0;273	}274 275	mutex_lock(&dev->mt76.mutex);276 277	ret = mt7915_mcu_muru_debug_get(phy);278	if (ret)279		goto exit;280 281	/* Non-HE Downlink*/282	seq_puts(file, "[Non-HE]\nDownlink\nData Type:  ");283 284	for (i = 0; i < 5; i++)285		seq_printf(file, "%8s | ", dl_non_he_type[i]);286 287	seq_puts(file, "\nTotal Count:");288	seq_printf(file, "%8u | %8u | %8u | %8u | %8u | ",289		   phy->mib.dl_cck_cnt,290		   phy->mib.dl_ofdm_cnt,291		   phy->mib.dl_htmix_cnt,292		   phy->mib.dl_htgf_cnt,293		   phy->mib.dl_vht_su_cnt);294 295	seq_puts(file, "\nDownlink MU-MIMO\nData Type:  ");296 297	for (i = 5; i < 8; i++)298		seq_printf(file, "%8s | ", dl_non_he_type[i]);299 300	seq_puts(file, "\nTotal Count:");301	seq_printf(file, "%8u | %8u | %8u | ",302		   phy->mib.dl_vht_2mu_cnt,303		   phy->mib.dl_vht_3mu_cnt,304		   phy->mib.dl_vht_4mu_cnt);305 306	sub_total_cnt = phy->mib.dl_vht_2mu_cnt +307			phy->mib.dl_vht_3mu_cnt +308			phy->mib.dl_vht_4mu_cnt;309 310	seq_printf(file, "\nTotal non-HE MU-MIMO DL PPDU count: %lld",311		   sub_total_cnt);312 313	total_ppdu_cnt = sub_total_cnt +314			 phy->mib.dl_cck_cnt +315			 phy->mib.dl_ofdm_cnt +316			 phy->mib.dl_htmix_cnt +317			 phy->mib.dl_htgf_cnt +318			 phy->mib.dl_vht_su_cnt;319 320	seq_printf(file, "\nAll non-HE DL PPDU count: %lld", total_ppdu_cnt);321 322	/* HE Downlink */323	seq_puts(file, "\n\n[HE]\nDownlink\nData Type:  ");324 325	for (i = 0; i < 2; i++)326		seq_printf(file, "%8s | ", dl_he_type[i]);327 328	seq_puts(file, "\nTotal Count:");329	seq_printf(file, "%8u | %8u | ",330		   phy->mib.dl_he_su_cnt, phy->mib.dl_he_ext_su_cnt);331 332	seq_puts(file, "\nDownlink MU-MIMO\nData Type:  ");333 334	for (i = 2; i < 5; i++)335		seq_printf(file, "%8s | ", dl_he_type[i]);336 337	seq_puts(file, "\nTotal Count:");338	seq_printf(file, "%8u | %8u | %8u | ",339		   phy->mib.dl_he_2mu_cnt, phy->mib.dl_he_3mu_cnt,340		   phy->mib.dl_he_4mu_cnt);341 342	seq_puts(file, "\nDownlink OFDMA\nData Type:  ");343 344	for (i = 5; i < 11; i++)345		seq_printf(file, "%8s | ", dl_he_type[i]);346 347	seq_puts(file, "\nTotal Count:");348	seq_printf(file, "%8u | %8u | %8u | %8u | %9u | %8u | ",349		   phy->mib.dl_he_2ru_cnt,350		   phy->mib.dl_he_3ru_cnt,351		   phy->mib.dl_he_4ru_cnt,352		   phy->mib.dl_he_5to8ru_cnt,353		   phy->mib.dl_he_9to16ru_cnt,354		   phy->mib.dl_he_gtr16ru_cnt);355 356	sub_total_cnt = phy->mib.dl_he_2mu_cnt +357			phy->mib.dl_he_3mu_cnt +358			phy->mib.dl_he_4mu_cnt;359	total_ppdu_cnt = sub_total_cnt;360 361	seq_printf(file, "\nTotal HE MU-MIMO DL PPDU count: %lld",362		   sub_total_cnt);363 364	sub_total_cnt = 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	total_ppdu_cnt += sub_total_cnt;371 372	seq_printf(file, "\nTotal HE OFDMA DL PPDU count: %lld",373		   sub_total_cnt);374 375	total_ppdu_cnt += phy->mib.dl_he_su_cnt + phy->mib.dl_he_ext_su_cnt;376 377	seq_printf(file, "\nAll HE DL PPDU count: %lld", total_ppdu_cnt);378 379	/* HE Uplink */380	seq_puts(file, "\n\nUplink");381	seq_puts(file, "\nTrigger-based Uplink MU-MIMO\nData Type:  ");382 383	for (i = 0; i < 3; i++)384		seq_printf(file, "%8s | ", ul_he_type[i]);385 386	seq_puts(file, "\nTotal Count:");387	seq_printf(file, "%8u | %8u | %8u | ",388		   phy->mib.ul_hetrig_2mu_cnt,389		   phy->mib.ul_hetrig_3mu_cnt,390		   phy->mib.ul_hetrig_4mu_cnt);391 392	seq_puts(file, "\nTrigger-based Uplink OFDMA\nData Type:  ");393 394	for (i = 3; i < 10; i++)395		seq_printf(file, "%8s | ", ul_he_type[i]);396 397	seq_puts(file, "\nTotal Count:");398	seq_printf(file, "%8u | %8u | %8u | %8u | %8u | %9u |  %7u | ",399		   phy->mib.ul_hetrig_su_cnt,400		   phy->mib.ul_hetrig_2ru_cnt,401		   phy->mib.ul_hetrig_3ru_cnt,402		   phy->mib.ul_hetrig_4ru_cnt,403		   phy->mib.ul_hetrig_5to8ru_cnt,404		   phy->mib.ul_hetrig_9to16ru_cnt,405		   phy->mib.ul_hetrig_gtr16ru_cnt);406 407	sub_total_cnt = phy->mib.ul_hetrig_2mu_cnt +408			phy->mib.ul_hetrig_3mu_cnt +409			phy->mib.ul_hetrig_4mu_cnt;410	total_ppdu_cnt = sub_total_cnt;411 412	seq_printf(file, "\nTotal HE MU-MIMO UL TB PPDU count: %lld",413		   sub_total_cnt);414 415	sub_total_cnt = phy->mib.ul_hetrig_2ru_cnt +416			phy->mib.ul_hetrig_3ru_cnt +417			phy->mib.ul_hetrig_4ru_cnt +418			phy->mib.ul_hetrig_5to8ru_cnt +419			phy->mib.ul_hetrig_9to16ru_cnt +420			phy->mib.ul_hetrig_gtr16ru_cnt;421	total_ppdu_cnt += sub_total_cnt;422 423	seq_printf(file, "\nTotal HE OFDMA UL TB PPDU count: %lld",424		   sub_total_cnt);425 426	total_ppdu_cnt += phy->mib.ul_hetrig_su_cnt;427 428	seq_printf(file, "\nAll HE UL TB PPDU count: %lld\n", total_ppdu_cnt);429 430exit:431	mutex_unlock(&dev->mt76.mutex);432 433	return ret;434}435DEFINE_SHOW_ATTRIBUTE(mt7915_muru_stats);436 437static int438mt7915_rdd_monitor(struct seq_file *s, void *data)439{440	struct mt7915_dev *dev = dev_get_drvdata(s->private);441	struct cfg80211_chan_def *chandef = &dev->rdd2_chandef;442	const char *bw;443	int ret = 0;444 445	mutex_lock(&dev->mt76.mutex);446 447	if (!cfg80211_chandef_valid(chandef)) {448		ret = -EINVAL;449		goto out;450	}451 452	if (!dev->rdd2_phy) {453		seq_puts(s, "not running\n");454		goto out;455	}456 457	switch (chandef->width) {458	case NL80211_CHAN_WIDTH_40:459		bw = "40";460		break;461	case NL80211_CHAN_WIDTH_80:462		bw = "80";463		break;464	case NL80211_CHAN_WIDTH_160:465		bw = "160";466		break;467	case NL80211_CHAN_WIDTH_80P80:468		bw = "80P80";469		break;470	default:471		bw = "20";472		break;473	}474 475	seq_printf(s, "channel %d (%d MHz) width %s MHz center1: %d MHz\n",476		   chandef->chan->hw_value, chandef->chan->center_freq,477		   bw, chandef->center_freq1);478out:479	mutex_unlock(&dev->mt76.mutex);480 481	return ret;482}483 484static int485mt7915_fw_debug_wm_set(void *data, u64 val)486{487	struct mt7915_dev *dev = data;488	enum {489		DEBUG_TXCMD = 62,490		DEBUG_CMD_RPT_TX,491		DEBUG_CMD_RPT_TRIG,492		DEBUG_SPL,493		DEBUG_RPT_RX,494	} debug;495	bool tx, rx, en;496	int ret;497 498	dev->fw.debug_wm = val ? MCU_FW_LOG_TO_HOST : 0;499 500	if (dev->fw.debug_bin)501		val = 16;502	else503		val = dev->fw.debug_wm;504 505	tx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(1));506	rx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(2));507	en = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(0));508 509	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, val);510	if (ret)511		goto out;512 513	for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) {514		if (debug == DEBUG_RPT_RX)515			val = en && rx;516		else517			val = en && tx;518 519		ret = mt7915_mcu_fw_dbg_ctrl(dev, debug, val);520		if (ret)521			goto out;522	}523 524	/* WM CPU info record control */525	mt76_clear(dev, MT_CPU_UTIL_CTRL, BIT(0));526	mt76_wr(dev, MT_DIC_CMD_REG_CMD, BIT(2) | BIT(13) |527		(dev->fw.debug_wm ? 0 : BIT(0)));528	mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR, BIT(5));529	mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR, BIT(5));530 531out:532	if (ret)533		dev->fw.debug_wm = 0;534 535	return ret;536}537 538static int539mt7915_fw_debug_wm_get(void *data, u64 *val)540{541	struct mt7915_dev *dev = data;542 543	*val = dev->fw.debug_wm;544 545	return 0;546}547 548DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wm, mt7915_fw_debug_wm_get,549			 mt7915_fw_debug_wm_set, "%lld\n");550 551static int552mt7915_fw_debug_wa_set(void *data, u64 val)553{554	struct mt7915_dev *dev = data;555	int ret;556 557	dev->fw.debug_wa = val ? MCU_FW_LOG_TO_HOST : 0;558 559	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, dev->fw.debug_wa);560	if (ret)561		goto out;562 563	ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),564				MCU_WA_PARAM_PDMA_RX, !!dev->fw.debug_wa, 0);565out:566	if (ret)567		dev->fw.debug_wa = 0;568 569	return ret;570}571 572static int573mt7915_fw_debug_wa_get(void *data, u64 *val)574{575	struct mt7915_dev *dev = data;576 577	*val = dev->fw.debug_wa;578 579	return 0;580}581 582DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7915_fw_debug_wa_get,583			 mt7915_fw_debug_wa_set, "%lld\n");584 585static struct dentry *586create_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode,587		   struct rchan_buf *buf, int *is_global)588{589	struct dentry *f;590 591	f = debugfs_create_file("fwlog_data", mode, parent, buf,592				&relay_file_operations);593	if (IS_ERR(f))594		return NULL;595 596	*is_global = 1;597 598	return f;599}600 601static int602remove_buf_file_cb(struct dentry *f)603{604	debugfs_remove(f);605 606	return 0;607}608 609static int610mt7915_fw_debug_bin_set(void *data, u64 val)611{612	static struct rchan_callbacks relay_cb = {613		.create_buf_file = create_buf_file_cb,614		.remove_buf_file = remove_buf_file_cb,615	};616	struct mt7915_dev *dev = data;617 618	if (!dev->relay_fwlog)619		dev->relay_fwlog = relay_open("fwlog_data", dev->debugfs_dir,620					    1500, 512, &relay_cb, NULL);621	if (!dev->relay_fwlog)622		return -ENOMEM;623 624	dev->fw.debug_bin = val;625 626	relay_reset(dev->relay_fwlog);627 628	return mt7915_fw_debug_wm_set(dev, dev->fw.debug_wm);629}630 631static int632mt7915_fw_debug_bin_get(void *data, u64 *val)633{634	struct mt7915_dev *dev = data;635 636	*val = dev->fw.debug_bin;637 638	return 0;639}640 641DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7915_fw_debug_bin_get,642			 mt7915_fw_debug_bin_set, "%lld\n");643 644static int645mt7915_fw_util_wm_show(struct seq_file *file, void *data)646{647	struct mt7915_dev *dev = file->private;648 649	seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WM_MCU_PC));650 651	if (dev->fw.debug_wm) {652		seq_printf(file, "Busy: %u%%  Peak busy: %u%%\n",653			   mt76_rr(dev, MT_CPU_UTIL_BUSY_PCT),654			   mt76_rr(dev, MT_CPU_UTIL_PEAK_BUSY_PCT));655		seq_printf(file, "Idle count: %u  Peak idle count: %u\n",656			   mt76_rr(dev, MT_CPU_UTIL_IDLE_CNT),657			   mt76_rr(dev, MT_CPU_UTIL_PEAK_IDLE_CNT));658	}659 660	return 0;661}662 663DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wm);664 665static int666mt7915_fw_util_wa_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_WA_MCU_PC));671 672	if (dev->fw.debug_wa)673		return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(QUERY),674					 MCU_WA_PARAM_CPU_UTIL, 0, 0);675 676	return 0;677}678 679DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wa);680 681static void682mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,683			   struct seq_file *file)684{685	struct mt7915_dev *dev = phy->dev;686	bool ext_phy = phy != &dev->phy;687	int bound[15], range[4], i;688	u8 band = phy->mt76->band_idx;689 690	/* Tx ampdu stat */691	for (i = 0; i < ARRAY_SIZE(range); i++)692		range[i] = mt76_rr(dev, MT_MIB_ARNG(band, i));693 694	for (i = 0; i < ARRAY_SIZE(bound); i++)695		bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1;696 697	seq_printf(file, "\nPhy %d, Phy band %d\n", ext_phy, band);698 699	seq_printf(file, "Length: %8d | ", bound[0]);700	for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)701		seq_printf(file, "%3d -%3d | ",702			   bound[i] + 1, bound[i + 1]);703 704	seq_puts(file, "\nCount:  ");705	for (i = 0; i < ARRAY_SIZE(bound); i++)706		seq_printf(file, "%8d | ", phy->mt76->aggr_stats[i]);707	seq_puts(file, "\n");708 709	seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);710}711 712static void713mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)714{715	struct mt76_mib_stats *mib = &phy->mib;716	static const char * const bw[] = {717		"BW20", "BW40", "BW80", "BW160"718	};719 720	/* Tx Beamformer monitor */721	seq_puts(s, "\nTx Beamformer applied PPDU counts: ");722 723	seq_printf(s, "iBF: %d, eBF: %d\n",724		   mib->tx_bf_ibf_ppdu_cnt,725		   mib->tx_bf_ebf_ppdu_cnt);726 727	/* Tx Beamformer Rx feedback monitor */728	seq_puts(s, "Tx Beamformer Rx feedback statistics: ");729 730	seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ",731		   mib->tx_bf_rx_fb_all_cnt,732		   mib->tx_bf_rx_fb_he_cnt,733		   mib->tx_bf_rx_fb_vht_cnt,734		   mib->tx_bf_rx_fb_ht_cnt);735 736	seq_printf(s, "%s, NC: %d, NR: %d\n",737		   bw[mib->tx_bf_rx_fb_bw],738		   mib->tx_bf_rx_fb_nc_cnt,739		   mib->tx_bf_rx_fb_nr_cnt);740 741	/* Tx Beamformee Rx NDPA & Tx feedback report */742	seq_printf(s, "Tx Beamformee successful feedback frames: %d\n",743		   mib->tx_bf_fb_cpl_cnt);744	seq_printf(s, "Tx Beamformee feedback triggered counts: %d\n",745		   mib->tx_bf_fb_trig_cnt);746 747	/* Tx SU & MU counters */748	seq_printf(s, "Tx multi-user Beamforming counts: %d\n",749		   mib->tx_bf_cnt);750	seq_printf(s, "Tx multi-user MPDU counts: %d\n", mib->tx_mu_mpdu_cnt);751	seq_printf(s, "Tx multi-user successful MPDU counts: %d\n",752		   mib->tx_mu_acked_mpdu_cnt);753	seq_printf(s, "Tx single-user successful MPDU counts: %d\n",754		   mib->tx_su_acked_mpdu_cnt);755 756	seq_puts(s, "\n");757}758 759static int760mt7915_tx_stats_show(struct seq_file *file, void *data)761{762	struct mt7915_phy *phy = file->private;763	struct mt7915_dev *dev = phy->dev;764	struct mt76_mib_stats *mib = &phy->mib;765	int i;766 767	mutex_lock(&dev->mt76.mutex);768 769	mt7915_ampdu_stat_read_phy(phy, file);770	mt7915_mac_update_stats(phy);771	mt7915_txbf_stat_read_phy(phy, file);772 773	/* Tx amsdu info */774	seq_puts(file, "Tx MSDU statistics:\n");775	for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {776		seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ",777			   i + 1, mib->tx_amsdu[i]);778		if (mib->tx_amsdu_cnt)779			seq_printf(file, "(%3d%%)\n",780				   mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt);781		else782			seq_puts(file, "\n");783	}784 785	mutex_unlock(&dev->mt76.mutex);786 787	return 0;788}789 790DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats);791 792static void793mt7915_hw_queue_read(struct seq_file *s, u32 size,794		     const struct hw_queue_map *map)795{796	struct mt7915_phy *phy = s->private;797	struct mt7915_dev *dev = phy->dev;798	u32 i, val;799 800	val = mt76_rr(dev, MT_FL_Q_EMPTY);801	for (i = 0; i < size; i++) {802		u32 ctrl, head, tail, queued;803 804		if (val & BIT(map[i].index))805			continue;806 807		ctrl = BIT(31) | (map[i].pid << 10) | ((u32)map[i].qid << 24);808		mt76_wr(dev, MT_FL_Q0_CTRL, ctrl);809 810		head = mt76_get_field(dev, MT_FL_Q2_CTRL,811				      GENMASK(11, 0));812		tail = mt76_get_field(dev, MT_FL_Q2_CTRL,813				      GENMASK(27, 16));814		queued = mt76_get_field(dev, MT_FL_Q3_CTRL,815					GENMASK(11, 0));816 817		seq_printf(s, "\t%s: ", map[i].name);818		seq_printf(s, "queued:0x%03x head:0x%03x tail:0x%03x\n",819			   queued, head, tail);820	}821}822 823static void824mt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)825{826	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;827	struct mt7915_dev *dev = msta->vif->phy->dev;828	struct seq_file *s = data;829	u8 ac;830 831	for (ac = 0; ac < 4; ac++) {832		u32 qlen, ctrl, val;833		u32 idx = msta->wcid.idx >> 5;834		u8 offs = msta->wcid.idx & GENMASK(4, 0);835 836		ctrl = BIT(31) | BIT(11) | (ac << 24);837		val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx));838 839		if (val & BIT(offs))840			continue;841 842		mt76_wr(dev, MT_FL_Q0_CTRL, ctrl | msta->wcid.idx);843		qlen = mt76_get_field(dev, MT_FL_Q3_CTRL,844				      GENMASK(11, 0));845		seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n",846			   sta->addr, msta->wcid.idx,847			   msta->vif->mt76.wmm_idx, ac, qlen);848	}849}850 851static int852mt7915_hw_queues_show(struct seq_file *file, void *data)853{854	struct mt7915_phy *phy = file->private;855	struct mt7915_dev *dev = phy->dev;856	static const struct hw_queue_map ple_queue_map[] = {857		{ "CPU_Q0",  0,  1, MT_CTX0	      },858		{ "CPU_Q1",  1,  1, MT_CTX0 + 1	      },859		{ "CPU_Q2",  2,  1, MT_CTX0 + 2	      },860		{ "CPU_Q3",  3,  1, MT_CTX0 + 3	      },861		{ "ALTX_Q0", 8,  2, MT_LMAC_ALTX0     },862		{ "BMC_Q0",  9,  2, MT_LMAC_BMC0      },863		{ "BCN_Q0",  10, 2, MT_LMAC_BCN0      },864		{ "PSMP_Q0", 11, 2, MT_LMAC_PSMP0     },865		{ "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 },866		{ "BMC_Q1",  13, 2, MT_LMAC_BMC0  + 4 },867		{ "BCN_Q1",  14, 2, MT_LMAC_BCN0  + 4 },868		{ "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 },869	};870	static const struct hw_queue_map pse_queue_map[] = {871		{ "CPU Q0",  0,  1, MT_CTX0	      },872		{ "CPU Q1",  1,  1, MT_CTX0 + 1	      },873		{ "CPU Q2",  2,  1, MT_CTX0 + 2	      },874		{ "CPU Q3",  3,  1, MT_CTX0 + 3	      },875		{ "HIF_Q0",  8,  0, MT_HIF0	      },876		{ "HIF_Q1",  9,  0, MT_HIF0 + 1	      },877		{ "HIF_Q2",  10, 0, MT_HIF0 + 2	      },878		{ "HIF_Q3",  11, 0, MT_HIF0 + 3	      },879		{ "HIF_Q4",  12, 0, MT_HIF0 + 4	      },880		{ "HIF_Q5",  13, 0, MT_HIF0 + 5	      },881		{ "LMAC_Q",  16, 2, 0		      },882		{ "MDP_TXQ", 17, 2, 1		      },883		{ "MDP_RXQ", 18, 2, 2		      },884		{ "SEC_TXQ", 19, 2, 3		      },885		{ "SEC_RXQ", 20, 2, 4		      },886	};887	u32 val, head, tail;888 889	/* ple queue */890	val = mt76_rr(dev, MT_PLE_FREEPG_CNT);891	head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0));892	tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16));893	seq_puts(file, "PLE page info:\n");894	seq_printf(file,895		   "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n",896		   val, head, tail);897 898	val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP);899	head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0));900	tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16));901	seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n",902		   val, head, tail);903 904	seq_puts(file, "PLE non-empty queue info:\n");905	mt7915_hw_queue_read(file, ARRAY_SIZE(ple_queue_map),906			     &ple_queue_map[0]);907 908	/* iterate per-sta ple queue */909	ieee80211_iterate_stations_atomic(phy->mt76->hw,910					  mt7915_sta_hw_queue_read, file);911	/* pse queue */912	seq_puts(file, "PSE non-empty queue info:\n");913	mt7915_hw_queue_read(file, ARRAY_SIZE(pse_queue_map),914			     &pse_queue_map[0]);915 916	return 0;917}918 919DEFINE_SHOW_ATTRIBUTE(mt7915_hw_queues);920 921static int922mt7915_xmit_queues_show(struct seq_file *file, void *data)923{924	struct mt7915_phy *phy = file->private;925	struct mt7915_dev *dev = phy->dev;926	struct {927		struct mt76_queue *q;928		char *queue;929	} queue_map[] = {930		{ phy->mt76->q_tx[MT_TXQ_BE],	 "   MAIN"  },931		{ dev->mt76.q_mcu[MT_MCUQ_WM],	 "  MCUWM"  },932		{ dev->mt76.q_mcu[MT_MCUQ_WA],	 "  MCUWA"  },933		{ dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" },934	};935	int i;936 937	seq_puts(file, "     queue | hw-queued |      head |      tail |\n");938	for (i = 0; i < ARRAY_SIZE(queue_map); i++) {939		struct mt76_queue *q = queue_map[i].q;940 941		if (!q)942			continue;943 944		seq_printf(file, "   %s | %9d | %9d | %9d |\n",945			   queue_map[i].queue, q->queued, q->head,946			   q->tail);947	}948 949	return 0;950}951 952DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues);953 954#define mt7915_txpower_puts(rate)						\955({										\956	len += scnprintf(buf + len, sz - len, "%-16s:", #rate " (TMAC)");	\957	for (i = 0; i < mt7915_sku_group_len[SKU_##rate]; i++, offs++)		\958		len += scnprintf(buf + len, sz - len, " %6d", txpwr[offs]);	\959	len += scnprintf(buf + len, sz - len, "\n");				\960})961 962#define mt7915_txpower_sets(rate, pwr, flag)			\963({								\964	offs += len;						\965	len = mt7915_sku_group_len[rate];			\966	if (mode == flag) {					\967		for (i = 0; i < len; i++)			\968			req.txpower_sku[offs + i] = pwr;	\969	}							\970})971 972static ssize_t973mt7915_rate_txpower_get(struct file *file, char __user *user_buf,974			size_t count, loff_t *ppos)975{976	struct mt7915_phy *phy = file->private_data;977	struct mt7915_dev *dev = phy->dev;978	s8 txpwr[MT7915_SKU_RATE_NUM];979	static const size_t sz = 2048;980	u8 band = phy->mt76->band_idx;981	int i, offs = 0, len = 0;982	ssize_t ret;983	char *buf;984	u32 reg;985 986	buf = kzalloc(sz, GFP_KERNEL);987	if (!buf)988		return -ENOMEM;989 990	ret = mt7915_mcu_get_txpower_sku(phy, txpwr, sizeof(txpwr));991	if (ret)992		goto out;993 994	/* Txpower propagation path: TMAC -> TXV -> BBP */995	len += scnprintf(buf + len, sz - len,996			 "\nPhy%d Tx power table (channel %d)\n",997			 phy != &dev->phy, phy->mt76->chandef.chan->hw_value);998	len += scnprintf(buf + len, sz - len, "%-16s  %6s %6s %6s %6s\n",999			 " ", "1m", "2m", "5m", "11m");1000	mt7915_txpower_puts(CCK);1001 1002	len += scnprintf(buf + len, sz - len,1003			 "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s\n",1004			 " ", "6m", "9m", "12m", "18m", "24m", "36m", "48m",1005			 "54m");1006	mt7915_txpower_puts(OFDM);1007 1008	len += scnprintf(buf + len, sz - len,1009			 "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s\n",1010			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4",1011			 "mcs5", "mcs6", "mcs7");1012	mt7915_txpower_puts(HT_BW20);1013 1014	len += scnprintf(buf + len, sz - len,1015			 "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",1016			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",1017			 "mcs6", "mcs7", "mcs32");1018	mt7915_txpower_puts(HT_BW40);1019 1020	len += scnprintf(buf + len, sz - len,1021			 "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",1022			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",1023			 "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11");1024	mt7915_txpower_puts(VHT_BW20);1025	mt7915_txpower_puts(VHT_BW40);1026	mt7915_txpower_puts(VHT_BW80);1027	mt7915_txpower_puts(VHT_BW160);1028	mt7915_txpower_puts(HE_RU26);1029	mt7915_txpower_puts(HE_RU52);1030	mt7915_txpower_puts(HE_RU106);1031	mt7915_txpower_puts(HE_RU242);1032	mt7915_txpower_puts(HE_RU484);1033	mt7915_txpower_puts(HE_RU996);1034	mt7915_txpower_puts(HE_RU2x996);1035 1036	reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_TPC_CTRL_STAT(band) :1037	      MT_WF_PHY_TPC_CTRL_STAT_MT7916(band);1038 1039	len += scnprintf(buf + len, sz - len, "\nTx power (bbp)  : %6ld\n",1040			 mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER));1041 1042	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);1043 1044out:1045	kfree(buf);1046	return ret;1047}1048 1049static ssize_t1050mt7915_rate_txpower_set(struct file *file, const char __user *user_buf,1051			size_t count, loff_t *ppos)1052{1053	int i, ret, pwr, pwr160 = 0, pwr80 = 0, pwr40 = 0, pwr20 = 0;1054	struct mt7915_phy *phy = file->private_data;1055	struct mt7915_dev *dev = phy->dev;1056	struct mt76_phy *mphy = phy->mt76;1057	struct mt7915_mcu_txpower_sku req = {1058		.format_id = TX_POWER_LIMIT_TABLE,1059		.band_idx = phy->mt76->band_idx,1060	};1061	char buf[100];1062	enum mac80211_rx_encoding mode;1063	u32 offs = 0, len = 0;1064 1065	if (count >= sizeof(buf))1066		return -EINVAL;1067 1068	if (copy_from_user(buf, user_buf, count))1069		return -EFAULT;1070 1071	if (count && buf[count - 1] == '\n')1072		buf[count - 1] = '\0';1073	else1074		buf[count] = '\0';1075 1076	if (sscanf(buf, "%u %u %u %u %u",1077		   &mode, &pwr160, &pwr80, &pwr40, &pwr20) != 5) {1078		dev_warn(dev->mt76.dev,1079			 "per bandwidth power limit: Mode BW160 BW80 BW40 BW20");1080		return -EINVAL;1081	}1082 1083	if (mode > RX_ENC_HE)1084		return -EINVAL;1085 1086	if (pwr160)1087		pwr160 = mt7915_get_power_bound(phy, pwr160);1088	if (pwr80)1089		pwr80 = mt7915_get_power_bound(phy, pwr80);1090	if (pwr40)1091		pwr40 = mt7915_get_power_bound(phy, pwr40);1092	if (pwr20)1093		pwr20 = mt7915_get_power_bound(phy, pwr20);1094 1095	if (pwr160 < 0 || pwr80 < 0 || pwr40 < 0 || pwr20 < 0)1096		return -EINVAL;1097 1098	mutex_lock(&dev->mt76.mutex);1099	ret = mt7915_mcu_get_txpower_sku(phy, req.txpower_sku,1100					 sizeof(req.txpower_sku));1101	if (ret)1102		goto out;1103 1104	mt7915_txpower_sets(SKU_CCK, pwr20, RX_ENC_LEGACY);1105	mt7915_txpower_sets(SKU_OFDM, pwr20, RX_ENC_LEGACY);1106	if (mode == RX_ENC_LEGACY)1107		goto skip;1108 1109	mt7915_txpower_sets(SKU_HT_BW20, pwr20, RX_ENC_HT);1110	mt7915_txpower_sets(SKU_HT_BW40, pwr40, RX_ENC_HT);1111	if (mode == RX_ENC_HT)1112		goto skip;1113 1114	mt7915_txpower_sets(SKU_VHT_BW20, pwr20, RX_ENC_VHT);1115	mt7915_txpower_sets(SKU_VHT_BW40, pwr40, RX_ENC_VHT);1116	mt7915_txpower_sets(SKU_VHT_BW80, pwr80, RX_ENC_VHT);1117	mt7915_txpower_sets(SKU_VHT_BW160, pwr160, RX_ENC_VHT);1118	if (mode == RX_ENC_VHT)1119		goto skip;1120 1121	mt7915_txpower_sets(SKU_HE_RU26, pwr20, RX_ENC_HE + 1);1122	mt7915_txpower_sets(SKU_HE_RU52, pwr20, RX_ENC_HE + 1);1123	mt7915_txpower_sets(SKU_HE_RU106, pwr20, RX_ENC_HE + 1);1124	mt7915_txpower_sets(SKU_HE_RU242, pwr20, RX_ENC_HE);1125	mt7915_txpower_sets(SKU_HE_RU484, pwr40, RX_ENC_HE);1126	mt7915_txpower_sets(SKU_HE_RU996, pwr80, RX_ENC_HE);1127	mt7915_txpower_sets(SKU_HE_RU2x996, pwr160, RX_ENC_HE);1128skip:1129	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),1130				&req, sizeof(req), true);1131	if (ret)1132		goto out;1133 1134	pwr = max3(pwr80, pwr40, pwr20);1135	mphy->txpower_cur = max3(mphy->txpower_cur, pwr160, pwr);1136out:1137	mutex_unlock(&dev->mt76.mutex);1138 1139	return ret ? ret : count;1140}1141 1142static const struct file_operations mt7915_rate_txpower_fops = {1143	.write = mt7915_rate_txpower_set,1144	.read = mt7915_rate_txpower_get,1145	.open = simple_open,1146	.owner = THIS_MODULE,1147	.llseek = default_llseek,1148};1149 1150static int1151mt7915_twt_stats(struct seq_file *s, void *data)1152{1153	struct mt7915_dev *dev = dev_get_drvdata(s->private);1154	struct mt7915_twt_flow *iter;1155 1156	rcu_read_lock();1157 1158	seq_puts(s, "     wcid |       id |    flags |      exp | mantissa");1159	seq_puts(s, " | duration |            tsf |\n");1160	list_for_each_entry_rcu(iter, &dev->twt_list, list)1161		seq_printf(s,1162			"%9d | %8d | %5c%c%c%c | %8d | %8d | %8d | %14lld |\n",1163			iter->wcid, iter->id,1164			iter->sched ? 's' : 'u',1165			iter->protection ? 'p' : '-',1166			iter->trigger ? 't' : '-',1167			iter->flowtype ? '-' : 'a',1168			iter->exp, iter->mantissa,1169			iter->duration, iter->tsf);1170 1171	rcu_read_unlock();1172 1173	return 0;1174}1175 1176/* The index of RF registers use the generic regidx, combined with two parts:1177 * WF selection [31:24] and offset [23:0].1178 */1179static int1180mt7915_rf_regval_get(void *data, u64 *val)1181{1182	struct mt7915_dev *dev = data;1183	u32 regval;1184	int ret;1185 1186	ret = mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &regval, false);1187	if (ret)1188		return ret;1189 1190	*val = regval;1191 1192	return 0;1193}1194 1195static int1196mt7915_rf_regval_set(void *data, u64 val)1197{1198	struct mt7915_dev *dev = data;1199	u32 val32 = val;1200 1201	return mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &val32, true);1202}1203 1204DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7915_rf_regval_get,1205			 mt7915_rf_regval_set, "0x%08llx\n");1206 1207int mt7915_init_debugfs(struct mt7915_phy *phy)1208{1209	struct mt7915_dev *dev = phy->dev;1210	bool ext_phy = phy != &dev->phy;1211	struct dentry *dir;1212 1213	dir = mt76_register_debugfs_fops(phy->mt76, NULL);1214	if (!dir)1215		return -ENOMEM;1216	debugfs_create_file("muru_debug", 0600, dir, dev, &fops_muru_debug);1217	debugfs_create_file("muru_stats", 0400, dir, phy,1218			    &mt7915_muru_stats_fops);1219	debugfs_create_file("hw-queues", 0400, dir, phy,1220			    &mt7915_hw_queues_fops);1221	debugfs_create_file("xmit-queues", 0400, dir, phy,1222			    &mt7915_xmit_queues_fops);1223	debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops);1224	debugfs_create_file("sys_recovery", 0600, dir, phy,1225			    &mt7915_sys_recovery_ops);1226	debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm);1227	debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa);1228	debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin);1229	debugfs_create_file("fw_util_wm", 0400, dir, dev,1230			    &mt7915_fw_util_wm_fops);1231	debugfs_create_file("fw_util_wa", 0400, dir, dev,1232			    &mt7915_fw_util_wa_fops);1233	debugfs_create_file("implicit_txbf", 0600, dir, dev,1234			    &fops_implicit_txbf);1235	debugfs_create_file("txpower_sku", 0400, dir, phy,1236			    &mt7915_rate_txpower_fops);1237	debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,1238				    mt7915_twt_stats);1239	debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);1240 1241	if (!dev->dbdc_support || phy->mt76->band_idx) {1242		debugfs_create_u32("dfs_hw_pattern", 0400, dir,1243				   &dev->hw_pattern);1244		debugfs_create_file("radar_trigger", 0200, dir, dev,1245				    &fops_radar_trigger);1246		debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir,1247					    mt7915_rdd_monitor);1248	}1249 1250	if (!ext_phy)1251		dev->debugfs_dir = dir;1252 1253	return 0;1254}1255 1256static void1257mt7915_debugfs_write_fwlog(struct mt7915_dev *dev, const void *hdr, int hdrlen,1258			 const void *data, int len)1259{1260	static DEFINE_SPINLOCK(lock);1261	unsigned long flags;1262	void *dest;1263 1264	spin_lock_irqsave(&lock, flags);1265	dest = relay_reserve(dev->relay_fwlog, hdrlen + len + 4);1266	if (dest) {1267		*(u32 *)dest = hdrlen + len;1268		dest += 4;1269 1270		if (hdrlen) {1271			memcpy(dest, hdr, hdrlen);1272			dest += hdrlen;1273		}1274 1275		memcpy(dest, data, len);1276		relay_flush(dev->relay_fwlog);1277	}1278	spin_unlock_irqrestore(&lock, flags);1279}1280 1281void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len)1282{1283	struct {1284		__le32 magic;1285		__le32 timestamp;1286		__le16 msg_type;1287		__le16 len;1288	} hdr = {1289		.magic = cpu_to_le32(FW_BIN_LOG_MAGIC),1290		.msg_type = cpu_to_le16(PKT_TYPE_RX_FW_MONITOR),1291	};1292 1293	if (!dev->relay_fwlog)1294		return;1295 1296	hdr.timestamp = cpu_to_le32(mt76_rr(dev, MT_LPON_FRCR(0)));1297	hdr.len = *(__le16 *)data;1298	mt7915_debugfs_write_fwlog(dev, &hdr, sizeof(hdr), data, len);1299}1300 1301bool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len)1302{1303	if (get_unaligned_le32(data) != FW_BIN_LOG_MAGIC)1304		return false;1305 1306	if (dev->relay_fwlog)1307		mt7915_debugfs_write_fwlog(dev, NULL, 0, data, len);1308 1309	return true;1310}1311 1312#ifdef CONFIG_MAC80211_DEBUGFS1313/** per-station debugfs **/1314 1315static ssize_t mt7915_sta_fixed_rate_set(struct file *file,1316					 const char __user *user_buf,1317					 size_t count, loff_t *ppos)1318{1319	struct ieee80211_sta *sta = file->private_data;1320	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;1321	struct mt7915_dev *dev = msta->vif->phy->dev;1322	struct ieee80211_vif *vif;1323	struct sta_phy phy = {};1324	char buf[100];1325	int ret;1326	u32 field;1327	u8 i, gi, he_ltf;1328 1329	if (count >= sizeof(buf))1330		return -EINVAL;1331 1332	if (copy_from_user(buf, user_buf, count))1333		return -EFAULT;1334 1335	if (count && buf[count - 1] == '\n')1336		buf[count - 1] = '\0';1337	else1338		buf[count] = '\0';1339 1340	/* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 91341	 * bw - bw20: 0, bw40: 1, bw80: 2, bw160: 31342	 * nss - vht: 1~4, he: 1~4, others: ignore1343	 * mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~21344	 * gi - (ht/vht) lgi: 0, sgi: 1; (he) 0.8us: 0, 1.6us: 1, 3.2us: 21345	 * ldpc - off: 0, on: 11346	 * stbc - off: 0, on: 11347	 * he_ltf - 1xltf: 0, 2xltf: 1, 4xltf: 21348	 */1349	if (sscanf(buf, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu",1350		   &phy.type, &phy.bw, &phy.nss, &phy.mcs, &gi,1351		   &phy.ldpc, &phy.stbc, &he_ltf) != 8) {1352		dev_warn(dev->mt76.dev,1353			 "format: Mode BW NSS MCS (HE)GI LDPC STBC HE_LTF\n");1354		field = RATE_PARAM_AUTO;1355		goto out;1356	}1357 1358	phy.ldpc = (phy.bw || phy.ldpc) * GENMASK(2, 0);1359	for (i = 0; i <= phy.bw; i++) {1360		phy.sgi |= gi << (i << sta->deflink.he_cap.has_he);1361		phy.he_ltf |= he_ltf << (i << sta->deflink.he_cap.has_he);1362	}1363	field = RATE_PARAM_FIXED;1364 1365out:1366	vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);1367	ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, field);1368	if (ret)1369		return -EFAULT;1370 1371	return count;1372}1373 1374static const struct file_operations fops_fixed_rate = {1375	.write = mt7915_sta_fixed_rate_set,1376	.open = simple_open,1377	.owner = THIS_MODULE,1378	.llseek = default_llseek,1379};1380 1381static int1382mt7915_queues_show(struct seq_file *s, void *data)1383{1384	struct ieee80211_sta *sta = s->private;1385 1386	mt7915_sta_hw_queue_read(s, sta);1387 1388	return 0;1389}1390 1391DEFINE_SHOW_ATTRIBUTE(mt7915_queues);1392 1393void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,1394			    struct ieee80211_sta *sta, struct dentry *dir)1395{1396	debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate);1397	debugfs_create_file("hw-queues", 0400, dir, sta, &mt7915_queues_fops);1398}1399 1400#endif1401