Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / uwb / uwb-debug.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Ultra Wide Band
4  * Debug support
5  *
6  * Copyright (C) 2005-2006 Intel Corporation
7  * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8  * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
9  *
10  * FIXME: doc
11  */
12
13 #include <linux/spinlock.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
16 #include <linux/notifier.h>
17 #include <linux/device.h>
18 #include <linux/debugfs.h>
19 #include <linux/uaccess.h>
20 #include <linux/seq_file.h>
21
22 #include <linux/uwb/debug-cmd.h>
23
24 #include "uwb-internal.h"
25
26 /*
27  * Debug interface
28  *
29  * Per radio controller debugfs files (in uwb/uwbN/):
30  *
31  * command: Flexible command interface (see <linux/uwb/debug-cmd.h>).
32  *
33  * reservations: information on reservations.
34  *
35  * accept: Set to true (Y or 1) to accept reservation requests from
36  * peers.
37  *
38  * drp_avail: DRP availability information.
39  */
40
41 struct uwb_dbg {
42         struct uwb_pal pal;
43
44         bool accept;
45         struct list_head rsvs;
46
47         struct dentry *root_d;
48         struct dentry *command_f;
49         struct dentry *reservations_f;
50         struct dentry *accept_f;
51         struct dentry *drp_avail_f;
52         spinlock_t list_lock;
53 };
54
55 static struct dentry *root_dir;
56
57 static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv)
58 {
59         struct uwb_dbg *dbg = rsv->pal_priv;
60
61         uwb_rsv_dump("debug", rsv);
62
63         if (rsv->state == UWB_RSV_STATE_NONE) {
64                 spin_lock(&dbg->list_lock);
65                 list_del(&rsv->pal_node);
66                 spin_unlock(&dbg->list_lock);
67                 uwb_rsv_destroy(rsv);
68         }
69 }
70
71 static int cmd_rsv_establish(struct uwb_rc *rc,
72                              struct uwb_dbg_cmd_rsv_establish *cmd)
73 {
74         struct uwb_mac_addr macaddr;
75         struct uwb_rsv *rsv;
76         struct uwb_dev *target;
77         int ret;
78
79         memcpy(&macaddr, cmd->target, sizeof(macaddr));
80         target = uwb_dev_get_by_macaddr(rc, &macaddr);
81         if (target == NULL)
82                 return -ENODEV;
83
84         rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, rc->dbg);
85         if (rsv == NULL) {
86                 uwb_dev_put(target);
87                 return -ENOMEM;
88         }
89
90         rsv->target.type  = UWB_RSV_TARGET_DEV;
91         rsv->target.dev   = target;
92         rsv->type         = cmd->type;
93         rsv->max_mas      = cmd->max_mas;
94         rsv->min_mas      = cmd->min_mas;
95         rsv->max_interval = cmd->max_interval;
96
97         ret = uwb_rsv_establish(rsv);
98         if (ret)
99                 uwb_rsv_destroy(rsv);
100         else {
101                 spin_lock(&(rc->dbg)->list_lock);
102                 list_add_tail(&rsv->pal_node, &rc->dbg->rsvs);
103                 spin_unlock(&(rc->dbg)->list_lock);
104         }
105         return ret;
106 }
107
108 static int cmd_rsv_terminate(struct uwb_rc *rc,
109                              struct uwb_dbg_cmd_rsv_terminate *cmd)
110 {
111         struct uwb_rsv *rsv, *found = NULL;
112         int i = 0;
113
114         spin_lock(&(rc->dbg)->list_lock);
115
116         list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) {
117                 if (i == cmd->index) {
118                         found = rsv;
119                         uwb_rsv_get(found);
120                         break;
121                 }
122                 i++;
123         }
124
125         spin_unlock(&(rc->dbg)->list_lock);
126
127         if (!found)
128                 return -EINVAL;
129
130         uwb_rsv_terminate(found);
131         uwb_rsv_put(found);
132
133         return 0;
134 }
135
136 static int cmd_ie_add(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_add)
137 {
138         return uwb_rc_ie_add(rc,
139                              (const struct uwb_ie_hdr *) ie_to_add->data,
140                              ie_to_add->len);
141 }
142
143 static int cmd_ie_rm(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_rm)
144 {
145         return uwb_rc_ie_rm(rc, ie_to_rm->data[0]);
146 }
147
148 static ssize_t command_write(struct file *file, const char __user *buf,
149                          size_t len, loff_t *off)
150 {
151         struct uwb_rc *rc = file->private_data;
152         struct uwb_dbg_cmd cmd;
153         int ret = 0;
154         
155         if (len != sizeof(struct uwb_dbg_cmd))
156                 return -EINVAL;
157
158         if (copy_from_user(&cmd, buf, len) != 0)
159                 return -EFAULT;
160
161         switch (cmd.type) {
162         case UWB_DBG_CMD_RSV_ESTABLISH:
163                 ret = cmd_rsv_establish(rc, &cmd.rsv_establish);
164                 break;
165         case UWB_DBG_CMD_RSV_TERMINATE:
166                 ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate);
167                 break;
168         case UWB_DBG_CMD_IE_ADD:
169                 ret = cmd_ie_add(rc, &cmd.ie_add);
170                 break;
171         case UWB_DBG_CMD_IE_RM:
172                 ret = cmd_ie_rm(rc, &cmd.ie_rm);
173                 break;
174         case UWB_DBG_CMD_RADIO_START:
175                 ret = uwb_radio_start(&rc->dbg->pal);
176                 break;
177         case UWB_DBG_CMD_RADIO_STOP:
178                 uwb_radio_stop(&rc->dbg->pal);
179                 break;
180         default:
181                 return -EINVAL;
182         }
183
184         return ret < 0 ? ret : len;
185 }
186
187 static const struct file_operations command_fops = {
188         .open   = simple_open,
189         .write  = command_write,
190         .read   = NULL,
191         .llseek = no_llseek,
192         .owner  = THIS_MODULE,
193 };
194
195 static int reservations_show(struct seq_file *s, void *p)
196 {
197         struct uwb_rc *rc = s->private;
198         struct uwb_rsv *rsv;
199
200         mutex_lock(&rc->rsvs_mutex);
201
202         list_for_each_entry(rsv, &rc->reservations, rc_node) {
203                 struct uwb_dev_addr devaddr;
204                 char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
205                 bool is_owner;
206
207                 uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
208                 if (rsv->target.type == UWB_RSV_TARGET_DEV) {
209                         devaddr = rsv->target.dev->dev_addr;
210                         is_owner = &rc->uwb_dev == rsv->owner;
211                 } else {
212                         devaddr = rsv->target.devaddr;
213                         is_owner = true;
214                 }
215                 uwb_dev_addr_print(target, sizeof(target), &devaddr);
216
217                 seq_printf(s, "%c %s -> %s: %s\n",
218                            is_owner ? 'O' : 'T',
219                            owner, target, uwb_rsv_state_str(rsv->state));
220                 seq_printf(s, "  stream: %d  type: %s\n",
221                            rsv->stream, uwb_rsv_type_str(rsv->type));
222                 seq_printf(s, "  %*pb\n", UWB_NUM_MAS, rsv->mas.bm);
223         }
224
225         mutex_unlock(&rc->rsvs_mutex);
226
227         return 0;
228 }
229 DEFINE_SHOW_ATTRIBUTE(reservations);
230
231 static int drp_avail_show(struct seq_file *s, void *p)
232 {
233         struct uwb_rc *rc = s->private;
234
235         seq_printf(s, "global:  %*pb\n", UWB_NUM_MAS, rc->drp_avail.global);
236         seq_printf(s, "local:   %*pb\n", UWB_NUM_MAS, rc->drp_avail.local);
237         seq_printf(s, "pending: %*pb\n", UWB_NUM_MAS, rc->drp_avail.pending);
238
239         return 0;
240 }
241 DEFINE_SHOW_ATTRIBUTE(drp_avail);
242
243 static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel)
244 {
245         struct device *dev = &pal->rc->uwb_dev.dev;
246
247         if (channel > 0)
248                 dev_info(dev, "debug: channel %d started\n", channel);
249         else
250                 dev_info(dev, "debug: channel stopped\n");
251 }
252
253 static void uwb_dbg_new_rsv(struct uwb_pal *pal, struct uwb_rsv *rsv)
254 {
255         struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal);
256
257         if (dbg->accept) {
258                 spin_lock(&dbg->list_lock);
259                 list_add_tail(&rsv->pal_node, &dbg->rsvs);
260                 spin_unlock(&dbg->list_lock);
261                 uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, dbg);
262         }
263 }
264
265 /**
266  * uwb_dbg_add_rc - add a debug interface for a radio controller
267  * @rc: the radio controller
268  */
269 void uwb_dbg_add_rc(struct uwb_rc *rc)
270 {
271         rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL);
272         if (rc->dbg == NULL)
273                 return;
274
275         INIT_LIST_HEAD(&rc->dbg->rsvs);
276         spin_lock_init(&(rc->dbg)->list_lock);
277
278         uwb_pal_init(&rc->dbg->pal);
279         rc->dbg->pal.rc = rc;
280         rc->dbg->pal.channel_changed = uwb_dbg_channel_changed;
281         rc->dbg->pal.new_rsv = uwb_dbg_new_rsv;
282         uwb_pal_register(&rc->dbg->pal);
283
284         if (root_dir) {
285                 rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev),
286                                                      root_dir);
287                 rc->dbg->command_f = debugfs_create_file("command", 0200,
288                                                          rc->dbg->root_d, rc,
289                                                          &command_fops);
290                 rc->dbg->reservations_f = debugfs_create_file("reservations", 0444,
291                                                               rc->dbg->root_d, rc,
292                                                               &reservations_fops);
293                 rc->dbg->accept_f = debugfs_create_bool("accept", 0644,
294                                                         rc->dbg->root_d,
295                                                         &rc->dbg->accept);
296                 rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444,
297                                                            rc->dbg->root_d, rc,
298                                                            &drp_avail_fops);
299         }
300 }
301
302 /**
303  * uwb_dbg_del_rc - remove a radio controller's debug interface
304  * @rc: the radio controller
305  */
306 void uwb_dbg_del_rc(struct uwb_rc *rc)
307 {
308         struct uwb_rsv *rsv, *t;
309
310         if (rc->dbg == NULL)
311                 return;
312
313         list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
314                 uwb_rsv_terminate(rsv);
315         }
316
317         uwb_pal_unregister(&rc->dbg->pal);
318
319         if (root_dir) {
320                 debugfs_remove(rc->dbg->drp_avail_f);
321                 debugfs_remove(rc->dbg->accept_f);
322                 debugfs_remove(rc->dbg->reservations_f);
323                 debugfs_remove(rc->dbg->command_f);
324                 debugfs_remove(rc->dbg->root_d);
325         }
326 }
327
328 /**
329  * uwb_dbg_exit - initialize the debug interface sub-module
330  */
331 void uwb_dbg_init(void)
332 {
333         root_dir = debugfs_create_dir("uwb", NULL);
334 }
335
336 /**
337  * uwb_dbg_exit - clean-up the debug interface sub-module
338  */
339 void uwb_dbg_exit(void)
340 {
341         debugfs_remove(root_dir);
342 }
343
344 /**
345  * uwb_dbg_create_pal_dir - create a debugfs directory for a PAL
346  * @pal: The PAL.
347  */
348 struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal)
349 {
350         struct uwb_rc *rc = pal->rc;
351
352         if (root_dir && rc->dbg && rc->dbg->root_d && pal->name)
353                 return debugfs_create_dir(pal->name, rc->dbg->root_d);
354         return NULL;
355 }