18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include "mt7915.h"
58c2ecf20Sopenharmony_ci#include "eeprom.h"
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/** global debugfs **/
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci/* test knob of system layer 1/2 error recovery */
108c2ecf20Sopenharmony_cistatic int mt7915_ser_trigger_set(void *data, u64 val)
118c2ecf20Sopenharmony_ci{
128c2ecf20Sopenharmony_ci	enum {
138c2ecf20Sopenharmony_ci		SER_SET_RECOVER_L1 = 1,
148c2ecf20Sopenharmony_ci		SER_SET_RECOVER_L2,
158c2ecf20Sopenharmony_ci		SER_ENABLE = 2,
168c2ecf20Sopenharmony_ci		SER_RECOVER
178c2ecf20Sopenharmony_ci	};
188c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = data;
198c2ecf20Sopenharmony_ci	int ret = 0;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	switch (val) {
228c2ecf20Sopenharmony_ci	case SER_SET_RECOVER_L1:
238c2ecf20Sopenharmony_ci	case SER_SET_RECOVER_L2:
248c2ecf20Sopenharmony_ci		ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), 0);
258c2ecf20Sopenharmony_ci		if (ret)
268c2ecf20Sopenharmony_ci			return ret;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci		return mt7915_mcu_set_ser(dev, SER_RECOVER, val, 0);
298c2ecf20Sopenharmony_ci	default:
308c2ecf20Sopenharmony_ci		break;
318c2ecf20Sopenharmony_ci	}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	return ret;
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_ser_trigger, NULL,
378c2ecf20Sopenharmony_ci			 mt7915_ser_trigger_set, "%lld\n");
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic int
408c2ecf20Sopenharmony_cimt7915_radar_trigger(void *data, u64 val)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = data;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	return mt7915_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, 1, 0, 0);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,
488c2ecf20Sopenharmony_ci			 mt7915_radar_trigger, "%lld\n");
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic int
518c2ecf20Sopenharmony_cimt7915_dbdc_set(void *data, u64 val)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = data;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (val)
568c2ecf20Sopenharmony_ci		mt7915_register_ext_phy(dev);
578c2ecf20Sopenharmony_ci	else
588c2ecf20Sopenharmony_ci		mt7915_unregister_ext_phy(dev);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	return 0;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic int
648c2ecf20Sopenharmony_cimt7915_dbdc_get(void *data, u64 *val)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = data;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	*val = !!mt7915_ext_phy(dev);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	return 0;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_dbdc, mt7915_dbdc_get,
748c2ecf20Sopenharmony_ci			 mt7915_dbdc_set, "%lld\n");
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic int
778c2ecf20Sopenharmony_cimt7915_fw_debug_set(void *data, u64 val)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = data;
808c2ecf20Sopenharmony_ci	enum {
818c2ecf20Sopenharmony_ci		DEBUG_TXCMD = 62,
828c2ecf20Sopenharmony_ci		DEBUG_CMD_RPT_TX,
838c2ecf20Sopenharmony_ci		DEBUG_CMD_RPT_TRIG,
848c2ecf20Sopenharmony_ci		DEBUG_SPL,
858c2ecf20Sopenharmony_ci		DEBUG_RPT_RX,
868c2ecf20Sopenharmony_ci	} debug;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	dev->fw_debug = !!val;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	mt7915_mcu_fw_log_2_host(dev, dev->fw_debug ? 2 : 0);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++)
938c2ecf20Sopenharmony_ci		mt7915_mcu_fw_dbg_ctrl(dev, debug, dev->fw_debug);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return 0;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int
998c2ecf20Sopenharmony_cimt7915_fw_debug_get(void *data, u64 *val)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = data;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	*val = dev->fw_debug;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug, mt7915_fw_debug_get,
1098c2ecf20Sopenharmony_ci			 mt7915_fw_debug_set, "%lld\n");
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic void
1128c2ecf20Sopenharmony_cimt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,
1138c2ecf20Sopenharmony_ci			   struct seq_file *file)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = file->private;
1168c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
1178c2ecf20Sopenharmony_ci	int bound[15], range[4], i, n;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (!phy)
1208c2ecf20Sopenharmony_ci		return;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	/* Tx ampdu stat */
1238c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(range); i++)
1248c2ecf20Sopenharmony_ci		range[i] = mt76_rr(dev, MT_MIB_ARNG(ext_phy, i));
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bound); i++)
1278c2ecf20Sopenharmony_ci		bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	seq_printf(file, "\nPhy %d\n", ext_phy);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	seq_printf(file, "Length: %8d | ", bound[0]);
1328c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
1338c2ecf20Sopenharmony_ci		seq_printf(file, "%3d -%3d | ",
1348c2ecf20Sopenharmony_ci			   bound[i] + 1, bound[i + 1]);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	seq_puts(file, "\nCount:  ");
1378c2ecf20Sopenharmony_ci	n = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0;
1388c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bound); i++)
1398c2ecf20Sopenharmony_ci		seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + n]);
1408c2ecf20Sopenharmony_ci	seq_puts(file, "\n");
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic void
1468c2ecf20Sopenharmony_cimt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = s->private;
1498c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
1508c2ecf20Sopenharmony_ci	int cnt;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	if (!phy)
1538c2ecf20Sopenharmony_ci		return;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	/* Tx Beamformer monitor */
1568c2ecf20Sopenharmony_ci	seq_puts(s, "\nTx Beamformer applied PPDU counts: ");
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(ext_phy));
1598c2ecf20Sopenharmony_ci	seq_printf(s, "iBF: %ld, eBF: %ld\n",
1608c2ecf20Sopenharmony_ci		   FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt),
1618c2ecf20Sopenharmony_ci		   FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt));
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* Tx Beamformer Rx feedback monitor */
1648c2ecf20Sopenharmony_ci	seq_puts(s, "Tx Beamformer Rx feedback statistics: ");
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(ext_phy));
1678c2ecf20Sopenharmony_ci	seq_printf(s, "All: %ld, HE: %ld, VHT: %ld, HT: %ld\n",
1688c2ecf20Sopenharmony_ci		   FIELD_GET(MT_ETBF_RX_FB_ALL, cnt),
1698c2ecf20Sopenharmony_ci		   FIELD_GET(MT_ETBF_RX_FB_HE, cnt),
1708c2ecf20Sopenharmony_ci		   FIELD_GET(MT_ETBF_RX_FB_VHT, cnt),
1718c2ecf20Sopenharmony_ci		   FIELD_GET(MT_ETBF_RX_FB_HT, cnt));
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/* Tx Beamformee Rx NDPA & Tx feedback report */
1748c2ecf20Sopenharmony_ci	cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(ext_phy));
1758c2ecf20Sopenharmony_ci	seq_printf(s, "Tx Beamformee successful feedback frames: %ld\n",
1768c2ecf20Sopenharmony_ci		   FIELD_GET(MT_ETBF_TX_FB_CPL, cnt));
1778c2ecf20Sopenharmony_ci	seq_printf(s, "Tx Beamformee feedback triggered counts: %ld\n",
1788c2ecf20Sopenharmony_ci		   FIELD_GET(MT_ETBF_TX_FB_TRI, cnt));
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* Tx SU & MU counters */
1818c2ecf20Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR34(ext_phy));
1828c2ecf20Sopenharmony_ci	seq_printf(s, "Tx multi-user Beamforming counts: %ld\n",
1838c2ecf20Sopenharmony_ci		   FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt));
1848c2ecf20Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_DR8(ext_phy));
1858c2ecf20Sopenharmony_ci	seq_printf(s, "Tx multi-user MPDU counts: %d\n", cnt);
1868c2ecf20Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_DR9(ext_phy));
1878c2ecf20Sopenharmony_ci	seq_printf(s, "Tx multi-user successful MPDU counts: %d\n", cnt);
1888c2ecf20Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_DR11(ext_phy));
1898c2ecf20Sopenharmony_ci	seq_printf(s, "Tx single-user successful MPDU counts: %d\n", cnt);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	seq_puts(s, "\n");
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int
1958c2ecf20Sopenharmony_cimt7915_tx_stats_read(struct seq_file *file, void *data)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = file->private;
1988c2ecf20Sopenharmony_ci	int stat[8], i, n;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	mt7915_ampdu_stat_read_phy(&dev->phy, file);
2018c2ecf20Sopenharmony_ci	mt7915_txbf_stat_read_phy(&dev->phy, file);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	mt7915_ampdu_stat_read_phy(mt7915_ext_phy(dev), file);
2048c2ecf20Sopenharmony_ci	mt7915_txbf_stat_read_phy(mt7915_ext_phy(dev), file);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/* Tx amsdu info */
2078c2ecf20Sopenharmony_ci	seq_puts(file, "Tx MSDU stat:\n");
2088c2ecf20Sopenharmony_ci	for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) {
2098c2ecf20Sopenharmony_ci		stat[i] = mt76_rr(dev,  MT_PLE_AMSDU_PACK_MSDU_CNT(i));
2108c2ecf20Sopenharmony_ci		n += stat[i];
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(stat); i++) {
2148c2ecf20Sopenharmony_ci		seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ",
2158c2ecf20Sopenharmony_ci			   i + 1, stat[i]);
2168c2ecf20Sopenharmony_ci		if (n != 0)
2178c2ecf20Sopenharmony_ci			seq_printf(file, "(%d%%)\n", stat[i] * 100 / n);
2188c2ecf20Sopenharmony_ci		else
2198c2ecf20Sopenharmony_ci			seq_puts(file, "\n");
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	return 0;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic int
2268c2ecf20Sopenharmony_cimt7915_tx_stats_open(struct inode *inode, struct file *f)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	return single_open(f, mt7915_tx_stats_read, inode->i_private);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic const struct file_operations fops_tx_stats = {
2328c2ecf20Sopenharmony_ci	.open = mt7915_tx_stats_open,
2338c2ecf20Sopenharmony_ci	.read = seq_read,
2348c2ecf20Sopenharmony_ci	.llseek = seq_lseek,
2358c2ecf20Sopenharmony_ci	.release = single_release,
2368c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
2378c2ecf20Sopenharmony_ci};
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic int mt7915_read_temperature(struct seq_file *s, void *data)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = dev_get_drvdata(s->private);
2428c2ecf20Sopenharmony_ci	int temp;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/* cpu */
2458c2ecf20Sopenharmony_ci	temp = mt7915_mcu_get_temperature(dev, 0);
2468c2ecf20Sopenharmony_ci	seq_printf(s, "Temperature: %d\n", temp);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	return 0;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic int
2528c2ecf20Sopenharmony_cimt7915_queues_acq(struct seq_file *s, void *data)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = dev_get_drvdata(s->private);
2558c2ecf20Sopenharmony_ci	int i;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++) {
2588c2ecf20Sopenharmony_ci		int j, acs = i / 4, index = i % 4;
2598c2ecf20Sopenharmony_ci		u32 ctrl, val, qlen = 0;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci		val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index));
2628c2ecf20Sopenharmony_ci		ctrl = BIT(31) | BIT(15) | (acs << 8);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci		for (j = 0; j < 32; j++) {
2658c2ecf20Sopenharmony_ci			if (val & BIT(j))
2668c2ecf20Sopenharmony_ci				continue;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci			mt76_wr(dev, MT_PLE_FL_Q0_CTRL,
2698c2ecf20Sopenharmony_ci				ctrl | (j + (index << 5)));
2708c2ecf20Sopenharmony_ci			qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL,
2718c2ecf20Sopenharmony_ci					       GENMASK(11, 0));
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci		seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen);
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	return 0;
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic int
2808c2ecf20Sopenharmony_cimt7915_queues_read(struct seq_file *s, void *data)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = dev_get_drvdata(s->private);
2838c2ecf20Sopenharmony_ci	static const struct {
2848c2ecf20Sopenharmony_ci		char *queue;
2858c2ecf20Sopenharmony_ci		int id;
2868c2ecf20Sopenharmony_ci	} queue_map[] = {
2878c2ecf20Sopenharmony_ci		{ "WFDMA0", MT_TXQ_BE },
2888c2ecf20Sopenharmony_ci		{ "MCUWM", MT_TXQ_MCU },
2898c2ecf20Sopenharmony_ci		{ "MCUWA", MT_TXQ_MCU_WA },
2908c2ecf20Sopenharmony_ci		{ "MCUFWQ", MT_TXQ_FWDL },
2918c2ecf20Sopenharmony_ci	};
2928c2ecf20Sopenharmony_ci	int i;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
2958c2ecf20Sopenharmony_ci		struct mt76_queue *q = dev->mt76.q_tx[queue_map[i].id];
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		if (!q)
2988c2ecf20Sopenharmony_ci			continue;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		seq_printf(s,
3018c2ecf20Sopenharmony_ci			   "%s:	queued=%d head=%d tail=%d\n",
3028c2ecf20Sopenharmony_ci			   queue_map[i].queue, q->queued, q->head,
3038c2ecf20Sopenharmony_ci			   q->tail);
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return 0;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic void
3108c2ecf20Sopenharmony_cimt7915_puts_rate_txpower(struct seq_file *s, s8 *delta,
3118c2ecf20Sopenharmony_ci			 s8 txpower_cur, int band)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	static const char * const sku_group_name[] = {
3148c2ecf20Sopenharmony_ci		"CCK", "OFDM", "HT20", "HT40",
3158c2ecf20Sopenharmony_ci		"VHT20", "VHT40", "VHT80", "VHT160",
3168c2ecf20Sopenharmony_ci		"RU26", "RU52", "RU106", "RU242/SU20",
3178c2ecf20Sopenharmony_ci		"RU484/SU40", "RU996/SU80", "RU2x996/SU160"
3188c2ecf20Sopenharmony_ci	};
3198c2ecf20Sopenharmony_ci	s8 txpower[MT7915_SKU_RATE_NUM];
3208c2ecf20Sopenharmony_ci	int i, idx = 0;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	for (i = 0; i < MT7915_SKU_RATE_NUM; i++)
3238c2ecf20Sopenharmony_ci		txpower[i] = DIV_ROUND_UP(txpower_cur + delta[i], 2);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_SKU_RATE_GROUP_NUM; i++) {
3268c2ecf20Sopenharmony_ci		const struct sku_group *sku = &mt7915_sku_groups[i];
3278c2ecf20Sopenharmony_ci		u32 offset = sku->offset[band];
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci		if (!offset) {
3308c2ecf20Sopenharmony_ci			idx += sku->len;
3318c2ecf20Sopenharmony_ci			continue;
3328c2ecf20Sopenharmony_ci		}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci		mt76_seq_puts_array(s, sku_group_name[i],
3358c2ecf20Sopenharmony_ci				    txpower + idx, sku->len);
3368c2ecf20Sopenharmony_ci		idx += sku->len;
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic int
3418c2ecf20Sopenharmony_cimt7915_read_rate_txpower(struct seq_file *s, void *data)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	struct mt7915_dev *dev = dev_get_drvdata(s->private);
3448c2ecf20Sopenharmony_ci	struct mt76_phy *mphy = &dev->mphy;
3458c2ecf20Sopenharmony_ci	enum nl80211_band band = mphy->chandef.chan->band;
3468c2ecf20Sopenharmony_ci	s8 *delta = dev->rate_power[band];
3478c2ecf20Sopenharmony_ci	s8 txpower_base = mphy->txpower_cur - delta[MT7915_SKU_MAX_DELTA_IDX];
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	seq_puts(s, "Band 0:\n");
3508c2ecf20Sopenharmony_ci	mt7915_puts_rate_txpower(s, delta, txpower_base, band);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (dev->mt76.phy2) {
3538c2ecf20Sopenharmony_ci		mphy = dev->mt76.phy2;
3548c2ecf20Sopenharmony_ci		band = mphy->chandef.chan->band;
3558c2ecf20Sopenharmony_ci		delta = dev->rate_power[band];
3568c2ecf20Sopenharmony_ci		txpower_base = mphy->txpower_cur -
3578c2ecf20Sopenharmony_ci			       delta[MT7915_SKU_MAX_DELTA_IDX];
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci		seq_puts(s, "Band 1:\n");
3608c2ecf20Sopenharmony_ci		mt7915_puts_rate_txpower(s, delta, txpower_base, band);
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	return 0;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ciint mt7915_init_debugfs(struct mt7915_dev *dev)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	struct dentry *dir;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	dir = mt76_register_debugfs(&dev->mt76);
3718c2ecf20Sopenharmony_ci	if (!dir)
3728c2ecf20Sopenharmony_ci		return -ENOMEM;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
3758c2ecf20Sopenharmony_ci				    mt7915_queues_read);
3768c2ecf20Sopenharmony_ci	debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
3778c2ecf20Sopenharmony_ci				    mt7915_queues_acq);
3788c2ecf20Sopenharmony_ci	debugfs_create_file("tx_stats", 0400, dir, dev, &fops_tx_stats);
3798c2ecf20Sopenharmony_ci	debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc);
3808c2ecf20Sopenharmony_ci	debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug);
3818c2ecf20Sopenharmony_ci	debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern);
3828c2ecf20Sopenharmony_ci	/* test knobs */
3838c2ecf20Sopenharmony_ci	debugfs_create_file("radar_trigger", 0200, dir, dev,
3848c2ecf20Sopenharmony_ci			    &fops_radar_trigger);
3858c2ecf20Sopenharmony_ci	debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger);
3868c2ecf20Sopenharmony_ci	debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir,
3878c2ecf20Sopenharmony_ci				    mt7915_read_temperature);
3888c2ecf20Sopenharmony_ci	debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir,
3898c2ecf20Sopenharmony_ci				    mt7915_read_rate_txpower);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	return 0;
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci#ifdef CONFIG_MAC80211_DEBUGFS
3958c2ecf20Sopenharmony_ci/** per-station debugfs **/
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci/* usage: <tx mode> <ldpc> <stbc> <bw> <gi> <nss> <mcs> */
3988c2ecf20Sopenharmony_cistatic int mt7915_sta_fixed_rate_set(void *data, u64 rate)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta = data;
4018c2ecf20Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	return mt7915_mcu_set_fixed_rate(msta->vif->phy->dev, sta, rate);
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_fixed_rate, NULL,
4078c2ecf20Sopenharmony_ci			 mt7915_sta_fixed_rate_set, "%llx\n");
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic int
4108c2ecf20Sopenharmony_cimt7915_sta_stats_read(struct seq_file *s, void *data)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta = s->private;
4138c2ecf20Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
4148c2ecf20Sopenharmony_ci	struct mt7915_sta_stats *stats = &msta->stats;
4158c2ecf20Sopenharmony_ci	struct rate_info *rate = &stats->prob_rate;
4168c2ecf20Sopenharmony_ci	static const char * const bw[] = {
4178c2ecf20Sopenharmony_ci		"BW20", "BW5", "BW10", "BW40",
4188c2ecf20Sopenharmony_ci		"BW80", "BW160", "BW_HE_RU"
4198c2ecf20Sopenharmony_ci	};
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	if (!rate->legacy && !rate->flags)
4228c2ecf20Sopenharmony_ci		return 0;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	seq_puts(s, "Probing rate - ");
4258c2ecf20Sopenharmony_ci	if (rate->flags & RATE_INFO_FLAGS_MCS)
4268c2ecf20Sopenharmony_ci		seq_puts(s, "HT ");
4278c2ecf20Sopenharmony_ci	else if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
4288c2ecf20Sopenharmony_ci		seq_puts(s, "VHT ");
4298c2ecf20Sopenharmony_ci	else if (rate->flags & RATE_INFO_FLAGS_HE_MCS)
4308c2ecf20Sopenharmony_ci		seq_puts(s, "HE ");
4318c2ecf20Sopenharmony_ci	else
4328c2ecf20Sopenharmony_ci		seq_printf(s, "Bitrate %d\n", rate->legacy);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (rate->flags) {
4358c2ecf20Sopenharmony_ci		seq_printf(s, "%s NSS%d MCS%d ",
4368c2ecf20Sopenharmony_ci			   bw[rate->bw], rate->nss, rate->mcs);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
4398c2ecf20Sopenharmony_ci			seq_puts(s, "SGI ");
4408c2ecf20Sopenharmony_ci		else if (rate->he_gi)
4418c2ecf20Sopenharmony_ci			seq_puts(s, "HE GI ");
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci		if (rate->he_dcm)
4448c2ecf20Sopenharmony_ci			seq_puts(s, "DCM ");
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	seq_printf(s, "\nPPDU PER: %ld.%1ld%%\n",
4488c2ecf20Sopenharmony_ci		   stats->per / 10, stats->per % 10);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	return 0;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic int
4548c2ecf20Sopenharmony_cimt7915_sta_stats_open(struct inode *inode, struct file *f)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	return single_open(f, mt7915_sta_stats_read, inode->i_private);
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cistatic const struct file_operations fops_sta_stats = {
4608c2ecf20Sopenharmony_ci	.open = mt7915_sta_stats_open,
4618c2ecf20Sopenharmony_ci	.read = seq_read,
4628c2ecf20Sopenharmony_ci	.llseek = seq_lseek,
4638c2ecf20Sopenharmony_ci	.release = single_release,
4648c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
4658c2ecf20Sopenharmony_ci};
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_civoid mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
4688c2ecf20Sopenharmony_ci			    struct ieee80211_sta *sta, struct dentry *dir)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate);
4718c2ecf20Sopenharmony_ci	debugfs_create_file("stats", 0400, dir, sta, &fops_sta_stats);
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci#endif
474