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