net:wireless:Support eswin usb wifi ECR6600U
[platform/kernel/linux-starfive.git] / drivers / net / wireless / eswin / ecrnx_fw_dump.c
1 /**
2  ******************************************************************************
3  *
4  * @file ecrnx_fw_dump.c
5  *
6  * @brief Definition of debug fs entries to process fw dump
7  *
8  * Copyright (C) ESWIN 2015-2020
9  *
10  ******************************************************************************
11  */
12
13
14 #include <linux/kmod.h>
15 #include <linux/debugfs.h>
16
17 #include "ecrnx_defs.h"
18 #include "ecrnx_debugfs.h"
19
20 static ssize_t ecrnx_dbgfs_rhd_read(struct file *file,
21                                    char __user *user_buf,
22                                    size_t count, loff_t *ppos)
23 {
24     struct ecrnx_hw *priv = file->private_data;
25     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
26     ssize_t read;
27
28     mutex_lock(&priv->dbgdump_elem.mutex);
29     if (!priv->debugfs.trace_prst) {
30         mutex_unlock(&priv->dbgdump_elem.mutex);
31         return 0;
32     }
33
34     read = simple_read_from_buffer(user_buf, count, ppos,
35                                    dump->rhd_mem,
36                                    dump->dbg_info.rhd_len);
37
38     mutex_unlock(&priv->dbgdump_elem.mutex);
39     return read;
40 }
41
42 DEBUGFS_READ_FILE_OPS(rhd);
43
44 static ssize_t ecrnx_dbgfs_rbd_read(struct file *file,
45                                    char __user *user_buf,
46                                    size_t count, loff_t *ppos)
47 {
48     struct ecrnx_hw *priv = file->private_data;
49     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
50     ssize_t read;
51
52     mutex_lock(&priv->dbgdump_elem.mutex);
53     if (!priv->debugfs.trace_prst) {
54         mutex_unlock(&priv->dbgdump_elem.mutex);
55         return 0;
56     }
57
58     read = simple_read_from_buffer(user_buf, count, ppos,
59                                    dump->rbd_mem,
60                                    dump->dbg_info.rbd_len);
61
62     mutex_unlock(&priv->dbgdump_elem.mutex);
63     return read;
64 }
65
66 DEBUGFS_READ_FILE_OPS(rbd);
67
68 static ssize_t ecrnx_dbgfs_thdx_read(struct file *file, char __user *user_buf,
69                                     size_t count, loff_t *ppos, int idx)
70 {
71     struct ecrnx_hw *priv = file->private_data;
72     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
73     ssize_t read;
74
75     mutex_lock(&priv->dbgdump_elem.mutex);
76     if (!priv->debugfs.trace_prst) {
77         mutex_unlock(&priv->dbgdump_elem.mutex);
78         return 0;
79     }
80
81     read = simple_read_from_buffer(user_buf, count, ppos,
82                                    &dump->thd_mem[idx],
83                                    dump->dbg_info.thd_len[idx]);
84
85     mutex_unlock(&priv->dbgdump_elem.mutex);
86     return read;
87 }
88
89 static ssize_t ecrnx_dbgfs_thd0_read(struct file *file,
90                                     char __user *user_buf,
91                                     size_t count, loff_t *ppos)
92 {
93     return ecrnx_dbgfs_thdx_read(file, user_buf, count, ppos, 0);
94 }
95 DEBUGFS_READ_FILE_OPS(thd0);
96
97 static ssize_t ecrnx_dbgfs_thd1_read(struct file *file,
98                                     char __user *user_buf,
99                                     size_t count, loff_t *ppos)
100 {
101     return ecrnx_dbgfs_thdx_read(file, user_buf, count, ppos, 1);
102 }
103 DEBUGFS_READ_FILE_OPS(thd1);
104
105 static ssize_t ecrnx_dbgfs_thd2_read(struct file *file,
106                                     char __user *user_buf,
107                                     size_t count, loff_t *ppos)
108 {
109     return ecrnx_dbgfs_thdx_read(file, user_buf, count, ppos, 2);
110 }
111 DEBUGFS_READ_FILE_OPS(thd2);
112
113 static ssize_t ecrnx_dbgfs_thd3_read(struct file *file,
114                                     char __user *user_buf,
115                                     size_t count, loff_t *ppos)
116 {
117     return ecrnx_dbgfs_thdx_read(file, user_buf, count, ppos, 3);
118 }
119 DEBUGFS_READ_FILE_OPS(thd3);
120
121 #if (NX_TXQ_CNT == 5)
122 static ssize_t ecrnx_dbgfs_thd4_read(struct file *file,
123                                     char __user *user_buf,
124                                     size_t count, loff_t *ppos)
125 {
126     return ecrnx_dbgfs_thdx_read(file, user_buf, count, ppos, 4);
127 }
128 DEBUGFS_READ_FILE_OPS(thd4);
129 #endif
130
131 static ssize_t ecrnx_dbgfs_mactrace_read(struct file *file,
132                                         char __user *user_buf,
133                                         size_t count, loff_t *ppos)
134 {
135     struct ecrnx_hw *priv = file->private_data;
136     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
137     ssize_t read;
138
139     mutex_lock(&priv->dbgdump_elem.mutex);
140     if (!priv->debugfs.trace_prst) {
141         char msg[64];
142         mutex_unlock(&priv->dbgdump_elem.mutex);
143         scnprintf(msg, sizeof(msg), "Force trigger\n");
144         ecrnx_dbgfs_trigger_fw_dump(priv, msg);
145
146         return 0;
147     }
148
149     read = simple_read_from_buffer(user_buf, count, ppos,
150                                   dump->la_mem,
151                                   dump->dbg_info.la_conf.trace_len);
152
153     mutex_unlock(&priv->dbgdump_elem.mutex);
154
155     return read;
156 }
157 DEBUGFS_READ_FILE_OPS(mactrace);
158
159 static ssize_t ecrnx_dbgfs_macdiags_read(struct file *file,
160                                         char __user *user_buf,
161                                         size_t count, loff_t *ppos)
162 {
163     struct ecrnx_hw *priv = file->private_data;
164     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
165     ssize_t read;
166
167     mutex_lock(&priv->dbgdump_elem.mutex);
168     if (!priv->debugfs.trace_prst) {
169         mutex_unlock(&priv->dbgdump_elem.mutex);
170         return 0;
171     }
172
173     read = simple_read_from_buffer(user_buf, count, ppos,
174                                    dump->dbg_info.diags_mac,
175                                    DBG_DIAGS_MAC_MAX * 2);
176
177     mutex_unlock(&priv->dbgdump_elem.mutex);
178     return read;
179 }
180
181 DEBUGFS_READ_FILE_OPS(macdiags);
182
183 static ssize_t ecrnx_dbgfs_phydiags_read(struct file *file,
184                                         char __user *user_buf,
185                                         size_t count, loff_t *ppos)
186 {
187     struct ecrnx_hw *priv = file->private_data;
188     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
189     ssize_t read;
190
191     mutex_lock(&priv->dbgdump_elem.mutex);
192     if (!priv->debugfs.trace_prst) {
193         mutex_unlock(&priv->dbgdump_elem.mutex);
194         return 0;
195     }
196
197     read = simple_read_from_buffer(user_buf, count, ppos,
198                                    dump->dbg_info.diags_phy,
199                                    DBG_DIAGS_PHY_MAX * 2);
200
201     mutex_unlock(&priv->dbgdump_elem.mutex);
202     return read;
203 }
204
205 DEBUGFS_READ_FILE_OPS(phydiags);
206
207 static ssize_t ecrnx_dbgfs_hwdiags_read(struct file *file,
208                                        char __user *user_buf,
209                                        size_t count, loff_t *ppos)
210 {
211     struct ecrnx_hw *priv = file->private_data;
212     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
213     char buf[16];
214     int ret;
215
216     mutex_lock(&priv->dbgdump_elem.mutex);
217     if (!priv->debugfs.trace_prst) {
218         mutex_unlock(&priv->dbgdump_elem.mutex);
219         return 0;
220     }
221
222     ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
223                     "%08X\n", dump->dbg_info.hw_diag);
224
225     mutex_unlock(&priv->dbgdump_elem.mutex);
226     return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
227 }
228
229 DEBUGFS_READ_FILE_OPS(hwdiags);
230
231 static ssize_t ecrnx_dbgfs_plfdiags_read(struct file *file,
232                                        char __user *user_buf,
233                                        size_t count, loff_t *ppos)
234 {
235     struct ecrnx_hw *priv = file->private_data;
236     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
237     char buf[16];
238     int ret;
239
240     mutex_lock(&priv->dbgdump_elem.mutex);
241     if (!priv->debugfs.trace_prst) {
242         mutex_unlock(&priv->dbgdump_elem.mutex);
243         return 0;
244     }
245
246     ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
247                     "%08X\n", dump->dbg_info.la_conf.diag_conf);
248
249     mutex_unlock(&priv->dbgdump_elem.mutex);
250     return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
251 }
252
253 DEBUGFS_READ_FILE_OPS(plfdiags);
254
255 static ssize_t ecrnx_dbgfs_swdiags_read(struct file *file,
256                                       char __user *user_buf,
257                                       size_t count, loff_t *ppos)
258 {
259     struct ecrnx_hw *priv = file->private_data;
260     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
261     ssize_t read;
262
263     mutex_lock(&priv->dbgdump_elem.mutex);
264     if (!priv->debugfs.trace_prst) {
265         mutex_unlock(&priv->dbgdump_elem.mutex);
266         return 0;
267     }
268
269     read = simple_read_from_buffer(user_buf, count, ppos,
270                                    &dump->dbg_info.sw_diag,
271                                    dump->dbg_info.sw_diag_len);
272
273     mutex_unlock(&priv->dbgdump_elem.mutex);
274     return read;
275 }
276
277 DEBUGFS_READ_FILE_OPS(swdiags);
278
279 static ssize_t ecrnx_dbgfs_error_read(struct file *file,
280                                      char __user *user_buf,
281                                      size_t count, loff_t *ppos)
282 {
283     struct ecrnx_hw *priv = file->private_data;
284     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
285     ssize_t read;
286
287     mutex_lock(&priv->dbgdump_elem.mutex);
288     if (!priv->debugfs.trace_prst) {
289         mutex_unlock(&priv->dbgdump_elem.mutex);
290         return 0;
291     }
292
293     read = simple_read_from_buffer(user_buf, count, ppos,
294                                    dump->dbg_info.error,
295                                    strlen((char *)dump->dbg_info.error));
296
297     mutex_unlock(&priv->dbgdump_elem.mutex);
298     return read;
299 }
300
301 DEBUGFS_READ_FILE_OPS(error);
302
303 static ssize_t ecrnx_dbgfs_rxdesc_read(struct file *file,
304                                       char __user *user_buf,
305                                       size_t count, loff_t *ppos)
306 {
307     struct ecrnx_hw *priv = file->private_data;
308     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
309     char buf[32];
310     int ret;
311     ssize_t read;
312
313     mutex_lock(&priv->dbgdump_elem.mutex);
314     if (!priv->debugfs.trace_prst) {
315         mutex_unlock(&priv->dbgdump_elem.mutex);
316         return 0;
317     }
318
319     ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
320                     "%08X\n%08X\n", dump->dbg_info.rhd,
321                     dump->dbg_info.rbd);
322     read = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
323
324     mutex_unlock(&priv->dbgdump_elem.mutex);
325     return read;
326 }
327
328 DEBUGFS_READ_FILE_OPS(rxdesc);
329
330 static ssize_t ecrnx_dbgfs_txdesc_read(struct file *file,
331                                       char __user *user_buf,
332                                       size_t count, loff_t *ppos)
333 {
334     struct ecrnx_hw *priv = file->private_data;
335     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
336     char buf[64];
337     int len = 0;
338     int i;
339
340     mutex_lock(&priv->dbgdump_elem.mutex);
341     if (!priv->debugfs.trace_prst) {
342         mutex_unlock(&priv->dbgdump_elem.mutex);
343         return 0;
344     }
345
346     for (i = 0; i < NX_TXQ_CNT; i++) {
347         len += scnprintf(&buf[len], min_t(size_t, sizeof(buf) - len - 1, count),
348                          "%08X\n", dump->dbg_info.thd[i]);
349     }
350
351     mutex_unlock(&priv->dbgdump_elem.mutex);
352     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
353 }
354
355 DEBUGFS_READ_FILE_OPS(txdesc);
356
357 static ssize_t ecrnx_dbgfs_macrxptr_read(struct file *file,
358                                         char __user *user_buf,
359                                         size_t count, loff_t *ppos)
360 {
361     struct ecrnx_hw *priv = file->private_data;
362     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
363     ssize_t read;
364
365     mutex_lock(&priv->dbgdump_elem.mutex);
366     if (!priv->debugfs.trace_prst) {
367         mutex_unlock(&priv->dbgdump_elem.mutex);
368         return 0;
369     }
370
371     read = simple_read_from_buffer(user_buf, count, ppos,
372                                    &dump->dbg_info.rhd_hw_ptr,
373                                    2 * sizeof(dump->dbg_info.rhd_hw_ptr));
374
375     mutex_unlock(&priv->dbgdump_elem.mutex);
376     return read;
377 }
378
379 DEBUGFS_READ_FILE_OPS(macrxptr);
380
381 static ssize_t ecrnx_dbgfs_lamacconf_read(struct file *file,
382                                          char __user *user_buf,
383                                          size_t count, loff_t *ppos)
384 {
385     struct ecrnx_hw *priv = file->private_data;
386     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
387     ssize_t read;
388
389     mutex_lock(&priv->dbgdump_elem.mutex);
390     if (!priv->debugfs.trace_prst) {
391         mutex_unlock(&priv->dbgdump_elem.mutex);
392         return 0;
393     }
394
395     read = simple_read_from_buffer(user_buf, count, ppos,
396                                    dump->dbg_info.la_conf.conf,
397                                    LA_CONF_LEN * 4);
398
399     mutex_unlock(&priv->dbgdump_elem.mutex);
400     return read;
401 }
402 DEBUGFS_READ_FILE_OPS(lamacconf);
403
404 static ssize_t ecrnx_dbgfs_chaninfo_read(struct file *file,
405                                         char __user *user_buf,
406                                         size_t count, loff_t *ppos)
407 {
408     struct ecrnx_hw *priv = file->private_data;
409     struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
410     char buf[4 * 32];
411     int ret;
412
413     mutex_lock(&priv->dbgdump_elem.mutex);
414     if (!priv->debugfs.trace_prst) {
415         mutex_unlock(&priv->dbgdump_elem.mutex);
416         return 0;
417     }
418
419     ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
420                     "type:          %d\n"
421                     "prim20_freq:   %d MHz\n"
422                     "center1_freq:  %d MHz\n"
423                     "center2_freq:  %d MHz\n",
424                     (dump->dbg_info.chan_info.info1 >> 8)  & 0xFF,
425                     (dump->dbg_info.chan_info.info1 >> 16) & 0xFFFF,
426                     (dump->dbg_info.chan_info.info2 >> 0)  & 0xFFFF,
427                     (dump->dbg_info.chan_info.info2 >> 16) & 0xFFFF);
428
429     mutex_unlock(&priv->dbgdump_elem.mutex);
430     return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
431 }
432
433 DEBUGFS_READ_FILE_OPS(chaninfo);
434
435 static ssize_t ecrnx_dbgfs_um_helper_read(struct file *file,
436                                          char __user *user_buf,
437                                          size_t count, loff_t *ppos)
438 {
439     struct ecrnx_hw *priv = file->private_data;
440     char buf[sizeof(priv->debugfs.helper_cmd)];
441     int ret;
442
443     ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
444                     "%s", priv->debugfs.helper_cmd);
445
446     return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
447 }
448
449 static ssize_t ecrnx_dbgfs_um_helper_write(struct file *file,
450                                           const char __user *user_buf,
451                                           size_t count, loff_t *ppos)
452 {
453     struct ecrnx_hw *priv = file->private_data;
454     int eobuf = min_t(size_t, sizeof(priv->debugfs.helper_cmd) - 1, count);
455
456     priv->debugfs.helper_cmd[eobuf] = '\0';
457     if (copy_from_user(priv->debugfs.helper_cmd, user_buf, eobuf))
458         return -EFAULT;
459
460     return count;
461 }
462
463 DEBUGFS_READ_WRITE_FILE_OPS(um_helper);
464
465 /*
466  * Calls a userspace pgm
467  */
468 int ecrnx_um_helper(struct ecrnx_debugfs *ecrnx_debugfs, const char *cmd)
469 {
470     struct ecrnx_hw *ecrnx_hw = container_of(ecrnx_debugfs, struct ecrnx_hw,
471                                            debugfs);
472     char *envp[] = { "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
473     char **argv;
474     int argc, ret;
475
476     if (!ecrnx_debugfs->dir ||
477         !strlen((cmd = cmd ? cmd : ecrnx_debugfs->helper_cmd)))
478         return 0;
479     argv = argv_split(in_interrupt() ? GFP_ATOMIC : GFP_KERNEL, cmd, &argc);
480     if (!argc)
481         return PTR_ERR(argv);
482
483     if ((ret = call_usermodehelper(argv[0], argv, envp,
484                                    UMH_WAIT_PROC | UMH_KILLABLE)))
485         dev_err(ecrnx_hw->dev, "Failed to call %s (%s returned %d)\n",
486                argv[0], cmd, ret);
487     argv_free(argv);
488
489     return ret;
490 }
491
492 static void ecrnx_um_helper_work(struct work_struct *ws)
493 {
494     struct ecrnx_debugfs *ecrnx_debugfs = container_of(ws, struct ecrnx_debugfs,
495                                                      helper_work);
496     struct ecrnx_hw *ecrnx_hw = container_of(ecrnx_debugfs, struct ecrnx_hw,
497                                            debugfs);
498     ecrnx_um_helper(ecrnx_debugfs, NULL);
499     if (!ecrnx_debugfs->unregistering)
500         ecrnx_umh_done(ecrnx_hw);
501     ecrnx_debugfs->helper_scheduled = false;
502 }
503
504 int ecrnx_trigger_um_helper(struct ecrnx_debugfs *ecrnx_debugfs)
505 {
506     struct ecrnx_hw *ecrnx_hw = container_of(ecrnx_debugfs, struct ecrnx_hw,
507                                            debugfs);
508
509     if (ecrnx_debugfs->helper_scheduled == true) {
510         dev_err(ecrnx_hw->dev, "%s: Already scheduled\n", __func__);
511         return -EBUSY;
512     }
513
514     spin_lock_bh(&ecrnx_debugfs->umh_lock);
515     if (ecrnx_debugfs->unregistering) {
516         spin_unlock_bh(&ecrnx_debugfs->umh_lock);
517         dev_err(ecrnx_hw->dev, "%s: unregistering\n", __func__);
518         return -ENOENT;
519     }
520     ecrnx_debugfs->helper_scheduled = true;
521     schedule_work(&ecrnx_debugfs->helper_work);
522     spin_unlock_bh(&ecrnx_debugfs->umh_lock);
523
524     return 0;
525 }
526 void ecrnx_wait_um_helper(struct ecrnx_hw *ecrnx_hw)
527 {
528     flush_work(&ecrnx_hw->debugfs.helper_work);
529 }
530
531 int ecrnx_dbgfs_register_fw_dump(struct ecrnx_hw *ecrnx_hw,
532                                 struct dentry *dir_drv,
533                                 struct dentry *dir_diags)
534 {
535
536     struct ecrnx_debugfs *ecrnx_debugfs = &ecrnx_hw->debugfs;
537
538     BUILD_BUG_ON(sizeof(CONFIG_ECRNX_UM_HELPER_DFLT) >=
539                  sizeof(ecrnx_debugfs->helper_cmd));
540     strncpy(ecrnx_debugfs->helper_cmd,
541             CONFIG_ECRNX_UM_HELPER_DFLT, sizeof(ecrnx_debugfs->helper_cmd));
542     INIT_WORK(&ecrnx_debugfs->helper_work, ecrnx_um_helper_work);
543     DEBUGFS_ADD_FILE(um_helper, dir_drv, S_IWUSR | S_IRUSR);
544
545     ecrnx_debugfs->trace_prst = ecrnx_debugfs->helper_scheduled = false;
546     spin_lock_init(&ecrnx_debugfs->umh_lock);
547     DEBUGFS_ADD_FILE(rhd,       dir_diags, S_IRUSR);
548     DEBUGFS_ADD_FILE(rbd,       dir_diags, S_IRUSR);
549     DEBUGFS_ADD_FILE(thd0,      dir_diags, S_IRUSR);
550     DEBUGFS_ADD_FILE(thd1,      dir_diags, S_IRUSR);
551     DEBUGFS_ADD_FILE(thd2,      dir_diags, S_IRUSR);
552     DEBUGFS_ADD_FILE(thd3,      dir_diags, S_IRUSR);
553 #if (NX_TXQ_CNT == 5)
554     DEBUGFS_ADD_FILE(thd4,      dir_diags, S_IRUSR);
555 #endif
556     DEBUGFS_ADD_FILE(mactrace,  dir_diags, S_IRUSR);
557     DEBUGFS_ADD_FILE(macdiags,  dir_diags, S_IRUSR);
558     DEBUGFS_ADD_FILE(phydiags,  dir_diags, S_IRUSR);
559     DEBUGFS_ADD_FILE(plfdiags,  dir_diags, S_IRUSR);
560     DEBUGFS_ADD_FILE(hwdiags,   dir_diags, S_IRUSR);
561     DEBUGFS_ADD_FILE(swdiags,   dir_diags, S_IRUSR);
562     DEBUGFS_ADD_FILE(error,     dir_diags, S_IRUSR);
563     DEBUGFS_ADD_FILE(rxdesc,    dir_diags, S_IRUSR);
564     DEBUGFS_ADD_FILE(txdesc,    dir_diags, S_IRUSR);
565     DEBUGFS_ADD_FILE(macrxptr,  dir_diags, S_IRUSR);
566     DEBUGFS_ADD_FILE(lamacconf, dir_diags, S_IRUSR);
567     DEBUGFS_ADD_FILE(chaninfo,  dir_diags, S_IRUSR);
568
569     return 0;
570
571   err:
572     return -1;
573 }