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