1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/debugfs.h>
17#include <linux/netdevice.h>
18#include <linux/module.h>
19#include <linux/devcoredump.h>
20
21#include <brcmu_wifi.h>
22#include <brcmu_utils.h>
23#include "core.h"
24#include "bus.h"
25#include "fweh.h"
26#include "debug.h"
27
28static struct dentry *root_folder;
29
30static int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
31 size_t len)
32{
33 void *dump;
34 size_t ramsize;
35 int err;
36
37 ramsize = brcmf_bus_get_ramsize(bus);
38 if (!ramsize)
39 return -ENOTSUPP;
40
41 dump = vzalloc(len + ramsize);
42 if (!dump)
43 return -ENOMEM;
44
45 memcpy(dump, data, len);
46 err = brcmf_bus_get_memdump(bus, dump + len, ramsize);
47 if (err) {
48 vfree(dump);
49 return err;
50 }
51
52 dev_coredumpv(bus->dev, dump, len + ramsize, GFP_KERNEL);
53
54 return 0;
55}
56
57static int brcmf_debug_psm_watchdog_notify(struct brcmf_if *ifp,
58 const struct brcmf_event_msg *evtmsg,
59 void *data)
60{
61 int err;
62
63 brcmf_dbg(TRACE, "enter: bsscfgidx=%d\n", ifp->bsscfgidx);
64
65 brcmf_err("PSM's watchdog has fired!\n");
66
67 err = brcmf_debug_create_memdump(ifp->drvr->bus_if, data,
68 evtmsg->datalen);
69 if (err)
70 brcmf_err("Failed to get memory dump, %d\n", err);
71
72 return err;
73}
74
75void brcmf_debugfs_init(void)
76{
77 root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
78 if (IS_ERR(root_folder))
79 root_folder = NULL;
80}
81
82void brcmf_debugfs_exit(void)
83{
84 if (!root_folder)
85 return;
86
87 debugfs_remove_recursive(root_folder);
88 root_folder = NULL;
89}
90
91int brcmf_debug_attach(struct brcmf_pub *drvr)
92{
93 struct device *dev = drvr->bus_if->dev;
94
95 if (!root_folder)
96 return -ENODEV;
97
98 drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
99 if (IS_ERR(drvr->dbgfs_dir))
100 return PTR_ERR(drvr->dbgfs_dir);
101
102
103 return brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,
104 brcmf_debug_psm_watchdog_notify);
105}
106
107void brcmf_debug_detach(struct brcmf_pub *drvr)
108{
109 brcmf_fweh_unregister(drvr, BRCMF_E_PSM_WATCHDOG);
110
111 if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
112 debugfs_remove_recursive(drvr->dbgfs_dir);
113}
114
115struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr)
116{
117 return drvr->dbgfs_dir;
118}
119
120int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
121 int (*read_fn)(struct seq_file *seq, void *data))
122{
123 struct dentry *e;
124
125 e = debugfs_create_devm_seqfile(drvr->bus_if->dev, fn,
126 drvr->dbgfs_dir, read_fn);
127 return PTR_ERR_OR_ZERO(e);
128}
129