at v2.6.28 367 lines 8.9 kB view raw
1/* 2 * Ultra Wide Band 3 * Debug support 4 * 5 * Copyright (C) 2005-2006 Intel Corporation 6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License version 10 * 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 * 02110-1301, USA. 21 * 22 * 23 * FIXME: doc 24 */ 25 26#include <linux/spinlock.h> 27#include <linux/module.h> 28#include <linux/slab.h> 29#include <linux/notifier.h> 30#include <linux/device.h> 31#include <linux/debugfs.h> 32#include <linux/uaccess.h> 33#include <linux/seq_file.h> 34 35#include <linux/uwb/debug-cmd.h> 36#define D_LOCAL 0 37#include <linux/uwb/debug.h> 38 39#include "uwb-internal.h" 40 41void dump_bytes(struct device *dev, const void *_buf, size_t rsize) 42{ 43 const char *buf = _buf; 44 char line[32]; 45 size_t offset = 0; 46 int cnt, cnt2; 47 for (cnt = 0; cnt < rsize; cnt += 8) { 48 size_t rtop = rsize - cnt < 8 ? rsize - cnt : 8; 49 for (offset = cnt2 = 0; cnt2 < rtop; cnt2++) { 50 offset += scnprintf(line + offset, sizeof(line) - offset, 51 "%02x ", buf[cnt + cnt2] & 0xff); 52 } 53 if (dev) 54 dev_info(dev, "%s\n", line); 55 else 56 printk(KERN_INFO "%s\n", line); 57 } 58} 59EXPORT_SYMBOL_GPL(dump_bytes); 60 61/* 62 * Debug interface 63 * 64 * Per radio controller debugfs files (in uwb/uwbN/): 65 * 66 * command: Flexible command interface (see <linux/uwb/debug-cmd.h>). 67 * 68 * reservations: information on reservations. 69 * 70 * accept: Set to true (Y or 1) to accept reservation requests from 71 * peers. 72 * 73 * drp_avail: DRP availability information. 74 */ 75 76struct uwb_dbg { 77 struct uwb_pal pal; 78 79 u32 accept; 80 struct list_head rsvs; 81 82 struct dentry *root_d; 83 struct dentry *command_f; 84 struct dentry *reservations_f; 85 struct dentry *accept_f; 86 struct dentry *drp_avail_f; 87}; 88 89static struct dentry *root_dir; 90 91static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv) 92{ 93 struct uwb_rc *rc = rsv->rc; 94 struct device *dev = &rc->uwb_dev.dev; 95 struct uwb_dev_addr devaddr; 96 char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE]; 97 98 uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr); 99 if (rsv->target.type == UWB_RSV_TARGET_DEV) 100 devaddr = rsv->target.dev->dev_addr; 101 else 102 devaddr = rsv->target.devaddr; 103 uwb_dev_addr_print(target, sizeof(target), &devaddr); 104 105 dev_dbg(dev, "debug: rsv %s -> %s: %s\n", 106 owner, target, uwb_rsv_state_str(rsv->state)); 107} 108 109static int cmd_rsv_establish(struct uwb_rc *rc, 110 struct uwb_dbg_cmd_rsv_establish *cmd) 111{ 112 struct uwb_mac_addr macaddr; 113 struct uwb_rsv *rsv; 114 struct uwb_dev *target; 115 int ret; 116 117 memcpy(&macaddr, cmd->target, sizeof(macaddr)); 118 target = uwb_dev_get_by_macaddr(rc, &macaddr); 119 if (target == NULL) 120 return -ENODEV; 121 122 rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, NULL); 123 if (rsv == NULL) { 124 uwb_dev_put(target); 125 return -ENOMEM; 126 } 127 128 rsv->owner = &rc->uwb_dev; 129 rsv->target.type = UWB_RSV_TARGET_DEV; 130 rsv->target.dev = target; 131 rsv->type = cmd->type; 132 rsv->max_mas = cmd->max_mas; 133 rsv->min_mas = cmd->min_mas; 134 rsv->sparsity = cmd->sparsity; 135 136 ret = uwb_rsv_establish(rsv); 137 if (ret) 138 uwb_rsv_destroy(rsv); 139 else 140 list_add_tail(&rsv->pal_node, &rc->dbg->rsvs); 141 142 return ret; 143} 144 145static int cmd_rsv_terminate(struct uwb_rc *rc, 146 struct uwb_dbg_cmd_rsv_terminate *cmd) 147{ 148 struct uwb_rsv *rsv, *found = NULL; 149 int i = 0; 150 151 list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) { 152 if (i == cmd->index) { 153 found = rsv; 154 break; 155 } 156 } 157 if (!found) 158 return -EINVAL; 159 160 list_del(&found->pal_node); 161 uwb_rsv_terminate(found); 162 163 return 0; 164} 165 166static int command_open(struct inode *inode, struct file *file) 167{ 168 file->private_data = inode->i_private; 169 170 return 0; 171} 172 173static ssize_t command_write(struct file *file, const char __user *buf, 174 size_t len, loff_t *off) 175{ 176 struct uwb_rc *rc = file->private_data; 177 struct uwb_dbg_cmd cmd; 178 int ret; 179 180 if (len != sizeof(struct uwb_dbg_cmd)) 181 return -EINVAL; 182 183 if (copy_from_user(&cmd, buf, len) != 0) 184 return -EFAULT; 185 186 switch (cmd.type) { 187 case UWB_DBG_CMD_RSV_ESTABLISH: 188 ret = cmd_rsv_establish(rc, &cmd.rsv_establish); 189 break; 190 case UWB_DBG_CMD_RSV_TERMINATE: 191 ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate); 192 break; 193 default: 194 return -EINVAL; 195 } 196 197 return ret < 0 ? ret : len; 198} 199 200static struct file_operations command_fops = { 201 .open = command_open, 202 .write = command_write, 203 .read = NULL, 204 .llseek = no_llseek, 205 .owner = THIS_MODULE, 206}; 207 208static int reservations_print(struct seq_file *s, void *p) 209{ 210 struct uwb_rc *rc = s->private; 211 struct uwb_rsv *rsv; 212 213 mutex_lock(&rc->rsvs_mutex); 214 215 list_for_each_entry(rsv, &rc->reservations, rc_node) { 216 struct uwb_dev_addr devaddr; 217 char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE]; 218 bool is_owner; 219 char buf[72]; 220 221 uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr); 222 if (rsv->target.type == UWB_RSV_TARGET_DEV) { 223 devaddr = rsv->target.dev->dev_addr; 224 is_owner = &rc->uwb_dev == rsv->owner; 225 } else { 226 devaddr = rsv->target.devaddr; 227 is_owner = true; 228 } 229 uwb_dev_addr_print(target, sizeof(target), &devaddr); 230 231 seq_printf(s, "%c %s -> %s: %s\n", 232 is_owner ? 'O' : 'T', 233 owner, target, uwb_rsv_state_str(rsv->state)); 234 seq_printf(s, " stream: %d type: %s\n", 235 rsv->stream, uwb_rsv_type_str(rsv->type)); 236 bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS); 237 seq_printf(s, " %s\n", buf); 238 } 239 240 mutex_unlock(&rc->rsvs_mutex); 241 242 return 0; 243} 244 245static int reservations_open(struct inode *inode, struct file *file) 246{ 247 return single_open(file, reservations_print, inode->i_private); 248} 249 250static struct file_operations reservations_fops = { 251 .open = reservations_open, 252 .read = seq_read, 253 .llseek = seq_lseek, 254 .release = single_release, 255 .owner = THIS_MODULE, 256}; 257 258static int drp_avail_print(struct seq_file *s, void *p) 259{ 260 struct uwb_rc *rc = s->private; 261 char buf[72]; 262 263 bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.global, UWB_NUM_MAS); 264 seq_printf(s, "global: %s\n", buf); 265 bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.local, UWB_NUM_MAS); 266 seq_printf(s, "local: %s\n", buf); 267 bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.pending, UWB_NUM_MAS); 268 seq_printf(s, "pending: %s\n", buf); 269 270 return 0; 271} 272 273static int drp_avail_open(struct inode *inode, struct file *file) 274{ 275 return single_open(file, drp_avail_print, inode->i_private); 276} 277 278static struct file_operations drp_avail_fops = { 279 .open = drp_avail_open, 280 .read = seq_read, 281 .llseek = seq_lseek, 282 .release = single_release, 283 .owner = THIS_MODULE, 284}; 285 286static void uwb_dbg_new_rsv(struct uwb_rsv *rsv) 287{ 288 struct uwb_rc *rc = rsv->rc; 289 290 if (rc->dbg->accept) 291 uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, NULL); 292} 293 294/** 295 * uwb_dbg_add_rc - add a debug interface for a radio controller 296 * @rc: the radio controller 297 */ 298void uwb_dbg_add_rc(struct uwb_rc *rc) 299{ 300 rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL); 301 if (rc->dbg == NULL) 302 return; 303 304 INIT_LIST_HEAD(&rc->dbg->rsvs); 305 306 uwb_pal_init(&rc->dbg->pal); 307 rc->dbg->pal.new_rsv = uwb_dbg_new_rsv; 308 uwb_pal_register(rc, &rc->dbg->pal); 309 if (root_dir) { 310 rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev), 311 root_dir); 312 rc->dbg->command_f = debugfs_create_file("command", 0200, 313 rc->dbg->root_d, rc, 314 &command_fops); 315 rc->dbg->reservations_f = debugfs_create_file("reservations", 0444, 316 rc->dbg->root_d, rc, 317 &reservations_fops); 318 rc->dbg->accept_f = debugfs_create_bool("accept", 0644, 319 rc->dbg->root_d, 320 &rc->dbg->accept); 321 rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444, 322 rc->dbg->root_d, rc, 323 &drp_avail_fops); 324 } 325} 326 327/** 328 * uwb_dbg_add_rc - remove a radio controller's debug interface 329 * @rc: the radio controller 330 */ 331void uwb_dbg_del_rc(struct uwb_rc *rc) 332{ 333 struct uwb_rsv *rsv, *t; 334 335 if (rc->dbg == NULL) 336 return; 337 338 list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) { 339 uwb_rsv_destroy(rsv); 340 } 341 342 uwb_pal_unregister(rc, &rc->dbg->pal); 343 344 if (root_dir) { 345 debugfs_remove(rc->dbg->drp_avail_f); 346 debugfs_remove(rc->dbg->accept_f); 347 debugfs_remove(rc->dbg->reservations_f); 348 debugfs_remove(rc->dbg->command_f); 349 debugfs_remove(rc->dbg->root_d); 350 } 351} 352 353/** 354 * uwb_dbg_exit - initialize the debug interface sub-module 355 */ 356void uwb_dbg_init(void) 357{ 358 root_dir = debugfs_create_dir("uwb", NULL); 359} 360 361/** 362 * uwb_dbg_exit - clean-up the debug interface sub-module 363 */ 364void uwb_dbg_exit(void) 365{ 366 debugfs_remove(root_dir); 367}