1290245Sgonzo/** 2290245Sgonzo * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved. 3290245Sgonzo * Copyright (c) 2010-2012 Broadcom. All rights reserved. 4290245Sgonzo * 5290245Sgonzo * Redistribution and use in source and binary forms, with or without 6290245Sgonzo * modification, are permitted provided that the following conditions 7290245Sgonzo * are met: 8290245Sgonzo * 1. Redistributions of source code must retain the above copyright 9290245Sgonzo * notice, this list of conditions, and the following disclaimer, 10290245Sgonzo * without modification. 11290245Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 12290245Sgonzo * notice, this list of conditions and the following disclaimer in the 13290245Sgonzo * documentation and/or other materials provided with the distribution. 14290245Sgonzo * 3. The names of the above-listed copyright holders may not be used 15290245Sgonzo * to endorse or promote products derived from this software without 16290245Sgonzo * specific prior written permission. 17290245Sgonzo * 18290245Sgonzo * ALTERNATIVELY, this software may be distributed under the terms of the 19290245Sgonzo * GNU General Public License ("GPL") version 2, as published by the Free 20290245Sgonzo * Software Foundation. 21290245Sgonzo * 22290245Sgonzo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 23290245Sgonzo * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 24290245Sgonzo * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25290245Sgonzo * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 26290245Sgonzo * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27290245Sgonzo * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28290245Sgonzo * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29290245Sgonzo * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30290245Sgonzo * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31290245Sgonzo * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32290245Sgonzo * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33290245Sgonzo */ 34290245Sgonzo 35290245Sgonzo 36290245Sgonzo#include <linux/debugfs.h> 37290245Sgonzo#include "vchiq_core.h" 38290245Sgonzo#include "vchiq_arm.h" 39290245Sgonzo#include "vchiq_debugfs.h" 40290245Sgonzo 41290245Sgonzo#ifdef CONFIG_DEBUG_FS 42290245Sgonzo 43290245Sgonzo/**************************************************************************** 44290245Sgonzo* 45290245Sgonzo* log category entries 46290245Sgonzo* 47290245Sgonzo***************************************************************************/ 48290245Sgonzo#define DEBUGFS_WRITE_BUF_SIZE 256 49290245Sgonzo 50290245Sgonzo#define VCHIQ_LOG_ERROR_STR "error" 51290245Sgonzo#define VCHIQ_LOG_WARNING_STR "warning" 52290245Sgonzo#define VCHIQ_LOG_INFO_STR "info" 53290245Sgonzo#define VCHIQ_LOG_TRACE_STR "trace" 54290245Sgonzo 55290245Sgonzo 56290245Sgonzo/* Top-level debug info */ 57290245Sgonzostruct vchiq_debugfs_info { 58290245Sgonzo /* Global 'vchiq' debugfs entry used by all instances */ 59290245Sgonzo struct dentry *vchiq_cfg_dir; 60290245Sgonzo 61290245Sgonzo /* one entry per client process */ 62290245Sgonzo struct dentry *clients; 63290245Sgonzo 64290245Sgonzo /* log categories */ 65290245Sgonzo struct dentry *log_categories; 66290245Sgonzo}; 67290245Sgonzo 68290245Sgonzostatic struct vchiq_debugfs_info debugfs_info; 69290245Sgonzo 70290245Sgonzo/* Log category debugfs entries */ 71290245Sgonzostruct vchiq_debugfs_log_entry { 72290245Sgonzo const char *name; 73290245Sgonzo int *plevel; 74290245Sgonzo struct dentry *dir; 75290245Sgonzo}; 76290245Sgonzo 77290245Sgonzostatic struct vchiq_debugfs_log_entry vchiq_debugfs_log_entries[] = { 78290245Sgonzo { "core", &vchiq_core_log_level }, 79290245Sgonzo { "msg", &vchiq_core_msg_log_level }, 80290245Sgonzo { "sync", &vchiq_sync_log_level }, 81290245Sgonzo { "susp", &vchiq_susp_log_level }, 82290245Sgonzo { "arm", &vchiq_arm_log_level }, 83290245Sgonzo}; 84290245Sgonzostatic int n_log_entries = 85290245Sgonzo sizeof(vchiq_debugfs_log_entries)/sizeof(vchiq_debugfs_log_entries[0]); 86290245Sgonzo 87290245Sgonzo 88290245Sgonzostatic struct dentry *vchiq_clients_top(void); 89290245Sgonzostatic struct dentry *vchiq_debugfs_top(void); 90290245Sgonzo 91290245Sgonzostatic int debugfs_log_show(struct seq_file *f, void *offset) 92290245Sgonzo{ 93290245Sgonzo int *levp = f->private; 94290245Sgonzo char *log_value = NULL; 95290245Sgonzo 96290245Sgonzo switch (*levp) { 97290245Sgonzo case VCHIQ_LOG_ERROR: 98290245Sgonzo log_value = VCHIQ_LOG_ERROR_STR; 99290245Sgonzo break; 100290245Sgonzo case VCHIQ_LOG_WARNING: 101290245Sgonzo log_value = VCHIQ_LOG_WARNING_STR; 102290245Sgonzo break; 103290245Sgonzo case VCHIQ_LOG_INFO: 104290245Sgonzo log_value = VCHIQ_LOG_INFO_STR; 105290245Sgonzo break; 106290245Sgonzo case VCHIQ_LOG_TRACE: 107290245Sgonzo log_value = VCHIQ_LOG_TRACE_STR; 108290245Sgonzo break; 109290245Sgonzo default: 110290245Sgonzo break; 111290245Sgonzo } 112290245Sgonzo 113290245Sgonzo seq_printf(f, "%s\n", log_value ? log_value : "(null)"); 114290245Sgonzo 115290245Sgonzo return 0; 116290245Sgonzo} 117290245Sgonzo 118290245Sgonzostatic int debugfs_log_open(struct inode *inode, struct file *file) 119290245Sgonzo{ 120290245Sgonzo return single_open(file, debugfs_log_show, inode->i_private); 121290245Sgonzo} 122290245Sgonzo 123290245Sgonzostatic int debugfs_log_write(struct file *file, 124290245Sgonzo const char __user *buffer, 125290245Sgonzo size_t count, loff_t *ppos) 126290245Sgonzo{ 127290245Sgonzo struct seq_file *f = (struct seq_file *)file->private_data; 128290245Sgonzo int *levp = f->private; 129290245Sgonzo char kbuf[DEBUGFS_WRITE_BUF_SIZE + 1]; 130290245Sgonzo 131290245Sgonzo memset(kbuf, 0, DEBUGFS_WRITE_BUF_SIZE + 1); 132290245Sgonzo if (count >= DEBUGFS_WRITE_BUF_SIZE) 133290245Sgonzo count = DEBUGFS_WRITE_BUF_SIZE; 134290245Sgonzo 135290245Sgonzo if (copy_from_user(kbuf, buffer, count) != 0) 136290245Sgonzo return -EFAULT; 137290245Sgonzo kbuf[count - 1] = 0; 138290245Sgonzo 139290245Sgonzo if (strncmp("error", kbuf, strlen("error")) == 0) 140290245Sgonzo *levp = VCHIQ_LOG_ERROR; 141290245Sgonzo else if (strncmp("warning", kbuf, strlen("warning")) == 0) 142290245Sgonzo *levp = VCHIQ_LOG_WARNING; 143290245Sgonzo else if (strncmp("info", kbuf, strlen("info")) == 0) 144290245Sgonzo *levp = VCHIQ_LOG_INFO; 145290245Sgonzo else if (strncmp("trace", kbuf, strlen("trace")) == 0) 146290245Sgonzo *levp = VCHIQ_LOG_TRACE; 147290245Sgonzo else 148290245Sgonzo *levp = VCHIQ_LOG_DEFAULT; 149290245Sgonzo 150290245Sgonzo *ppos += count; 151290245Sgonzo 152290245Sgonzo return count; 153290245Sgonzo} 154290245Sgonzo 155290245Sgonzostatic const struct file_operations debugfs_log_fops = { 156290245Sgonzo .owner = THIS_MODULE, 157290245Sgonzo .open = debugfs_log_open, 158290245Sgonzo .write = debugfs_log_write, 159290245Sgonzo .read = seq_read, 160290245Sgonzo .llseek = seq_lseek, 161290245Sgonzo .release = single_release, 162290245Sgonzo}; 163290245Sgonzo 164290245Sgonzo/* create an entry under <debugfs>/vchiq/log for each log category */ 165290245Sgonzostatic int vchiq_debugfs_create_log_entries(struct dentry *top) 166290245Sgonzo{ 167290245Sgonzo struct dentry *dir; 168290245Sgonzo size_t i; 169290245Sgonzo int ret = 0; 170290245Sgonzo dir = debugfs_create_dir("log", vchiq_debugfs_top()); 171290245Sgonzo if (!dir) 172290245Sgonzo return -ENOMEM; 173290245Sgonzo debugfs_info.log_categories = dir; 174290245Sgonzo 175290245Sgonzo for (i = 0; i < n_log_entries; i++) { 176290245Sgonzo void *levp = (void *)vchiq_debugfs_log_entries[i].plevel; 177290245Sgonzo dir = debugfs_create_file(vchiq_debugfs_log_entries[i].name, 178290245Sgonzo 0644, 179290245Sgonzo debugfs_info.log_categories, 180290245Sgonzo levp, 181290245Sgonzo &debugfs_log_fops); 182290245Sgonzo if (!dir) { 183290245Sgonzo ret = -ENOMEM; 184290245Sgonzo break; 185290245Sgonzo } 186290245Sgonzo 187290245Sgonzo vchiq_debugfs_log_entries[i].dir = dir; 188290245Sgonzo } 189290245Sgonzo return ret; 190290245Sgonzo} 191290245Sgonzo 192290245Sgonzostatic int debugfs_usecount_show(struct seq_file *f, void *offset) 193290245Sgonzo{ 194290245Sgonzo VCHIQ_INSTANCE_T instance = f->private; 195290245Sgonzo int use_count; 196290245Sgonzo 197290245Sgonzo use_count = vchiq_instance_get_use_count(instance); 198290245Sgonzo seq_printf(f, "%d\n", use_count); 199290245Sgonzo 200290245Sgonzo return 0; 201290245Sgonzo} 202290245Sgonzo 203290245Sgonzostatic int debugfs_usecount_open(struct inode *inode, struct file *file) 204290245Sgonzo{ 205290245Sgonzo return single_open(file, debugfs_usecount_show, inode->i_private); 206290245Sgonzo} 207290245Sgonzo 208290245Sgonzostatic const struct file_operations debugfs_usecount_fops = { 209290245Sgonzo .owner = THIS_MODULE, 210290245Sgonzo .open = debugfs_usecount_open, 211290245Sgonzo .read = seq_read, 212290245Sgonzo .llseek = seq_lseek, 213290245Sgonzo .release = single_release, 214290245Sgonzo}; 215290245Sgonzo 216290245Sgonzostatic int debugfs_trace_show(struct seq_file *f, void *offset) 217290245Sgonzo{ 218290245Sgonzo VCHIQ_INSTANCE_T instance = f->private; 219290245Sgonzo int trace; 220290245Sgonzo 221290245Sgonzo trace = vchiq_instance_get_trace(instance); 222290245Sgonzo seq_printf(f, "%s\n", trace ? "Y" : "N"); 223290245Sgonzo 224290245Sgonzo return 0; 225290245Sgonzo} 226290245Sgonzo 227290245Sgonzostatic int debugfs_trace_open(struct inode *inode, struct file *file) 228290245Sgonzo{ 229290245Sgonzo return single_open(file, debugfs_trace_show, inode->i_private); 230290245Sgonzo} 231290245Sgonzo 232290245Sgonzostatic int debugfs_trace_write(struct file *file, 233290245Sgonzo const char __user *buffer, 234290245Sgonzo size_t count, loff_t *ppos) 235290245Sgonzo{ 236290245Sgonzo struct seq_file *f = (struct seq_file *)file->private_data; 237290245Sgonzo VCHIQ_INSTANCE_T instance = f->private; 238290245Sgonzo char firstchar; 239290245Sgonzo 240290245Sgonzo if (copy_from_user(&firstchar, buffer, 1) != 0) 241290245Sgonzo return -EFAULT; 242290245Sgonzo 243290245Sgonzo switch (firstchar) { 244290245Sgonzo case 'Y': 245290245Sgonzo case 'y': 246290245Sgonzo case '1': 247290245Sgonzo vchiq_instance_set_trace(instance, 1); 248290245Sgonzo break; 249290245Sgonzo case 'N': 250290245Sgonzo case 'n': 251290245Sgonzo case '0': 252290245Sgonzo vchiq_instance_set_trace(instance, 0); 253290245Sgonzo break; 254290245Sgonzo default: 255290245Sgonzo break; 256290245Sgonzo } 257290245Sgonzo 258290245Sgonzo *ppos += count; 259290245Sgonzo 260290245Sgonzo return count; 261290245Sgonzo} 262290245Sgonzo 263290245Sgonzostatic const struct file_operations debugfs_trace_fops = { 264290245Sgonzo .owner = THIS_MODULE, 265290245Sgonzo .open = debugfs_trace_open, 266290245Sgonzo .write = debugfs_trace_write, 267290245Sgonzo .read = seq_read, 268290245Sgonzo .llseek = seq_lseek, 269290245Sgonzo .release = single_release, 270290245Sgonzo}; 271290245Sgonzo 272290245Sgonzo/* add an instance (process) to the debugfs entries */ 273290245Sgonzoint vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance) 274290245Sgonzo{ 275290245Sgonzo char pidstr[16]; 276290245Sgonzo struct dentry *top, *use_count, *trace; 277290245Sgonzo struct dentry *clients = vchiq_clients_top(); 278290245Sgonzo 279290245Sgonzo snprintf(pidstr, sizeof(pidstr), "%d", 280290245Sgonzo vchiq_instance_get_pid(instance)); 281290245Sgonzo 282290245Sgonzo top = debugfs_create_dir(pidstr, clients); 283290245Sgonzo if (!top) 284290245Sgonzo goto fail_top; 285290245Sgonzo 286290245Sgonzo use_count = debugfs_create_file("use_count", 287290245Sgonzo 0444, top, 288290245Sgonzo instance, 289290245Sgonzo &debugfs_usecount_fops); 290290245Sgonzo if (!use_count) 291290245Sgonzo goto fail_use_count; 292290245Sgonzo 293290245Sgonzo trace = debugfs_create_file("trace", 294290245Sgonzo 0644, top, 295290245Sgonzo instance, 296290245Sgonzo &debugfs_trace_fops); 297290245Sgonzo if (!trace) 298290245Sgonzo goto fail_trace; 299290245Sgonzo 300290245Sgonzo vchiq_instance_get_debugfs_node(instance)->dentry = top; 301290245Sgonzo 302290245Sgonzo return 0; 303290245Sgonzo 304290245Sgonzofail_trace: 305290245Sgonzo debugfs_remove(use_count); 306290245Sgonzofail_use_count: 307290245Sgonzo debugfs_remove(top); 308290245Sgonzofail_top: 309290245Sgonzo return -ENOMEM; 310290245Sgonzo} 311290245Sgonzo 312290245Sgonzovoid vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance) 313290245Sgonzo{ 314290245Sgonzo VCHIQ_DEBUGFS_NODE_T *node = vchiq_instance_get_debugfs_node(instance); 315290245Sgonzo debugfs_remove_recursive(node->dentry); 316290245Sgonzo} 317290245Sgonzo 318290245Sgonzo 319290245Sgonzoint vchiq_debugfs_init(void) 320290245Sgonzo{ 321290245Sgonzo BUG_ON(debugfs_info.vchiq_cfg_dir != NULL); 322290245Sgonzo 323290245Sgonzo debugfs_info.vchiq_cfg_dir = debugfs_create_dir("vchiq", NULL); 324290245Sgonzo if (debugfs_info.vchiq_cfg_dir == NULL) 325290245Sgonzo goto fail; 326290245Sgonzo 327290245Sgonzo debugfs_info.clients = debugfs_create_dir("clients", 328290245Sgonzo vchiq_debugfs_top()); 329290245Sgonzo if (!debugfs_info.clients) 330290245Sgonzo goto fail; 331290245Sgonzo 332290245Sgonzo if (vchiq_debugfs_create_log_entries(vchiq_debugfs_top()) != 0) 333290245Sgonzo goto fail; 334290245Sgonzo 335290245Sgonzo return 0; 336290245Sgonzo 337290245Sgonzofail: 338290245Sgonzo vchiq_debugfs_deinit(); 339290245Sgonzo vchiq_log_error(vchiq_arm_log_level, 340290245Sgonzo "%s: failed to create debugfs directory", 341290245Sgonzo __func__); 342290245Sgonzo 343290245Sgonzo return -ENOMEM; 344290245Sgonzo} 345290245Sgonzo 346290245Sgonzo/* remove all the debugfs entries */ 347290245Sgonzovoid vchiq_debugfs_deinit(void) 348290245Sgonzo{ 349290245Sgonzo debugfs_remove_recursive(vchiq_debugfs_top()); 350290245Sgonzo} 351290245Sgonzo 352290245Sgonzostatic struct dentry *vchiq_clients_top(void) 353290245Sgonzo{ 354290245Sgonzo return debugfs_info.clients; 355290245Sgonzo} 356290245Sgonzo 357290245Sgonzostatic struct dentry *vchiq_debugfs_top(void) 358290245Sgonzo{ 359290245Sgonzo BUG_ON(debugfs_info.vchiq_cfg_dir == NULL); 360290245Sgonzo return debugfs_info.vchiq_cfg_dir; 361290245Sgonzo} 362290245Sgonzo 363290245Sgonzo#else /* CONFIG_DEBUG_FS */ 364290245Sgonzo 365290245Sgonzoint vchiq_debugfs_init(void) 366290245Sgonzo{ 367290245Sgonzo return 0; 368290245Sgonzo} 369290245Sgonzo 370290245Sgonzovoid vchiq_debugfs_deinit(void) 371290245Sgonzo{ 372290245Sgonzo} 373290245Sgonzo 374290245Sgonzoint vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance) 375290245Sgonzo{ 376290245Sgonzo return 0; 377290245Sgonzo} 378290245Sgonzo 379290245Sgonzovoid vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance) 380290245Sgonzo{ 381290245Sgonzo} 382290245Sgonzo 383290245Sgonzo#endif /* CONFIG_DEBUG_FS */ 384