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