xref: /linux/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c (revision 3263039d757c7e27c0cd287a9df80a8b85edfb79)
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_reg_set(void *data, u64 val)
9 {
10 	struct mt7921_dev *dev = data;
11 
12 	mt7921_mutex_acquire(dev);
13 	mt76_wr(dev, dev->mt76.debugfs_reg, val);
14 	mt7921_mutex_release(dev);
15 
16 	return 0;
17 }
18 
19 static int
20 mt7921_reg_get(void *data, u64 *val)
21 {
22 	struct mt7921_dev *dev = data;
23 
24 	mt7921_mutex_acquire(dev);
25 	*val = mt76_rr(dev, dev->mt76.debugfs_reg);
26 	mt7921_mutex_release(dev);
27 
28 	return 0;
29 }
30 
31 DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt7921_reg_get, mt7921_reg_set,
32 			 "0x%08llx\n");
33 static int
34 mt7921_fw_debug_set(void *data, u64 val)
35 {
36 	struct mt7921_dev *dev = data;
37 
38 	mt7921_mutex_acquire(dev);
39 
40 	dev->fw_debug = (u8)val;
41 	mt7921_mcu_fw_log_2_host(dev, dev->fw_debug);
42 
43 	mt7921_mutex_release(dev);
44 
45 	return 0;
46 }
47 
48 static int
49 mt7921_fw_debug_get(void *data, u64 *val)
50 {
51 	struct mt7921_dev *dev = data;
52 
53 	*val = dev->fw_debug;
54 
55 	return 0;
56 }
57 
58 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug, mt7921_fw_debug_get,
59 			 mt7921_fw_debug_set, "%lld\n");
60 
61 static void
62 mt7921_ampdu_stat_read_phy(struct mt7921_phy *phy,
63 			   struct seq_file *file)
64 {
65 	struct mt7921_dev *dev = file->private;
66 	int bound[15], range[4], i;
67 
68 	if (!phy)
69 		return;
70 
71 	mt7921_mac_update_mib_stats(phy);
72 
73 	/* Tx ampdu stat */
74 	for (i = 0; i < ARRAY_SIZE(range); i++)
75 		range[i] = mt76_rr(dev, MT_MIB_ARNG(0, i));
76 
77 	for (i = 0; i < ARRAY_SIZE(bound); i++)
78 		bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1;
79 
80 	seq_printf(file, "\nPhy0\n");
81 
82 	seq_printf(file, "Length: %8d | ", bound[0]);
83 	for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
84 		seq_printf(file, "%3d  %3d | ", bound[i] + 1, bound[i + 1]);
85 
86 	seq_puts(file, "\nCount:  ");
87 	for (i = 0; i < ARRAY_SIZE(bound); i++)
88 		seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]);
89 	seq_puts(file, "\n");
90 
91 	seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);
92 }
93 
94 static int
95 mt7921_tx_stats_show(struct seq_file *file, void *data)
96 {
97 	struct mt7921_dev *dev = file->private;
98 	int stat[8], i, n;
99 
100 	mt7921_mutex_acquire(dev);
101 
102 	mt7921_ampdu_stat_read_phy(&dev->phy, file);
103 
104 	/* Tx amsdu info */
105 	seq_puts(file, "Tx MSDU stat:\n");
106 	for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) {
107 		stat[i] = mt76_rr(dev,  MT_PLE_AMSDU_PACK_MSDU_CNT(i));
108 		n += stat[i];
109 	}
110 
111 	mt7921_mutex_release(dev);
112 
113 	for (i = 0; i < ARRAY_SIZE(stat); i++) {
114 		seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ",
115 			   i + 1, stat[i]);
116 		if (n != 0)
117 			seq_printf(file, "(%d%%)\n", stat[i] * 100 / n);
118 		else
119 			seq_puts(file, "\n");
120 	}
121 
122 	return 0;
123 }
124 
125 DEFINE_SHOW_ATTRIBUTE(mt7921_tx_stats);
126 
127 static int
128 mt7921_queues_acq(struct seq_file *s, void *data)
129 {
130 	struct mt7921_dev *dev = dev_get_drvdata(s->private);
131 	int i;
132 
133 	mt7921_mutex_acquire(dev);
134 
135 	for (i = 0; i < 16; i++) {
136 		int j, acs = i / 4, index = i % 4;
137 		u32 ctrl, val, qlen = 0;
138 
139 		val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index));
140 		ctrl = BIT(31) | BIT(15) | (acs << 8);
141 
142 		for (j = 0; j < 32; j++) {
143 			if (val & BIT(j))
144 				continue;
145 
146 			mt76_wr(dev, MT_PLE_FL_Q0_CTRL,
147 				ctrl | (j + (index << 5)));
148 			qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL,
149 					       GENMASK(11, 0));
150 		}
151 		seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen);
152 	}
153 
154 	mt7921_mutex_release(dev);
155 
156 	return 0;
157 }
158 
159 static int
160 mt7921_queues_read(struct seq_file *s, void *data)
161 {
162 	struct mt7921_dev *dev = dev_get_drvdata(s->private);
163 	struct {
164 		struct mt76_queue *q;
165 		char *queue;
166 	} queue_map[] = {
167 		{ dev->mphy.q_tx[MT_TXQ_BE],	 "WFDMA0" },
168 		{ dev->mt76.q_mcu[MT_MCUQ_WM],	 "MCUWM"  },
169 		{ dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" },
170 	};
171 	int i;
172 
173 	for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
174 		struct mt76_queue *q = queue_map[i].q;
175 
176 		if (!q)
177 			continue;
178 
179 		seq_printf(s,
180 			   "%s:	queued=%d head=%d tail=%d\n",
181 			   queue_map[i].queue, q->queued, q->head,
182 			   q->tail);
183 	}
184 
185 	return 0;
186 }
187 
188 static void
189 mt7921_seq_puts_array(struct seq_file *file, const char *str,
190 		      s8 *val, int len)
191 {
192 	int i;
193 
194 	seq_printf(file, "%-16s:", str);
195 	for (i = 0; i < len; i++)
196 		if (val[i] == 127)
197 			seq_printf(file, " %6s", "N.A");
198 		else
199 			seq_printf(file, " %6d", val[i]);
200 	seq_puts(file, "\n");
201 }
202 
203 #define mt7921_print_txpwr_entry(prefix, rate)				\
204 ({									\
205 	mt7921_seq_puts_array(s, #prefix " (user)",			\
206 			      txpwr.data[TXPWR_USER].rate,		\
207 			      ARRAY_SIZE(txpwr.data[TXPWR_USER].rate)); \
208 	mt7921_seq_puts_array(s, #prefix " (eeprom)",			\
209 			      txpwr.data[TXPWR_EEPROM].rate,		\
210 			      ARRAY_SIZE(txpwr.data[TXPWR_EEPROM].rate)); \
211 	mt7921_seq_puts_array(s, #prefix " (tmac)",			\
212 			      txpwr.data[TXPWR_MAC].rate,		\
213 			      ARRAY_SIZE(txpwr.data[TXPWR_MAC].rate));	\
214 })
215 
216 static int
217 mt7921_txpwr(struct seq_file *s, void *data)
218 {
219 	struct mt7921_dev *dev = dev_get_drvdata(s->private);
220 	struct mt7921_txpwr txpwr;
221 	int ret;
222 
223 	mt7921_mutex_acquire(dev);
224 	ret = mt7921_get_txpwr_info(dev, &txpwr);
225 	mt7921_mutex_release(dev);
226 
227 	if (ret)
228 		return ret;
229 
230 	seq_printf(s, "Tx power table (channel %d)\n", txpwr.ch);
231 	seq_printf(s, "%-16s  %6s %6s %6s %6s\n",
232 		   " ", "1m", "2m", "5m", "11m");
233 	mt7921_print_txpwr_entry(CCK, cck);
234 
235 	seq_printf(s, "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s\n",
236 		   " ", "6m", "9m", "12m", "18m", "24m", "36m",
237 		   "48m", "54m");
238 	mt7921_print_txpwr_entry(OFDM, ofdm);
239 
240 	seq_printf(s, "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s\n",
241 		   " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
242 		   "mcs6", "mcs7");
243 	mt7921_print_txpwr_entry(HT20, ht20);
244 
245 	seq_printf(s, "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
246 		   " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
247 		   "mcs6", "mcs7", "mcs32");
248 	mt7921_print_txpwr_entry(HT40, ht40);
249 
250 	seq_printf(s, "%-16s  %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
251 		   " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
252 		   "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11");
253 	mt7921_print_txpwr_entry(VHT20, vht20);
254 	mt7921_print_txpwr_entry(VHT40, vht40);
255 	mt7921_print_txpwr_entry(VHT80, vht80);
256 	mt7921_print_txpwr_entry(VHT160, vht160);
257 	mt7921_print_txpwr_entry(HE26, he26);
258 	mt7921_print_txpwr_entry(HE52, he52);
259 	mt7921_print_txpwr_entry(HE106, he106);
260 	mt7921_print_txpwr_entry(HE242, he242);
261 	mt7921_print_txpwr_entry(HE484, he484);
262 	mt7921_print_txpwr_entry(HE996, he996);
263 	mt7921_print_txpwr_entry(HE996x2, he996x2);
264 
265 	return 0;
266 }
267 
268 static void
269 mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
270 {
271 	struct mt7921_dev *dev = priv;
272 
273 	mt7921_mcu_set_beacon_filter(dev, vif, dev->pm.enable);
274 }
275 
276 static int
277 mt7921_pm_set(void *data, u64 val)
278 {
279 	struct mt7921_dev *dev = data;
280 	struct mt76_connac_pm *pm = &dev->pm;
281 
282 	mt7921_mutex_acquire(dev);
283 
284 	if (val == pm->enable)
285 		goto out;
286 
287 	if (!pm->enable) {
288 		pm->stats.last_wake_event = jiffies;
289 		pm->stats.last_doze_event = jiffies;
290 	}
291 	pm->enable = val;
292 
293 	ieee80211_iterate_active_interfaces(mt76_hw(dev),
294 					    IEEE80211_IFACE_ITER_RESUME_ALL,
295 					    mt7921_pm_interface_iter, dev);
296 
297 	mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable);
298 
299 out:
300 	mt7921_mutex_release(dev);
301 
302 	return 0;
303 }
304 
305 static int
306 mt7921_pm_get(void *data, u64 *val)
307 {
308 	struct mt7921_dev *dev = data;
309 
310 	*val = dev->pm.enable;
311 
312 	return 0;
313 }
314 
315 DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n");
316 
317 static int
318 mt7921_deep_sleep_set(void *data, u64 val)
319 {
320 	struct mt7921_dev *dev = data;
321 	struct mt76_connac_pm *pm = &dev->pm;
322 	bool enable = !!val;
323 
324 	mt7921_mutex_acquire(dev);
325 	if (pm->ds_enable != enable) {
326 		mt76_connac_mcu_set_deep_sleep(&dev->mt76, enable);
327 		pm->ds_enable = enable;
328 	}
329 	mt7921_mutex_release(dev);
330 
331 	return 0;
332 }
333 
334 static int
335 mt7921_deep_sleep_get(void *data, u64 *val)
336 {
337 	struct mt7921_dev *dev = data;
338 
339 	*val = dev->pm.ds_enable;
340 
341 	return 0;
342 }
343 
344 DEFINE_DEBUGFS_ATTRIBUTE(fops_ds, mt7921_deep_sleep_get,
345 			 mt7921_deep_sleep_set, "%lld\n");
346 
347 static int
348 mt7921_pm_stats(struct seq_file *s, void *data)
349 {
350 	struct mt7921_dev *dev = dev_get_drvdata(s->private);
351 	struct mt76_connac_pm *pm = &dev->pm;
352 
353 	unsigned long awake_time = pm->stats.awake_time;
354 	unsigned long doze_time = pm->stats.doze_time;
355 
356 	if (!test_bit(MT76_STATE_PM, &dev->mphy.state))
357 		awake_time += jiffies - pm->stats.last_wake_event;
358 	else
359 		doze_time += jiffies - pm->stats.last_doze_event;
360 
361 	seq_printf(s, "awake time: %14u\ndoze time: %15u\n",
362 		   jiffies_to_msecs(awake_time),
363 		   jiffies_to_msecs(doze_time));
364 
365 	seq_printf(s, "low power wakes: %9d\n", pm->stats.lp_wake);
366 
367 	return 0;
368 }
369 
370 static int
371 mt7921_pm_idle_timeout_set(void *data, u64 val)
372 {
373 	struct mt7921_dev *dev = data;
374 
375 	dev->pm.idle_timeout = msecs_to_jiffies(val);
376 
377 	return 0;
378 }
379 
380 static int
381 mt7921_pm_idle_timeout_get(void *data, u64 *val)
382 {
383 	struct mt7921_dev *dev = data;
384 
385 	*val = jiffies_to_msecs(dev->pm.idle_timeout);
386 
387 	return 0;
388 }
389 
390 DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt7921_pm_idle_timeout_get,
391 			 mt7921_pm_idle_timeout_set, "%lld\n");
392 
393 static int mt7921_chip_reset(void *data, u64 val)
394 {
395 	struct mt7921_dev *dev = data;
396 	int ret = 0;
397 
398 	switch (val) {
399 	case 1:
400 		/* Reset wifisys directly. */
401 		mt7921_reset(&dev->mt76);
402 		break;
403 	default:
404 		/* Collect the core dump before reset wifisys. */
405 		mt7921_mutex_acquire(dev);
406 		ret = mt76_connac_mcu_chip_config(&dev->mt76);
407 		mt7921_mutex_release(dev);
408 		break;
409 	}
410 
411 	return ret;
412 }
413 
414 DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7921_chip_reset, "%lld\n");
415 
416 int mt7921_init_debugfs(struct mt7921_dev *dev)
417 {
418 	struct dentry *dir;
419 
420 	dir = mt76_register_debugfs_fops(&dev->mphy, &fops_regval);
421 	if (!dir)
422 		return -ENOMEM;
423 
424 	debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
425 				    mt7921_queues_read);
426 	debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
427 				    mt7921_queues_acq);
428 	debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir,
429 				    mt7921_txpwr);
430 	debugfs_create_file("tx_stats", 0400, dir, dev, &mt7921_tx_stats_fops);
431 	debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug);
432 	debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm);
433 	debugfs_create_file("idle-timeout", 0600, dir, dev,
434 			    &fops_pm_idle_timeout);
435 	debugfs_create_file("chip_reset", 0600, dir, dev, &fops_reset);
436 	debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir,
437 				    mt7921_pm_stats);
438 	debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds);
439 
440 	return 0;
441 }
442