xref: /openbmc/linux/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c (revision 8b0adbe3e38dbe5aae9edf6f5159ffdca7cfbdf1)
1 // SPDX-License-Identifier: ISC
2 /* Copyright (C) 2020 MediaTek Inc. */
3 
4 #include "mt7921.h"
5 #include "eeprom.h"
6 
7 static int
8 mt7921_fw_debug_set(void *data, u64 val)
9 {
10 	struct mt7921_dev *dev = data;
11 
12 	dev->fw_debug = (u8)val;
13 
14 	mt7921_mcu_fw_log_2_host(dev, dev->fw_debug);
15 
16 	return 0;
17 }
18 
19 static int
20 mt7921_fw_debug_get(void *data, u64 *val)
21 {
22 	struct mt7921_dev *dev = data;
23 
24 	*val = dev->fw_debug;
25 
26 	return 0;
27 }
28 
29 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug, mt7921_fw_debug_get,
30 			 mt7921_fw_debug_set, "%lld\n");
31 
32 static void
33 mt7921_ampdu_stat_read_phy(struct mt7921_phy *phy,
34 			   struct seq_file *file)
35 {
36 	struct mt7921_dev *dev = file->private;
37 	int bound[15], range[4], i;
38 
39 	if (!phy)
40 		return;
41 
42 	/* Tx ampdu stat */
43 	for (i = 0; i < ARRAY_SIZE(range); i++)
44 		range[i] = mt76_rr(dev, MT_MIB_ARNG(0, i));
45 
46 	for (i = 0; i < ARRAY_SIZE(bound); i++)
47 		bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i) + 1;
48 
49 	seq_printf(file, "\nPhy0\n");
50 
51 	seq_printf(file, "Length: %8d | ", bound[0]);
52 	for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
53 		seq_printf(file, "%3d -%3d | ",
54 			   bound[i] + 1, bound[i + 1]);
55 
56 	seq_puts(file, "\nCount:  ");
57 	for (i = 0; i < ARRAY_SIZE(bound); i++)
58 		seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]);
59 	seq_puts(file, "\n");
60 
61 	seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);
62 }
63 
64 static int
65 mt7921_tx_stats_show(struct seq_file *file, void *data)
66 {
67 	struct mt7921_dev *dev = file->private;
68 	int stat[8], i, n;
69 
70 	mt7921_ampdu_stat_read_phy(&dev->phy, file);
71 
72 	/* Tx amsdu info */
73 	seq_puts(file, "Tx MSDU stat:\n");
74 	for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) {
75 		stat[i] = mt76_rr(dev,  MT_PLE_AMSDU_PACK_MSDU_CNT(i));
76 		n += stat[i];
77 	}
78 
79 	for (i = 0; i < ARRAY_SIZE(stat); i++) {
80 		seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ",
81 			   i + 1, stat[i]);
82 		if (n != 0)
83 			seq_printf(file, "(%d%%)\n", stat[i] * 100 / n);
84 		else
85 			seq_puts(file, "\n");
86 	}
87 
88 	return 0;
89 }
90 
91 DEFINE_SHOW_ATTRIBUTE(mt7921_tx_stats);
92 
93 static int
94 mt7921_queues_acq(struct seq_file *s, void *data)
95 {
96 	struct mt7921_dev *dev = dev_get_drvdata(s->private);
97 	int i;
98 
99 	for (i = 0; i < 16; i++) {
100 		int j, acs = i / 4, index = i % 4;
101 		u32 ctrl, val, qlen = 0;
102 
103 		val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index));
104 		ctrl = BIT(31) | BIT(15) | (acs << 8);
105 
106 		for (j = 0; j < 32; j++) {
107 			if (val & BIT(j))
108 				continue;
109 
110 			mt76_wr(dev, MT_PLE_FL_Q0_CTRL,
111 				ctrl | (j + (index << 5)));
112 			qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL,
113 					       GENMASK(11, 0));
114 		}
115 		seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen);
116 	}
117 
118 	return 0;
119 }
120 
121 static int
122 mt7921_queues_read(struct seq_file *s, void *data)
123 {
124 	struct mt7921_dev *dev = dev_get_drvdata(s->private);
125 	struct {
126 		struct mt76_queue *q;
127 		char *queue;
128 	} queue_map[] = {
129 		{ dev->mphy.q_tx[MT_TXQ_BE],	 "WFDMA0" },
130 		{ dev->mt76.q_mcu[MT_MCUQ_WM],	 "MCUWM"  },
131 		{ dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" },
132 	};
133 	int i;
134 
135 	for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
136 		struct mt76_queue *q = queue_map[i].q;
137 
138 		if (!q)
139 			continue;
140 
141 		seq_printf(s,
142 			   "%s:	queued=%d head=%d tail=%d\n",
143 			   queue_map[i].queue, q->queued, q->head,
144 			   q->tail);
145 	}
146 
147 	return 0;
148 }
149 
150 static int
151 mt7921_pm_set(void *data, u64 val)
152 {
153 	struct mt7921_dev *dev = data;
154 	struct mt76_phy *mphy = dev->phy.mt76;
155 	int ret = 0;
156 
157 	mt7921_mutex_acquire(dev);
158 
159 	dev->pm.enable = val;
160 
161 	ieee80211_iterate_active_interfaces(mphy->hw,
162 					    IEEE80211_IFACE_ITER_RESUME_ALL,
163 					    mt7921_pm_interface_iter, mphy->priv);
164 	mt7921_mutex_release(dev);
165 
166 	return ret;
167 }
168 
169 static int
170 mt7921_pm_get(void *data, u64 *val)
171 {
172 	struct mt7921_dev *dev = data;
173 
174 	*val = dev->pm.enable;
175 
176 	return 0;
177 }
178 
179 DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n");
180 
181 static int
182 mt7921_pm_idle_timeout_set(void *data, u64 val)
183 {
184 	struct mt7921_dev *dev = data;
185 
186 	dev->pm.idle_timeout = msecs_to_jiffies(val);
187 
188 	return 0;
189 }
190 
191 static int
192 mt7921_pm_idle_timeout_get(void *data, u64 *val)
193 {
194 	struct mt7921_dev *dev = data;
195 
196 	*val = jiffies_to_msecs(dev->pm.idle_timeout);
197 
198 	return 0;
199 }
200 
201 DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt7921_pm_idle_timeout_get,
202 			 mt7921_pm_idle_timeout_set, "%lld\n");
203 
204 static int mt7921_config(void *data, u64 val)
205 {
206 	struct mt7921_dev *dev = data;
207 	int ret;
208 
209 	mt7921_mutex_acquire(dev);
210 	ret = mt76_connac_mcu_chip_config(&dev->mt76);
211 	mt7921_mutex_release(dev);
212 
213 	return ret;
214 }
215 
216 DEFINE_DEBUGFS_ATTRIBUTE(fops_config, NULL, mt7921_config, "%lld\n");
217 
218 int mt7921_init_debugfs(struct mt7921_dev *dev)
219 {
220 	struct dentry *dir;
221 
222 	dir = mt76_register_debugfs(&dev->mt76);
223 	if (!dir)
224 		return -ENOMEM;
225 
226 	debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
227 				    mt7921_queues_read);
228 	debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
229 				    mt7921_queues_acq);
230 	debugfs_create_file("tx_stats", 0400, dir, dev, &mt7921_tx_stats_fops);
231 	debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug);
232 	debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm);
233 	debugfs_create_file("idle-timeout", 0600, dir, dev,
234 			    &fops_pm_idle_timeout);
235 	debugfs_create_file("chip_config", 0600, dir, dev, &fops_config);
236 
237 	return 0;
238 }
239