162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/relay.h>
562306a36Sopenharmony_ci#include "mt7915.h"
662306a36Sopenharmony_ci#include "eeprom.h"
762306a36Sopenharmony_ci#include "mcu.h"
862306a36Sopenharmony_ci#include "mac.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define FW_BIN_LOG_MAGIC	0x44e98caf
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/** global debugfs **/
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistruct hw_queue_map {
1562306a36Sopenharmony_ci	const char *name;
1662306a36Sopenharmony_ci	u8 index;
1762306a36Sopenharmony_ci	u8 pid;
1862306a36Sopenharmony_ci	u8 qid;
1962306a36Sopenharmony_ci};
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic int
2262306a36Sopenharmony_cimt7915_implicit_txbf_set(void *data, u64 val)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	/* The existing connected stations shall reconnect to apply
2762306a36Sopenharmony_ci	 * new implicit txbf configuration.
2862306a36Sopenharmony_ci	 */
2962306a36Sopenharmony_ci	dev->ibf = !!val;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE);
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic int
3562306a36Sopenharmony_cimt7915_implicit_txbf_get(void *data, u64 *val)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	*val = dev->ibf;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	return 0;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7915_implicit_txbf_get,
4562306a36Sopenharmony_ci			 mt7915_implicit_txbf_set, "%lld\n");
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* test knob of system error recovery */
4862306a36Sopenharmony_cistatic ssize_t
4962306a36Sopenharmony_cimt7915_sys_recovery_set(struct file *file, const char __user *user_buf,
5062306a36Sopenharmony_ci			size_t count, loff_t *ppos)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	struct mt7915_phy *phy = file->private_data;
5362306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
5462306a36Sopenharmony_ci	bool band = phy->mt76->band_idx;
5562306a36Sopenharmony_ci	char buf[16];
5662306a36Sopenharmony_ci	int ret = 0;
5762306a36Sopenharmony_ci	u16 val;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (count >= sizeof(buf))
6062306a36Sopenharmony_ci		return -EINVAL;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf, count))
6362306a36Sopenharmony_ci		return -EFAULT;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (count && buf[count - 1] == '\n')
6662306a36Sopenharmony_ci		buf[count - 1] = '\0';
6762306a36Sopenharmony_ci	else
6862306a36Sopenharmony_ci		buf[count] = '\0';
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	if (kstrtou16(buf, 0, &val))
7162306a36Sopenharmony_ci		return -EINVAL;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	switch (val) {
7462306a36Sopenharmony_ci	/*
7562306a36Sopenharmony_ci	 * 0: grab firmware current SER state.
7662306a36Sopenharmony_ci	 * 1: trigger & enable system error L1 recovery.
7762306a36Sopenharmony_ci	 * 2: trigger & enable system error L2 recovery.
7862306a36Sopenharmony_ci	 * 3: trigger & enable system error L3 rx abort.
7962306a36Sopenharmony_ci	 * 4: trigger & enable system error L3 tx abort
8062306a36Sopenharmony_ci	 * 5: trigger & enable system error L3 tx disable.
8162306a36Sopenharmony_ci	 * 6: trigger & enable system error L3 bf recovery.
8262306a36Sopenharmony_ci	 * 7: trigger & enable system error full recovery.
8362306a36Sopenharmony_ci	 * 8: trigger firmware crash.
8462306a36Sopenharmony_ci	 */
8562306a36Sopenharmony_ci	case SER_QUERY:
8662306a36Sopenharmony_ci		ret = mt7915_mcu_set_ser(dev, 0, 0, band);
8762306a36Sopenharmony_ci		break;
8862306a36Sopenharmony_ci	case SER_SET_RECOVER_L1:
8962306a36Sopenharmony_ci	case SER_SET_RECOVER_L2:
9062306a36Sopenharmony_ci	case SER_SET_RECOVER_L3_RX_ABORT:
9162306a36Sopenharmony_ci	case SER_SET_RECOVER_L3_TX_ABORT:
9262306a36Sopenharmony_ci	case SER_SET_RECOVER_L3_TX_DISABLE:
9362306a36Sopenharmony_ci	case SER_SET_RECOVER_L3_BF:
9462306a36Sopenharmony_ci		ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), band);
9562306a36Sopenharmony_ci		if (ret)
9662306a36Sopenharmony_ci			return ret;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci		ret = mt7915_mcu_set_ser(dev, SER_RECOVER, val, band);
9962306a36Sopenharmony_ci		break;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* enable full chip reset */
10262306a36Sopenharmony_ci	case SER_SET_RECOVER_FULL:
10362306a36Sopenharmony_ci		mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
10462306a36Sopenharmony_ci		ret = mt7915_mcu_set_ser(dev, 1, 3, band);
10562306a36Sopenharmony_ci		if (ret)
10662306a36Sopenharmony_ci			return ret;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		dev->recovery.state |= MT_MCU_CMD_WDT_MASK;
10962306a36Sopenharmony_ci		mt7915_reset(dev);
11062306a36Sopenharmony_ci		break;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/* WARNING: trigger firmware crash */
11362306a36Sopenharmony_ci	case SER_SET_SYSTEM_ASSERT:
11462306a36Sopenharmony_ci		mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR, BIT(18));
11562306a36Sopenharmony_ci		mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_SOFT_ADDR, BIT(18));
11662306a36Sopenharmony_ci		break;
11762306a36Sopenharmony_ci	default:
11862306a36Sopenharmony_ci		break;
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	return ret ? ret : count;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic ssize_t
12562306a36Sopenharmony_cimt7915_sys_recovery_get(struct file *file, char __user *user_buf,
12662306a36Sopenharmony_ci			size_t count, loff_t *ppos)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct mt7915_phy *phy = file->private_data;
12962306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
13062306a36Sopenharmony_ci	char *buff;
13162306a36Sopenharmony_ci	int desc = 0;
13262306a36Sopenharmony_ci	ssize_t ret;
13362306a36Sopenharmony_ci	static const size_t bufsz = 1024;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	buff = kmalloc(bufsz, GFP_KERNEL);
13662306a36Sopenharmony_ci	if (!buff)
13762306a36Sopenharmony_ci		return -ENOMEM;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/* HELP */
14062306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
14162306a36Sopenharmony_ci			  "Please echo the correct value ...\n");
14262306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
14362306a36Sopenharmony_ci			  "0: grab firmware transient SER state\n");
14462306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
14562306a36Sopenharmony_ci			  "1: trigger system error L1 recovery\n");
14662306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
14762306a36Sopenharmony_ci			  "2: trigger system error L2 recovery\n");
14862306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
14962306a36Sopenharmony_ci			  "3: trigger system error L3 rx abort\n");
15062306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
15162306a36Sopenharmony_ci			  "4: trigger system error L3 tx abort\n");
15262306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
15362306a36Sopenharmony_ci			  "5: trigger system error L3 tx disable\n");
15462306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
15562306a36Sopenharmony_ci			  "6: trigger system error L3 bf recovery\n");
15662306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
15762306a36Sopenharmony_ci			  "7: trigger system error full recovery\n");
15862306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
15962306a36Sopenharmony_ci			  "8: trigger firmware crash\n");
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* SER statistics */
16262306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
16362306a36Sopenharmony_ci			  "\nlet's dump firmware SER statistics...\n");
16462306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
16562306a36Sopenharmony_ci			  "::E  R , SER_STATUS        = 0x%08x\n",
16662306a36Sopenharmony_ci			  mt76_rr(dev, MT_SWDEF_SER_STATS));
16762306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
16862306a36Sopenharmony_ci			  "::E  R , SER_PLE_ERR       = 0x%08x\n",
16962306a36Sopenharmony_ci			  mt76_rr(dev, MT_SWDEF_PLE_STATS));
17062306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
17162306a36Sopenharmony_ci			  "::E  R , SER_PLE_ERR_1     = 0x%08x\n",
17262306a36Sopenharmony_ci			  mt76_rr(dev, MT_SWDEF_PLE1_STATS));
17362306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
17462306a36Sopenharmony_ci			  "::E  R , SER_PLE_ERR_AMSDU = 0x%08x\n",
17562306a36Sopenharmony_ci			  mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATS));
17662306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
17762306a36Sopenharmony_ci			  "::E  R , SER_PSE_ERR       = 0x%08x\n",
17862306a36Sopenharmony_ci			  mt76_rr(dev, MT_SWDEF_PSE_STATS));
17962306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
18062306a36Sopenharmony_ci			  "::E  R , SER_PSE_ERR_1     = 0x%08x\n",
18162306a36Sopenharmony_ci			  mt76_rr(dev, MT_SWDEF_PSE1_STATS));
18262306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
18362306a36Sopenharmony_ci			  "::E  R , SER_LMAC_WISR6_B0 = 0x%08x\n",
18462306a36Sopenharmony_ci			  mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATS));
18562306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
18662306a36Sopenharmony_ci			  "::E  R , SER_LMAC_WISR6_B1 = 0x%08x\n",
18762306a36Sopenharmony_ci			  mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATS));
18862306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
18962306a36Sopenharmony_ci			  "::E  R , SER_LMAC_WISR7_B0 = 0x%08x\n",
19062306a36Sopenharmony_ci			  mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATS));
19162306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
19262306a36Sopenharmony_ci			  "::E  R , SER_LMAC_WISR7_B1 = 0x%08x\n",
19362306a36Sopenharmony_ci			  mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS));
19462306a36Sopenharmony_ci	desc += scnprintf(buff + desc, bufsz - desc,
19562306a36Sopenharmony_ci			  "\nSYS_RESET_COUNT: WM %d, WA %d\n",
19662306a36Sopenharmony_ci			  dev->recovery.wm_reset_count,
19762306a36Sopenharmony_ci			  dev->recovery.wa_reset_count);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
20062306a36Sopenharmony_ci	kfree(buff);
20162306a36Sopenharmony_ci	return ret;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic const struct file_operations mt7915_sys_recovery_ops = {
20562306a36Sopenharmony_ci	.write = mt7915_sys_recovery_set,
20662306a36Sopenharmony_ci	.read = mt7915_sys_recovery_get,
20762306a36Sopenharmony_ci	.open = simple_open,
20862306a36Sopenharmony_ci	.llseek = default_llseek,
20962306a36Sopenharmony_ci};
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic int
21262306a36Sopenharmony_cimt7915_radar_trigger(void *data, u64 val)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (val > MT_RX_SEL2)
21762306a36Sopenharmony_ci		return -EINVAL;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_RADAR_EMULATE,
22062306a36Sopenharmony_ci				       val, 0, 0);
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,
22462306a36Sopenharmony_ci			 mt7915_radar_trigger, "%lld\n");
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic int
22762306a36Sopenharmony_cimt7915_muru_debug_set(void *data, u64 val)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	dev->muru_debug = val;
23262306a36Sopenharmony_ci	mt7915_mcu_muru_debug_set(dev, dev->muru_debug);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return 0;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic int
23862306a36Sopenharmony_cimt7915_muru_debug_get(void *data, u64 *val)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	*val = dev->muru_debug;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return 0;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_muru_debug, mt7915_muru_debug_get,
24862306a36Sopenharmony_ci			 mt7915_muru_debug_set, "%lld\n");
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic int mt7915_muru_stats_show(struct seq_file *file, void *data)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct mt7915_phy *phy = file->private;
25362306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
25462306a36Sopenharmony_ci	static const char * const dl_non_he_type[] = {
25562306a36Sopenharmony_ci		"CCK", "OFDM", "HT MIX", "HT GF",
25662306a36Sopenharmony_ci		"VHT SU", "VHT 2MU", "VHT 3MU", "VHT 4MU"
25762306a36Sopenharmony_ci	};
25862306a36Sopenharmony_ci	static const char * const dl_he_type[] = {
25962306a36Sopenharmony_ci		"HE SU", "HE EXT", "HE 2MU", "HE 3MU", "HE 4MU",
26062306a36Sopenharmony_ci		"HE 2RU", "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU",
26162306a36Sopenharmony_ci		"HE >16RU"
26262306a36Sopenharmony_ci	};
26362306a36Sopenharmony_ci	static const char * const ul_he_type[] = {
26462306a36Sopenharmony_ci		"HE 2MU", "HE 3MU", "HE 4MU", "HE SU", "HE 2RU",
26562306a36Sopenharmony_ci		"HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU", "HE >16RU"
26662306a36Sopenharmony_ci	};
26762306a36Sopenharmony_ci	int ret, i;
26862306a36Sopenharmony_ci	u64 total_ppdu_cnt, sub_total_cnt;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (!dev->muru_debug) {
27162306a36Sopenharmony_ci		seq_puts(file, "Please enable muru_debug first.\n");
27262306a36Sopenharmony_ci		return 0;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	mutex_lock(&dev->mt76.mutex);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ret = mt7915_mcu_muru_debug_get(phy);
27862306a36Sopenharmony_ci	if (ret)
27962306a36Sopenharmony_ci		goto exit;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	/* Non-HE Downlink*/
28262306a36Sopenharmony_ci	seq_puts(file, "[Non-HE]\nDownlink\nData Type:  ");
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	for (i = 0; i < 5; i++)
28562306a36Sopenharmony_ci		seq_printf(file, "%8s | ", dl_non_he_type[i]);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	seq_puts(file, "\nTotal Count:");
28862306a36Sopenharmony_ci	seq_printf(file, "%8u | %8u | %8u | %8u | %8u | ",
28962306a36Sopenharmony_ci		   phy->mib.dl_cck_cnt,
29062306a36Sopenharmony_ci		   phy->mib.dl_ofdm_cnt,
29162306a36Sopenharmony_ci		   phy->mib.dl_htmix_cnt,
29262306a36Sopenharmony_ci		   phy->mib.dl_htgf_cnt,
29362306a36Sopenharmony_ci		   phy->mib.dl_vht_su_cnt);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	seq_puts(file, "\nDownlink MU-MIMO\nData Type:  ");
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	for (i = 5; i < 8; i++)
29862306a36Sopenharmony_ci		seq_printf(file, "%8s | ", dl_non_he_type[i]);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	seq_puts(file, "\nTotal Count:");
30162306a36Sopenharmony_ci	seq_printf(file, "%8u | %8u | %8u | ",
30262306a36Sopenharmony_ci		   phy->mib.dl_vht_2mu_cnt,
30362306a36Sopenharmony_ci		   phy->mib.dl_vht_3mu_cnt,
30462306a36Sopenharmony_ci		   phy->mib.dl_vht_4mu_cnt);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	sub_total_cnt = phy->mib.dl_vht_2mu_cnt +
30762306a36Sopenharmony_ci			phy->mib.dl_vht_3mu_cnt +
30862306a36Sopenharmony_ci			phy->mib.dl_vht_4mu_cnt;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	seq_printf(file, "\nTotal non-HE MU-MIMO DL PPDU count: %lld",
31162306a36Sopenharmony_ci		   sub_total_cnt);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	total_ppdu_cnt = sub_total_cnt +
31462306a36Sopenharmony_ci			 phy->mib.dl_cck_cnt +
31562306a36Sopenharmony_ci			 phy->mib.dl_ofdm_cnt +
31662306a36Sopenharmony_ci			 phy->mib.dl_htmix_cnt +
31762306a36Sopenharmony_ci			 phy->mib.dl_htgf_cnt +
31862306a36Sopenharmony_ci			 phy->mib.dl_vht_su_cnt;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	seq_printf(file, "\nAll non-HE DL PPDU count: %lld", total_ppdu_cnt);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	/* HE Downlink */
32362306a36Sopenharmony_ci	seq_puts(file, "\n\n[HE]\nDownlink\nData Type:  ");
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	for (i = 0; i < 2; i++)
32662306a36Sopenharmony_ci		seq_printf(file, "%8s | ", dl_he_type[i]);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	seq_puts(file, "\nTotal Count:");
32962306a36Sopenharmony_ci	seq_printf(file, "%8u | %8u | ",
33062306a36Sopenharmony_ci		   phy->mib.dl_he_su_cnt, phy->mib.dl_he_ext_su_cnt);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	seq_puts(file, "\nDownlink MU-MIMO\nData Type:  ");
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	for (i = 2; i < 5; i++)
33562306a36Sopenharmony_ci		seq_printf(file, "%8s | ", dl_he_type[i]);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	seq_puts(file, "\nTotal Count:");
33862306a36Sopenharmony_ci	seq_printf(file, "%8u | %8u | %8u | ",
33962306a36Sopenharmony_ci		   phy->mib.dl_he_2mu_cnt, phy->mib.dl_he_3mu_cnt,
34062306a36Sopenharmony_ci		   phy->mib.dl_he_4mu_cnt);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	seq_puts(file, "\nDownlink OFDMA\nData Type:  ");
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	for (i = 5; i < 11; i++)
34562306a36Sopenharmony_ci		seq_printf(file, "%8s | ", dl_he_type[i]);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	seq_puts(file, "\nTotal Count:");
34862306a36Sopenharmony_ci	seq_printf(file, "%8u | %8u | %8u | %8u | %9u | %8u | ",
34962306a36Sopenharmony_ci		   phy->mib.dl_he_2ru_cnt,
35062306a36Sopenharmony_ci		   phy->mib.dl_he_3ru_cnt,
35162306a36Sopenharmony_ci		   phy->mib.dl_he_4ru_cnt,
35262306a36Sopenharmony_ci		   phy->mib.dl_he_5to8ru_cnt,
35362306a36Sopenharmony_ci		   phy->mib.dl_he_9to16ru_cnt,
35462306a36Sopenharmony_ci		   phy->mib.dl_he_gtr16ru_cnt);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	sub_total_cnt = phy->mib.dl_he_2mu_cnt +
35762306a36Sopenharmony_ci			phy->mib.dl_he_3mu_cnt +
35862306a36Sopenharmony_ci			phy->mib.dl_he_4mu_cnt;
35962306a36Sopenharmony_ci	total_ppdu_cnt = sub_total_cnt;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	seq_printf(file, "\nTotal HE MU-MIMO DL PPDU count: %lld",
36262306a36Sopenharmony_ci		   sub_total_cnt);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	sub_total_cnt = phy->mib.dl_he_2ru_cnt +
36562306a36Sopenharmony_ci			phy->mib.dl_he_3ru_cnt +
36662306a36Sopenharmony_ci			phy->mib.dl_he_4ru_cnt +
36762306a36Sopenharmony_ci			phy->mib.dl_he_5to8ru_cnt +
36862306a36Sopenharmony_ci			phy->mib.dl_he_9to16ru_cnt +
36962306a36Sopenharmony_ci			phy->mib.dl_he_gtr16ru_cnt;
37062306a36Sopenharmony_ci	total_ppdu_cnt += sub_total_cnt;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	seq_printf(file, "\nTotal HE OFDMA DL PPDU count: %lld",
37362306a36Sopenharmony_ci		   sub_total_cnt);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	total_ppdu_cnt += phy->mib.dl_he_su_cnt + phy->mib.dl_he_ext_su_cnt;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	seq_printf(file, "\nAll HE DL PPDU count: %lld", total_ppdu_cnt);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/* HE Uplink */
38062306a36Sopenharmony_ci	seq_puts(file, "\n\nUplink");
38162306a36Sopenharmony_ci	seq_puts(file, "\nTrigger-based Uplink MU-MIMO\nData Type:  ");
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	for (i = 0; i < 3; i++)
38462306a36Sopenharmony_ci		seq_printf(file, "%8s | ", ul_he_type[i]);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	seq_puts(file, "\nTotal Count:");
38762306a36Sopenharmony_ci	seq_printf(file, "%8u | %8u | %8u | ",
38862306a36Sopenharmony_ci		   phy->mib.ul_hetrig_2mu_cnt,
38962306a36Sopenharmony_ci		   phy->mib.ul_hetrig_3mu_cnt,
39062306a36Sopenharmony_ci		   phy->mib.ul_hetrig_4mu_cnt);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	seq_puts(file, "\nTrigger-based Uplink OFDMA\nData Type:  ");
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	for (i = 3; i < 10; i++)
39562306a36Sopenharmony_ci		seq_printf(file, "%8s | ", ul_he_type[i]);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	seq_puts(file, "\nTotal Count:");
39862306a36Sopenharmony_ci	seq_printf(file, "%8u | %8u | %8u | %8u | %8u | %9u |  %7u | ",
39962306a36Sopenharmony_ci		   phy->mib.ul_hetrig_su_cnt,
40062306a36Sopenharmony_ci		   phy->mib.ul_hetrig_2ru_cnt,
40162306a36Sopenharmony_ci		   phy->mib.ul_hetrig_3ru_cnt,
40262306a36Sopenharmony_ci		   phy->mib.ul_hetrig_4ru_cnt,
40362306a36Sopenharmony_ci		   phy->mib.ul_hetrig_5to8ru_cnt,
40462306a36Sopenharmony_ci		   phy->mib.ul_hetrig_9to16ru_cnt,
40562306a36Sopenharmony_ci		   phy->mib.ul_hetrig_gtr16ru_cnt);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	sub_total_cnt = phy->mib.ul_hetrig_2mu_cnt +
40862306a36Sopenharmony_ci			phy->mib.ul_hetrig_3mu_cnt +
40962306a36Sopenharmony_ci			phy->mib.ul_hetrig_4mu_cnt;
41062306a36Sopenharmony_ci	total_ppdu_cnt = sub_total_cnt;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	seq_printf(file, "\nTotal HE MU-MIMO UL TB PPDU count: %lld",
41362306a36Sopenharmony_ci		   sub_total_cnt);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	sub_total_cnt = phy->mib.ul_hetrig_2ru_cnt +
41662306a36Sopenharmony_ci			phy->mib.ul_hetrig_3ru_cnt +
41762306a36Sopenharmony_ci			phy->mib.ul_hetrig_4ru_cnt +
41862306a36Sopenharmony_ci			phy->mib.ul_hetrig_5to8ru_cnt +
41962306a36Sopenharmony_ci			phy->mib.ul_hetrig_9to16ru_cnt +
42062306a36Sopenharmony_ci			phy->mib.ul_hetrig_gtr16ru_cnt;
42162306a36Sopenharmony_ci	total_ppdu_cnt += sub_total_cnt;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	seq_printf(file, "\nTotal HE OFDMA UL TB PPDU count: %lld",
42462306a36Sopenharmony_ci		   sub_total_cnt);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	total_ppdu_cnt += phy->mib.ul_hetrig_su_cnt;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	seq_printf(file, "\nAll HE UL TB PPDU count: %lld\n", total_ppdu_cnt);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ciexit:
43162306a36Sopenharmony_ci	mutex_unlock(&dev->mt76.mutex);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return ret;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_muru_stats);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic int
43862306a36Sopenharmony_cimt7915_rdd_monitor(struct seq_file *s, void *data)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	struct mt7915_dev *dev = dev_get_drvdata(s->private);
44162306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &dev->rdd2_chandef;
44262306a36Sopenharmony_ci	const char *bw;
44362306a36Sopenharmony_ci	int ret = 0;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	mutex_lock(&dev->mt76.mutex);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	if (!cfg80211_chandef_valid(chandef)) {
44862306a36Sopenharmony_ci		ret = -EINVAL;
44962306a36Sopenharmony_ci		goto out;
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (!dev->rdd2_phy) {
45362306a36Sopenharmony_ci		seq_puts(s, "not running\n");
45462306a36Sopenharmony_ci		goto out;
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	switch (chandef->width) {
45862306a36Sopenharmony_ci	case NL80211_CHAN_WIDTH_40:
45962306a36Sopenharmony_ci		bw = "40";
46062306a36Sopenharmony_ci		break;
46162306a36Sopenharmony_ci	case NL80211_CHAN_WIDTH_80:
46262306a36Sopenharmony_ci		bw = "80";
46362306a36Sopenharmony_ci		break;
46462306a36Sopenharmony_ci	case NL80211_CHAN_WIDTH_160:
46562306a36Sopenharmony_ci		bw = "160";
46662306a36Sopenharmony_ci		break;
46762306a36Sopenharmony_ci	case NL80211_CHAN_WIDTH_80P80:
46862306a36Sopenharmony_ci		bw = "80P80";
46962306a36Sopenharmony_ci		break;
47062306a36Sopenharmony_ci	default:
47162306a36Sopenharmony_ci		bw = "20";
47262306a36Sopenharmony_ci		break;
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	seq_printf(s, "channel %d (%d MHz) width %s MHz center1: %d MHz\n",
47662306a36Sopenharmony_ci		   chandef->chan->hw_value, chandef->chan->center_freq,
47762306a36Sopenharmony_ci		   bw, chandef->center_freq1);
47862306a36Sopenharmony_ciout:
47962306a36Sopenharmony_ci	mutex_unlock(&dev->mt76.mutex);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	return ret;
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic int
48562306a36Sopenharmony_cimt7915_fw_debug_wm_set(void *data, u64 val)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
48862306a36Sopenharmony_ci	enum {
48962306a36Sopenharmony_ci		DEBUG_TXCMD = 62,
49062306a36Sopenharmony_ci		DEBUG_CMD_RPT_TX,
49162306a36Sopenharmony_ci		DEBUG_CMD_RPT_TRIG,
49262306a36Sopenharmony_ci		DEBUG_SPL,
49362306a36Sopenharmony_ci		DEBUG_RPT_RX,
49462306a36Sopenharmony_ci	} debug;
49562306a36Sopenharmony_ci	bool tx, rx, en;
49662306a36Sopenharmony_ci	int ret;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	dev->fw.debug_wm = val ? MCU_FW_LOG_TO_HOST : 0;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (dev->fw.debug_bin)
50162306a36Sopenharmony_ci		val = 16;
50262306a36Sopenharmony_ci	else
50362306a36Sopenharmony_ci		val = dev->fw.debug_wm;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	tx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(1));
50662306a36Sopenharmony_ci	rx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(2));
50762306a36Sopenharmony_ci	en = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(0));
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, val);
51062306a36Sopenharmony_ci	if (ret)
51162306a36Sopenharmony_ci		goto out;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) {
51462306a36Sopenharmony_ci		if (debug == DEBUG_RPT_RX)
51562306a36Sopenharmony_ci			val = en && rx;
51662306a36Sopenharmony_ci		else
51762306a36Sopenharmony_ci			val = en && tx;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci		ret = mt7915_mcu_fw_dbg_ctrl(dev, debug, val);
52062306a36Sopenharmony_ci		if (ret)
52162306a36Sopenharmony_ci			goto out;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/* WM CPU info record control */
52562306a36Sopenharmony_ci	mt76_clear(dev, MT_CPU_UTIL_CTRL, BIT(0));
52662306a36Sopenharmony_ci	mt76_wr(dev, MT_DIC_CMD_REG_CMD, BIT(2) | BIT(13) | !dev->fw.debug_wm);
52762306a36Sopenharmony_ci	mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR, BIT(5));
52862306a36Sopenharmony_ci	mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR, BIT(5));
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ciout:
53162306a36Sopenharmony_ci	if (ret)
53262306a36Sopenharmony_ci		dev->fw.debug_wm = 0;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	return ret;
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic int
53862306a36Sopenharmony_cimt7915_fw_debug_wm_get(void *data, u64 *val)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	*val = dev->fw.debug_wm;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	return 0;
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wm, mt7915_fw_debug_wm_get,
54862306a36Sopenharmony_ci			 mt7915_fw_debug_wm_set, "%lld\n");
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic int
55162306a36Sopenharmony_cimt7915_fw_debug_wa_set(void *data, u64 val)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
55462306a36Sopenharmony_ci	int ret;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	dev->fw.debug_wa = val ? MCU_FW_LOG_TO_HOST : 0;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, dev->fw.debug_wa);
55962306a36Sopenharmony_ci	if (ret)
56062306a36Sopenharmony_ci		goto out;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
56362306a36Sopenharmony_ci				MCU_WA_PARAM_PDMA_RX, !!dev->fw.debug_wa, 0);
56462306a36Sopenharmony_ciout:
56562306a36Sopenharmony_ci	if (ret)
56662306a36Sopenharmony_ci		dev->fw.debug_wa = 0;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	return ret;
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_cistatic int
57262306a36Sopenharmony_cimt7915_fw_debug_wa_get(void *data, u64 *val)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	*val = dev->fw.debug_wa;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	return 0;
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7915_fw_debug_wa_get,
58262306a36Sopenharmony_ci			 mt7915_fw_debug_wa_set, "%lld\n");
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_cistatic struct dentry *
58562306a36Sopenharmony_cicreate_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode,
58662306a36Sopenharmony_ci		   struct rchan_buf *buf, int *is_global)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	struct dentry *f;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	f = debugfs_create_file("fwlog_data", mode, parent, buf,
59162306a36Sopenharmony_ci				&relay_file_operations);
59262306a36Sopenharmony_ci	if (IS_ERR(f))
59362306a36Sopenharmony_ci		return NULL;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	*is_global = 1;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	return f;
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic int
60162306a36Sopenharmony_ciremove_buf_file_cb(struct dentry *f)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	debugfs_remove(f);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	return 0;
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic int
60962306a36Sopenharmony_cimt7915_fw_debug_bin_set(void *data, u64 val)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	static struct rchan_callbacks relay_cb = {
61262306a36Sopenharmony_ci		.create_buf_file = create_buf_file_cb,
61362306a36Sopenharmony_ci		.remove_buf_file = remove_buf_file_cb,
61462306a36Sopenharmony_ci	};
61562306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (!dev->relay_fwlog)
61862306a36Sopenharmony_ci		dev->relay_fwlog = relay_open("fwlog_data", dev->debugfs_dir,
61962306a36Sopenharmony_ci					    1500, 512, &relay_cb, NULL);
62062306a36Sopenharmony_ci	if (!dev->relay_fwlog)
62162306a36Sopenharmony_ci		return -ENOMEM;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	dev->fw.debug_bin = val;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	relay_reset(dev->relay_fwlog);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	return mt7915_fw_debug_wm_set(dev, dev->fw.debug_wm);
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic int
63162306a36Sopenharmony_cimt7915_fw_debug_bin_get(void *data, u64 *val)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	*val = dev->fw.debug_bin;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	return 0;
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7915_fw_debug_bin_get,
64162306a36Sopenharmony_ci			 mt7915_fw_debug_bin_set, "%lld\n");
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cistatic int
64462306a36Sopenharmony_cimt7915_fw_util_wm_show(struct seq_file *file, void *data)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	struct mt7915_dev *dev = file->private;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WM_MCU_PC));
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	if (dev->fw.debug_wm) {
65162306a36Sopenharmony_ci		seq_printf(file, "Busy: %u%%  Peak busy: %u%%\n",
65262306a36Sopenharmony_ci			   mt76_rr(dev, MT_CPU_UTIL_BUSY_PCT),
65362306a36Sopenharmony_ci			   mt76_rr(dev, MT_CPU_UTIL_PEAK_BUSY_PCT));
65462306a36Sopenharmony_ci		seq_printf(file, "Idle count: %u  Peak idle count: %u\n",
65562306a36Sopenharmony_ci			   mt76_rr(dev, MT_CPU_UTIL_IDLE_CNT),
65662306a36Sopenharmony_ci			   mt76_rr(dev, MT_CPU_UTIL_PEAK_IDLE_CNT));
65762306a36Sopenharmony_ci	}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	return 0;
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wm);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic int
66562306a36Sopenharmony_cimt7915_fw_util_wa_show(struct seq_file *file, void *data)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	struct mt7915_dev *dev = file->private;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WA_MCU_PC));
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	if (dev->fw.debug_wa)
67262306a36Sopenharmony_ci		return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(QUERY),
67362306a36Sopenharmony_ci					 MCU_WA_PARAM_CPU_UTIL, 0, 0);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	return 0;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wa);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic void
68162306a36Sopenharmony_cimt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,
68262306a36Sopenharmony_ci			   struct seq_file *file)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
68562306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
68662306a36Sopenharmony_ci	int bound[15], range[4], i;
68762306a36Sopenharmony_ci	u8 band = phy->mt76->band_idx;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	/* Tx ampdu stat */
69062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(range); i++)
69162306a36Sopenharmony_ci		range[i] = mt76_rr(dev, MT_MIB_ARNG(band, i));
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bound); i++)
69462306a36Sopenharmony_ci		bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	seq_printf(file, "\nPhy %d, Phy band %d\n", ext_phy, band);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	seq_printf(file, "Length: %8d | ", bound[0]);
69962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
70062306a36Sopenharmony_ci		seq_printf(file, "%3d -%3d | ",
70162306a36Sopenharmony_ci			   bound[i] + 1, bound[i + 1]);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	seq_puts(file, "\nCount:  ");
70462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bound); i++)
70562306a36Sopenharmony_ci		seq_printf(file, "%8d | ", phy->mt76->aggr_stats[i]);
70662306a36Sopenharmony_ci	seq_puts(file, "\n");
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic void
71262306a36Sopenharmony_cimt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	struct mt76_mib_stats *mib = &phy->mib;
71562306a36Sopenharmony_ci	static const char * const bw[] = {
71662306a36Sopenharmony_ci		"BW20", "BW40", "BW80", "BW160"
71762306a36Sopenharmony_ci	};
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	/* Tx Beamformer monitor */
72062306a36Sopenharmony_ci	seq_puts(s, "\nTx Beamformer applied PPDU counts: ");
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	seq_printf(s, "iBF: %d, eBF: %d\n",
72362306a36Sopenharmony_ci		   mib->tx_bf_ibf_ppdu_cnt,
72462306a36Sopenharmony_ci		   mib->tx_bf_ebf_ppdu_cnt);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	/* Tx Beamformer Rx feedback monitor */
72762306a36Sopenharmony_ci	seq_puts(s, "Tx Beamformer Rx feedback statistics: ");
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ",
73062306a36Sopenharmony_ci		   mib->tx_bf_rx_fb_all_cnt,
73162306a36Sopenharmony_ci		   mib->tx_bf_rx_fb_he_cnt,
73262306a36Sopenharmony_ci		   mib->tx_bf_rx_fb_vht_cnt,
73362306a36Sopenharmony_ci		   mib->tx_bf_rx_fb_ht_cnt);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	seq_printf(s, "%s, NC: %d, NR: %d\n",
73662306a36Sopenharmony_ci		   bw[mib->tx_bf_rx_fb_bw],
73762306a36Sopenharmony_ci		   mib->tx_bf_rx_fb_nc_cnt,
73862306a36Sopenharmony_ci		   mib->tx_bf_rx_fb_nr_cnt);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	/* Tx Beamformee Rx NDPA & Tx feedback report */
74162306a36Sopenharmony_ci	seq_printf(s, "Tx Beamformee successful feedback frames: %d\n",
74262306a36Sopenharmony_ci		   mib->tx_bf_fb_cpl_cnt);
74362306a36Sopenharmony_ci	seq_printf(s, "Tx Beamformee feedback triggered counts: %d\n",
74462306a36Sopenharmony_ci		   mib->tx_bf_fb_trig_cnt);
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	/* Tx SU & MU counters */
74762306a36Sopenharmony_ci	seq_printf(s, "Tx multi-user Beamforming counts: %d\n",
74862306a36Sopenharmony_ci		   mib->tx_bf_cnt);
74962306a36Sopenharmony_ci	seq_printf(s, "Tx multi-user MPDU counts: %d\n", mib->tx_mu_mpdu_cnt);
75062306a36Sopenharmony_ci	seq_printf(s, "Tx multi-user successful MPDU counts: %d\n",
75162306a36Sopenharmony_ci		   mib->tx_mu_acked_mpdu_cnt);
75262306a36Sopenharmony_ci	seq_printf(s, "Tx single-user successful MPDU counts: %d\n",
75362306a36Sopenharmony_ci		   mib->tx_su_acked_mpdu_cnt);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	seq_puts(s, "\n");
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cistatic int
75962306a36Sopenharmony_cimt7915_tx_stats_show(struct seq_file *file, void *data)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	struct mt7915_phy *phy = file->private;
76262306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
76362306a36Sopenharmony_ci	struct mt76_mib_stats *mib = &phy->mib;
76462306a36Sopenharmony_ci	int i;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	mutex_lock(&dev->mt76.mutex);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	mt7915_ampdu_stat_read_phy(phy, file);
76962306a36Sopenharmony_ci	mt7915_mac_update_stats(phy);
77062306a36Sopenharmony_ci	mt7915_txbf_stat_read_phy(phy, file);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	/* Tx amsdu info */
77362306a36Sopenharmony_ci	seq_puts(file, "Tx MSDU statistics:\n");
77462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
77562306a36Sopenharmony_ci		seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ",
77662306a36Sopenharmony_ci			   i + 1, mib->tx_amsdu[i]);
77762306a36Sopenharmony_ci		if (mib->tx_amsdu_cnt)
77862306a36Sopenharmony_ci			seq_printf(file, "(%3d%%)\n",
77962306a36Sopenharmony_ci				   mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt);
78062306a36Sopenharmony_ci		else
78162306a36Sopenharmony_ci			seq_puts(file, "\n");
78262306a36Sopenharmony_ci	}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	mutex_unlock(&dev->mt76.mutex);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	return 0;
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic void
79262306a36Sopenharmony_cimt7915_hw_queue_read(struct seq_file *s, u32 size,
79362306a36Sopenharmony_ci		     const struct hw_queue_map *map)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	struct mt7915_phy *phy = s->private;
79662306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
79762306a36Sopenharmony_ci	u32 i, val;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	val = mt76_rr(dev, MT_FL_Q_EMPTY);
80062306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
80162306a36Sopenharmony_ci		u32 ctrl, head, tail, queued;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci		if (val & BIT(map[i].index))
80462306a36Sopenharmony_ci			continue;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci		ctrl = BIT(31) | (map[i].pid << 10) | ((u32)map[i].qid << 24);
80762306a36Sopenharmony_ci		mt76_wr(dev, MT_FL_Q0_CTRL, ctrl);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci		head = mt76_get_field(dev, MT_FL_Q2_CTRL,
81062306a36Sopenharmony_ci				      GENMASK(11, 0));
81162306a36Sopenharmony_ci		tail = mt76_get_field(dev, MT_FL_Q2_CTRL,
81262306a36Sopenharmony_ci				      GENMASK(27, 16));
81362306a36Sopenharmony_ci		queued = mt76_get_field(dev, MT_FL_Q3_CTRL,
81462306a36Sopenharmony_ci					GENMASK(11, 0));
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci		seq_printf(s, "\t%s: ", map[i].name);
81762306a36Sopenharmony_ci		seq_printf(s, "queued:0x%03x head:0x%03x tail:0x%03x\n",
81862306a36Sopenharmony_ci			   queued, head, tail);
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic void
82362306a36Sopenharmony_cimt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
82662306a36Sopenharmony_ci	struct mt7915_dev *dev = msta->vif->phy->dev;
82762306a36Sopenharmony_ci	struct seq_file *s = data;
82862306a36Sopenharmony_ci	u8 ac;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	for (ac = 0; ac < 4; ac++) {
83162306a36Sopenharmony_ci		u32 qlen, ctrl, val;
83262306a36Sopenharmony_ci		u32 idx = msta->wcid.idx >> 5;
83362306a36Sopenharmony_ci		u8 offs = msta->wcid.idx & GENMASK(4, 0);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci		ctrl = BIT(31) | BIT(11) | (ac << 24);
83662306a36Sopenharmony_ci		val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx));
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci		if (val & BIT(offs))
83962306a36Sopenharmony_ci			continue;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci		mt76_wr(dev, MT_FL_Q0_CTRL, ctrl | msta->wcid.idx);
84262306a36Sopenharmony_ci		qlen = mt76_get_field(dev, MT_FL_Q3_CTRL,
84362306a36Sopenharmony_ci				      GENMASK(11, 0));
84462306a36Sopenharmony_ci		seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n",
84562306a36Sopenharmony_ci			   sta->addr, msta->wcid.idx,
84662306a36Sopenharmony_ci			   msta->vif->mt76.wmm_idx, ac, qlen);
84762306a36Sopenharmony_ci	}
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_cistatic int
85162306a36Sopenharmony_cimt7915_hw_queues_show(struct seq_file *file, void *data)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	struct mt7915_phy *phy = file->private;
85462306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
85562306a36Sopenharmony_ci	static const struct hw_queue_map ple_queue_map[] = {
85662306a36Sopenharmony_ci		{ "CPU_Q0",  0,  1, MT_CTX0	      },
85762306a36Sopenharmony_ci		{ "CPU_Q1",  1,  1, MT_CTX0 + 1	      },
85862306a36Sopenharmony_ci		{ "CPU_Q2",  2,  1, MT_CTX0 + 2	      },
85962306a36Sopenharmony_ci		{ "CPU_Q3",  3,  1, MT_CTX0 + 3	      },
86062306a36Sopenharmony_ci		{ "ALTX_Q0", 8,  2, MT_LMAC_ALTX0     },
86162306a36Sopenharmony_ci		{ "BMC_Q0",  9,  2, MT_LMAC_BMC0      },
86262306a36Sopenharmony_ci		{ "BCN_Q0",  10, 2, MT_LMAC_BCN0      },
86362306a36Sopenharmony_ci		{ "PSMP_Q0", 11, 2, MT_LMAC_PSMP0     },
86462306a36Sopenharmony_ci		{ "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 },
86562306a36Sopenharmony_ci		{ "BMC_Q1",  13, 2, MT_LMAC_BMC0  + 4 },
86662306a36Sopenharmony_ci		{ "BCN_Q1",  14, 2, MT_LMAC_BCN0  + 4 },
86762306a36Sopenharmony_ci		{ "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 },
86862306a36Sopenharmony_ci	};
86962306a36Sopenharmony_ci	static const struct hw_queue_map pse_queue_map[] = {
87062306a36Sopenharmony_ci		{ "CPU Q0",  0,  1, MT_CTX0	      },
87162306a36Sopenharmony_ci		{ "CPU Q1",  1,  1, MT_CTX0 + 1	      },
87262306a36Sopenharmony_ci		{ "CPU Q2",  2,  1, MT_CTX0 + 2	      },
87362306a36Sopenharmony_ci		{ "CPU Q3",  3,  1, MT_CTX0 + 3	      },
87462306a36Sopenharmony_ci		{ "HIF_Q0",  8,  0, MT_HIF0	      },
87562306a36Sopenharmony_ci		{ "HIF_Q1",  9,  0, MT_HIF0 + 1	      },
87662306a36Sopenharmony_ci		{ "HIF_Q2",  10, 0, MT_HIF0 + 2	      },
87762306a36Sopenharmony_ci		{ "HIF_Q3",  11, 0, MT_HIF0 + 3	      },
87862306a36Sopenharmony_ci		{ "HIF_Q4",  12, 0, MT_HIF0 + 4	      },
87962306a36Sopenharmony_ci		{ "HIF_Q5",  13, 0, MT_HIF0 + 5	      },
88062306a36Sopenharmony_ci		{ "LMAC_Q",  16, 2, 0		      },
88162306a36Sopenharmony_ci		{ "MDP_TXQ", 17, 2, 1		      },
88262306a36Sopenharmony_ci		{ "MDP_RXQ", 18, 2, 2		      },
88362306a36Sopenharmony_ci		{ "SEC_TXQ", 19, 2, 3		      },
88462306a36Sopenharmony_ci		{ "SEC_RXQ", 20, 2, 4		      },
88562306a36Sopenharmony_ci	};
88662306a36Sopenharmony_ci	u32 val, head, tail;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	/* ple queue */
88962306a36Sopenharmony_ci	val = mt76_rr(dev, MT_PLE_FREEPG_CNT);
89062306a36Sopenharmony_ci	head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0));
89162306a36Sopenharmony_ci	tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16));
89262306a36Sopenharmony_ci	seq_puts(file, "PLE page info:\n");
89362306a36Sopenharmony_ci	seq_printf(file,
89462306a36Sopenharmony_ci		   "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n",
89562306a36Sopenharmony_ci		   val, head, tail);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP);
89862306a36Sopenharmony_ci	head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0));
89962306a36Sopenharmony_ci	tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16));
90062306a36Sopenharmony_ci	seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n",
90162306a36Sopenharmony_ci		   val, head, tail);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	seq_puts(file, "PLE non-empty queue info:\n");
90462306a36Sopenharmony_ci	mt7915_hw_queue_read(file, ARRAY_SIZE(ple_queue_map),
90562306a36Sopenharmony_ci			     &ple_queue_map[0]);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	/* iterate per-sta ple queue */
90862306a36Sopenharmony_ci	ieee80211_iterate_stations_atomic(phy->mt76->hw,
90962306a36Sopenharmony_ci					  mt7915_sta_hw_queue_read, file);
91062306a36Sopenharmony_ci	/* pse queue */
91162306a36Sopenharmony_ci	seq_puts(file, "PSE non-empty queue info:\n");
91262306a36Sopenharmony_ci	mt7915_hw_queue_read(file, ARRAY_SIZE(pse_queue_map),
91362306a36Sopenharmony_ci			     &pse_queue_map[0]);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	return 0;
91662306a36Sopenharmony_ci}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_hw_queues);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_cistatic int
92162306a36Sopenharmony_cimt7915_xmit_queues_show(struct seq_file *file, void *data)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci	struct mt7915_phy *phy = file->private;
92462306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
92562306a36Sopenharmony_ci	struct {
92662306a36Sopenharmony_ci		struct mt76_queue *q;
92762306a36Sopenharmony_ci		char *queue;
92862306a36Sopenharmony_ci	} queue_map[] = {
92962306a36Sopenharmony_ci		{ phy->mt76->q_tx[MT_TXQ_BE],	 "   MAIN"  },
93062306a36Sopenharmony_ci		{ dev->mt76.q_mcu[MT_MCUQ_WM],	 "  MCUWM"  },
93162306a36Sopenharmony_ci		{ dev->mt76.q_mcu[MT_MCUQ_WA],	 "  MCUWA"  },
93262306a36Sopenharmony_ci		{ dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" },
93362306a36Sopenharmony_ci	};
93462306a36Sopenharmony_ci	int i;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	seq_puts(file, "     queue | hw-queued |      head |      tail |\n");
93762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
93862306a36Sopenharmony_ci		struct mt76_queue *q = queue_map[i].q;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci		if (!q)
94162306a36Sopenharmony_ci			continue;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci		seq_printf(file, "   %s | %9d | %9d | %9d |\n",
94462306a36Sopenharmony_ci			   queue_map[i].queue, q->queued, q->head,
94562306a36Sopenharmony_ci			   q->tail);
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	return 0;
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci#define mt7915_txpower_puts(rate)						\
95462306a36Sopenharmony_ci({										\
95562306a36Sopenharmony_ci	len += scnprintf(buf + len, sz - len, "%-16s:", #rate " (TMAC)");	\
95662306a36Sopenharmony_ci	for (i = 0; i < mt7915_sku_group_len[SKU_##rate]; i++, offs++)		\
95762306a36Sopenharmony_ci		len += scnprintf(buf + len, sz - len, " %6d", txpwr[offs]);	\
95862306a36Sopenharmony_ci	len += scnprintf(buf + len, sz - len, "\n");				\
95962306a36Sopenharmony_ci})
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci#define mt7915_txpower_sets(rate, pwr, flag)			\
96262306a36Sopenharmony_ci({								\
96362306a36Sopenharmony_ci	offs += len;						\
96462306a36Sopenharmony_ci	len = mt7915_sku_group_len[rate];			\
96562306a36Sopenharmony_ci	if (mode == flag) {					\
96662306a36Sopenharmony_ci		for (i = 0; i < len; i++)			\
96762306a36Sopenharmony_ci			req.txpower_sku[offs + i] = pwr;	\
96862306a36Sopenharmony_ci	}							\
96962306a36Sopenharmony_ci})
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cistatic ssize_t
97262306a36Sopenharmony_cimt7915_rate_txpower_get(struct file *file, char __user *user_buf,
97362306a36Sopenharmony_ci			size_t count, loff_t *ppos)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	struct mt7915_phy *phy = file->private_data;
97662306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
97762306a36Sopenharmony_ci	s8 txpwr[MT7915_SKU_RATE_NUM];
97862306a36Sopenharmony_ci	static const size_t sz = 2048;
97962306a36Sopenharmony_ci	u8 band = phy->mt76->band_idx;
98062306a36Sopenharmony_ci	int i, offs = 0, len = 0;
98162306a36Sopenharmony_ci	ssize_t ret;
98262306a36Sopenharmony_ci	char *buf;
98362306a36Sopenharmony_ci	u32 reg;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	buf = kzalloc(sz, GFP_KERNEL);
98662306a36Sopenharmony_ci	if (!buf)
98762306a36Sopenharmony_ci		return -ENOMEM;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	ret = mt7915_mcu_get_txpower_sku(phy, txpwr, sizeof(txpwr));
99062306a36Sopenharmony_ci	if (ret)
99162306a36Sopenharmony_ci		goto out;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	/* Txpower propagation path: TMAC -> TXV -> BBP */
99462306a36Sopenharmony_ci	len += scnprintf(buf + len, sz - len,
99562306a36Sopenharmony_ci			 "\nPhy%d Tx power table (channel %d)\n",
99662306a36Sopenharmony_ci			 phy != &dev->phy, phy->mt76->chandef.chan->hw_value);
99762306a36Sopenharmony_ci	len += scnprintf(buf + len, sz - len, "%-16s  %6s %6s %6s %6s\n",
99862306a36Sopenharmony_ci			 " ", "1m", "2m", "5m", "11m");
99962306a36Sopenharmony_ci	mt7915_txpower_puts(CCK);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	len += scnprintf(buf + len, sz - len,
100262306a36Sopenharmony_ci			 "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s\n",
100362306a36Sopenharmony_ci			 " ", "6m", "9m", "12m", "18m", "24m", "36m", "48m",
100462306a36Sopenharmony_ci			 "54m");
100562306a36Sopenharmony_ci	mt7915_txpower_puts(OFDM);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	len += scnprintf(buf + len, sz - len,
100862306a36Sopenharmony_ci			 "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s\n",
100962306a36Sopenharmony_ci			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4",
101062306a36Sopenharmony_ci			 "mcs5", "mcs6", "mcs7");
101162306a36Sopenharmony_ci	mt7915_txpower_puts(HT_BW20);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	len += scnprintf(buf + len, sz - len,
101462306a36Sopenharmony_ci			 "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
101562306a36Sopenharmony_ci			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
101662306a36Sopenharmony_ci			 "mcs6", "mcs7", "mcs32");
101762306a36Sopenharmony_ci	mt7915_txpower_puts(HT_BW40);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	len += scnprintf(buf + len, sz - len,
102062306a36Sopenharmony_ci			 "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
102162306a36Sopenharmony_ci			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
102262306a36Sopenharmony_ci			 "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11");
102362306a36Sopenharmony_ci	mt7915_txpower_puts(VHT_BW20);
102462306a36Sopenharmony_ci	mt7915_txpower_puts(VHT_BW40);
102562306a36Sopenharmony_ci	mt7915_txpower_puts(VHT_BW80);
102662306a36Sopenharmony_ci	mt7915_txpower_puts(VHT_BW160);
102762306a36Sopenharmony_ci	mt7915_txpower_puts(HE_RU26);
102862306a36Sopenharmony_ci	mt7915_txpower_puts(HE_RU52);
102962306a36Sopenharmony_ci	mt7915_txpower_puts(HE_RU106);
103062306a36Sopenharmony_ci	mt7915_txpower_puts(HE_RU242);
103162306a36Sopenharmony_ci	mt7915_txpower_puts(HE_RU484);
103262306a36Sopenharmony_ci	mt7915_txpower_puts(HE_RU996);
103362306a36Sopenharmony_ci	mt7915_txpower_puts(HE_RU2x996);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_TPC_CTRL_STAT(band) :
103662306a36Sopenharmony_ci	      MT_WF_PHY_TPC_CTRL_STAT_MT7916(band);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	len += scnprintf(buf + len, sz - len, "\nTx power (bbp)  : %6ld\n",
103962306a36Sopenharmony_ci			 mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER));
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ciout:
104462306a36Sopenharmony_ci	kfree(buf);
104562306a36Sopenharmony_ci	return ret;
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistatic ssize_t
104962306a36Sopenharmony_cimt7915_rate_txpower_set(struct file *file, const char __user *user_buf,
105062306a36Sopenharmony_ci			size_t count, loff_t *ppos)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	struct mt7915_phy *phy = file->private_data;
105362306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
105462306a36Sopenharmony_ci	struct mt76_phy *mphy = phy->mt76;
105562306a36Sopenharmony_ci	struct mt7915_mcu_txpower_sku req = {
105662306a36Sopenharmony_ci		.format_id = TX_POWER_LIMIT_TABLE,
105762306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
105862306a36Sopenharmony_ci	};
105962306a36Sopenharmony_ci	char buf[100];
106062306a36Sopenharmony_ci	int i, ret, pwr160 = 0, pwr80 = 0, pwr40 = 0, pwr20 = 0;
106162306a36Sopenharmony_ci	enum mac80211_rx_encoding mode;
106262306a36Sopenharmony_ci	u32 offs = 0, len = 0;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	if (count >= sizeof(buf))
106562306a36Sopenharmony_ci		return -EINVAL;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf, count))
106862306a36Sopenharmony_ci		return -EFAULT;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	if (count && buf[count - 1] == '\n')
107162306a36Sopenharmony_ci		buf[count - 1] = '\0';
107262306a36Sopenharmony_ci	else
107362306a36Sopenharmony_ci		buf[count] = '\0';
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	if (sscanf(buf, "%u %u %u %u %u",
107662306a36Sopenharmony_ci		   &mode, &pwr160, &pwr80, &pwr40, &pwr20) != 5) {
107762306a36Sopenharmony_ci		dev_warn(dev->mt76.dev,
107862306a36Sopenharmony_ci			 "per bandwidth power limit: Mode BW160 BW80 BW40 BW20");
107962306a36Sopenharmony_ci		return -EINVAL;
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	if (mode > RX_ENC_HE)
108362306a36Sopenharmony_ci		return -EINVAL;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	if (pwr160)
108662306a36Sopenharmony_ci		pwr160 = mt7915_get_power_bound(phy, pwr160);
108762306a36Sopenharmony_ci	if (pwr80)
108862306a36Sopenharmony_ci		pwr80 = mt7915_get_power_bound(phy, pwr80);
108962306a36Sopenharmony_ci	if (pwr40)
109062306a36Sopenharmony_ci		pwr40 = mt7915_get_power_bound(phy, pwr40);
109162306a36Sopenharmony_ci	if (pwr20)
109262306a36Sopenharmony_ci		pwr20 = mt7915_get_power_bound(phy, pwr20);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	if (pwr160 < 0 || pwr80 < 0 || pwr40 < 0 || pwr20 < 0)
109562306a36Sopenharmony_ci		return -EINVAL;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	mutex_lock(&dev->mt76.mutex);
109862306a36Sopenharmony_ci	ret = mt7915_mcu_get_txpower_sku(phy, req.txpower_sku,
109962306a36Sopenharmony_ci					 sizeof(req.txpower_sku));
110062306a36Sopenharmony_ci	if (ret)
110162306a36Sopenharmony_ci		goto out;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_CCK, pwr20, RX_ENC_LEGACY);
110462306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_OFDM, pwr20, RX_ENC_LEGACY);
110562306a36Sopenharmony_ci	if (mode == RX_ENC_LEGACY)
110662306a36Sopenharmony_ci		goto skip;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_HT_BW20, pwr20, RX_ENC_HT);
110962306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_HT_BW40, pwr40, RX_ENC_HT);
111062306a36Sopenharmony_ci	if (mode == RX_ENC_HT)
111162306a36Sopenharmony_ci		goto skip;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_VHT_BW20, pwr20, RX_ENC_VHT);
111462306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_VHT_BW40, pwr40, RX_ENC_VHT);
111562306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_VHT_BW80, pwr80, RX_ENC_VHT);
111662306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_VHT_BW160, pwr160, RX_ENC_VHT);
111762306a36Sopenharmony_ci	if (mode == RX_ENC_VHT)
111862306a36Sopenharmony_ci		goto skip;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_HE_RU26, pwr20, RX_ENC_HE + 1);
112162306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_HE_RU52, pwr20, RX_ENC_HE + 1);
112262306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_HE_RU106, pwr20, RX_ENC_HE + 1);
112362306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_HE_RU242, pwr20, RX_ENC_HE);
112462306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_HE_RU484, pwr40, RX_ENC_HE);
112562306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_HE_RU996, pwr80, RX_ENC_HE);
112662306a36Sopenharmony_ci	mt7915_txpower_sets(SKU_HE_RU2x996, pwr160, RX_ENC_HE);
112762306a36Sopenharmony_ciskip:
112862306a36Sopenharmony_ci	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),
112962306a36Sopenharmony_ci				&req, sizeof(req), true);
113062306a36Sopenharmony_ci	if (ret)
113162306a36Sopenharmony_ci		goto out;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	mphy->txpower_cur = max(mphy->txpower_cur,
113462306a36Sopenharmony_ci				max(pwr160, max(pwr80, max(pwr40, pwr20))));
113562306a36Sopenharmony_ciout:
113662306a36Sopenharmony_ci	mutex_unlock(&dev->mt76.mutex);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	return ret ? ret : count;
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistatic const struct file_operations mt7915_rate_txpower_fops = {
114262306a36Sopenharmony_ci	.write = mt7915_rate_txpower_set,
114362306a36Sopenharmony_ci	.read = mt7915_rate_txpower_get,
114462306a36Sopenharmony_ci	.open = simple_open,
114562306a36Sopenharmony_ci	.owner = THIS_MODULE,
114662306a36Sopenharmony_ci	.llseek = default_llseek,
114762306a36Sopenharmony_ci};
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_cistatic int
115062306a36Sopenharmony_cimt7915_twt_stats(struct seq_file *s, void *data)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	struct mt7915_dev *dev = dev_get_drvdata(s->private);
115362306a36Sopenharmony_ci	struct mt7915_twt_flow *iter;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	rcu_read_lock();
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	seq_puts(s, "     wcid |       id |    flags |      exp | mantissa");
115862306a36Sopenharmony_ci	seq_puts(s, " | duration |            tsf |\n");
115962306a36Sopenharmony_ci	list_for_each_entry_rcu(iter, &dev->twt_list, list)
116062306a36Sopenharmony_ci		seq_printf(s,
116162306a36Sopenharmony_ci			"%9d | %8d | %5c%c%c%c | %8d | %8d | %8d | %14lld |\n",
116262306a36Sopenharmony_ci			iter->wcid, iter->id,
116362306a36Sopenharmony_ci			iter->sched ? 's' : 'u',
116462306a36Sopenharmony_ci			iter->protection ? 'p' : '-',
116562306a36Sopenharmony_ci			iter->trigger ? 't' : '-',
116662306a36Sopenharmony_ci			iter->flowtype ? '-' : 'a',
116762306a36Sopenharmony_ci			iter->exp, iter->mantissa,
116862306a36Sopenharmony_ci			iter->duration, iter->tsf);
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	rcu_read_unlock();
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	return 0;
117362306a36Sopenharmony_ci}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci/* The index of RF registers use the generic regidx, combined with two parts:
117662306a36Sopenharmony_ci * WF selection [31:24] and offset [23:0].
117762306a36Sopenharmony_ci */
117862306a36Sopenharmony_cistatic int
117962306a36Sopenharmony_cimt7915_rf_regval_get(void *data, u64 *val)
118062306a36Sopenharmony_ci{
118162306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
118262306a36Sopenharmony_ci	u32 regval;
118362306a36Sopenharmony_ci	int ret;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	ret = mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &regval, false);
118662306a36Sopenharmony_ci	if (ret)
118762306a36Sopenharmony_ci		return ret;
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	*val = regval;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	return 0;
119262306a36Sopenharmony_ci}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_cistatic int
119562306a36Sopenharmony_cimt7915_rf_regval_set(void *data, u64 val)
119662306a36Sopenharmony_ci{
119762306a36Sopenharmony_ci	struct mt7915_dev *dev = data;
119862306a36Sopenharmony_ci	u32 val32 = val;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	return mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &val32, true);
120162306a36Sopenharmony_ci}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7915_rf_regval_get,
120462306a36Sopenharmony_ci			 mt7915_rf_regval_set, "0x%08llx\n");
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ciint mt7915_init_debugfs(struct mt7915_phy *phy)
120762306a36Sopenharmony_ci{
120862306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
120962306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
121062306a36Sopenharmony_ci	struct dentry *dir;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	dir = mt76_register_debugfs_fops(phy->mt76, NULL);
121362306a36Sopenharmony_ci	if (!dir)
121462306a36Sopenharmony_ci		return -ENOMEM;
121562306a36Sopenharmony_ci	debugfs_create_file("muru_debug", 0600, dir, dev, &fops_muru_debug);
121662306a36Sopenharmony_ci	debugfs_create_file("muru_stats", 0400, dir, phy,
121762306a36Sopenharmony_ci			    &mt7915_muru_stats_fops);
121862306a36Sopenharmony_ci	debugfs_create_file("hw-queues", 0400, dir, phy,
121962306a36Sopenharmony_ci			    &mt7915_hw_queues_fops);
122062306a36Sopenharmony_ci	debugfs_create_file("xmit-queues", 0400, dir, phy,
122162306a36Sopenharmony_ci			    &mt7915_xmit_queues_fops);
122262306a36Sopenharmony_ci	debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops);
122362306a36Sopenharmony_ci	debugfs_create_file("sys_recovery", 0600, dir, phy,
122462306a36Sopenharmony_ci			    &mt7915_sys_recovery_ops);
122562306a36Sopenharmony_ci	debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm);
122662306a36Sopenharmony_ci	debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa);
122762306a36Sopenharmony_ci	debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin);
122862306a36Sopenharmony_ci	debugfs_create_file("fw_util_wm", 0400, dir, dev,
122962306a36Sopenharmony_ci			    &mt7915_fw_util_wm_fops);
123062306a36Sopenharmony_ci	debugfs_create_file("fw_util_wa", 0400, dir, dev,
123162306a36Sopenharmony_ci			    &mt7915_fw_util_wa_fops);
123262306a36Sopenharmony_ci	debugfs_create_file("implicit_txbf", 0600, dir, dev,
123362306a36Sopenharmony_ci			    &fops_implicit_txbf);
123462306a36Sopenharmony_ci	debugfs_create_file("txpower_sku", 0400, dir, phy,
123562306a36Sopenharmony_ci			    &mt7915_rate_txpower_fops);
123662306a36Sopenharmony_ci	debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,
123762306a36Sopenharmony_ci				    mt7915_twt_stats);
123862306a36Sopenharmony_ci	debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	if (!dev->dbdc_support || phy->mt76->band_idx) {
124162306a36Sopenharmony_ci		debugfs_create_u32("dfs_hw_pattern", 0400, dir,
124262306a36Sopenharmony_ci				   &dev->hw_pattern);
124362306a36Sopenharmony_ci		debugfs_create_file("radar_trigger", 0200, dir, dev,
124462306a36Sopenharmony_ci				    &fops_radar_trigger);
124562306a36Sopenharmony_ci		debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir,
124662306a36Sopenharmony_ci					    mt7915_rdd_monitor);
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	if (!ext_phy)
125062306a36Sopenharmony_ci		dev->debugfs_dir = dir;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	return 0;
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic void
125662306a36Sopenharmony_cimt7915_debugfs_write_fwlog(struct mt7915_dev *dev, const void *hdr, int hdrlen,
125762306a36Sopenharmony_ci			 const void *data, int len)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	static DEFINE_SPINLOCK(lock);
126062306a36Sopenharmony_ci	unsigned long flags;
126162306a36Sopenharmony_ci	void *dest;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	spin_lock_irqsave(&lock, flags);
126462306a36Sopenharmony_ci	dest = relay_reserve(dev->relay_fwlog, hdrlen + len + 4);
126562306a36Sopenharmony_ci	if (dest) {
126662306a36Sopenharmony_ci		*(u32 *)dest = hdrlen + len;
126762306a36Sopenharmony_ci		dest += 4;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci		if (hdrlen) {
127062306a36Sopenharmony_ci			memcpy(dest, hdr, hdrlen);
127162306a36Sopenharmony_ci			dest += hdrlen;
127262306a36Sopenharmony_ci		}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci		memcpy(dest, data, len);
127562306a36Sopenharmony_ci		relay_flush(dev->relay_fwlog);
127662306a36Sopenharmony_ci	}
127762306a36Sopenharmony_ci	spin_unlock_irqrestore(&lock, flags);
127862306a36Sopenharmony_ci}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_civoid mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len)
128162306a36Sopenharmony_ci{
128262306a36Sopenharmony_ci	struct {
128362306a36Sopenharmony_ci		__le32 magic;
128462306a36Sopenharmony_ci		__le32 timestamp;
128562306a36Sopenharmony_ci		__le16 msg_type;
128662306a36Sopenharmony_ci		__le16 len;
128762306a36Sopenharmony_ci	} hdr = {
128862306a36Sopenharmony_ci		.magic = cpu_to_le32(FW_BIN_LOG_MAGIC),
128962306a36Sopenharmony_ci		.msg_type = cpu_to_le16(PKT_TYPE_RX_FW_MONITOR),
129062306a36Sopenharmony_ci	};
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	if (!dev->relay_fwlog)
129362306a36Sopenharmony_ci		return;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	hdr.timestamp = cpu_to_le32(mt76_rr(dev, MT_LPON_FRCR(0)));
129662306a36Sopenharmony_ci	hdr.len = *(__le16 *)data;
129762306a36Sopenharmony_ci	mt7915_debugfs_write_fwlog(dev, &hdr, sizeof(hdr), data, len);
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_cibool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len)
130162306a36Sopenharmony_ci{
130262306a36Sopenharmony_ci	if (get_unaligned_le32(data) != FW_BIN_LOG_MAGIC)
130362306a36Sopenharmony_ci		return false;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	if (dev->relay_fwlog)
130662306a36Sopenharmony_ci		mt7915_debugfs_write_fwlog(dev, NULL, 0, data, len);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	return true;
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_DEBUGFS
131262306a36Sopenharmony_ci/** per-station debugfs **/
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_cistatic ssize_t mt7915_sta_fixed_rate_set(struct file *file,
131562306a36Sopenharmony_ci					 const char __user *user_buf,
131662306a36Sopenharmony_ci					 size_t count, loff_t *ppos)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	struct ieee80211_sta *sta = file->private_data;
131962306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
132062306a36Sopenharmony_ci	struct mt7915_dev *dev = msta->vif->phy->dev;
132162306a36Sopenharmony_ci	struct ieee80211_vif *vif;
132262306a36Sopenharmony_ci	struct sta_phy phy = {};
132362306a36Sopenharmony_ci	char buf[100];
132462306a36Sopenharmony_ci	int ret;
132562306a36Sopenharmony_ci	u32 field;
132662306a36Sopenharmony_ci	u8 i, gi, he_ltf;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if (count >= sizeof(buf))
132962306a36Sopenharmony_ci		return -EINVAL;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf, count))
133262306a36Sopenharmony_ci		return -EFAULT;
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	if (count && buf[count - 1] == '\n')
133562306a36Sopenharmony_ci		buf[count - 1] = '\0';
133662306a36Sopenharmony_ci	else
133762306a36Sopenharmony_ci		buf[count] = '\0';
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	/* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 9
134062306a36Sopenharmony_ci	 * bw - bw20: 0, bw40: 1, bw80: 2, bw160: 3
134162306a36Sopenharmony_ci	 * nss - vht: 1~4, he: 1~4, others: ignore
134262306a36Sopenharmony_ci	 * mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~2
134362306a36Sopenharmony_ci	 * gi - (ht/vht) lgi: 0, sgi: 1; (he) 0.8us: 0, 1.6us: 1, 3.2us: 2
134462306a36Sopenharmony_ci	 * ldpc - off: 0, on: 1
134562306a36Sopenharmony_ci	 * stbc - off: 0, on: 1
134662306a36Sopenharmony_ci	 * he_ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2
134762306a36Sopenharmony_ci	 */
134862306a36Sopenharmony_ci	if (sscanf(buf, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu",
134962306a36Sopenharmony_ci		   &phy.type, &phy.bw, &phy.nss, &phy.mcs, &gi,
135062306a36Sopenharmony_ci		   &phy.ldpc, &phy.stbc, &he_ltf) != 8) {
135162306a36Sopenharmony_ci		dev_warn(dev->mt76.dev,
135262306a36Sopenharmony_ci			 "format: Mode BW NSS MCS (HE)GI LDPC STBC HE_LTF\n");
135362306a36Sopenharmony_ci		field = RATE_PARAM_AUTO;
135462306a36Sopenharmony_ci		goto out;
135562306a36Sopenharmony_ci	}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	phy.ldpc = (phy.bw || phy.ldpc) * GENMASK(2, 0);
135862306a36Sopenharmony_ci	for (i = 0; i <= phy.bw; i++) {
135962306a36Sopenharmony_ci		phy.sgi |= gi << (i << sta->deflink.he_cap.has_he);
136062306a36Sopenharmony_ci		phy.he_ltf |= he_ltf << (i << sta->deflink.he_cap.has_he);
136162306a36Sopenharmony_ci	}
136262306a36Sopenharmony_ci	field = RATE_PARAM_FIXED;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ciout:
136562306a36Sopenharmony_ci	vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
136662306a36Sopenharmony_ci	ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, field);
136762306a36Sopenharmony_ci	if (ret)
136862306a36Sopenharmony_ci		return -EFAULT;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	return count;
137162306a36Sopenharmony_ci}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_cistatic const struct file_operations fops_fixed_rate = {
137462306a36Sopenharmony_ci	.write = mt7915_sta_fixed_rate_set,
137562306a36Sopenharmony_ci	.open = simple_open,
137662306a36Sopenharmony_ci	.owner = THIS_MODULE,
137762306a36Sopenharmony_ci	.llseek = default_llseek,
137862306a36Sopenharmony_ci};
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_cistatic int
138162306a36Sopenharmony_cimt7915_queues_show(struct seq_file *s, void *data)
138262306a36Sopenharmony_ci{
138362306a36Sopenharmony_ci	struct ieee80211_sta *sta = s->private;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	mt7915_sta_hw_queue_read(s, sta);
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	return 0;
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mt7915_queues);
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_civoid mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
139362306a36Sopenharmony_ci			    struct ieee80211_sta *sta, struct dentry *dir)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate);
139662306a36Sopenharmony_ci	debugfs_create_file("hw-queues", 0400, dir, sta, &mt7915_queues_fops);
139762306a36Sopenharmony_ci}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci#endif
1400