blob: f217cbaad012cbb475aa9851d45fa3dba1b2303e [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/**
2 ******************************************************************************
3 *
4 * @file rwnx_debugfs.c
5 *
6 * @brief Definition of debugfs entries
7 *
8 * Copyright (C) RivieraWaves 2012-2019
9 *
10 ******************************************************************************
11 */
12
13
14#include <linux/kernel.h>
15#include <linux/kmod.h>
16#include <linux/debugfs.h>
17#include <linux/string.h>
18#include <linux/sort.h>
19#include <linux/vmalloc.h>
20
21#include "rwnx_debugfs.h"
22#include "rwnx_msg_tx.h"
23#include "rwnx_radar.h"
24#include "rwnx_tx.h"
25
26#ifdef CONFIG_DEBUG_FS
27#ifdef CONFIG_RWNX_FULLMAC
28static ssize_t rwnx_dbgfs_stats_read(struct file *file,
29 char __user *user_buf,
30 size_t count, loff_t *ppos)
31{
32 struct rwnx_hw *priv = file->private_data;
33 char *buf;
34 int ret;
35 int i, skipped;
36 ssize_t read;
37 int bufsz = (NX_TXQ_CNT) * 20 + (ARRAY_SIZE(priv->stats.amsdus_rx) + 1) * 40
38 + (ARRAY_SIZE(priv->stats.ampdus_tx) * 30);
39
40 if (*ppos)
41 return 0;
42
43 buf = kmalloc(bufsz, GFP_ATOMIC);
44 if (buf == NULL)
45 return 0;
46
47 ret = scnprintf(buf, bufsz, "TXQs CFM balances ");
48 for (i = 0; i < NX_TXQ_CNT; i++)
49 ret += scnprintf(&buf[ret], bufsz - ret,
50 " [%1d]:%3d", i,
51 priv->stats.cfm_balance[i]);
52
53 ret += scnprintf(&buf[ret], bufsz - ret, "\n");
54
55#ifdef CONFIG_RWNX_SPLIT_TX_BUF
56 ret += scnprintf(&buf[ret], bufsz - ret,
57 "\nAMSDU[len] done failed received\n");
58 for (i = skipped = 0; i < NX_TX_PAYLOAD_MAX; i++) {
59 if (priv->stats.amsdus[i].done) {
60 per = DIV_ROUND_UP((priv->stats.amsdus[i].failed) *
61 100, priv->stats.amsdus[i].done);
62 } else if (priv->stats.amsdus_rx[i]) {
63 per = 0;
64 } else {
65 per = 0;
66 skipped = 1;
67 continue;
68 }
69 if (skipped) {
70 ret += scnprintf(&buf[ret], bufsz - ret, " ...\n");
71 skipped = 0;
72 }
73
74 ret += scnprintf(&buf[ret], bufsz - ret,
75 " [%2d] %10d %8d(%3d%%) %10d\n", i ? i + 1 : i,
76 priv->stats.amsdus[i].done,
77 priv->stats.amsdus[i].failed, per,
78 priv->stats.amsdus_rx[i]);
79 }
80
81 for (; i < ARRAY_SIZE(priv->stats.amsdus_rx); i++) {
82 if (!priv->stats.amsdus_rx[i]) {
83 skipped = 1;
84 continue;
85 }
86 if (skipped) {
87 ret += scnprintf(&buf[ret], bufsz - ret, " ...\n");
88 skipped = 0;
89 }
90
91 ret += scnprintf(&buf[ret], bufsz - ret,
92 " [%2d] %10d\n",
93 i + 1, priv->stats.amsdus_rx[i]);
94 }
95#else
96 ret += scnprintf(&buf[ret], bufsz - ret,
97 "\nAMSDU[len] received\n");
98 for (i = skipped = 0; i < ARRAY_SIZE(priv->stats.amsdus_rx); i++) {
99 if (!priv->stats.amsdus_rx[i]) {
100 skipped = 1;
101 continue;
102 }
103 if (skipped) {
104 ret += scnprintf(&buf[ret], bufsz - ret,
105 " ...\n");
106 skipped = 0;
107 }
108
109 ret += scnprintf(&buf[ret], bufsz - ret,
110 " [%2d] %10d\n",
111 i + 1, priv->stats.amsdus_rx[i]);
112 }
113
114#endif /* CONFIG_RWNX_SPLIT_TX_BUF */
115
116 ret += scnprintf(&buf[ret], bufsz - ret,
117 "\nAMPDU[len] done received\n");
118 for (i = skipped = 0; i < ARRAY_SIZE(priv->stats.ampdus_tx); i++) {
119 if (!priv->stats.ampdus_tx[i] && !priv->stats.ampdus_rx[i]) {
120 skipped = 1;
121 continue;
122 }
123 if (skipped) {
124 ret += scnprintf(&buf[ret], bufsz - ret,
125 " ...\n");
126 skipped = 0;
127 }
128
129 ret += scnprintf(&buf[ret], bufsz - ret,
130 " [%2d] %9d %9d\n", i ? i + 1 : i,
131 priv->stats.ampdus_tx[i], priv->stats.ampdus_rx[i]);
132 }
133
134 ret += scnprintf(&buf[ret], bufsz - ret,
135 "#mpdu missed %9d\n",
136 priv->stats.ampdus_rx_miss);
137 read = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
138
139 kfree(buf);
140
141 return read;
142}
143#endif /* CONFIG_RWNX_FULLMAC */
144
145static ssize_t rwnx_dbgfs_stats_write(struct file *file,
146 const char __user *user_buf,
147 size_t count, loff_t *ppos)
148{
149 struct rwnx_hw *priv = file->private_data;
150
151 /* Prevent from interrupt preemption as these statistics are updated under
152 * interrupt */
153 spin_lock_bh(&priv->tx_lock);
154
155 memset(&priv->stats, 0, sizeof(priv->stats));
156
157 spin_unlock_bh(&priv->tx_lock);
158
159 return count;
160}
161
162DEBUGFS_READ_WRITE_FILE_OPS(stats);
163
164#define TXQ_STA_PREF "tid|"
165#define TXQ_STA_PREF_FMT "%3d|"
166
167#ifdef CONFIG_RWNX_FULLMAC
168#define TXQ_VIF_PREF "type|"
169#define TXQ_VIF_PREF_FMT "%4s|"
170#else
171#define TXQ_VIF_PREF "AC|"
172#define TXQ_VIF_PREF_FMT "%2s|"
173#endif /* CONFIG_RWNX_FULLMAC */
174
175#define TXQ_HDR "idx| status|credit|ready|retry"
176#define TXQ_HDR_FMT "%3d|%s%s%s%s%s%s%s|%6d|%5d|%5d"
177
178#ifdef CONFIG_RWNX_AMSDUS_TX
179#ifdef CONFIG_RWNX_FULLMAC
180#define TXQ_HDR_SUFF "|amsdu"
181#define TXQ_HDR_SUFF_FMT "|%5d"
182#else
183#define TXQ_HDR_SUFF "|amsdu-ht|amdsu-vht"
184#define TXQ_HDR_SUFF_FMT "|%8d|%9d"
185#endif /* CONFIG_RWNX_FULLMAC */
186#else
187#define TXQ_HDR_SUFF ""
188#define TXQ_HDR_SUF_FMT ""
189#endif /* CONFIG_RWNX_AMSDUS_TX */
190
191#define TXQ_HDR_MAX_LEN (sizeof(TXQ_STA_PREF) + sizeof(TXQ_HDR) + sizeof(TXQ_HDR_SUFF) + 1)
192
193#ifdef CONFIG_RWNX_FULLMAC
194#define PS_HDR "Legacy PS: ready=%d, sp=%d / UAPSD: ready=%d, sp=%d"
195#define PS_HDR_LEGACY "Legacy PS: ready=%d, sp=%d"
196#define PS_HDR_UAPSD "UAPSD: ready=%d, sp=%d"
197#define PS_HDR_MAX_LEN sizeof("Legacy PS: ready=xxx, sp=xxx / UAPSD: ready=xxx, sp=xxx\n")
198#else
199#define PS_HDR ""
200#define PS_HDR_MAX_LEN 0
201#endif /* CONFIG_RWNX_FULLMAC */
202
203#define STA_HDR "** STA %d (%pM)\n"
204#define STA_HDR_MAX_LEN (sizeof("- STA xx (xx:xx:xx:xx:xx:xx)\n") + PS_HDR_MAX_LEN)
205
206#ifdef CONFIG_RWNX_FULLMAC
207#define VIF_HDR "* VIF [%d] %s\n"
208#define VIF_HDR_MAX_LEN (sizeof(VIF_HDR) + IFNAMSIZ)
209#else
210#define VIF_HDR "* VIF [%d]\n"
211#define VIF_HDR_MAX_LEN sizeof(VIF_HDR)
212#endif
213
214
215#ifdef CONFIG_RWNX_AMSDUS_TX
216
217#ifdef CONFIG_RWNX_FULLMAC
218#define VIF_SEP "---------------------------------------\n"
219#else
220#define VIF_SEP "----------------------------------------------------\n"
221#endif /* CONFIG_RWNX_FULLMAC */
222
223#else /* ! CONFIG_RWNX_AMSDUS_TX */
224#define VIF_SEP "---------------------------------\n"
225#endif /* CONFIG_RWNX_AMSDUS_TX*/
226
227#define VIF_SEP_LEN sizeof(VIF_SEP)
228
229#define CAPTION "status: L=in hwq list, F=stop full, P=stop sta PS, V=stop vif PS, C=stop channel, S=stop CSA, M=stop MU"
230#define CAPTION_LEN sizeof(CAPTION)
231
232#define STA_TXQ 0
233#define VIF_TXQ 1
234
235static int rwnx_dbgfs_txq(char *buf, size_t size, struct rwnx_txq *txq, int type, int tid, char *name)
236{
237 int res, idx = 0;
238
239 if (type == STA_TXQ) {
240 res = scnprintf(&buf[idx], size, TXQ_STA_PREF_FMT, tid);
241 idx += res;
242 size -= res;
243 } else {
244 res = scnprintf(&buf[idx], size, TXQ_VIF_PREF_FMT, name);
245 idx += res;
246 size -= res;
247 }
248
249 res = scnprintf(&buf[idx], size, TXQ_HDR_FMT, txq->idx,
250 (txq->status & RWNX_TXQ_IN_HWQ_LIST) ? "L" : " ",
251 (txq->status & RWNX_TXQ_STOP_FULL) ? "F" : " ",
252 (txq->status & RWNX_TXQ_STOP_STA_PS) ? "P" : " ",
253 (txq->status & RWNX_TXQ_STOP_VIF_PS) ? "V" : " ",
254 (txq->status & RWNX_TXQ_STOP_CHAN) ? "C" : " ",
255 (txq->status & RWNX_TXQ_STOP_CSA) ? "S" : " ",
256 (txq->status & RWNX_TXQ_STOP_MU_POS) ? "M" : " ",
257 txq->credits, skb_queue_len(&txq->sk_list),
258 txq->nb_retry);
259 idx += res;
260 size -= res;
261
262#ifdef CONFIG_RWNX_AMSDUS_TX
263 if (type == STA_TXQ) {
264 res = scnprintf(&buf[idx], size, TXQ_HDR_SUFF_FMT,
265#ifdef CONFIG_RWNX_FULLMAC
266 txq->amsdu_len
267#else
268 txq->amsdu_ht_len_cap, txq->amsdu_vht_len_cap
269#endif /* CONFIG_RWNX_FULLMAC */
270 );
271 idx += res;
272 size -= res;
273 }
274#endif
275
276 res = scnprintf(&buf[idx], size, "\n");
277 idx += res;
278 size -= res;
279
280 return idx;
281}
282
283static int rwnx_dbgfs_txq_sta(char *buf, size_t size, struct rwnx_sta *rwnx_sta,
284 struct rwnx_hw *rwnx_hw)
285{
286 int tid, res, idx = 0;
287 struct rwnx_txq *txq;
288
289 res = scnprintf(&buf[idx], size, "\n" STA_HDR,
290 rwnx_sta->sta_idx,
291#ifdef CONFIG_RWNX_FULLMAC
292 rwnx_sta->mac_addr
293#endif /* CONFIG_RWNX_FULLMAC */
294 );
295 idx += res;
296 size -= res;
297
298#ifdef CONFIG_RWNX_FULLMAC
299 if (rwnx_sta->ps.active) {
300 if (rwnx_sta->uapsd_tids &&
301 (rwnx_sta->uapsd_tids == ((1 << NX_NB_TXQ_PER_STA) - 1)))
302 res = scnprintf(&buf[idx], size, PS_HDR_UAPSD "\n",
303 rwnx_sta->ps.pkt_ready[UAPSD_ID],
304 rwnx_sta->ps.sp_cnt[UAPSD_ID]);
305 else if (rwnx_sta->uapsd_tids)
306 res = scnprintf(&buf[idx], size, PS_HDR "\n",
307 rwnx_sta->ps.pkt_ready[LEGACY_PS_ID],
308 rwnx_sta->ps.sp_cnt[LEGACY_PS_ID],
309 rwnx_sta->ps.pkt_ready[UAPSD_ID],
310 rwnx_sta->ps.sp_cnt[UAPSD_ID]);
311 else
312 res = scnprintf(&buf[idx], size, PS_HDR_LEGACY "\n",
313 rwnx_sta->ps.pkt_ready[LEGACY_PS_ID],
314 rwnx_sta->ps.sp_cnt[LEGACY_PS_ID]);
315 idx += res;
316 size -= res;
317 } else {
318 res = scnprintf(&buf[idx], size, "\n");
319 idx += res;
320 size -= res;
321 }
322#endif /* CONFIG_RWNX_FULLMAC */
323
324
325 res = scnprintf(&buf[idx], size, TXQ_STA_PREF TXQ_HDR TXQ_HDR_SUFF "\n");
326 idx += res;
327 size -= res;
328
329
330 foreach_sta_txq(rwnx_sta, txq, tid, rwnx_hw) {
331 res = rwnx_dbgfs_txq(&buf[idx], size, txq, STA_TXQ, tid, NULL);
332 idx += res;
333 size -= res;
334 }
335
336 return idx;
337}
338
339static int rwnx_dbgfs_txq_vif(char *buf, size_t size, struct rwnx_vif *rwnx_vif,
340 struct rwnx_hw *rwnx_hw)
341{
342 int res, idx = 0;
343 struct rwnx_txq *txq;
344 struct rwnx_sta *rwnx_sta;
345
346#ifdef CONFIG_RWNX_FULLMAC
347 res = scnprintf(&buf[idx], size, VIF_HDR, rwnx_vif->vif_index, rwnx_vif->ndev->name);
348 idx += res;
349 size -= res;
350 if (!rwnx_vif->up || rwnx_vif->ndev == NULL)
351 return idx;
352
353#else
354 int ac;
355 char ac_name[2] = {'0', '\0'};
356
357 res = scnprintf(&buf[idx], size, VIF_HDR, rwnx_vif->vif_index);
358 idx += res;
359 size -= res;
360#endif /* CONFIG_RWNX_FULLMAC */
361
362#ifdef CONFIG_RWNX_FULLMAC
363 if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_AP ||
364 RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_GO ||
365 RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_MESH_POINT) {
366 res = scnprintf(&buf[idx], size, TXQ_VIF_PREF TXQ_HDR "\n");
367 idx += res;
368 size -= res;
369 txq = rwnx_txq_vif_get(rwnx_vif, NX_UNK_TXQ_TYPE);
370 res = rwnx_dbgfs_txq(&buf[idx], size, txq, VIF_TXQ, 0, "UNK");
371 idx += res;
372 size -= res;
373 txq = rwnx_txq_vif_get(rwnx_vif, NX_BCMC_TXQ_TYPE);
374 res = rwnx_dbgfs_txq(&buf[idx], size, txq, VIF_TXQ, 0, "BCMC");
375 idx += res;
376 size -= res;
377 rwnx_sta = &rwnx_hw->sta_table[rwnx_vif->ap.bcmc_index];
378 if (rwnx_sta->ps.active) {
379 res = scnprintf(&buf[idx], size, PS_HDR_LEGACY "\n",
380 rwnx_sta->ps.sp_cnt[LEGACY_PS_ID],
381 rwnx_sta->ps.sp_cnt[LEGACY_PS_ID]);
382 idx += res;
383 size -= res;
384 } else {
385 res = scnprintf(&buf[idx], size, "\n");
386 idx += res;
387 size -= res;
388 }
389
390 list_for_each_entry(rwnx_sta, &rwnx_vif->ap.sta_list, list) {
391 res = rwnx_dbgfs_txq_sta(&buf[idx], size, rwnx_sta, rwnx_hw);
392 idx += res;
393 size -= res;
394 }
395 } else if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_STATION ||
396 RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_CLIENT) {
397 if (rwnx_vif->sta.ap) {
398 res = rwnx_dbgfs_txq_sta(&buf[idx], size, rwnx_vif->sta.ap, rwnx_hw);
399 idx += res;
400 size -= res;
401 }
402 }
403
404#else
405 res = scnprintf(&buf[idx], size, TXQ_VIF_PREF TXQ_HDR "\n");
406 idx += res;
407 size -= res;
408
409 foreach_vif_txq(rwnx_vif, txq, ac) {
410 ac_name[0]++;
411 res = rwnx_dbgfs_txq(&buf[idx], size, txq, VIF_TXQ, 0, ac_name);
412 idx += res;
413 size -= res;
414 }
415
416 list_for_each_entry(rwnx_sta, &rwnx_vif->stations, list) {
417 res = rwnx_dbgfs_txq_sta(&buf[idx], size, rwnx_sta, rwnx_hw);
418 idx += res;
419 size -= res;
420 }
421#endif /* CONFIG_RWNX_FULLMAC */
422 return idx;
423}
424
425extern u8 debug_print;
426static ssize_t rwnx_dbgfs_debug_write(struct file *file,
427 const char __user *user_buf,
428 size_t count, loff_t *ppos)
429{
430 //struct rwnx_hw *rw_hw = file->private_data;
431 //struct rwnx_vif *rw_vif;
432 char buf[64];
433 size_t len = min_t(size_t, count, sizeof(buf) - 1);
434 int debug_level=0;
435
436 if (copy_from_user(buf, user_buf, len))
437 return -EFAULT;
438 buf[len] = '\0';
439
440 /* Read the written NOA information */
441 if (sscanf(buf, "%d", &debug_level) > 0) {
442 printk("aicwifi debug_level : %d -> %d\n", debug_print, debug_level);
443 debug_print = debug_level;
444 return count;
445 }
446
447 return count;
448}
449
450DEBUGFS_WRITE_FILE_OPS(debug);
451
452static ssize_t rwnx_dbgfs_txq_read(struct file *file,
453 char __user *user_buf,
454 size_t count, loff_t *ppos)
455{
456 struct rwnx_hw *rwnx_hw = file->private_data;
457 struct rwnx_vif *vif;
458 char *buf;
459 int idx, res;
460 ssize_t read;
461 size_t bufsz = ((NX_VIRT_DEV_MAX * (VIF_HDR_MAX_LEN + 2 * VIF_SEP_LEN)) +
462 (NX_REMOTE_STA_MAX * STA_HDR_MAX_LEN) +
463 ((NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX + NX_NB_TXQ) *
464 TXQ_HDR_MAX_LEN) + CAPTION_LEN);
465
466 /* everything is read in one go */
467 if (*ppos)
468 return 0;
469
470 bufsz = min_t(size_t, bufsz, count);
471 buf = kmalloc(bufsz, GFP_ATOMIC);
472 if (buf == NULL)
473 return 0;
474
475 bufsz--;
476 idx = 0;
477
478 res = scnprintf(&buf[idx], bufsz, CAPTION);
479 idx += res;
480 bufsz -= res;
481
482 //spin_lock_bh(&rwnx_hw->tx_lock);
483 list_for_each_entry(vif, &rwnx_hw->vifs, list) {
484 res = scnprintf(&buf[idx], bufsz, "\n"VIF_SEP);
485 idx += res;
486 bufsz -= res;
487 res = rwnx_dbgfs_txq_vif(&buf[idx], bufsz, vif, rwnx_hw);
488 idx += res;
489 bufsz -= res;
490 res = scnprintf(&buf[idx], bufsz, VIF_SEP);
491 idx += res;
492 bufsz -= res;
493 }
494 //spin_unlock_bh(&rwnx_hw->tx_lock);
495
496 read = simple_read_from_buffer(user_buf, count, ppos, buf, idx);
497 kfree(buf);
498
499 return read;
500}
501DEBUGFS_READ_FILE_OPS(txq);
502
503static ssize_t rwnx_dbgfs_acsinfo_read(struct file *file,
504 char __user *user_buf,
505 size_t count, loff_t *ppos)
506{
507 struct rwnx_hw *priv = file->private_data;
508#ifdef CONFIG_RWNX_FULLMAC
509 struct wiphy *wiphy = priv->wiphy;
510#endif //CONFIG_RWNX_FULLMAC
511 int survey_cnt = 0;
512 int len = 0;
513 int band, chan_cnt;
514 int band_max = NL80211_BAND_5GHZ;
515 char *buf = (char *)vmalloc((SCAN_CHANNEL_MAX + 1) * 43);
516 ssize_t size;
517
518 if (!buf)
519 return 0;
520
521 if (priv->band_5g_support)
522 band_max = NL80211_BAND_5GHZ + 1;
523
524 mutex_lock(&priv->dbgdump.mutex);
525
526 len += scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
527 "FREQ TIME(ms) BUSY(ms) NOISE(dBm)\n");
528
529 for (band = NL80211_BAND_2GHZ; band < band_max; band++) {
530 for (chan_cnt = 0; chan_cnt < wiphy->bands[band]->n_channels; chan_cnt++) {
531 struct rwnx_survey_info *p_survey_info = &priv->survey[survey_cnt];
532 struct ieee80211_channel *p_chan = &wiphy->bands[band]->channels[chan_cnt];
533
534 if (p_survey_info->filled) {
535 len += scnprintf(&buf[len], min_t(size_t, sizeof(buf) - len - 1, count),
536 "%d %03d %03d %d\n",
537 p_chan->center_freq,
538 p_survey_info->chan_time_ms,
539 p_survey_info->chan_time_busy_ms,
540 p_survey_info->noise_dbm);
541 } else {
542 len += scnprintf(&buf[len], min_t(size_t, sizeof(buf) -len -1, count),
543 "%d NOT AVAILABLE\n",
544 p_chan->center_freq);
545 }
546
547 survey_cnt++;
548 }
549 }
550
551 mutex_unlock(&priv->dbgdump.mutex);
552
553 size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
554 vfree(buf);
555
556 return size;
557}
558
559DEBUGFS_READ_FILE_OPS(acsinfo);
560
561static ssize_t rwnx_dbgfs_fw_dbg_read(struct file *file,
562 char __user *user_buf,
563 size_t count, loff_t *ppos)
564{
565 char help[] = "usage: [MOD:<ALL|KE|DBG|IPC|DMA|MM|TX|RX|PHY>]* "
566 "[DBG:<NONE|CRT|ERR|WRN|INF|VRB>]\n";
567
568 return simple_read_from_buffer(user_buf, count, ppos, help, sizeof(help));
569}
570
571
572static ssize_t rwnx_dbgfs_fw_dbg_write(struct file *file,
573 const char __user *user_buf,
574 size_t count, loff_t *ppos)
575{
576 struct rwnx_hw *priv = file->private_data;
577 char buf[32];
578 int idx = 0;
579 u32 mod = 0;
580 size_t len = min_t(size_t, count, sizeof(buf) - 1);
581
582 if (copy_from_user(buf, user_buf, len))
583 return -EFAULT;
584 buf[len] = '\0';
585
586#define RWNX_MOD_TOKEN(str, val) \
587 do { \
588 if (strncmp(&buf[idx], str, sizeof(str) - 1) == 0) { \
589 idx += sizeof(str) - 1; \
590 mod |= val; \
591 continue; \
592 } \
593 } while (0)
594
595#define RWNX_DBG_TOKEN(str, val) \
596 do { \
597 if (strncmp(&buf[idx], str, sizeof(str) - 1) == 0) { \
598 idx += sizeof(str) - 1; \
599 dbg = val; \
600 goto dbg_done; \
601 } \
602 } while (0)
603
604 while ((idx + 4) < len) {
605 if (strncmp(&buf[idx], "MOD:", 4) == 0) {
606 idx += 4;
607 RWNX_MOD_TOKEN("ALL", 0xffffffff);
608 RWNX_MOD_TOKEN("KE", BIT(0));
609 RWNX_MOD_TOKEN("DBG", BIT(1));
610 RWNX_MOD_TOKEN("IPC", BIT(2));
611 RWNX_MOD_TOKEN("DMA", BIT(3));
612 RWNX_MOD_TOKEN("MM", BIT(4));
613 RWNX_MOD_TOKEN("TX", BIT(5));
614 RWNX_MOD_TOKEN("RX", BIT(6));
615 RWNX_MOD_TOKEN("PHY", BIT(7));
616 idx++;
617 } else if (strncmp(&buf[idx], "DBG:", 4) == 0) {
618 u32 dbg = 0;
619 idx += 4;
620 RWNX_DBG_TOKEN("NONE", 0);
621 RWNX_DBG_TOKEN("CRT", 1);
622 RWNX_DBG_TOKEN("ERR", 2);
623 RWNX_DBG_TOKEN("WRN", 3);
624 RWNX_DBG_TOKEN("INF", 4);
625 RWNX_DBG_TOKEN("VRB", 5);
626 idx++;
627 continue;
628 dbg_done:
629 rwnx_send_dbg_set_sev_filter_req(priv, dbg);
630 } else {
631 idx++;
632 }
633 }
634
635 if (mod) {
636 rwnx_send_dbg_set_mod_filter_req(priv, mod);
637 }
638
639 return count;
640}
641
642DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg);
643
644static ssize_t rwnx_dbgfs_sys_stats_read(struct file *file,
645 char __user *user_buf,
646 size_t count, loff_t *ppos)
647{
648 struct rwnx_hw *priv = file->private_data;
649 char buf[3*64];
650 int len = 0;
651 ssize_t read;
652 int error = 0;
653 struct dbg_get_sys_stat_cfm cfm;
654 u32 sleep_int, sleep_frac, doze_int, doze_frac;
655
656 RWNX_DBG(RWNX_FN_ENTRY_STR);
657
658 /* Get the information from the FW */
659 error = rwnx_send_dbg_get_sys_stat_req(priv, &cfm);
660 if (error)
661 return error;
662
663 if (cfm.stats_time == 0)
664 return 0;
665
666 sleep_int = ((cfm.cpu_sleep_time * 100) / cfm.stats_time);
667 sleep_frac = (((cfm.cpu_sleep_time * 100) % cfm.stats_time) * 10) / cfm.stats_time;
668 doze_int = ((cfm.doze_time * 100) / cfm.stats_time);
669 doze_frac = (((cfm.doze_time * 100) % cfm.stats_time) * 10) / cfm.stats_time;
670
671 len += scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
672 "\nSystem statistics:\n");
673 len += scnprintf(&buf[len], min_t(size_t, sizeof(buf) - 1, count),
674 " CPU sleep [%%]: %d.%d\n", sleep_int, sleep_frac);
675 len += scnprintf(&buf[len], min_t(size_t, sizeof(buf) - 1, count),
676 " Doze [%%]: %d.%d\n", doze_int, doze_frac);
677
678 read = simple_read_from_buffer(user_buf, count, ppos, buf, len);
679
680 return read;
681}
682
683DEBUGFS_READ_FILE_OPS(sys_stats);
684
685#ifdef CONFIG_RWNX_MUMIMO_TX
686static ssize_t rwnx_dbgfs_mu_group_read(struct file *file,
687 char __user *user_buf,
688 size_t count, loff_t *ppos)
689{
690 struct rwnx_hw *rwnx_hw = file->private_data;
691 struct rwnx_mu_info *mu = &rwnx_hw->mu;
692 struct rwnx_mu_group *group;
693 size_t bufsz = NX_MU_GROUP_MAX * sizeof("xx = (xx - xx - xx - xx)\n") + 50;
694 char *buf;
695 int j, res, idx = 0;
696
697 if (*ppos)
698 return 0;
699
700 buf = kmalloc(bufsz, GFP_ATOMIC);
701 if (buf == NULL)
702 return 0;
703
704 res = scnprintf(&buf[idx], bufsz, "MU Group list (%d groups, %d users max)\n",
705 NX_MU_GROUP_MAX, CONFIG_USER_MAX);
706 idx += res;
707 bufsz -= res;
708
709 list_for_each_entry(group, &mu->active_groups, list) {
710 if (group->user_cnt) {
711 res = scnprintf(&buf[idx], bufsz, "%2d = (", group->group_id);
712 idx += res;
713 bufsz -= res;
714 for (j = 0; j < (CONFIG_USER_MAX - 1) ; j++) {
715 if (group->users[j])
716 res = scnprintf(&buf[idx], bufsz, "%2d - ",
717 group->users[j]->sta_idx);
718 else
719 res = scnprintf(&buf[idx], bufsz, ".. - ");
720
721 idx += res;
722 bufsz -= res;
723 }
724
725 if (group->users[j])
726 res = scnprintf(&buf[idx], bufsz, "%2d)\n",
727 group->users[j]->sta_idx);
728 else
729 res = scnprintf(&buf[idx], bufsz, "..)\n");
730
731 idx += res;
732 bufsz -= res;
733 }
734 }
735
736 res = simple_read_from_buffer(user_buf, count, ppos, buf, idx);
737 kfree(buf);
738
739 return res;
740}
741
742DEBUGFS_READ_FILE_OPS(mu_group);
743#endif
744
745#ifdef CONFIG_RWNX_P2P_DEBUGFS
746static ssize_t rwnx_dbgfs_oppps_write(struct file *file,
747 const char __user *user_buf,
748 size_t count, loff_t *ppos)
749{
750 struct rwnx_hw *rw_hw = file->private_data;
751 struct rwnx_vif *rw_vif;
752 char buf[32];
753 size_t len = min_t(size_t, count, sizeof(buf) - 1);
754 int ctw;
755
756 if (copy_from_user(buf, user_buf, len))
757 return -EFAULT;
758 buf[len] = '\0';
759
760 /* Read the written CT Window (provided in ms) value */
761 if (sscanf(buf, "ctw=%d", &ctw) > 0) {
762 /* Check if at least one VIF is configured as P2P GO */
763 list_for_each_entry(rw_vif, &rw_hw->vifs, list) {
764#ifdef CONFIG_RWNX_FULLMAC
765 if (RWNX_VIF_TYPE(rw_vif) == NL80211_IFTYPE_P2P_GO) {
766#endif /* CONFIG_RWNX_FULLMAC */
767 struct mm_set_p2p_oppps_cfm cfm;
768
769 /* Forward request to the embedded and wait for confirmation */
770 rwnx_send_p2p_oppps_req(rw_hw, rw_vif, (u8)ctw, &cfm);
771
772 break;
773 }
774 }
775 }
776
777 return count;
778}
779
780DEBUGFS_WRITE_FILE_OPS(oppps);
781
782static ssize_t rwnx_dbgfs_noa_write(struct file *file,
783 const char __user *user_buf,
784 size_t count, loff_t *ppos)
785{
786 struct rwnx_hw *rw_hw = file->private_data;
787 struct rwnx_vif *rw_vif;
788 char buf[64];
789 size_t len = min_t(size_t, count, sizeof(buf) - 1);
790 int noa_count, interval, duration, dyn_noa;
791
792 if (copy_from_user(buf, user_buf, len))
793 return -EFAULT;
794 buf[len] = '\0';
795
796 /* Read the written NOA information */
797 if (sscanf(buf, "count=%d interval=%d duration=%d dyn=%d",
798 &noa_count, &interval, &duration, &dyn_noa) > 0) {
799 /* Check if at least one VIF is configured as P2P GO */
800 list_for_each_entry(rw_vif, &rw_hw->vifs, list) {
801#ifdef CONFIG_RWNX_FULLMAC
802 if (RWNX_VIF_TYPE(rw_vif) == NL80211_IFTYPE_P2P_GO) {
803#endif /* CONFIG_RWNX_FULLMAC */
804 struct mm_set_p2p_noa_cfm cfm;
805
806 /* Forward request to the embedded and wait for confirmation */
807 rwnx_send_p2p_noa_req(rw_hw, rw_vif, noa_count, interval,
808 duration, (dyn_noa > 0), &cfm);
809
810 break;
811 }
812 }
813 }
814
815 return count;
816}
817
818DEBUGFS_WRITE_FILE_OPS(noa);
819#endif /* CONFIG_RWNX_P2P_DEBUGFS */
820
821static char fw_log_buffer[FW_LOG_SIZE];
822
823static ssize_t rwnx_dbgfs_fw_log_read(struct file *file,
824 char __user *user_buf,
825 size_t count, loff_t *ppos)
826{
827 struct rwnx_hw *priv = file->private_data;
828 size_t not_cpy;
829 size_t nb_cpy;
830 char *log = fw_log_buffer;
831
832 printk("%s, %d, %p, %p\n", __func__, priv->debugfs.fw_log.buf.size, priv->debugfs.fw_log.buf.start, priv->debugfs.fw_log.buf.dataend);
833 //spin_lock_bh(&priv->debugfs.fw_log.lock);
834
835 if ((priv->debugfs.fw_log.buf.start + priv->debugfs.fw_log.buf.size) >= priv->debugfs.fw_log.buf.dataend) {
836 memcpy(log, priv->debugfs.fw_log.buf.start, priv->debugfs.fw_log.buf.dataend - priv->debugfs.fw_log.buf.start);
837 not_cpy = copy_to_user(user_buf, log, priv->debugfs.fw_log.buf.dataend - priv->debugfs.fw_log.buf.start);
838 nb_cpy = priv->debugfs.fw_log.buf.dataend - priv->debugfs.fw_log.buf.start - not_cpy;
839 priv->debugfs.fw_log.buf.start = priv->debugfs.fw_log.buf.data;
840 } else {
841 memcpy(log, priv->debugfs.fw_log.buf.start, priv->debugfs.fw_log.buf.size);
842 not_cpy = copy_to_user(user_buf, log, priv->debugfs.fw_log.buf.size);
843 nb_cpy = priv->debugfs.fw_log.buf.size - not_cpy;
844 priv->debugfs.fw_log.buf.start = priv->debugfs.fw_log.buf.start + priv->debugfs.fw_log.buf.size - not_cpy;
845 }
846
847 priv->debugfs.fw_log.buf.size -= nb_cpy;
848 //spin_unlock_bh(&priv->debugfs.fw_log.lock);
849
850 printk("nb_cpy=%lu, not_cpy=%lu, start=%p, end=%p\n", (long unsigned int)nb_cpy, (long unsigned int)not_cpy, priv->debugfs.fw_log.buf.start, priv->debugfs.fw_log.buf.end);
851 return nb_cpy;
852}
853
854static ssize_t rwnx_dbgfs_fw_log_write(struct file *file,
855 const char __user *user_buf,
856 size_t count, loff_t *ppos)
857{
858 //struct rwnx_hw *priv = file->private_data;
859
860 printk("%s\n", __func__);
861 return count;
862}
863DEBUGFS_READ_WRITE_FILE_OPS(fw_log);
864
865#ifdef CONFIG_RWNX_RADAR
866static ssize_t rwnx_dbgfs_pulses_read(struct file *file,
867 char __user *user_buf,
868 size_t count, loff_t *ppos,
869 int rd_idx)
870{
871 struct rwnx_hw *priv = file->private_data;
872 char *buf;
873 int len = 0;
874 int bufsz;
875 int i;
876 int index;
877 struct rwnx_radar_pulses *p = &priv->radar.pulses[rd_idx];
878 ssize_t read;
879
880 if (*ppos != 0)
881 return 0;
882
883 /* Prevent from interrupt preemption */
884 spin_lock_bh(&priv->radar.lock);
885 bufsz = p->count * 34 + 51;
886 bufsz += rwnx_radar_dump_pattern_detector(NULL, 0, &priv->radar, rd_idx);
887 buf = kmalloc(bufsz, GFP_ATOMIC);
888 if (buf == NULL) {
889 spin_unlock_bh(&priv->radar.lock);
890 return 0;
891 }
892
893 if (p->count) {
894 len += scnprintf(&buf[len], bufsz - len,
895 " PRI WIDTH FOM FREQ\n");
896 index = p->index;
897 for (i = 0; i < p->count; i++) {
898 struct radar_pulse *pulse;
899
900 if (index > 0)
901 index--;
902 else
903 index = RWNX_RADAR_PULSE_MAX - 1;
904
905 pulse = (struct radar_pulse *) &p->buffer[index];
906
907 len += scnprintf(&buf[len], bufsz - len,
908 "%05dus %03dus %2d%% %+3dMHz\n", pulse->rep,
909 2 * pulse->len, 6 * pulse->fom, 2*pulse->freq);
910 }
911 }
912
913 len += rwnx_radar_dump_pattern_detector(&buf[len], bufsz - len,
914 &priv->radar, rd_idx);
915
916 spin_unlock_bh(&priv->radar.lock);
917
918 read = simple_read_from_buffer(user_buf, count, ppos, buf, len);
919
920 kfree(buf);
921
922 return read;
923}
924
925static ssize_t rwnx_dbgfs_pulses_prim_read(struct file *file,
926 char __user *user_buf,
927 size_t count, loff_t *ppos)
928{
929 return rwnx_dbgfs_pulses_read(file, user_buf, count, ppos, 0);
930}
931
932DEBUGFS_READ_FILE_OPS(pulses_prim);
933
934static ssize_t rwnx_dbgfs_pulses_sec_read(struct file *file,
935 char __user *user_buf,
936 size_t count, loff_t *ppos)
937{
938 return rwnx_dbgfs_pulses_read(file, user_buf, count, ppos, 1);
939}
940
941DEBUGFS_READ_FILE_OPS(pulses_sec);
942
943static ssize_t rwnx_dbgfs_detected_read(struct file *file,
944 char __user *user_buf,
945 size_t count, loff_t *ppos)
946{
947 struct rwnx_hw *priv = file->private_data;
948 char *buf;
949 int bufsz, len = 0;
950 ssize_t read;
951
952 if (*ppos != 0)
953 return 0;
954
955 bufsz = 5; // RIU:\n
956 bufsz += rwnx_radar_dump_radar_detected(NULL, 0, &priv->radar,
957 RWNX_RADAR_RIU);
958
959 if (priv->phy.cnt > 1) {
960 bufsz += 5; // FCU:\n
961 bufsz += rwnx_radar_dump_radar_detected(NULL, 0, &priv->radar,
962 RWNX_RADAR_FCU);
963 }
964
965 buf = kmalloc(bufsz, GFP_KERNEL);
966 if (buf == NULL) {
967 return 0;
968 }
969
970 len = scnprintf(&buf[len], bufsz, "RIU:\n");
971 len += rwnx_radar_dump_radar_detected(&buf[len], bufsz - len, &priv->radar,
972 RWNX_RADAR_RIU);
973
974 if (priv->phy.cnt > 1) {
975 len += scnprintf(&buf[len], bufsz - len, "FCU:\n");
976 len += rwnx_radar_dump_radar_detected(&buf[len], bufsz - len,
977 &priv->radar, RWNX_RADAR_FCU);
978 }
979
980 read = simple_read_from_buffer(user_buf, count, ppos, buf, len);
981
982 kfree(buf);
983
984 return read;
985}
986
987DEBUGFS_READ_FILE_OPS(detected);
988
989static ssize_t rwnx_dbgfs_enable_read(struct file *file,
990 char __user *user_buf,
991 size_t count, loff_t *ppos)
992{
993 struct rwnx_hw *priv = file->private_data;
994 char buf[32];
995 int ret;
996 ssize_t read;
997
998 ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
999 "RIU=%d FCU=%d\n", priv->radar.dpd[RWNX_RADAR_RIU]->enabled,
1000 priv->radar.dpd[RWNX_RADAR_FCU]->enabled);
1001
1002 read = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1003
1004 return read;
1005}
1006
1007static ssize_t rwnx_dbgfs_enable_write(struct file *file,
1008 const char __user *user_buf,
1009 size_t count, loff_t *ppos)
1010{
1011 struct rwnx_hw *priv = file->private_data;
1012 char buf[32];
1013 int val;
1014 size_t len = min_t(size_t, count, sizeof(buf) - 1);
1015
1016 if (copy_from_user(buf, user_buf, len))
1017 return -EFAULT;
1018
1019 buf[len] = '\0';
1020
1021 if (sscanf(buf, "RIU=%d", &val) > 0)
1022 rwnx_radar_detection_enable(&priv->radar, val, RWNX_RADAR_RIU);
1023
1024 if (sscanf(buf, "FCU=%d", &val) > 0)
1025 rwnx_radar_detection_enable(&priv->radar, val, RWNX_RADAR_FCU);
1026
1027 return count;
1028}
1029
1030DEBUGFS_READ_WRITE_FILE_OPS(enable);
1031
1032static ssize_t rwnx_dbgfs_band_read(struct file *file,
1033 char __user *user_buf,
1034 size_t count, loff_t *ppos)
1035{
1036 struct rwnx_hw *priv = file->private_data;
1037 char buf[32];
1038 int ret;
1039 ssize_t read;
1040
1041 ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
1042 "BAND=%d\n", priv->phy.sec_chan.band);
1043
1044 read = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1045
1046 return read;
1047}
1048
1049static ssize_t rwnx_dbgfs_band_write(struct file *file,
1050 const char __user *user_buf,
1051 size_t count, loff_t *ppos)
1052{
1053 struct rwnx_hw *priv = file->private_data;
1054 char buf[32];
1055 int val;
1056 size_t len = min_t(size_t, count, sizeof(buf) - 1);
1057 int band_max = NL80211_BAND_5GHZ;
1058
1059 if (priv->band_5g_support)
1060 band_max = NL80211_BAND_5GHZ + 1;
1061
1062 if (copy_from_user(buf, user_buf, len))
1063 return -EFAULT;
1064
1065 buf[len] = '\0';
1066
1067 if ((sscanf(buf, "%d", &val) > 0) && (val >= 0) && (val < band_max))
1068 priv->phy.sec_chan.band = val;
1069
1070 return count;
1071}
1072
1073DEBUGFS_READ_WRITE_FILE_OPS(band);
1074
1075static ssize_t rwnx_dbgfs_type_read(struct file *file,
1076 char __user *user_buf,
1077 size_t count, loff_t *ppos)
1078{
1079 struct rwnx_hw *priv = file->private_data;
1080 char buf[32];
1081 int ret;
1082 ssize_t read;
1083
1084 ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
1085 "TYPE=%d\n", priv->phy.sec_chan.type);
1086
1087 read = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1088
1089 return read;
1090}
1091
1092static ssize_t rwnx_dbgfs_type_write(struct file *file,
1093 const char __user *user_buf,
1094 size_t count, loff_t *ppos)
1095{
1096 struct rwnx_hw *priv = file->private_data;
1097 char buf[32];
1098 int val;
1099 size_t len = min_t(size_t, count, sizeof(buf) - 1);
1100
1101 if (copy_from_user(buf, user_buf, len))
1102 return -EFAULT;
1103
1104 buf[len] = '\0';
1105
1106 if ((sscanf(buf, "%d", &val) > 0) && (val >= PHY_CHNL_BW_20) &&
1107 (val <= PHY_CHNL_BW_80P80))
1108 priv->phy.sec_chan.type = val;
1109
1110 return count;
1111}
1112
1113DEBUGFS_READ_WRITE_FILE_OPS(type);
1114
1115static ssize_t rwnx_dbgfs_prim20_read(struct file *file,
1116 char __user *user_buf,
1117 size_t count, loff_t *ppos)
1118{
1119 struct rwnx_hw *priv = file->private_data;
1120 char buf[32];
1121 int ret;
1122 ssize_t read;
1123
1124 ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
1125 "PRIM20=%dMHz\n", priv->phy.sec_chan.prim20_freq);
1126
1127 read = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1128
1129 return read;
1130}
1131
1132static ssize_t rwnx_dbgfs_prim20_write(struct file *file,
1133 const char __user *user_buf,
1134 size_t count, loff_t *ppos)
1135{
1136 struct rwnx_hw *priv = file->private_data;
1137 char buf[32];
1138 int val;
1139 size_t len = min_t(size_t, count, sizeof(buf) - 1);
1140
1141 if (copy_from_user(buf, user_buf, len))
1142 return -EFAULT;
1143
1144 buf[len] = '\0';
1145
1146 if (sscanf(buf, "%d", &val) > 0)
1147 priv->phy.sec_chan.prim20_freq = val;
1148
1149 return count;
1150}
1151
1152DEBUGFS_READ_WRITE_FILE_OPS(prim20);
1153
1154static ssize_t rwnx_dbgfs_center1_read(struct file *file,
1155 char __user *user_buf,
1156 size_t count, loff_t *ppos)
1157{
1158 struct rwnx_hw *priv = file->private_data;
1159 char buf[32];
1160 int ret;
1161 ssize_t read;
1162
1163 ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
1164 "CENTER1=%dMHz\n", priv->phy.sec_chan.center_freq1);
1165
1166 read = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1167
1168 return read;
1169}
1170
1171static ssize_t rwnx_dbgfs_center1_write(struct file *file,
1172 const char __user *user_buf,
1173 size_t count, loff_t *ppos)
1174{
1175 struct rwnx_hw *priv = file->private_data;
1176 char buf[32];
1177 int val;
1178 size_t len = min_t(size_t, count, sizeof(buf) - 1);
1179
1180 if (copy_from_user(buf, user_buf, len))
1181 return -EFAULT;
1182
1183 buf[len] = '\0';
1184
1185 if (sscanf(buf, "%d", &val) > 0)
1186 priv->phy.sec_chan.center_freq1 = val;
1187
1188 return count;
1189}
1190
1191DEBUGFS_READ_WRITE_FILE_OPS(center1);
1192
1193static ssize_t rwnx_dbgfs_center2_read(struct file *file,
1194 char __user *user_buf,
1195 size_t count, loff_t *ppos)
1196{
1197 struct rwnx_hw *priv = file->private_data;
1198 char buf[32];
1199 int ret;
1200 ssize_t read;
1201
1202 ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
1203 "CENTER2=%dMHz\n", priv->phy.sec_chan.center_freq2);
1204
1205 read = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1206
1207 return read;
1208}
1209
1210static ssize_t rwnx_dbgfs_center2_write(struct file *file,
1211 const char __user *user_buf,
1212 size_t count, loff_t *ppos)
1213{
1214 struct rwnx_hw *priv = file->private_data;
1215 char buf[32];
1216 int val;
1217 size_t len = min_t(size_t, count, sizeof(buf) - 1);
1218
1219 if (copy_from_user(buf, user_buf, len))
1220 return -EFAULT;
1221
1222 buf[len] = '\0';
1223
1224 if (sscanf(buf, "%d", &val) > 0)
1225 priv->phy.sec_chan.center_freq2 = val;
1226
1227 return count;
1228}
1229
1230DEBUGFS_READ_WRITE_FILE_OPS(center2);
1231
1232
1233static ssize_t rwnx_dbgfs_set_read(struct file *file,
1234 char __user *user_buf,
1235 size_t count, loff_t *ppos)
1236{
1237 return 0;
1238}
1239
1240static ssize_t rwnx_dbgfs_set_write(struct file *file,
1241 const char __user *user_buf,
1242 size_t count, loff_t *ppos)
1243{
1244 struct rwnx_hw *priv = file->private_data;
1245
1246 rwnx_send_set_channel(priv, 1, NULL);
1247 rwnx_radar_detection_enable(&priv->radar, RWNX_RADAR_DETECT_ENABLE,
1248 RWNX_RADAR_FCU);
1249
1250 return count;
1251}
1252
1253DEBUGFS_READ_WRITE_FILE_OPS(set);
1254#endif /* CONFIG_RWNX_RADAR */
1255
1256static ssize_t rwnx_dbgfs_regdbg_write(struct file *file,
1257 const char __user *user_buf,
1258 size_t count, loff_t *ppos)
1259{
1260 struct rwnx_hw *priv = file->private_data;
1261 char buf[32];
1262 u32 addr,val, oper;
1263 size_t len = min_t(size_t, count, sizeof(buf) - 1);
1264 struct dbg_mem_read_cfm mem_read_cfm;
1265 int ret;
1266
1267 if (copy_from_user(buf, user_buf, len))
1268 return -EFAULT;
1269
1270 buf[len] = '\0';
1271
1272 if (sscanf(buf, "%x %x %x" , &oper, &addr, &val ) > 0)
1273 printk("addr=%x, val=%x,oper=%d\n", addr, val, oper);
1274
1275 if(oper== 0) {
1276 ret = rwnx_send_dbg_mem_read_req(priv, addr, &mem_read_cfm);
1277 printk("[0x%x] = [0x%x]\n", mem_read_cfm.memaddr, mem_read_cfm.memdata);
1278 } else if (oper == 1) {
1279 ret = rwnx_send_dbg_mem_read_req(priv, addr, &mem_read_cfm);
1280 printk("before write : [0x%x] = [0x%x]\n", mem_read_cfm.memaddr, mem_read_cfm.memdata);
1281 ret = rwnx_send_dbg_mem_block_write_req(priv, addr, 4, &val);
1282 ret = rwnx_send_dbg_mem_read_req(priv, addr, &mem_read_cfm);
1283 printk("after write : [0x%x] = [0x%x]\n", mem_read_cfm.memaddr, mem_read_cfm.memdata);
1284 }
1285
1286 return count;
1287}
1288
1289DEBUGFS_WRITE_FILE_OPS(regdbg);
1290
1291static ssize_t rwnx_dbgfs_vendor_hwconfig_write(struct file *file,
1292 const char __user *user_buf,
1293 size_t count, loff_t *ppos)
1294{
1295 struct rwnx_hw *priv = file->private_data;
1296 char buf[64];
1297 int32_t addr[14];
1298 int32_t addr_out[12];
1299 u32_l hwconfig_id;
1300 size_t len = min_t(size_t,count,sizeof(buf)-1);
1301 int ret;
1302 printk("%s\n",__func__);
1303 //choose the type of write info by struct
1304 //struct mm_set_vendor_trx_param_req trx_param;
1305
1306 if(copy_from_user(buf,user_buf,len)) {
1307 return -EFAULT;
1308 }
1309
1310 buf[len] = '\0';
1311 ret = sscanf(buf, "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
1312 &hwconfig_id, &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5], &addr[6], &addr[7], &addr[8], &addr[9], &addr[10], &addr[11], &addr[12], &addr[13]);
1313 if(ret > 15) {
1314 printk("param error > 15\n");
1315 } else {
1316 switch(hwconfig_id)
1317 {
1318 case 0:
1319 if(ret != 5) {
1320 printk("param error != 5\n");
1321 break;}
1322 ret = rwnx_send_vendor_hwconfig_req(priv, hwconfig_id, addr, NULL);
1323 printk("ACS_TXOP_REQ bk:0x%x be:0x%x vi:0x%x vo:0x%x\n",addr[0], addr[1], addr[2], addr[3]);
1324 break;
1325 case 1:
1326 if(ret != 15) {
1327 printk("param error != 15\n");
1328 break;}
1329 ret = rwnx_send_vendor_hwconfig_req(priv, hwconfig_id, addr, NULL);
1330 printk("CHANNEL_ACCESS_REQ edca:%x,%x,%x,%x, vif:%x, retry_cnt:%x, rts:%x, long_nav:%x, cfe:%x, rc_retry_cnt:%x:%x:%x ccademod_th %x remove_1m2m %x\n",
1331 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13]);
1332 break;
1333 case 2:
1334 if(ret != 7) {
1335 printk("param error != 7\n");
1336 break;}
1337 ret = rwnx_send_vendor_hwconfig_req(priv, hwconfig_id, addr, NULL);
1338 printk("MAC_TIMESCALE_REQ sifsA:%x,sifsB:%x,slot:%x,ofdm_delay:%x,long_delay:%x,short_delay:%x\n",
1339 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
1340 break;
1341 case 3:
1342 if(ret != 6) {
1343 printk("param error != 6\n");
1344 break;}
1345 addr[1] = ~addr[1] + 1;
1346 addr[2] = ~addr[2] + 1;
1347 addr[3] = ~addr[3] + 1;
1348 addr[4] = ~addr[4] + 1;
1349 ret = rwnx_send_vendor_hwconfig_req(priv, hwconfig_id, addr, NULL);
1350 printk("CCA_THRESHOLD_REQ auto_cca:%d, cca20p_rise:%d cca20s_rise:%d cca20p_fail:%d cca20s_fail:%d\n",
1351 addr[0], addr[1], addr[2], addr[3], addr[4]);
1352 break;
1353 case 4: // BWMODE_REQ
1354 if (ret != 2) {
1355 printk("param error != 2\n");
1356 } else {
1357 ret = rwnx_send_vendor_hwconfig_req(priv, hwconfig_id, addr, NULL);
1358 printk("BWMODE_REQ md=%d\n", addr[0]);
1359 }
1360 break;
1361 case 5: // CHIP_TEMP_GET_REQ
1362 if (ret != 1) {
1363 printk("param error != 1\n");
1364 } else {
1365 ret = rwnx_send_vendor_hwconfig_req(priv, hwconfig_id, addr, addr_out);
1366 printk("CHIP_TEMP_GET_REQ degree=%d\n", addr_out[0]);
1367 }
1368 break;
1369 default:
1370 printk("param error\n");
1371 break;
1372 }
1373 if(ret) {
1374 printk("rwnx_send_vendor_hwconfig_req fail: %x\n", ret);
1375 }
1376 }
1377
1378 return count;
1379}
1380
1381DEBUGFS_WRITE_FILE_OPS(vendor_hwconfig);
1382
1383static ssize_t rwnx_dbgfs_vendor_swconfig_write(struct file *file,
1384 const char __user *user_buf,
1385 size_t count, loff_t *ppos)
1386{
1387 struct rwnx_hw *priv = file->private_data;
1388 char buf[64];
1389 int32_t addr[12];
1390 int32_t addr_out[12];
1391 u32_l swconfig_id;
1392 size_t len = min_t(size_t, count, sizeof(buf) - 1);
1393 int ret;
1394 printk("%s\n", __func__);
1395
1396 if (copy_from_user(buf, user_buf, len)) {
1397 return -EFAULT;
1398 }
1399
1400 buf[len] = '\0';
1401 ret = sscanf(buf, "%x %x %x", &swconfig_id, &addr[0], &addr[1]);
1402 if (ret > 3) {
1403 printk("param error > 3\n");
1404 } else {
1405 switch (swconfig_id)
1406 {
1407 case 0: // BCN_CFG_REQ
1408 if (ret != 2) {
1409 printk("param error != 2\n");
1410 } else {
1411 ret = rwnx_send_vendor_swconfig_req(priv, swconfig_id, addr, addr_out);
1412 printk("BCN_CFG_REQ set_en=%d, get_en=%d\n", addr[0], addr_out[0]);
1413 }
1414 break;
1415
1416 case 1: // TEMP_COMP_SET_REQ
1417 if (ret != 3) {
1418 printk("param error != 3\n");
1419 } else {
1420 ret = rwnx_send_vendor_swconfig_req(priv, swconfig_id, addr, addr_out);
1421 printk("TEMP_COMP_SET_REQ set_en=%d, tmr=%dms, get_st=%d\n",
1422 addr[0], addr[1], addr_out[0]);
1423 }
1424 break;
1425
1426 case 2: // TEMP_COMP_GET_REQ
1427 if (ret != 1) {
1428 printk("param error != 1\n");
1429 } else {
1430 ret = rwnx_send_vendor_swconfig_req(priv, swconfig_id, addr, addr_out);
1431 printk("TEMP_COMP_GET_REQ get_st=%d, degree=%d\n", addr_out[0], addr_out[1]);
1432 }
1433 break;
1434
1435 case 3: // EXT_FLAGS_SET_REQ
1436 if (ret != 2) {
1437 printk("param error != 2\n");
1438 } else {
1439 ret = rwnx_send_vendor_swconfig_req(priv, swconfig_id, addr, addr_out);
1440 printk("EXT_FLAGS_SET_REQ set ext_flags=0x%x, get ext_flags=0x%x\n",
1441 addr[0], addr_out[0]);
1442 }
1443 break;
1444
1445 case 4: // EXT_FLAGS_GET_REQ
1446 if (ret != 1) {
1447 printk("param error != 1\n");
1448 } else {
1449 ret = rwnx_send_vendor_swconfig_req(priv, swconfig_id, addr, addr_out);
1450 printk("EXT_FLAGS_GET_REQ get ext_flags=0x%x\n", addr_out[0]);
1451 }
1452 break;
1453
1454 case 5: // EXT_FLAGS_MASK_SET_REQ
1455 if (ret != 3) {
1456 printk("param error != 3\n");
1457 } else {
1458 ret = rwnx_send_vendor_swconfig_req(priv, swconfig_id, addr, addr_out);
1459 printk("EXT_FLAGS_MASK_SET_REQ set ext_flags mask=0x%x, val=0x%x, get ext_flags=0x%x\n",
1460 addr[0], addr[1], addr_out[0]);
1461 }
1462 break;
1463
1464 default:
1465 printk("param error\n");
1466 break;
1467 }
1468
1469 if (ret) {
1470 printk("rwnx_send_vendor_swconfig_req fail: %x\n", ret);
1471 }
1472 }
1473
1474 return count;
1475}
1476
1477DEBUGFS_WRITE_FILE_OPS(vendor_swconfig);
1478
1479static ssize_t rwnx_dbgfs_agg_disable_write(struct file *file,
1480 const char __user *user_buf,
1481 size_t count, loff_t *ppos)
1482{
1483 struct rwnx_hw *priv = file->private_data;
1484 char buf[64];
1485 int agg_disable, agg_disable_rx, sta_idx;
1486 size_t len = min_t(size_t, count, sizeof(buf) - 1);
1487 int ret;
1488 printk("%s\n", __func__);
1489
1490 if (copy_from_user(buf, user_buf, len)) {
1491 return -EFAULT;
1492 }
1493
1494 buf[len] = '\0';
1495 ret = sscanf(buf, "%d %d %d", &agg_disable, &agg_disable_rx, &sta_idx);
1496 if ((ret > 3) || (ret < 2)) {
1497 printk("param error: cnt=%d\n", ret);
1498 } else {
1499 if (ret < 3) {
1500 sta_idx = RWNX_INVALID_STA;
1501 }
1502 printk("disable_agg: T=%d, R=%d, staidx=%d\n", agg_disable, agg_disable_rx, sta_idx);
1503 ret = rwnx_send_disable_agg_req(priv, (u8_l)agg_disable, (u8_l)agg_disable_rx, (u8_l)sta_idx);
1504 if (ret) {
1505 printk("rwnx_send_disable_agg_req fail: %d\n", ret);
1506 }
1507 }
1508
1509 return count;
1510}
1511
1512DEBUGFS_WRITE_FILE_OPS(agg_disable);
1513
1514static ssize_t rwnx_dbgfs_set_roc_write(struct file *file,
1515 const char __user *user_buf,
1516 size_t count, loff_t *ppos)
1517{
1518 struct rwnx_hw *priv = file->private_data;
1519 struct rwnx_vif *vif = NULL;
1520 char buf[64];
1521 int roc_start, chan_freq, duration;
1522 size_t len = min_t(size_t, count, sizeof(buf) - 1);
1523 int ret;
1524 int if_type = NL80211_IFTYPE_STATION;
1525 printk("%s\n", __func__);
1526
1527 if (copy_from_user(buf, user_buf, len)) {
1528 return -EFAULT;
1529 }
1530
1531 buf[len] = '\0';
1532 ret = sscanf(buf, "%d %d %d", &roc_start, &chan_freq, &duration);
1533
1534 list_for_each_entry(vif, &priv->vifs, list) {
1535 if (RWNX_VIF_TYPE(vif) == if_type) {
1536 break;
1537 }
1538 }
1539 if ((ret > 3) || (ret < 1)) {
1540 printk("param error: cnt=%d\n", ret);
1541 } else if (vif) {
1542 struct ieee80211_channel chan_entry = {0,};
1543 struct ieee80211_channel *chan = &chan_entry;
1544 struct mm_remain_on_channel_cfm roc_cfm;
1545 if (ret < 3) {
1546 duration = 2000;
1547 if (ret < 2) {
1548 chan_freq = 2412;
1549 }
1550 }
1551 printk("set_roc: start=%d, freq=%d\n", roc_start, chan_freq);
1552 if (roc_start) {
1553 if (chan_freq <= 2484) {
1554 chan->band = NL80211_BAND_2GHZ;
1555 } else {
1556 chan->band = NL80211_BAND_5GHZ;
1557 }
1558 chan->center_freq = chan_freq;
1559 chan->max_power = 18;
1560 ret = rwnx_send_roc(priv, vif, chan, duration, &roc_cfm);
1561 if (ret) {
1562 printk("rwnx_send_roc fail: %d\n", ret);
1563 } else {
1564 printk("roc_cfm: opcode=%x, st=%d, idx=%d\n", roc_cfm.op_code, roc_cfm.status, roc_cfm.chan_ctxt_index);
1565 }
1566 } else {
1567 ret = rwnx_send_cancel_roc(priv);
1568 if (ret) {
1569 printk("rwnx_send_cancel_roc fail: %d\n", ret);
1570 }
1571 }
1572 }
1573
1574 return count;
1575}
1576
1577DEBUGFS_WRITE_FILE_OPS(set_roc);
1578
1579#ifdef CONFIG_RWNX_FULLMAC
1580
1581#define LINE_MAX_SZ 150
1582
1583struct st {
1584 char line[LINE_MAX_SZ + 1];
1585 unsigned int r_idx;
1586};
1587
1588static int compare_idx(const void *st1, const void *st2)
1589{
1590 int index1 = ((struct st *)st1)->r_idx;
1591 int index2 = ((struct st *)st2)->r_idx;
1592
1593 if (index1 > index2)
1594 return 1;
1595 if (index1 < index2)
1596 return -1;
1597
1598 return 0;
1599}
1600
1601static const int ru_size[] = {
1602 26,
1603 52,
1604 106,
1605 242,
1606 484,
1607 996
1608};
1609
1610static int print_rate(char *buf, int size, int format, int nss, int mcs, int bw,
1611 int sgi, int pre, int *r_idx)
1612{
1613 int res = 0;
1614 int bitrates_cck[4] = { 10, 20, 55, 110 };
1615 int bitrates_ofdm[8] = { 6, 9, 12, 18, 24, 36, 48, 54};
1616 char he_gi[3][4] = {"0.8", "1.6", "3.2"};
1617
1618 if (format < FORMATMOD_HT_MF) {
1619 if (mcs < 4) {
1620 if (r_idx) {
1621 *r_idx = (mcs * 2) + pre;
1622 res = scnprintf(buf, size - res, "%3d ", *r_idx);
1623 }
1624 res += scnprintf(&buf[res], size - res, "L-CCK/%cP %2u.%1uM ",
1625 pre > 0 ? 'L' : 'S',
1626 bitrates_cck[mcs] / 10,
1627 bitrates_cck[mcs] % 10);
1628 } else {
1629 mcs -= 4;
1630 if (r_idx) {
1631 *r_idx = N_CCK + mcs;
1632 res = scnprintf(buf, size - res, "%3d ", *r_idx);
1633 }
1634 res += scnprintf(&buf[res], size - res, "L-OFDM %2u.0M ",
1635 bitrates_ofdm[mcs]);
1636 }
1637 } else if (format < FORMATMOD_VHT) {
1638 if (r_idx) {
1639 *r_idx = N_CCK + N_OFDM + nss * 32 + mcs * 4 + bw * 2 + sgi;
1640 res = scnprintf(buf, size - res, "%3d ", *r_idx);
1641 }
1642 mcs += nss * 8;
1643 res += scnprintf(&buf[res], size - res, "HT%d/%cGI MCS%-2d ",
1644 20 * (1 << bw), sgi ? 'S' : 'L', mcs);
1645 } else if (format == FORMATMOD_VHT) {
1646 if (r_idx) {
1647 *r_idx = N_CCK + N_OFDM + N_HT + nss * 80 + mcs * 8 + bw * 2 + sgi;
1648 res = scnprintf(buf, size - res, "%3d ", *r_idx);
1649 }
1650 res += scnprintf(&buf[res], size - res, "VHT%d/%cGI%*cMCS%d/%1d ",
1651 20 * (1 << bw), sgi ? 'S' : 'L', bw > 2 ? 5 : 6, ' ',
1652 mcs, nss + 1);
1653 } else if (format == FORMATMOD_HE_SU) {
1654 if (r_idx) {
1655 *r_idx = N_CCK + N_OFDM + N_HT + N_VHT + nss * 144 + mcs * 12 + bw * 3 + sgi;
1656 res = scnprintf(buf, size - res, "%3d ", *r_idx);
1657 }
1658 res += scnprintf(&buf[res], size - res, "HE%d/GI%s%*cMCS%d/%1d%*c",
1659 20 * (1 << bw), he_gi[sgi], bw > 2 ? 4 : 5, ' ',
1660 mcs, nss + 1, mcs > 9 ? 1 : 2, ' ');
1661 } else {
1662 if (r_idx) {
1663 *r_idx = N_CCK + N_OFDM + N_HT + N_VHT + N_HE_SU + nss * 216 + mcs * 18 + bw * 3 + sgi;
1664 res = scnprintf(buf, size - res, "%3d ", *r_idx);
1665 }
1666 res += scnprintf(&buf[res], size - res, "HEMU-%d/GI%s%*cMCS%d/%1d%*c",
1667 ru_size[bw], he_gi[sgi], bw > 1 ? 1 : 2, ' ',
1668 mcs, nss + 1, mcs > 9 ? 1 : 2, ' ');
1669
1670 }
1671
1672 return res;
1673}
1674
1675static int print_rate_from_cfg(char *buf, int size, u32 rate_config, int *r_idx, int ru_size)
1676{
1677 union rwnx_rate_ctrl_info *r_cfg = (union rwnx_rate_ctrl_info *)&rate_config;
1678 union rwnx_mcs_index *mcs_index = (union rwnx_mcs_index *)&rate_config;
1679 unsigned int ft, pre, gi, bw, nss, mcs, len;
1680
1681 ft = r_cfg->formatModTx;
1682 pre = r_cfg->giAndPreTypeTx >> 1;
1683 gi = r_cfg->giAndPreTypeTx;
1684 bw = r_cfg->bwTx;
1685 if (ft == FORMATMOD_HE_MU) {
1686 mcs = mcs_index->he.mcs;
1687 nss = mcs_index->he.nss;
1688 bw = ru_size;
1689 } else if (ft == FORMATMOD_HE_SU) {
1690 mcs = mcs_index->he.mcs;
1691 nss = mcs_index->he.nss;
1692 } else if (ft == FORMATMOD_VHT) {
1693 mcs = mcs_index->vht.mcs;
1694 nss = mcs_index->vht.nss;
1695 } else if (ft >= FORMATMOD_HT_MF) {
1696 mcs = mcs_index->ht.mcs;
1697 nss = mcs_index->ht.nss;
1698 } else {
1699 mcs = mcs_index->legacy;
1700 nss = 0;
1701 }
1702
1703 len = print_rate(buf, size, ft, nss, mcs, bw, gi, pre, r_idx);
1704 return len;
1705}
1706
1707static void idx_to_rate_cfg(int idx, union rwnx_rate_ctrl_info *r_cfg, int *ru_size)
1708{
1709 r_cfg->value = 0;
1710 if (idx < N_CCK) {
1711 r_cfg->formatModTx = FORMATMOD_NON_HT;
1712 r_cfg->giAndPreTypeTx = (idx & 1) << 1;
1713 r_cfg->mcsIndexTx = idx / 2;
1714 } else if (idx < (N_CCK + N_OFDM)) {
1715 r_cfg->formatModTx = FORMATMOD_NON_HT;
1716 r_cfg->mcsIndexTx = idx - N_CCK + 4;
1717 } else if (idx < (N_CCK + N_OFDM + N_HT)) {
1718 union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg;
1719
1720 idx -= (N_CCK + N_OFDM);
1721 r_cfg->formatModTx = FORMATMOD_HT_MF;
1722 r->ht.nss = idx / (8*2*2);
1723 r->ht.mcs = (idx % (8*2*2)) / (2*2);
1724 r_cfg->bwTx = ((idx % (8*2*2)) % (2*2)) / 2;
1725 r_cfg->giAndPreTypeTx = idx & 1;
1726 } else if (idx < (N_CCK + N_OFDM + N_HT + N_VHT)) {
1727 union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg;
1728
1729 idx -= (N_CCK + N_OFDM + N_HT);
1730 r_cfg->formatModTx = FORMATMOD_VHT;
1731 r->vht.nss = idx / (10*4*2);
1732 r->vht.mcs = (idx % (10*4*2)) / (4*2);
1733 r_cfg->bwTx = ((idx % (10*4*2)) % (4*2)) / 2;
1734 r_cfg->giAndPreTypeTx = idx & 1;
1735 } else if (idx < (N_CCK + N_OFDM + N_HT + N_VHT + N_HE_SU)) {
1736 union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg;
1737
1738 idx -= (N_CCK + N_OFDM + N_HT + N_VHT);
1739 r_cfg->formatModTx = FORMATMOD_HE_SU;
1740 r->vht.nss = idx / (12*4*3);
1741 r->vht.mcs = (idx % (12*4*3)) / (4*3);
1742 r_cfg->bwTx = ((idx % (12*4*3)) % (4*3)) / 3;
1743 r_cfg->giAndPreTypeTx = idx % 3;
1744 } else {
1745 union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg;
1746
1747 BUG_ON(ru_size == NULL);
1748
1749 idx -= (N_CCK + N_OFDM + N_HT + N_VHT + N_HE_SU);
1750 r_cfg->formatModTx = FORMATMOD_HE_MU;
1751 r->vht.nss = idx / (12*6*3);
1752 r->vht.mcs = (idx % (12*6*3)) / (6*3);
1753 *ru_size = ((idx % (12*6*3)) % (6*3)) / 3;
1754 r_cfg->giAndPreTypeTx = idx % 3;
1755 r_cfg->bwTx = 0;
1756 }
1757}
1758
1759static void idx_to_rate_cfg1(unsigned int formatmod,
1760 unsigned int mcs,unsigned int nss,
1761 unsigned int bwTx,unsigned int gi,
1762 union rwnx_rate_ctrl_info *r_cfg, int *ru_size)
1763{
1764 r_cfg->value = 0;
1765
1766 switch(formatmod){
1767 case FORMATMOD_NON_HT:
1768 {
1769 r_cfg->formatModTx = formatmod;
1770 r_cfg->giAndPreTypeTx = 1;
1771 r_cfg->mcsIndexTx = mcs;
1772 break;
1773 }
1774 case FORMATMOD_NON_HT_DUP_OFDM:
1775 {
1776 r_cfg->formatModTx = formatmod;
1777 r_cfg->giAndPreTypeTx = gi;
1778 r_cfg->mcsIndexTx = mcs;
1779 break;
1780 }
1781 case FORMATMOD_HT_MF:
1782 {
1783 union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg;
1784
1785 r_cfg->formatModTx = formatmod;
1786 r->ht.nss = nss;
1787 r->ht.mcs = mcs;
1788 r_cfg->bwTx = bwTx;
1789 r_cfg->giAndPreTypeTx = gi;
1790 break;
1791 }
1792 case FORMATMOD_VHT:
1793 case FORMATMOD_HE_SU:
1794 {
1795 union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg;
1796
1797 r_cfg->formatModTx = formatmod;
1798 r->vht.nss = nss;
1799 r->vht.mcs = mcs;
1800 r_cfg->bwTx = bwTx;
1801 r_cfg->giAndPreTypeTx = gi;
1802 break;
1803 }
1804 case FORMATMOD_HE_MU:
1805 {
1806 union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg;
1807
1808 r_cfg->formatModTx = formatmod;
1809 r->he.nss = nss;
1810 r->he.mcs = mcs;
1811 r_cfg->bwTx = 0;
1812 r_cfg->giAndPreTypeTx = gi;
1813 break;
1814 }
1815 default:
1816 printk("Don't have the formatmod");
1817 }
1818}
1819
1820static ssize_t rwnx_dbgfs_rc_stats_read(struct file *file,
1821 char __user *user_buf,
1822 size_t count, loff_t *ppos)
1823{
1824 struct rwnx_sta *sta = NULL;
1825 struct rwnx_hw *priv = file->private_data;
1826 char *buf;
1827 int bufsz, len = 0;
1828 ssize_t read;
1829 int i = 0;
1830 int error = 0;
1831 struct me_rc_stats_cfm me_rc_stats_cfm;
1832 unsigned int no_samples;
1833 struct st *st;
1834 u8 mac[6];
1835
1836 RWNX_DBG(RWNX_FN_ENTRY_STR);
1837
1838 /* everything should fit in one call */
1839 if (*ppos)
1840 return 0;
1841
1842 /* Get the station index from MAC address */
1843 sscanf(file->f_path.dentry->d_parent->d_iname, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
1844 &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
1845 //if (mac == NULL)
1846 // return 0;
1847 sta = rwnx_get_sta(priv, mac);
1848 if (sta == NULL)
1849 return 0;
1850
1851 /* Forward the information to the LMAC */
1852 error = rwnx_send_me_rc_stats(priv, sta->sta_idx, &me_rc_stats_cfm);
1853 if (error)
1854 return error;
1855
1856 no_samples = me_rc_stats_cfm.no_samples;
1857 if (no_samples == 0)
1858 return 0;
1859
1860 bufsz = no_samples * LINE_MAX_SZ + 500;
1861
1862 buf = kmalloc(bufsz + 1, GFP_ATOMIC);
1863 if (buf == NULL)
1864 return 0;
1865
1866 st = kmalloc(sizeof(struct st) * no_samples, GFP_ATOMIC);
1867 if (st == NULL) {
1868 kfree(buf);
1869 return 0;
1870 }
1871
1872 for (i = 0; i < no_samples; i++) {
1873 unsigned int tp, eprob;
1874 len = print_rate_from_cfg(st[i].line, LINE_MAX_SZ,
1875 me_rc_stats_cfm.rate_stats[i].rate_config,
1876 &st[i].r_idx, 0);
1877
1878 if (me_rc_stats_cfm.sw_retry_step != 0) {
1879 len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len, "%c",
1880 me_rc_stats_cfm.retry_step_idx[me_rc_stats_cfm.sw_retry_step] == i ? '*' : ' ');
1881 } else {
1882 len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len, " ");
1883 }
1884 len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len, "%c",
1885 me_rc_stats_cfm.retry_step_idx[0] == i ? 'T' : ' ');
1886 len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len, "%c",
1887 me_rc_stats_cfm.retry_step_idx[1] == i ? 't' : ' ');
1888 len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len, "%c ",
1889 me_rc_stats_cfm.retry_step_idx[2] == i ? 'P' : ' ');
1890
1891 tp = me_rc_stats_cfm.tp[i] / 10;
1892 len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len, " %4u.%1u",
1893 tp / 10, tp % 10);
1894
1895 eprob = ((me_rc_stats_cfm.rate_stats[i].probability * 1000) >> 16) + 1;
1896 len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len,
1897 " %4u.%1u %5u(%6u) %6u",
1898 eprob / 10, eprob % 10,
1899 me_rc_stats_cfm.rate_stats[i].success,
1900 me_rc_stats_cfm.rate_stats[i].attempts,
1901 me_rc_stats_cfm.rate_stats[i].sample_skipped);
1902 }
1903 len = scnprintf(buf, bufsz,
1904 "\nTX rate info for %02X:%02X:%02X:%02X:%02X:%02X:\n",
1905 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
1906
1907 len += scnprintf(&buf[len], bufsz - len,
1908 " # type rate tpt eprob ok( tot) skipped\n");
1909
1910 // add sorted statistics to the buffer
1911 sort(st, no_samples, sizeof(st[0]), compare_idx, NULL);
1912 for (i = 0; i < no_samples; i++) {
1913 len += scnprintf(&buf[len], bufsz - len, "%s\n", st[i].line);
1914 }
1915
1916 // display HE TB statistics if any
1917 if (me_rc_stats_cfm.rate_stats[RC_HE_STATS_IDX].rate_config != 0) {
1918 unsigned int tp, eprob;
1919 struct rc_rate_stats *rate_stats = &me_rc_stats_cfm.rate_stats[RC_HE_STATS_IDX];
1920 int ru_index = rate_stats->ru_and_length & 0x07;
1921 int ul_length = rate_stats->ru_and_length >> 3;
1922
1923 len += scnprintf(&buf[len], bufsz - len,
1924 "\nHE TB rate info:\n");
1925
1926 len += scnprintf(&buf[len], bufsz - len,
1927 " type rate tpt eprob ok( tot) ul_length\n ");
1928 len += print_rate_from_cfg(&buf[len], bufsz - len, rate_stats->rate_config,
1929 NULL, ru_index);
1930
1931 tp = me_rc_stats_cfm.tp[RC_HE_STATS_IDX] / 10;
1932 len += scnprintf(&buf[len], bufsz - len, " %4u.%1u",
1933 tp / 10, tp % 10);
1934
1935 eprob = ((rate_stats->probability * 1000) >> 16) + 1;
1936 len += scnprintf(&buf[len], bufsz - len,
1937 " %4u.%1u %5u(%6u) %6u\n",
1938 eprob / 10, eprob % 10,
1939 rate_stats->success,
1940 rate_stats->attempts,
1941 ul_length);
1942 }
1943
1944 len += scnprintf(&buf[len], bufsz - len, "\n MPDUs AMPDUs AvLen trialP");
1945 len += scnprintf(&buf[len], bufsz - len, "\n%6u %6u %3d.%1d %6u\n",
1946 me_rc_stats_cfm.ampdu_len,
1947 me_rc_stats_cfm.ampdu_packets,
1948 me_rc_stats_cfm.avg_ampdu_len >> 16,
1949 ((me_rc_stats_cfm.avg_ampdu_len * 10) >> 16) % 10,
1950 me_rc_stats_cfm.sample_wait);
1951
1952 read = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1953
1954 kfree(buf);
1955 kfree(st);
1956
1957 return read;
1958}
1959
1960DEBUGFS_READ_FILE_OPS(rc_stats);
1961
1962static ssize_t rwnx_dbgfs_rc_fixed_rate_idx_write(struct file *file,
1963 const char __user *user_buf,
1964 size_t count, loff_t *ppos)
1965{
1966 struct rwnx_sta *sta = NULL;
1967 struct rwnx_hw *priv = file->private_data;
1968 u8 mac[6];
1969 char buf[20];
1970 int fixed_rate_idx = 1;
1971 unsigned int formatmod, mcs, nss, bwTx, gi;
1972 union rwnx_rate_ctrl_info rate_config;
1973 union rwnx_rate_ctrl_info *r_cfg=&rate_config;
1974 int error = 0;
1975 size_t len = min_t(size_t, count, sizeof(buf) - 1);
1976
1977 RWNX_DBG(RWNX_FN_ENTRY_STR);
1978
1979 /* Get the station index from MAC address */
1980 sscanf(file->f_path.dentry->d_parent->d_iname, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
1981 &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
1982 if (mac == NULL)
1983 return 0;
1984 sta = rwnx_get_sta(priv, mac);
1985 if (sta == NULL)
1986 return 0;
1987
1988 /* Get the content of the file */
1989 if (copy_from_user(buf, user_buf, len))
1990 return -EFAULT;
1991 buf[len] = '\0';
1992 //sscanf(buf, "%i\n", &fixed_rate_idx);
1993 sscanf(buf, "%u %u %u %u %u",&formatmod, &mcs, &nss, &bwTx, &gi);
1994 printk("%u %u %u %u %u\n",formatmod, mcs, nss, bwTx, gi);
1995
1996 if((formatmod > 6) || (mcs > 11) || (nss > 8) || (bwTx > 6) || (gi > 3)){
1997 printk("error parameter");
1998 return len;
1999 }
2000
2001 /* Convert rate index into rate configuration */
2002 if ((fixed_rate_idx < 0) || (fixed_rate_idx >= (N_CCK + N_OFDM + N_HT + N_VHT + N_HE_SU)))
2003 {
2004 // disable fixed rate
2005 rate_config.value = (u32)-1;
2006 }
2007 else
2008 {
2009 //idx_to_rate_cfg(fixed_rate_idx, &rate_config, NULL);
2010 idx_to_rate_cfg1(formatmod, mcs, nss, bwTx, gi, &rate_config, NULL);
2011 }
2012
2013 printk("formatModTx=%u mcsIndexTx=%u bwTx=%u giAndPreTypeTx=%u\n",r_cfg->formatModTx,r_cfg->mcsIndexTx,r_cfg->bwTx,r_cfg->giAndPreTypeTx);
2014 // Forward the request to the LMAC
2015 if ((error = rwnx_send_me_rc_set_rate(priv, sta->sta_idx,
2016 (u16)rate_config.value)) != 0)
2017 {
2018 return error;
2019 }
2020
2021 printk("send success \n");
2022 priv->debugfs.rc_config[sta->sta_idx] = (int)rate_config.value;
2023 return len;
2024
2025}
2026
2027DEBUGFS_WRITE_FILE_OPS(rc_fixed_rate_idx);
2028
2029static ssize_t rwnx_dbgfs_last_rx_read(struct file *file,
2030 char __user *user_buf,
2031 size_t count, loff_t *ppos)
2032{
2033 struct rwnx_sta *sta = NULL;
2034 struct rwnx_hw *priv = file->private_data;
2035 struct rwnx_rx_rate_stats *rate_stats;
2036 char *buf;
2037 int bufsz, i, len = 0;
2038 ssize_t read;
2039 unsigned int fmt, pre, bw, nss, mcs, gi;
2040 u8 mac[6];
2041 struct rx_vector_1 *last_rx;
2042 char hist[] = "##################################################";
2043 int hist_len = sizeof(hist) - 1;
2044 u8 nrx;
2045
2046 RWNX_DBG(RWNX_FN_ENTRY_STR);
2047
2048 /* everything should fit in one call */
2049 if (*ppos)
2050 return 0;
2051
2052 /* Get the station index from MAC address */
2053 sscanf(file->f_path.dentry->d_parent->d_iname, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
2054 &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
2055// if (mac == NULL)
2056// return 0;
2057 sta = rwnx_get_sta(priv, mac);
2058 if (sta == NULL)
2059 return 0;
2060
2061 rate_stats = &sta->stats.rx_rate;
2062 bufsz = (rate_stats->rate_cnt * (50 + hist_len) + 200);
2063 buf = kmalloc(bufsz + 1, GFP_ATOMIC);
2064 if (buf == NULL)
2065 return 0;
2066
2067 // Get number of RX paths
2068 nrx = (priv->version_cfm.version_phy_1 & MDM_NRX_MASK) >> MDM_NRX_LSB;
2069
2070 len += scnprintf(buf, bufsz,
2071 "\nRX rate info for %02X:%02X:%02X:%02X:%02X:%02X:\n",
2072 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
2073
2074 // Display Statistics
2075 for (i = 0; i < rate_stats->size; i++) {
2076 if (rate_stats->table[i]) {
2077 union rwnx_rate_ctrl_info rate_config;
2078 int percent = (rate_stats->table[i] * 1000) / rate_stats->cpt;
2079 int p;
2080 int ru_size = 0;
2081
2082 idx_to_rate_cfg(i, &rate_config, &ru_size);
2083 len += print_rate_from_cfg(&buf[len], bufsz - len,
2084 rate_config.value, NULL, ru_size);
2085 p = (percent * hist_len) / 1000;
2086 len += scnprintf(&buf[len], bufsz - len, ": %6d(%3d.%1d%%)%.*s\n",
2087 rate_stats->table[i],
2088 percent / 10, percent % 10, p, hist);
2089 }
2090 }
2091
2092 // Display detailed info of the last received rate
2093 last_rx = &sta->stats.last_rx.rx_vect1;
2094
2095 len += scnprintf(&buf[len], bufsz - len, "\nLast received rate\n"
2096 " type rate LDPC STBC BEAMFM DCM DOPPLER %s\n",
2097 (nrx > 1) ? "rssi1(dBm) rssi2(dBm)" : "rssi(dBm)");
2098
2099 fmt = last_rx->format_mod;
2100 bw = last_rx->ch_bw;
2101 pre = last_rx->pre_type;
2102 if (fmt >= FORMATMOD_HE_SU) {
2103 mcs = last_rx->he.mcs;
2104 nss = last_rx->he.nss;
2105 gi = last_rx->he.gi_type;
2106 if (fmt == FORMATMOD_HE_MU)
2107 bw = last_rx->he.ru_size;
2108 } else if (fmt == FORMATMOD_VHT) {
2109 mcs = last_rx->vht.mcs;
2110 nss = last_rx->vht.nss;
2111 gi = last_rx->vht.short_gi;
2112 } else if (fmt >= FORMATMOD_HT_MF) {
2113 mcs = last_rx->ht.mcs % 8;
2114 nss = last_rx->ht.mcs / 8;;
2115 gi = last_rx->ht.short_gi;
2116 } else {
2117 BUG_ON((mcs = legrates_lut[last_rx->leg_rate].idx) == -1);
2118 nss = 0;
2119 gi = 0;
2120 }
2121
2122 len += print_rate(&buf[len], bufsz - len, fmt, nss, mcs, bw, gi, pre, NULL);
2123
2124 /* flags for HT/VHT/HE */
2125 if (fmt >= FORMATMOD_HE_SU) {
2126 len += scnprintf(&buf[len], bufsz - len, " %c %c %c %c %c",
2127 last_rx->he.fec ? 'L' : ' ',
2128 last_rx->he.stbc ? 'S' : ' ',
2129 last_rx->he.beamformed ? 'B' : ' ',
2130 last_rx->he.dcm ? 'D' : ' ',
2131 last_rx->he.doppler ? 'D' : ' ');
2132 } else if (fmt == FORMATMOD_VHT) {
2133 len += scnprintf(&buf[len], bufsz - len, " %c %c %c ",
2134 last_rx->vht.fec ? 'L' : ' ',
2135 last_rx->vht.stbc ? 'S' : ' ',
2136 last_rx->vht.beamformed ? 'B' : ' ');
2137 } else if (fmt >= FORMATMOD_HT_MF) {
2138 len += scnprintf(&buf[len], bufsz - len, " %c %c ",
2139 last_rx->ht.fec ? 'L' : ' ',
2140 last_rx->ht.stbc ? 'S' : ' ');
2141 } else {
2142 len += scnprintf(&buf[len], bufsz - len, " ");
2143 }
2144 if (nrx > 1) {
2145 len += scnprintf(&buf[len], bufsz - len, " %-4d %d\n",
2146 last_rx->rssi1, last_rx->rssi1);
2147 } else {
2148 len += scnprintf(&buf[len], bufsz - len, " %d\n", last_rx->rssi1);
2149 }
2150
2151 read = simple_read_from_buffer(user_buf, count, ppos, buf, len);
2152
2153 kfree(buf);
2154 return read;
2155}
2156
2157static ssize_t rwnx_dbgfs_last_rx_write(struct file *file,
2158 const char __user *user_buf,
2159 size_t count, loff_t *ppos)
2160{
2161 struct rwnx_sta *sta = NULL;
2162 struct rwnx_hw *priv = file->private_data;
2163 u8 mac[6];
2164
2165 /* Get the station index from MAC address */
2166 sscanf(file->f_path.dentry->d_parent->d_iname, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
2167 &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
2168// if (mac == NULL)
2169// return 0;
2170 sta = rwnx_get_sta(priv, mac);
2171 if (sta == NULL)
2172 return 0;
2173
2174 /* Prevent from interrupt preemption as these statistics are updated under
2175 * interrupt */
2176 spin_lock_bh(&priv->tx_lock);
2177 memset(sta->stats.rx_rate.table, 0,
2178 sta->stats.rx_rate.size * sizeof(sta->stats.rx_rate.table[0]));
2179 sta->stats.rx_rate.cpt = 0;
2180 sta->stats.rx_rate.rate_cnt = 0;
2181 spin_unlock_bh(&priv->tx_lock);
2182
2183 return count;
2184}
2185
2186DEBUGFS_READ_WRITE_FILE_OPS(last_rx);
2187
2188#endif /* CONFIG_RWNX_FULLMAC */
2189
2190#ifdef CONFIG_RWNX_FULLMAC
2191static void rwnx_rc_stat_work(struct work_struct *ws)
2192{
2193 struct rwnx_debugfs *rwnx_debugfs = container_of(ws, struct rwnx_debugfs,
2194 rc_stat_work);
2195 struct rwnx_hw *rwnx_hw = container_of(rwnx_debugfs, struct rwnx_hw,
2196 debugfs);
2197 struct rwnx_sta *sta;
2198 uint8_t ridx, sta_idx;
2199
2200 ridx = rwnx_debugfs->rc_read;
2201 sta_idx = rwnx_debugfs->rc_sta[ridx];
2202 if (sta_idx > (NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX)) {
2203 WARN(1, "Invalid sta index %d", sta_idx);
2204 return;
2205 }
2206
2207 rwnx_debugfs->rc_sta[ridx] = 0xFF;
2208 ridx = (ridx + 1) % ARRAY_SIZE(rwnx_debugfs->rc_sta);
2209 rwnx_debugfs->rc_read = ridx;
2210 sta = &rwnx_hw->sta_table[sta_idx];
2211 if (!sta) {
2212 WARN(1, "Invalid sta %d", sta_idx);
2213 return;
2214 }
2215
2216 if (rwnx_debugfs->dir_sta[sta_idx] == NULL) {
2217 /* register the sta */
2218 struct dentry *dir_rc = rwnx_debugfs->dir_rc;
2219 struct dentry *dir_sta;
2220 struct dentry *file;
2221 char sta_name[18];
2222 struct rwnx_rx_rate_stats *rate_stats = &sta->stats.rx_rate;
2223 int nb_rx_rate = N_CCK + N_OFDM;
2224 struct rwnx_rc_config_save *rc_cfg, *next;
2225
2226 if (sta->sta_idx >= NX_REMOTE_STA_MAX) {
2227 scnprintf(sta_name, sizeof(sta_name), "bc_mc");
2228 } else {
2229 scnprintf(sta_name, sizeof(sta_name), "%pM", sta->mac_addr);
2230 }
2231
2232 dir_sta = debugfs_create_dir(sta_name, dir_rc);
2233 if (!dir_sta)
2234 goto error;
2235
2236 rwnx_debugfs->dir_sta[sta->sta_idx] = dir_sta;
2237
2238 file = debugfs_create_file("stats", S_IRUSR, dir_sta, rwnx_hw,
2239 &rwnx_dbgfs_rc_stats_ops);
2240 if (IS_ERR_OR_NULL(file))
2241 goto error_after_dir;
2242
2243 file = debugfs_create_file("fixed_rate_idx", S_IWUSR, dir_sta, rwnx_hw,
2244 &rwnx_dbgfs_rc_fixed_rate_idx_ops);
2245 if (IS_ERR_OR_NULL(file))
2246 goto error_after_dir;
2247
2248 file = debugfs_create_file("rx_rate", S_IRUSR | S_IWUSR, dir_sta, rwnx_hw,
2249 &rwnx_dbgfs_last_rx_ops);
2250 if (IS_ERR_OR_NULL(file))
2251 goto error_after_dir;
2252
2253 if (rwnx_hw->mod_params->ht_on)
2254 nb_rx_rate += N_HT;
2255
2256 if (rwnx_hw->mod_params->vht_on)
2257 nb_rx_rate += N_VHT;
2258
2259 if (rwnx_hw->mod_params->he_on)
2260 nb_rx_rate += N_HE_SU + N_HE_MU;
2261
2262 rate_stats->table = kzalloc(nb_rx_rate * sizeof(rate_stats->table[0]),
2263 GFP_KERNEL);
2264 if (!rate_stats->table)
2265 goto error_after_dir;
2266
2267 rate_stats->size = nb_rx_rate;
2268 rate_stats->cpt = 0;
2269 rate_stats->rate_cnt = 0;
2270
2271 /* By default enable rate contoller */
2272 rwnx_debugfs->rc_config[sta_idx] = -1;
2273
2274 /* Unless we already fix the rate for this station */
2275 list_for_each_entry_safe(rc_cfg, next, &rwnx_debugfs->rc_config_save, list) {
2276 if (jiffies_to_msecs(jiffies - rc_cfg->timestamp) > RC_CONFIG_DUR) {
2277 list_del(&rc_cfg->list);
2278 kfree(rc_cfg);
2279 } else if (!memcmp(rc_cfg->mac_addr, sta->mac_addr, ETH_ALEN)) {
2280 rwnx_debugfs->rc_config[sta_idx] = rc_cfg->rate;
2281 list_del(&rc_cfg->list);
2282 kfree(rc_cfg);
2283 break;
2284 }
2285 }
2286
2287 if ((rwnx_debugfs->rc_config[sta_idx] >= 0) &&
2288 rwnx_send_me_rc_set_rate(rwnx_hw, sta_idx,
2289 (u16)rwnx_debugfs->rc_config[sta_idx]))
2290 rwnx_debugfs->rc_config[sta_idx] = -1;
2291
2292 } else {
2293 /* unregister the sta */
2294 if (sta->stats.rx_rate.table) {
2295 kfree(sta->stats.rx_rate.table);
2296 sta->stats.rx_rate.table = NULL;
2297 }
2298 sta->stats.rx_rate.size = 0;
2299 sta->stats.rx_rate.cpt = 0;
2300 sta->stats.rx_rate.rate_cnt = 0;
2301
2302 /* If fix rate was set for this station, save the configuration in case
2303 we reconnect to this station within RC_CONFIG_DUR msec */
2304 if (rwnx_debugfs->rc_config[sta_idx] >= 0) {
2305 struct rwnx_rc_config_save *rc_cfg;
2306 rc_cfg = kmalloc(sizeof(*rc_cfg), GFP_KERNEL);
2307 if (rc_cfg) {
2308 rc_cfg->rate = rwnx_debugfs->rc_config[sta_idx];
2309 rc_cfg->timestamp = jiffies;
2310 memcpy(rc_cfg->mac_addr, sta->mac_addr, ETH_ALEN);
2311 list_add_tail(&rc_cfg->list, &rwnx_debugfs->rc_config_save);
2312 }
2313 }
2314
2315 debugfs_remove_recursive(rwnx_debugfs->dir_sta[sta_idx]);
2316 rwnx_debugfs->dir_sta[sta->sta_idx] = NULL;
2317 }
2318
2319 return;
2320
2321error_after_dir:
2322 debugfs_remove_recursive(rwnx_debugfs->dir_sta[sta_idx]);
2323 rwnx_debugfs->dir_sta[sta->sta_idx] = NULL;
2324error:
2325 dev_err(rwnx_hw->dev,
2326 "Error while (un)registering debug entry for sta %d\n", sta_idx);
2327}
2328
2329void _rwnx_dbgfs_rc_stat_write(struct rwnx_debugfs *rwnx_debugfs, uint8_t sta_idx)
2330{
2331 uint8_t widx = rwnx_debugfs->rc_write;
2332 if (rwnx_debugfs->rc_sta[widx] != 0XFF) {
2333 WARN(1, "Overlap in debugfs rc_sta table\n");
2334 }
2335
2336 if (rwnx_debugfs->unregistering)
2337 return;
2338
2339 rwnx_debugfs->rc_sta[widx] = sta_idx;
2340 widx = (widx + 1) % ARRAY_SIZE(rwnx_debugfs->rc_sta);
2341 rwnx_debugfs->rc_write = widx;
2342
2343 schedule_work(&rwnx_debugfs->rc_stat_work);
2344}
2345
2346void rwnx_dbgfs_register_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta)
2347{
2348 _rwnx_dbgfs_rc_stat_write(&rwnx_hw->debugfs, sta->sta_idx);
2349}
2350
2351void rwnx_dbgfs_unregister_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta)
2352{
2353 _rwnx_dbgfs_rc_stat_write(&rwnx_hw->debugfs, sta->sta_idx);
2354}
2355#endif /* CONFIG_RWNX_FULLMAC */
2356
2357int rwnx_dbgfs_register(struct rwnx_hw *rwnx_hw, const char *name)
2358{
2359#ifdef CONFIG_RWNX_FULLMAC
2360 struct dentry *phyd = rwnx_hw->wiphy->debugfsdir;
2361 struct dentry *dir_rc;
2362#endif /* CONFIG_RWNX_FULLMAC */
2363 struct rwnx_debugfs *rwnx_debugfs = &rwnx_hw->debugfs;
2364 struct dentry *dir_drv, *dir_diags;
2365
2366 RWNX_DBG(RWNX_FN_ENTRY_STR);
2367
2368 dir_drv = debugfs_create_dir(name, phyd);
2369 if (!dir_drv)
2370 return -ENOMEM;
2371
2372 rwnx_debugfs->dir = dir_drv;
2373 rwnx_debugfs->unregistering = false;
2374
2375 dir_diags = debugfs_create_dir("diags", dir_drv);
2376 if (!dir_diags)
2377 goto err;
2378
2379#ifdef CONFIG_RWNX_FULLMAC
2380 dir_rc = debugfs_create_dir("rc", dir_drv);
2381 if (!dir_rc)
2382 goto err;
2383 rwnx_debugfs->dir_rc = dir_rc;
2384 INIT_WORK(&rwnx_debugfs->rc_stat_work, rwnx_rc_stat_work);
2385 INIT_LIST_HEAD(&rwnx_debugfs->rc_config_save);
2386 rwnx_debugfs->rc_write = rwnx_debugfs->rc_read = 0;
2387 memset(rwnx_debugfs->rc_sta, 0xFF, sizeof(rwnx_debugfs->rc_sta));
2388#endif
2389
2390 DEBUGFS_ADD_U32(tcp_pacing_shift, dir_drv, &rwnx_hw->tcp_pacing_shift,
2391 S_IWUSR | S_IRUSR);
2392 DEBUGFS_ADD_FILE(stats, dir_drv, S_IWUSR | S_IRUSR);
2393 DEBUGFS_ADD_FILE(sys_stats, dir_drv, S_IRUSR);
2394 DEBUGFS_ADD_FILE(txq, dir_drv, S_IRUSR);
2395 DEBUGFS_ADD_FILE(acsinfo, dir_drv, S_IRUSR);
2396 DEBUGFS_ADD_FILE(debug, dir_drv, S_IWUSR);
2397#ifdef CONFIG_RWNX_MUMIMO_TX
2398 DEBUGFS_ADD_FILE(mu_group, dir_drv, S_IRUSR);
2399#endif
2400 DEBUGFS_ADD_FILE(regdbg, dir_drv, S_IWUSR);
2401 DEBUGFS_ADD_FILE(vendor_hwconfig, dir_drv,S_IWUSR);
2402 DEBUGFS_ADD_FILE(vendor_swconfig, dir_drv,S_IWUSR);
2403 DEBUGFS_ADD_FILE(agg_disable, dir_drv,S_IWUSR);
2404 DEBUGFS_ADD_FILE(set_roc, dir_drv,S_IWUSR);
2405
2406#ifdef CONFIG_RWNX_P2P_DEBUGFS
2407 {
2408 /* Create a p2p directory */
2409 struct dentry *dir_p2p;
2410 dir_p2p = debugfs_create_dir("p2p", dir_drv);
2411 if (!dir_p2p)
2412 goto err;
2413
2414 /* Add file allowing to control Opportunistic PS */
2415 DEBUGFS_ADD_FILE(oppps, dir_p2p, S_IRUSR);
2416 /* Add file allowing to control Notice of Absence */
2417 DEBUGFS_ADD_FILE(noa, dir_p2p, S_IRUSR);
2418 }
2419#endif /* CONFIG_RWNX_P2P_DEBUGFS */
2420
2421 if (rwnx_hw->fwlog_en) {
2422 rwnx_fw_log_init(&rwnx_hw->debugfs.fw_log);
2423 DEBUGFS_ADD_FILE(fw_log, dir_drv, S_IWUSR | S_IRUSR);
2424 }
2425#ifdef CONFIG_RWNX_RADAR
2426 {
2427 struct dentry *dir_radar, *dir_sec;
2428 dir_radar = debugfs_create_dir("radar", dir_drv);
2429 if (!dir_radar)
2430 goto err;
2431
2432 DEBUGFS_ADD_FILE(pulses_prim, dir_radar, S_IRUSR);
2433 DEBUGFS_ADD_FILE(detected, dir_radar, S_IRUSR);
2434 DEBUGFS_ADD_FILE(enable, dir_radar, S_IRUSR);
2435
2436 if (rwnx_hw->phy.cnt == 2) {
2437 DEBUGFS_ADD_FILE(pulses_sec, dir_radar, S_IRUSR);
2438
2439 dir_sec = debugfs_create_dir("sec", dir_radar);
2440 if (!dir_sec)
2441 goto err;
2442
2443 DEBUGFS_ADD_FILE(band, dir_sec, S_IWUSR | S_IRUSR);
2444 DEBUGFS_ADD_FILE(type, dir_sec, S_IWUSR | S_IRUSR);
2445 DEBUGFS_ADD_FILE(prim20, dir_sec, S_IWUSR | S_IRUSR);
2446 DEBUGFS_ADD_FILE(center1, dir_sec, S_IWUSR | S_IRUSR);
2447 DEBUGFS_ADD_FILE(center2, dir_sec, S_IWUSR | S_IRUSR);
2448 DEBUGFS_ADD_FILE(set, dir_sec, S_IWUSR | S_IRUSR);
2449 }
2450 }
2451#endif /* CONFIG_RWNX_RADAR */
2452 return 0;
2453
2454err:
2455 rwnx_dbgfs_unregister(rwnx_hw);
2456 return -ENOMEM;
2457}
2458
2459void rwnx_dbgfs_unregister(struct rwnx_hw *rwnx_hw)
2460{
2461 struct rwnx_debugfs *rwnx_debugfs = &rwnx_hw->debugfs;
2462#ifdef CONFIG_RWNX_FULLMAC
2463 struct rwnx_rc_config_save *cfg, *next;
2464#endif
2465
2466#ifdef CONFIG_RWNX_FULLMAC
2467 list_for_each_entry_safe(cfg, next, &rwnx_debugfs->rc_config_save, list) {
2468 list_del(&cfg->list);
2469 kfree(cfg);
2470 }
2471#endif /* CONFIG_RWNX_FULLMAC */
2472
2473 if (rwnx_hw->fwlog_en)
2474 rwnx_fw_log_deinit(&rwnx_hw->debugfs.fw_log);
2475
2476 if (!rwnx_hw->debugfs.dir)
2477 return;
2478
2479 rwnx_debugfs->unregistering = true;
2480#ifdef CONFIG_RWNX_FULLMAC
2481 flush_work(&rwnx_debugfs->rc_stat_work);
2482#endif
2483 debugfs_remove_recursive(rwnx_hw->debugfs.dir);
2484 rwnx_hw->debugfs.dir = NULL;
2485}
2486
2487#endif /* CONFIG_DEBUG_FS */
2488