]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blob - drivers/net/wimax/i2400m/debugfs.c
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 268
[mirror_ubuntu-eoan-kernel.git] / drivers / net / wimax / i2400m / debugfs.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Intel Wireless WiMAX Connection 2400m
4 * Debugfs interfaces to manipulate driver and device information
5 *
6 * Copyright (C) 2007 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 */
9
10 #include <linux/debugfs.h>
11 #include <linux/netdevice.h>
12 #include <linux/etherdevice.h>
13 #include <linux/spinlock.h>
14 #include <linux/device.h>
15 #include <linux/export.h>
16 #include "i2400m.h"
17
18
19 #define D_SUBMODULE debugfs
20 #include "debug-levels.h"
21
22 static
23 int debugfs_netdev_queue_stopped_get(void *data, u64 *val)
24 {
25 struct i2400m *i2400m = data;
26 *val = netif_queue_stopped(i2400m->wimax_dev.net_dev);
27 return 0;
28 }
29 DEFINE_SIMPLE_ATTRIBUTE(fops_netdev_queue_stopped,
30 debugfs_netdev_queue_stopped_get,
31 NULL, "%llu\n");
32
33
34 static
35 struct dentry *debugfs_create_netdev_queue_stopped(
36 const char *name, struct dentry *parent, struct i2400m *i2400m)
37 {
38 return debugfs_create_file(name, 0400, parent, i2400m,
39 &fops_netdev_queue_stopped);
40 }
41
42 /*
43 * We don't allow partial reads of this file, as then the reader would
44 * get weirdly confused data as it is updated.
45 *
46 * So or you read it all or nothing; if you try to read with an offset
47 * != 0, we consider you are done reading.
48 */
49 static
50 ssize_t i2400m_rx_stats_read(struct file *filp, char __user *buffer,
51 size_t count, loff_t *ppos)
52 {
53 struct i2400m *i2400m = filp->private_data;
54 char buf[128];
55 unsigned long flags;
56
57 if (*ppos != 0)
58 return 0;
59 if (count < sizeof(buf))
60 return -ENOSPC;
61 spin_lock_irqsave(&i2400m->rx_lock, flags);
62 snprintf(buf, sizeof(buf), "%u %u %u %u %u %u %u\n",
63 i2400m->rx_pl_num, i2400m->rx_pl_min,
64 i2400m->rx_pl_max, i2400m->rx_num,
65 i2400m->rx_size_acc,
66 i2400m->rx_size_min, i2400m->rx_size_max);
67 spin_unlock_irqrestore(&i2400m->rx_lock, flags);
68 return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
69 }
70
71
72 /* Any write clears the stats */
73 static
74 ssize_t i2400m_rx_stats_write(struct file *filp, const char __user *buffer,
75 size_t count, loff_t *ppos)
76 {
77 struct i2400m *i2400m = filp->private_data;
78 unsigned long flags;
79
80 spin_lock_irqsave(&i2400m->rx_lock, flags);
81 i2400m->rx_pl_num = 0;
82 i2400m->rx_pl_max = 0;
83 i2400m->rx_pl_min = UINT_MAX;
84 i2400m->rx_num = 0;
85 i2400m->rx_size_acc = 0;
86 i2400m->rx_size_min = UINT_MAX;
87 i2400m->rx_size_max = 0;
88 spin_unlock_irqrestore(&i2400m->rx_lock, flags);
89 return count;
90 }
91
92 static
93 const struct file_operations i2400m_rx_stats_fops = {
94 .owner = THIS_MODULE,
95 .open = simple_open,
96 .read = i2400m_rx_stats_read,
97 .write = i2400m_rx_stats_write,
98 .llseek = default_llseek,
99 };
100
101
102 /* See i2400m_rx_stats_read() */
103 static
104 ssize_t i2400m_tx_stats_read(struct file *filp, char __user *buffer,
105 size_t count, loff_t *ppos)
106 {
107 struct i2400m *i2400m = filp->private_data;
108 char buf[128];
109 unsigned long flags;
110
111 if (*ppos != 0)
112 return 0;
113 if (count < sizeof(buf))
114 return -ENOSPC;
115 spin_lock_irqsave(&i2400m->tx_lock, flags);
116 snprintf(buf, sizeof(buf), "%u %u %u %u %u %u %u\n",
117 i2400m->tx_pl_num, i2400m->tx_pl_min,
118 i2400m->tx_pl_max, i2400m->tx_num,
119 i2400m->tx_size_acc,
120 i2400m->tx_size_min, i2400m->tx_size_max);
121 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
122 return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
123 }
124
125 /* Any write clears the stats */
126 static
127 ssize_t i2400m_tx_stats_write(struct file *filp, const char __user *buffer,
128 size_t count, loff_t *ppos)
129 {
130 struct i2400m *i2400m = filp->private_data;
131 unsigned long flags;
132
133 spin_lock_irqsave(&i2400m->tx_lock, flags);
134 i2400m->tx_pl_num = 0;
135 i2400m->tx_pl_max = 0;
136 i2400m->tx_pl_min = UINT_MAX;
137 i2400m->tx_num = 0;
138 i2400m->tx_size_acc = 0;
139 i2400m->tx_size_min = UINT_MAX;
140 i2400m->tx_size_max = 0;
141 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
142 return count;
143 }
144
145 static
146 const struct file_operations i2400m_tx_stats_fops = {
147 .owner = THIS_MODULE,
148 .open = simple_open,
149 .read = i2400m_tx_stats_read,
150 .write = i2400m_tx_stats_write,
151 .llseek = default_llseek,
152 };
153
154
155 /* Write 1 to ask the device to go into suspend */
156 static
157 int debugfs_i2400m_suspend_set(void *data, u64 val)
158 {
159 int result;
160 struct i2400m *i2400m = data;
161 result = i2400m_cmd_enter_powersave(i2400m);
162 if (result >= 0)
163 result = 0;
164 return result;
165 }
166 DEFINE_SIMPLE_ATTRIBUTE(fops_i2400m_suspend,
167 NULL, debugfs_i2400m_suspend_set,
168 "%llu\n");
169
170 static
171 struct dentry *debugfs_create_i2400m_suspend(
172 const char *name, struct dentry *parent, struct i2400m *i2400m)
173 {
174 return debugfs_create_file(name, 0200, parent, i2400m,
175 &fops_i2400m_suspend);
176 }
177
178
179 /*
180 * Reset the device
181 *
182 * Write 0 to ask the device to soft reset, 1 to cold reset, 2 to bus
183 * reset (as defined by enum i2400m_reset_type).
184 */
185 static
186 int debugfs_i2400m_reset_set(void *data, u64 val)
187 {
188 int result;
189 struct i2400m *i2400m = data;
190 enum i2400m_reset_type rt = val;
191 switch(rt) {
192 case I2400M_RT_WARM:
193 case I2400M_RT_COLD:
194 case I2400M_RT_BUS:
195 result = i2400m_reset(i2400m, rt);
196 if (result >= 0)
197 result = 0;
198 break;
199 default:
200 result = -EINVAL;
201 }
202 return result;
203 }
204 DEFINE_SIMPLE_ATTRIBUTE(fops_i2400m_reset,
205 NULL, debugfs_i2400m_reset_set,
206 "%llu\n");
207
208 static
209 struct dentry *debugfs_create_i2400m_reset(
210 const char *name, struct dentry *parent, struct i2400m *i2400m)
211 {
212 return debugfs_create_file(name, 0200, parent, i2400m,
213 &fops_i2400m_reset);
214 }
215
216
217 #define __debugfs_register(prefix, name, parent) \
218 do { \
219 result = d_level_register_debugfs(prefix, name, parent); \
220 if (result < 0) \
221 goto error; \
222 } while (0)
223
224
225 int i2400m_debugfs_add(struct i2400m *i2400m)
226 {
227 int result;
228 struct device *dev = i2400m_dev(i2400m);
229 struct dentry *dentry = i2400m->wimax_dev.debugfs_dentry;
230 struct dentry *fd;
231
232 dentry = debugfs_create_dir("i2400m", dentry);
233 result = PTR_ERR(dentry);
234 if (IS_ERR(dentry)) {
235 if (result == -ENODEV)
236 result = 0; /* No debugfs support */
237 goto error;
238 }
239 i2400m->debugfs_dentry = dentry;
240 __debugfs_register("dl_", control, dentry);
241 __debugfs_register("dl_", driver, dentry);
242 __debugfs_register("dl_", debugfs, dentry);
243 __debugfs_register("dl_", fw, dentry);
244 __debugfs_register("dl_", netdev, dentry);
245 __debugfs_register("dl_", rfkill, dentry);
246 __debugfs_register("dl_", rx, dentry);
247 __debugfs_register("dl_", tx, dentry);
248
249 fd = debugfs_create_size_t("tx_in", 0400, dentry,
250 &i2400m->tx_in);
251 result = PTR_ERR(fd);
252 if (IS_ERR(fd) && result != -ENODEV) {
253 dev_err(dev, "Can't create debugfs entry "
254 "tx_in: %d\n", result);
255 goto error;
256 }
257
258 fd = debugfs_create_size_t("tx_out", 0400, dentry,
259 &i2400m->tx_out);
260 result = PTR_ERR(fd);
261 if (IS_ERR(fd) && result != -ENODEV) {
262 dev_err(dev, "Can't create debugfs entry "
263 "tx_out: %d\n", result);
264 goto error;
265 }
266
267 fd = debugfs_create_u32("state", 0600, dentry,
268 &i2400m->state);
269 result = PTR_ERR(fd);
270 if (IS_ERR(fd) && result != -ENODEV) {
271 dev_err(dev, "Can't create debugfs entry "
272 "state: %d\n", result);
273 goto error;
274 }
275
276 /*
277 * Trace received messages from user space
278 *
279 * In order to tap the bidirectional message stream in the
280 * 'msg' pipe, user space can read from the 'msg' pipe;
281 * however, due to limitations in libnl, we can't know what
282 * the different applications are sending down to the kernel.
283 *
284 * So we have this hack where the driver will echo any message
285 * received on the msg pipe from user space [through a call to
286 * wimax_dev->op_msg_from_user() into
287 * i2400m_op_msg_from_user()] into the 'trace' pipe that this
288 * driver creates.
289 *
290 * So then, reading from both the 'trace' and 'msg' pipes in
291 * user space will provide a full dump of the traffic.
292 *
293 * Write 1 to activate, 0 to clear.
294 *
295 * It is not really very atomic, but it is also not too
296 * critical.
297 */
298 fd = debugfs_create_u8("trace_msg_from_user", 0600, dentry,
299 &i2400m->trace_msg_from_user);
300 result = PTR_ERR(fd);
301 if (IS_ERR(fd) && result != -ENODEV) {
302 dev_err(dev, "Can't create debugfs entry "
303 "trace_msg_from_user: %d\n", result);
304 goto error;
305 }
306
307 fd = debugfs_create_netdev_queue_stopped("netdev_queue_stopped",
308 dentry, i2400m);
309 result = PTR_ERR(fd);
310 if (IS_ERR(fd) && result != -ENODEV) {
311 dev_err(dev, "Can't create debugfs entry "
312 "netdev_queue_stopped: %d\n", result);
313 goto error;
314 }
315
316 fd = debugfs_create_file("rx_stats", 0600, dentry, i2400m,
317 &i2400m_rx_stats_fops);
318 result = PTR_ERR(fd);
319 if (IS_ERR(fd) && result != -ENODEV) {
320 dev_err(dev, "Can't create debugfs entry "
321 "rx_stats: %d\n", result);
322 goto error;
323 }
324
325 fd = debugfs_create_file("tx_stats", 0600, dentry, i2400m,
326 &i2400m_tx_stats_fops);
327 result = PTR_ERR(fd);
328 if (IS_ERR(fd) && result != -ENODEV) {
329 dev_err(dev, "Can't create debugfs entry "
330 "tx_stats: %d\n", result);
331 goto error;
332 }
333
334 fd = debugfs_create_i2400m_suspend("suspend", dentry, i2400m);
335 result = PTR_ERR(fd);
336 if (IS_ERR(fd) && result != -ENODEV) {
337 dev_err(dev, "Can't create debugfs entry suspend: %d\n",
338 result);
339 goto error;
340 }
341
342 fd = debugfs_create_i2400m_reset("reset", dentry, i2400m);
343 result = PTR_ERR(fd);
344 if (IS_ERR(fd) && result != -ENODEV) {
345 dev_err(dev, "Can't create debugfs entry reset: %d\n", result);
346 goto error;
347 }
348
349 result = 0;
350 error:
351 return result;
352 }
353
354 void i2400m_debugfs_rm(struct i2400m *i2400m)
355 {
356 debugfs_remove_recursive(i2400m->debugfs_dentry);
357 }