Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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