Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 : : /* 3 : : * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved. 4 : : * Copyright (c) 2010-2012 Broadcom. All rights reserved. 5 : : */ 6 : : 7 : : #include <linux/debugfs.h> 8 : : #include "vchiq_core.h" 9 : : #include "vchiq_arm.h" 10 : : #include "vchiq_debugfs.h" 11 : : 12 : : #ifdef CONFIG_DEBUG_FS 13 : : 14 : : /**************************************************************************** 15 : : * 16 : : * log category entries 17 : : * 18 : : ***************************************************************************/ 19 : : #define DEBUGFS_WRITE_BUF_SIZE 256 20 : : 21 : : #define VCHIQ_LOG_ERROR_STR "error" 22 : : #define VCHIQ_LOG_WARNING_STR "warning" 23 : : #define VCHIQ_LOG_INFO_STR "info" 24 : : #define VCHIQ_LOG_TRACE_STR "trace" 25 : : 26 : : /* Global 'vchiq' debugfs and clients entry used by all instances */ 27 : : static struct dentry *vchiq_dbg_dir; 28 : : static struct dentry *vchiq_dbg_clients; 29 : : 30 : : /* Log category debugfs entries */ 31 : : struct vchiq_debugfs_log_entry { 32 : : const char *name; 33 : : void *plevel; 34 : : }; 35 : : 36 : : static struct vchiq_debugfs_log_entry vchiq_debugfs_log_entries[] = { 37 : : { "core", &vchiq_core_log_level }, 38 : : { "msg", &vchiq_core_msg_log_level }, 39 : : { "sync", &vchiq_sync_log_level }, 40 : : { "susp", &vchiq_susp_log_level }, 41 : : { "arm", &vchiq_arm_log_level }, 42 : : }; 43 : : static int n_log_entries = ARRAY_SIZE(vchiq_debugfs_log_entries); 44 : : 45 : 0 : static int debugfs_log_show(struct seq_file *f, void *offset) 46 : : { 47 : 0 : int *levp = f->private; 48 : : char *log_value = NULL; 49 : : 50 : 0 : switch (*levp) { 51 : : case VCHIQ_LOG_ERROR: 52 : : log_value = VCHIQ_LOG_ERROR_STR; 53 : : break; 54 : : case VCHIQ_LOG_WARNING: 55 : : log_value = VCHIQ_LOG_WARNING_STR; 56 : : break; 57 : : case VCHIQ_LOG_INFO: 58 : : log_value = VCHIQ_LOG_INFO_STR; 59 : : break; 60 : : case VCHIQ_LOG_TRACE: 61 : : log_value = VCHIQ_LOG_TRACE_STR; 62 : : break; 63 : : default: 64 : : break; 65 : : } 66 : : 67 : 0 : seq_printf(f, "%s\n", log_value ? log_value : "(null)"); 68 : : 69 : 0 : return 0; 70 : : } 71 : : 72 : 0 : static int debugfs_log_open(struct inode *inode, struct file *file) 73 : : { 74 : 0 : return single_open(file, debugfs_log_show, inode->i_private); 75 : : } 76 : : 77 : 0 : static ssize_t debugfs_log_write(struct file *file, 78 : : const char __user *buffer, 79 : : size_t count, loff_t *ppos) 80 : : { 81 : 0 : struct seq_file *f = (struct seq_file *)file->private_data; 82 : 0 : int *levp = f->private; 83 : : char kbuf[DEBUGFS_WRITE_BUF_SIZE + 1]; 84 : : 85 : 0 : memset(kbuf, 0, DEBUGFS_WRITE_BUF_SIZE + 1); 86 : 0 : if (count >= DEBUGFS_WRITE_BUF_SIZE) 87 : : count = DEBUGFS_WRITE_BUF_SIZE; 88 : : 89 : 0 : if (copy_from_user(kbuf, buffer, count)) 90 : : return -EFAULT; 91 : 0 : kbuf[count - 1] = 0; 92 : : 93 : 0 : if (strncmp("error", kbuf, strlen("error")) == 0) 94 : 0 : *levp = VCHIQ_LOG_ERROR; 95 : 0 : else if (strncmp("warning", kbuf, strlen("warning")) == 0) 96 : 0 : *levp = VCHIQ_LOG_WARNING; 97 : 0 : else if (strncmp("info", kbuf, strlen("info")) == 0) 98 : 0 : *levp = VCHIQ_LOG_INFO; 99 : 0 : else if (strncmp("trace", kbuf, strlen("trace")) == 0) 100 : 0 : *levp = VCHIQ_LOG_TRACE; 101 : : else 102 : 0 : *levp = VCHIQ_LOG_DEFAULT; 103 : : 104 : 0 : *ppos += count; 105 : : 106 : 0 : return count; 107 : : } 108 : : 109 : : static const struct file_operations debugfs_log_fops = { 110 : : .owner = THIS_MODULE, 111 : : .open = debugfs_log_open, 112 : : .write = debugfs_log_write, 113 : : .read = seq_read, 114 : : .llseek = seq_lseek, 115 : : .release = single_release, 116 : : }; 117 : : 118 : 0 : static int debugfs_usecount_show(struct seq_file *f, void *offset) 119 : : { 120 : 0 : VCHIQ_INSTANCE_T instance = f->private; 121 : : int use_count; 122 : : 123 : 0 : use_count = vchiq_instance_get_use_count(instance); 124 : 0 : seq_printf(f, "%d\n", use_count); 125 : : 126 : 0 : return 0; 127 : : } 128 : 0 : DEFINE_SHOW_ATTRIBUTE(debugfs_usecount); 129 : : 130 : 0 : static int debugfs_trace_show(struct seq_file *f, void *offset) 131 : : { 132 : 0 : VCHIQ_INSTANCE_T instance = f->private; 133 : : int trace; 134 : : 135 : 0 : trace = vchiq_instance_get_trace(instance); 136 : 0 : seq_printf(f, "%s\n", trace ? "Y" : "N"); 137 : : 138 : 0 : return 0; 139 : : } 140 : : 141 : 0 : static int debugfs_trace_open(struct inode *inode, struct file *file) 142 : : { 143 : 0 : return single_open(file, debugfs_trace_show, inode->i_private); 144 : : } 145 : : 146 : 0 : static ssize_t debugfs_trace_write(struct file *file, 147 : : const char __user *buffer, 148 : : size_t count, loff_t *ppos) 149 : : { 150 : 0 : struct seq_file *f = (struct seq_file *)file->private_data; 151 : 0 : VCHIQ_INSTANCE_T instance = f->private; 152 : : char firstchar; 153 : : 154 : 0 : if (copy_from_user(&firstchar, buffer, 1)) 155 : : return -EFAULT; 156 : : 157 : 0 : switch (firstchar) { 158 : : case 'Y': 159 : : case 'y': 160 : : case '1': 161 : 0 : vchiq_instance_set_trace(instance, 1); 162 : 0 : break; 163 : : case 'N': 164 : : case 'n': 165 : : case '0': 166 : 0 : vchiq_instance_set_trace(instance, 0); 167 : 0 : break; 168 : : default: 169 : : break; 170 : : } 171 : : 172 : 0 : *ppos += count; 173 : : 174 : 0 : return count; 175 : : } 176 : : 177 : : static const struct file_operations debugfs_trace_fops = { 178 : : .owner = THIS_MODULE, 179 : : .open = debugfs_trace_open, 180 : : .write = debugfs_trace_write, 181 : : .read = seq_read, 182 : : .llseek = seq_lseek, 183 : : .release = single_release, 184 : : }; 185 : : 186 : : /* add an instance (process) to the debugfs entries */ 187 : 0 : void vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance) 188 : : { 189 : : char pidstr[16]; 190 : : struct dentry *top; 191 : : 192 : 0 : snprintf(pidstr, sizeof(pidstr), "%d", 193 : : vchiq_instance_get_pid(instance)); 194 : : 195 : 0 : top = debugfs_create_dir(pidstr, vchiq_dbg_clients); 196 : : 197 : 0 : debugfs_create_file("use_count", 0444, top, instance, 198 : : &debugfs_usecount_fops); 199 : 0 : debugfs_create_file("trace", 0644, top, instance, &debugfs_trace_fops); 200 : : 201 : 0 : vchiq_instance_get_debugfs_node(instance)->dentry = top; 202 : 0 : } 203 : : 204 : 0 : void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance) 205 : : { 206 : 0 : struct vchiq_debugfs_node *node = 207 : : vchiq_instance_get_debugfs_node(instance); 208 : : 209 : 0 : debugfs_remove_recursive(node->dentry); 210 : 0 : } 211 : : 212 : 2 : void vchiq_debugfs_init(void) 213 : : { 214 : : struct dentry *dir; 215 : : int i; 216 : : 217 : 2 : vchiq_dbg_dir = debugfs_create_dir("vchiq", NULL); 218 : 2 : vchiq_dbg_clients = debugfs_create_dir("clients", vchiq_dbg_dir); 219 : : 220 : : /* create an entry under <debugfs>/vchiq/log for each log category */ 221 : 2 : dir = debugfs_create_dir("log", vchiq_dbg_dir); 222 : : 223 : 2 : for (i = 0; i < n_log_entries; i++) 224 : 2 : debugfs_create_file(vchiq_debugfs_log_entries[i].name, 0644, 225 : : dir, vchiq_debugfs_log_entries[i].plevel, 226 : : &debugfs_log_fops); 227 : 2 : } 228 : : 229 : : /* remove all the debugfs entries */ 230 : 0 : void vchiq_debugfs_deinit(void) 231 : : { 232 : 0 : debugfs_remove_recursive(vchiq_dbg_dir); 233 : 0 : } 234 : : 235 : : #else /* CONFIG_DEBUG_FS */ 236 : : 237 : : void vchiq_debugfs_init(void) 238 : : { 239 : : } 240 : : 241 : : void vchiq_debugfs_deinit(void) 242 : : { 243 : : } 244 : : 245 : : void vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance) 246 : : { 247 : : } 248 : : 249 : : void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance) 250 : : { 251 : : } 252 : : 253 : : #endif /* CONFIG_DEBUG_FS */