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