1 // SPDX-License-Identifier: ISC
2 /* Copyright (C) 2020 MediaTek Inc. */
3 
4 #include "mt7915.h"
5 #include "eeprom.h"
6 #include "mcu.h"
7 
8 /** global debugfs **/
9 
10 struct hw_queue_map {
11 	const char *name;
12 	u8 index;
13 	u8 pid;
14 	u8 qid;
15 };
16 
17 static int
18 mt7915_implicit_txbf_set(void *data, u64 val)
19 {
20 	struct mt7915_dev *dev = data;
21 
22 	if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
23 		return -EBUSY;
24 
25 	dev->ibf = !!val;
26 
27 	return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE);
28 }
29 
30 static int
31 mt7915_implicit_txbf_get(void *data, u64 *val)
32 {
33 	struct mt7915_dev *dev = data;
34 
35 	*val = dev->ibf;
36 
37 	return 0;
38 }
39 
40 DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7915_implicit_txbf_get,
41 			 mt7915_implicit_txbf_set, "%lld\n");
42 
43 /* test knob of system layer 1/2 error recovery */
44 static int mt7915_ser_trigger_set(void *data, u64 val)
45 {
46 	enum {
47 		SER_SET_RECOVER_L1 = 1,
48 		SER_SET_RECOVER_L2,
49 		SER_ENABLE = 2,
50 		SER_RECOVER
51 	};
52 	struct mt7915_dev *dev = data;
53 	int ret = 0;
54 
55 	switch (val) {
56 	case SER_SET_RECOVER_L1:
57 	case SER_SET_RECOVER_L2:
58 		ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), 0);
59 		if (ret)
60 			return ret;
61 
62 		return mt7915_mcu_set_ser(dev, SER_RECOVER, val, 0);
63 	default:
64 		break;
65 	}
66 
67 	return ret;
68 }
69 
70 DEFINE_DEBUGFS_ATTRIBUTE(fops_ser_trigger, NULL,
71 			 mt7915_ser_trigger_set, "%lld\n");
72 
73 static int
74 mt7915_radar_trigger(void *data, u64 val)
75 {
76 	struct mt7915_dev *dev = data;
77 
78 	return mt7915_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, 1, 0, 0);
79 }
80 
81 DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,
82 			 mt7915_radar_trigger, "%lld\n");
83 
84 static int
85 mt7915_fw_debug_wm_set(void *data, u64 val)
86 {
87 	struct mt7915_dev *dev = data;
88 	enum {
89 		DEBUG_TXCMD = 62,
90 		DEBUG_CMD_RPT_TX,
91 		DEBUG_CMD_RPT_TRIG,
92 		DEBUG_SPL,
93 		DEBUG_RPT_RX,
94 	} debug;
95 	int ret;
96 
97 	dev->fw_debug_wm = val ? MCU_FW_LOG_TO_HOST : 0;
98 
99 	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, dev->fw_debug_wm);
100 	if (ret)
101 		return ret;
102 
103 	for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) {
104 		ret = mt7915_mcu_fw_dbg_ctrl(dev, debug, !!dev->fw_debug_wm);
105 		if (ret)
106 			return ret;
107 	}
108 
109 	/* WM CPU info record control */
110 	mt76_clear(dev, MT_CPU_UTIL_CTRL, BIT(0));
111 	mt76_wr(dev, MT_DIC_CMD_REG_CMD, BIT(2) | BIT(13) | !dev->fw_debug_wm);
112 	mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR, BIT(5));
113 	mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR, BIT(5));
114 
115 	return 0;
116 }
117 
118 static int
119 mt7915_fw_debug_wm_get(void *data, u64 *val)
120 {
121 	struct mt7915_dev *dev = data;
122 
123 	*val = dev->fw_debug_wm;
124 
125 	return 0;
126 }
127 
128 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wm, mt7915_fw_debug_wm_get,
129 			 mt7915_fw_debug_wm_set, "%lld\n");
130 
131 static int
132 mt7915_fw_debug_wa_set(void *data, u64 val)
133 {
134 	struct mt7915_dev *dev = data;
135 	int ret;
136 
137 	dev->fw_debug_wa = val ? MCU_FW_LOG_TO_HOST : 0;
138 
139 	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, dev->fw_debug_wa);
140 	if (ret)
141 		return ret;
142 
143 	return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_PDMA_RX,
144 				 !!dev->fw_debug_wa, 0);
145 }
146 
147 static int
148 mt7915_fw_debug_wa_get(void *data, u64 *val)
149 {
150 	struct mt7915_dev *dev = data;
151 
152 	*val = dev->fw_debug_wa;
153 
154 	return 0;
155 }
156 
157 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7915_fw_debug_wa_get,
158 			 mt7915_fw_debug_wa_set, "%lld\n");
159 
160 static int
161 mt7915_fw_util_wm_show(struct seq_file *file, void *data)
162 {
163 	struct mt7915_dev *dev = file->private;
164 
165 	if (dev->fw_debug_wm) {
166 		seq_printf(file, "Busy: %u%%  Peak busy: %u%%\n",
167 			   mt76_rr(dev, MT_CPU_UTIL_BUSY_PCT),
168 			   mt76_rr(dev, MT_CPU_UTIL_PEAK_BUSY_PCT));
169 		seq_printf(file, "Idle count: %u  Peak idle count: %u\n",
170 			   mt76_rr(dev, MT_CPU_UTIL_IDLE_CNT),
171 			   mt76_rr(dev, MT_CPU_UTIL_PEAK_IDLE_CNT));
172 	}
173 
174 	return 0;
175 }
176 
177 DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wm);
178 
179 static int
180 mt7915_fw_util_wa_show(struct seq_file *file, void *data)
181 {
182 	struct mt7915_dev *dev = file->private;
183 
184 	if (dev->fw_debug_wa)
185 		return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(QUERY),
186 					 MCU_WA_PARAM_CPU_UTIL, 0, 0);
187 
188 	return 0;
189 }
190 
191 DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wa);
192 
193 static void
194 mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,
195 			   struct seq_file *file)
196 {
197 	struct mt7915_dev *dev = phy->dev;
198 	bool ext_phy = phy != &dev->phy;
199 	int bound[15], range[4], i, n;
200 
201 	/* Tx ampdu stat */
202 	for (i = 0; i < ARRAY_SIZE(range); i++)
203 		range[i] = mt76_rr(dev, MT_MIB_ARNG(ext_phy, i));
204 
205 	for (i = 0; i < ARRAY_SIZE(bound); i++)
206 		bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1;
207 
208 	seq_printf(file, "\nPhy %d\n", ext_phy);
209 
210 	seq_printf(file, "Length: %8d | ", bound[0]);
211 	for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
212 		seq_printf(file, "%3d -%3d | ",
213 			   bound[i] + 1, bound[i + 1]);
214 
215 	seq_puts(file, "\nCount:  ");
216 	n = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0;
217 	for (i = 0; i < ARRAY_SIZE(bound); i++)
218 		seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + n]);
219 	seq_puts(file, "\n");
220 
221 	seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);
222 }
223 
224 static void
225 mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)
226 {
227 	static const char * const bw[] = {
228 		"BW20", "BW40", "BW80", "BW160"
229 	};
230 	struct mib_stats *mib = &phy->mib;
231 
232 	/* Tx Beamformer monitor */
233 	seq_puts(s, "\nTx Beamformer applied PPDU counts: ");
234 
235 	seq_printf(s, "iBF: %d, eBF: %d\n",
236 		   mib->tx_bf_ibf_ppdu_cnt,
237 		   mib->tx_bf_ebf_ppdu_cnt);
238 
239 	/* Tx Beamformer Rx feedback monitor */
240 	seq_puts(s, "Tx Beamformer Rx feedback statistics: ");
241 
242 	seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ",
243 		   mib->tx_bf_rx_fb_all_cnt,
244 		   mib->tx_bf_rx_fb_he_cnt,
245 		   mib->tx_bf_rx_fb_vht_cnt,
246 		   mib->tx_bf_rx_fb_ht_cnt);
247 
248 	seq_printf(s, "%s, NC: %d, NR: %d\n",
249 		   bw[mib->tx_bf_rx_fb_bw],
250 		   mib->tx_bf_rx_fb_nc_cnt,
251 		   mib->tx_bf_rx_fb_nr_cnt);
252 
253 	/* Tx Beamformee Rx NDPA & Tx feedback report */
254 	seq_printf(s, "Tx Beamformee successful feedback frames: %d\n",
255 		   mib->tx_bf_fb_cpl_cnt);
256 	seq_printf(s, "Tx Beamformee feedback triggered counts: %d\n",
257 		   mib->tx_bf_fb_trig_cnt);
258 
259 	/* Tx SU & MU counters */
260 	seq_printf(s, "Tx multi-user Beamforming counts: %d\n",
261 		   mib->tx_bf_cnt);
262 	seq_printf(s, "Tx multi-user MPDU counts: %d\n", mib->tx_mu_mpdu_cnt);
263 	seq_printf(s, "Tx multi-user successful MPDU counts: %d\n",
264 		   mib->tx_mu_acked_mpdu_cnt);
265 	seq_printf(s, "Tx single-user successful MPDU counts: %d\n",
266 		   mib->tx_su_acked_mpdu_cnt);
267 
268 	seq_puts(s, "\n");
269 }
270 
271 static int
272 mt7915_tx_stats_show(struct seq_file *file, void *data)
273 {
274 	struct mt7915_phy *phy = file->private;
275 	struct mt7915_dev *dev = phy->dev;
276 	struct mib_stats *mib = &phy->mib;
277 	int i;
278 
279 	mutex_lock(&dev->mt76.mutex);
280 
281 	mt7915_ampdu_stat_read_phy(phy, file);
282 	mt7915_mac_update_stats(phy);
283 	mt7915_txbf_stat_read_phy(phy, file);
284 
285 	/* Tx amsdu info */
286 	seq_puts(file, "Tx MSDU statistics:\n");
287 	for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
288 		seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ",
289 			   i + 1, mib->tx_amsdu[i]);
290 		if (mib->tx_amsdu_cnt)
291 			seq_printf(file, "(%3d%%)\n",
292 				   mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt);
293 		else
294 			seq_puts(file, "\n");
295 	}
296 
297 	mutex_unlock(&dev->mt76.mutex);
298 
299 	return 0;
300 }
301 
302 DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats);
303 
304 static void
305 mt7915_hw_queue_read(struct seq_file *s, u32 base, u32 size,
306 		     const struct hw_queue_map *map)
307 {
308 	struct mt7915_phy *phy = s->private;
309 	struct mt7915_dev *dev = phy->dev;
310 	u32 i, val;
311 
312 	val = mt76_rr(dev, base + MT_FL_Q_EMPTY);
313 	for (i = 0; i < size; i++) {
314 		u32 ctrl, head, tail, queued;
315 
316 		if (val & BIT(map[i].index))
317 			continue;
318 
319 		ctrl = BIT(31) | (map[i].pid << 10) | (map[i].qid << 24);
320 		mt76_wr(dev, base + MT_FL_Q0_CTRL, ctrl);
321 
322 		head = mt76_get_field(dev, base + MT_FL_Q2_CTRL,
323 				      GENMASK(11, 0));
324 		tail = mt76_get_field(dev, base + MT_FL_Q2_CTRL,
325 				      GENMASK(27, 16));
326 		queued = mt76_get_field(dev, base + MT_FL_Q3_CTRL,
327 					GENMASK(11, 0));
328 
329 		seq_printf(s, "\t%s: ", map[i].name);
330 		seq_printf(s, "queued:0x%03x head:0x%03x tail:0x%03x\n",
331 			   queued, head, tail);
332 	}
333 }
334 
335 static void
336 mt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
337 {
338 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
339 	struct mt7915_dev *dev = msta->vif->phy->dev;
340 	struct seq_file *s = data;
341 	u8 ac;
342 
343 	for (ac = 0; ac < 4; ac++) {
344 		u32 qlen, ctrl, val;
345 		u32 idx = msta->wcid.idx >> 5;
346 		u8 offs = msta->wcid.idx & GENMASK(4, 0);
347 
348 		ctrl = BIT(31) | BIT(11) | (ac << 24);
349 		val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx));
350 
351 		if (val & BIT(offs))
352 			continue;
353 
354 		mt76_wr(dev, MT_PLE_BASE + MT_FL_Q0_CTRL, ctrl | msta->wcid.idx);
355 		qlen = mt76_get_field(dev, MT_PLE_BASE + MT_FL_Q3_CTRL,
356 				      GENMASK(11, 0));
357 		seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n",
358 			   sta->addr, msta->wcid.idx, msta->vif->wmm_idx,
359 			   ac, qlen);
360 	}
361 }
362 
363 static int
364 mt7915_hw_queues_show(struct seq_file *file, void *data)
365 {
366 	struct mt7915_phy *phy = file->private;
367 	struct mt7915_dev *dev = phy->dev;
368 	static const struct hw_queue_map ple_queue_map[] = {
369 		{ "CPU_Q0",  0,  1, MT_CTX0	      },
370 		{ "CPU_Q1",  1,  1, MT_CTX0 + 1	      },
371 		{ "CPU_Q2",  2,  1, MT_CTX0 + 2	      },
372 		{ "CPU_Q3",  3,  1, MT_CTX0 + 3	      },
373 		{ "ALTX_Q0", 8,  2, MT_LMAC_ALTX0     },
374 		{ "BMC_Q0",  9,  2, MT_LMAC_BMC0      },
375 		{ "BCN_Q0",  10, 2, MT_LMAC_BCN0      },
376 		{ "PSMP_Q0", 11, 2, MT_LMAC_PSMP0     },
377 		{ "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 },
378 		{ "BMC_Q1",  13, 2, MT_LMAC_BMC0  + 4 },
379 		{ "BCN_Q1",  14, 2, MT_LMAC_BCN0  + 4 },
380 		{ "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 },
381 	};
382 	static const struct hw_queue_map pse_queue_map[] = {
383 		{ "CPU Q0",  0,  1, MT_CTX0	      },
384 		{ "CPU Q1",  1,  1, MT_CTX0 + 1	      },
385 		{ "CPU Q2",  2,  1, MT_CTX0 + 2	      },
386 		{ "CPU Q3",  3,  1, MT_CTX0 + 3	      },
387 		{ "HIF_Q0",  8,  0, MT_HIF0	      },
388 		{ "HIF_Q1",  9,  0, MT_HIF0 + 1	      },
389 		{ "HIF_Q2",  10, 0, MT_HIF0 + 2	      },
390 		{ "HIF_Q3",  11, 0, MT_HIF0 + 3	      },
391 		{ "HIF_Q4",  12, 0, MT_HIF0 + 4	      },
392 		{ "HIF_Q5",  13, 0, MT_HIF0 + 5	      },
393 		{ "LMAC_Q",  16, 2, 0		      },
394 		{ "MDP_TXQ", 17, 2, 1		      },
395 		{ "MDP_RXQ", 18, 2, 2		      },
396 		{ "SEC_TXQ", 19, 2, 3		      },
397 		{ "SEC_RXQ", 20, 2, 4		      },
398 	};
399 	u32 val, head, tail;
400 
401 	/* ple queue */
402 	val = mt76_rr(dev, MT_PLE_FREEPG_CNT);
403 	head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0));
404 	tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16));
405 	seq_puts(file, "PLE page info:\n");
406 	seq_printf(file,
407 		   "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n",
408 		   val, head, tail);
409 
410 	val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP);
411 	head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0));
412 	tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16));
413 	seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n",
414 		   val, head, tail);
415 
416 	seq_puts(file, "PLE non-empty queue info:\n");
417 	mt7915_hw_queue_read(file, MT_PLE_BASE, ARRAY_SIZE(ple_queue_map),
418 			     &ple_queue_map[0]);
419 
420 	/* iterate per-sta ple queue */
421 	ieee80211_iterate_stations_atomic(phy->mt76->hw,
422 					  mt7915_sta_hw_queue_read, file);
423 	/* pse queue */
424 	seq_puts(file, "PSE non-empty queue info:\n");
425 	mt7915_hw_queue_read(file, MT_PSE_BASE, ARRAY_SIZE(pse_queue_map),
426 			     &pse_queue_map[0]);
427 
428 	return 0;
429 }
430 
431 DEFINE_SHOW_ATTRIBUTE(mt7915_hw_queues);
432 
433 static int
434 mt7915_xmit_queues_show(struct seq_file *file, void *data)
435 {
436 	struct mt7915_phy *phy = file->private;
437 	struct mt7915_dev *dev = phy->dev;
438 	struct {
439 		struct mt76_queue *q;
440 		char *queue;
441 	} queue_map[] = {
442 		{ phy->mt76->q_tx[MT_TXQ_BE],	 "   MAIN"  },
443 		{ dev->mt76.q_mcu[MT_MCUQ_WM],	 "  MCUWM"  },
444 		{ dev->mt76.q_mcu[MT_MCUQ_WA],	 "  MCUWA"  },
445 		{ dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" },
446 	};
447 	int i;
448 
449 	seq_puts(file, "     queue | hw-queued |      head |      tail |\n");
450 	for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
451 		struct mt76_queue *q = queue_map[i].q;
452 
453 		if (!q)
454 			continue;
455 
456 		seq_printf(file, "   %s | %9d | %9d | %9d |\n",
457 			   queue_map[i].queue, q->queued, q->head,
458 			   q->tail);
459 	}
460 
461 	return 0;
462 }
463 
464 DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues);
465 
466 static int
467 mt7915_rate_txpower_show(struct seq_file *file, void *data)
468 {
469 	static const char * const sku_group_name[] = {
470 		"CCK", "OFDM", "HT20", "HT40",
471 		"VHT20", "VHT40", "VHT80", "VHT160",
472 		"RU26", "RU52", "RU106", "RU242/SU20",
473 		"RU484/SU40", "RU996/SU80", "RU2x996/SU160"
474 	};
475 	struct mt7915_phy *phy = file->private;
476 	s8 txpower[MT7915_SKU_RATE_NUM], *buf;
477 	int i;
478 
479 	seq_printf(file, "\nBand %d\n", phy != &phy->dev->phy);
480 	mt7915_mcu_get_txpower_sku(phy, txpower, sizeof(txpower));
481 	for (i = 0, buf = txpower; i < ARRAY_SIZE(mt7915_sku_group_len); i++) {
482 		u8 mcs_num = mt7915_sku_group_len[i];
483 
484 		if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160)
485 			mcs_num = 10;
486 
487 		mt76_seq_puts_array(file, sku_group_name[i], buf, mcs_num);
488 		buf += mt7915_sku_group_len[i];
489 	}
490 
491 	return 0;
492 }
493 
494 DEFINE_SHOW_ATTRIBUTE(mt7915_rate_txpower);
495 
496 static int
497 mt7915_twt_stats(struct seq_file *s, void *data)
498 {
499 	struct mt7915_dev *dev = dev_get_drvdata(s->private);
500 	struct mt7915_twt_flow *iter;
501 
502 	rcu_read_lock();
503 
504 	seq_puts(s, "     wcid |       id |    flags |      exp | mantissa");
505 	seq_puts(s, " | duration |            tsf |\n");
506 	list_for_each_entry_rcu(iter, &dev->twt_list, list)
507 		seq_printf(s,
508 			"%9d | %8d | %5c%c%c%c | %8d | %8d | %8d | %14lld |\n",
509 			iter->wcid, iter->id,
510 			iter->sched ? 's' : 'u',
511 			iter->protection ? 'p' : '-',
512 			iter->trigger ? 't' : '-',
513 			iter->flowtype ? '-' : 'a',
514 			iter->exp, iter->mantissa,
515 			iter->duration, iter->tsf);
516 
517 	rcu_read_unlock();
518 
519 	return 0;
520 }
521 
522 int mt7915_init_debugfs(struct mt7915_phy *phy)
523 {
524 	struct mt7915_dev *dev = phy->dev;
525 	bool ext_phy = phy != &dev->phy;
526 	struct dentry *dir;
527 
528 	dir = mt76_register_debugfs_fops(phy->mt76, NULL);
529 	if (!dir)
530 		return -ENOMEM;
531 
532 	debugfs_create_file("hw-queues", 0400, dir, phy,
533 			    &mt7915_hw_queues_fops);
534 	debugfs_create_file("xmit-queues", 0400, dir, phy,
535 			    &mt7915_xmit_queues_fops);
536 	debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops);
537 	debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm);
538 	debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa);
539 	debugfs_create_file("fw_util_wm", 0400, dir, dev,
540 			    &mt7915_fw_util_wm_fops);
541 	debugfs_create_file("fw_util_wa", 0400, dir, dev,
542 			    &mt7915_fw_util_wa_fops);
543 	debugfs_create_file("implicit_txbf", 0600, dir, dev,
544 			    &fops_implicit_txbf);
545 	debugfs_create_file("txpower_sku", 0400, dir, phy,
546 			    &mt7915_rate_txpower_fops);
547 	debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,
548 				    mt7915_twt_stats);
549 	debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger);
550 	if (!dev->dbdc_support || ext_phy) {
551 		debugfs_create_u32("dfs_hw_pattern", 0400, dir,
552 				   &dev->hw_pattern);
553 		debugfs_create_file("radar_trigger", 0200, dir, dev,
554 				    &fops_radar_trigger);
555 	}
556 
557 	return 0;
558 }
559 
560 #ifdef CONFIG_MAC80211_DEBUGFS
561 /** per-station debugfs **/
562 
563 static ssize_t mt7915_sta_fixed_rate_set(struct file *file,
564 					 const char __user *user_buf,
565 					 size_t count, loff_t *ppos)
566 {
567 	struct ieee80211_sta *sta = file->private_data;
568 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
569 	struct mt7915_dev *dev = msta->vif->phy->dev;
570 	struct ieee80211_vif *vif;
571 	struct sta_phy phy = {};
572 	char buf[100];
573 	int ret;
574 	u32 field;
575 	u8 i, gi, he_ltf;
576 
577 	if (count >= sizeof(buf))
578 		return -EINVAL;
579 
580 	if (copy_from_user(buf, user_buf, count))
581 		return -EFAULT;
582 
583 	if (count && buf[count - 1] == '\n')
584 		buf[count - 1] = '\0';
585 	else
586 		buf[count] = '\0';
587 
588 	/* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 9
589 	 * bw - bw20: 0, bw40: 1, bw80: 2, bw160: 3
590 	 * nss - vht: 1~4, he: 1~4, others: ignore
591 	 * mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~2
592 	 * gi - (ht/vht) lgi: 0, sgi: 1; (he) 0.8us: 0, 1.6us: 1, 3.2us: 2
593 	 * ldpc - off: 0, on: 1
594 	 * stbc - off: 0, on: 1
595 	 * he_ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2
596 	 */
597 	if (sscanf(buf, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu",
598 		   &phy.type, &phy.bw, &phy.nss, &phy.mcs, &gi,
599 		   &phy.ldpc, &phy.stbc, &he_ltf) != 8) {
600 		dev_warn(dev->mt76.dev,
601 			 "format: Mode BW NSS MCS (HE)GI LDPC STBC HE_LTF\n");
602 		field = RATE_PARAM_AUTO;
603 		goto out;
604 	}
605 
606 	phy.ldpc = (phy.bw || phy.ldpc) * GENMASK(2, 0);
607 	for (i = 0; i <= phy.bw; i++) {
608 		phy.sgi |= gi << (i << sta->he_cap.has_he);
609 		phy.he_ltf |= he_ltf << (i << sta->he_cap.has_he);
610 	}
611 	field = RATE_PARAM_FIXED;
612 
613 out:
614 	vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
615 	ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, field);
616 	if (ret)
617 		return -EFAULT;
618 
619 	return count;
620 }
621 
622 static const struct file_operations fops_fixed_rate = {
623 	.write = mt7915_sta_fixed_rate_set,
624 	.open = simple_open,
625 	.owner = THIS_MODULE,
626 	.llseek = default_llseek,
627 };
628 
629 static int
630 mt7915_queues_show(struct seq_file *s, void *data)
631 {
632 	struct ieee80211_sta *sta = s->private;
633 
634 	mt7915_sta_hw_queue_read(s, sta);
635 
636 	return 0;
637 }
638 
639 DEFINE_SHOW_ATTRIBUTE(mt7915_queues);
640 
641 void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
642 			    struct ieee80211_sta *sta, struct dentry *dir)
643 {
644 	debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate);
645 	debugfs_create_file("hw-queues", 0400, dir, sta, &mt7915_queues_fops);
646 }
647 
648 #endif
649