Path: blob/main/sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.c
48383 views
/**1* Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.2* Copyright (c) 2010-2012 Broadcom. All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions, and the following disclaimer,9* without modification.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13* 3. The names of the above-listed copyright holders may not be used14* to endorse or promote products derived from this software without15* specific prior written permission.16*17* ALTERNATIVELY, this software may be distributed under the terms of the18* GNU General Public License ("GPL") version 2, as published by the Free19* Software Foundation.20*21* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS22* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,23* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR24* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR25* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,26* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,27* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR28* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF29* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING30* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS31* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.32*/333435#include <linux/debugfs.h>36#include "vchiq_core.h"37#include "vchiq_arm.h"38#include "vchiq_debugfs.h"3940#ifdef CONFIG_DEBUG_FS4142/****************************************************************************43*44* log category entries45*46***************************************************************************/47#define DEBUGFS_WRITE_BUF_SIZE 2564849#define VCHIQ_LOG_ERROR_STR "error"50#define VCHIQ_LOG_WARNING_STR "warning"51#define VCHIQ_LOG_INFO_STR "info"52#define VCHIQ_LOG_TRACE_STR "trace"535455/* Top-level debug info */56struct vchiq_debugfs_info {57/* Global 'vchiq' debugfs entry used by all instances */58struct dentry *vchiq_cfg_dir;5960/* one entry per client process */61struct dentry *clients;6263/* log categories */64struct dentry *log_categories;65};6667static struct vchiq_debugfs_info debugfs_info;6869/* Log category debugfs entries */70struct vchiq_debugfs_log_entry {71const char *name;72int *plevel;73struct dentry *dir;74};7576static struct vchiq_debugfs_log_entry vchiq_debugfs_log_entries[] = {77{ "core", &vchiq_core_log_level },78{ "msg", &vchiq_core_msg_log_level },79{ "sync", &vchiq_sync_log_level },80{ "susp", &vchiq_susp_log_level },81{ "arm", &vchiq_arm_log_level },82};83static int n_log_entries =84sizeof(vchiq_debugfs_log_entries)/sizeof(vchiq_debugfs_log_entries[0]);858687static struct dentry *vchiq_clients_top(void);88static struct dentry *vchiq_debugfs_top(void);8990static int debugfs_log_show(struct seq_file *f, void *offset)91{92int *levp = f->private;93char *log_value = NULL;9495switch (*levp) {96case VCHIQ_LOG_ERROR:97log_value = VCHIQ_LOG_ERROR_STR;98break;99case VCHIQ_LOG_WARNING:100log_value = VCHIQ_LOG_WARNING_STR;101break;102case VCHIQ_LOG_INFO:103log_value = VCHIQ_LOG_INFO_STR;104break;105case VCHIQ_LOG_TRACE:106log_value = VCHIQ_LOG_TRACE_STR;107break;108default:109break;110}111112seq_printf(f, "%s\n", log_value ? log_value : "(null)");113114return 0;115}116117static int debugfs_log_open(struct inode *inode, struct file *file)118{119return single_open(file, debugfs_log_show, inode->i_private);120}121122static int debugfs_log_write(struct file *file,123const char __user *buffer,124size_t count, loff_t *ppos)125{126struct seq_file *f = (struct seq_file *)file->private_data;127int *levp = f->private;128char kbuf[DEBUGFS_WRITE_BUF_SIZE + 1];129130memset(kbuf, 0, DEBUGFS_WRITE_BUF_SIZE + 1);131if (count >= DEBUGFS_WRITE_BUF_SIZE)132count = DEBUGFS_WRITE_BUF_SIZE;133134if (copy_from_user(kbuf, buffer, count) != 0)135return -EFAULT;136kbuf[count - 1] = 0;137138if (strncmp("error", kbuf, strlen("error")) == 0)139*levp = VCHIQ_LOG_ERROR;140else if (strncmp("warning", kbuf, strlen("warning")) == 0)141*levp = VCHIQ_LOG_WARNING;142else if (strncmp("info", kbuf, strlen("info")) == 0)143*levp = VCHIQ_LOG_INFO;144else if (strncmp("trace", kbuf, strlen("trace")) == 0)145*levp = VCHIQ_LOG_TRACE;146else147*levp = VCHIQ_LOG_DEFAULT;148149*ppos += count;150151return count;152}153154static const struct file_operations debugfs_log_fops = {155.owner = THIS_MODULE,156.open = debugfs_log_open,157.write = debugfs_log_write,158.read = seq_read,159.llseek = seq_lseek,160.release = single_release,161};162163/* create an entry under <debugfs>/vchiq/log for each log category */164static int vchiq_debugfs_create_log_entries(struct dentry *top)165{166struct dentry *dir;167size_t i;168int ret = 0;169dir = debugfs_create_dir("log", vchiq_debugfs_top());170if (!dir)171return -ENOMEM;172debugfs_info.log_categories = dir;173174for (i = 0; i < n_log_entries; i++) {175void *levp = (void *)vchiq_debugfs_log_entries[i].plevel;176dir = debugfs_create_file(vchiq_debugfs_log_entries[i].name,1770644,178debugfs_info.log_categories,179levp,180&debugfs_log_fops);181if (!dir) {182ret = -ENOMEM;183break;184}185186vchiq_debugfs_log_entries[i].dir = dir;187}188return ret;189}190191static int debugfs_usecount_show(struct seq_file *f, void *offset)192{193VCHIQ_INSTANCE_T instance = f->private;194int use_count;195196use_count = vchiq_instance_get_use_count(instance);197seq_printf(f, "%d\n", use_count);198199return 0;200}201202static int debugfs_usecount_open(struct inode *inode, struct file *file)203{204return single_open(file, debugfs_usecount_show, inode->i_private);205}206207static const struct file_operations debugfs_usecount_fops = {208.owner = THIS_MODULE,209.open = debugfs_usecount_open,210.read = seq_read,211.llseek = seq_lseek,212.release = single_release,213};214215static int debugfs_trace_show(struct seq_file *f, void *offset)216{217VCHIQ_INSTANCE_T instance = f->private;218int trace;219220trace = vchiq_instance_get_trace(instance);221seq_printf(f, "%s\n", trace ? "Y" : "N");222223return 0;224}225226static int debugfs_trace_open(struct inode *inode, struct file *file)227{228return single_open(file, debugfs_trace_show, inode->i_private);229}230231static int debugfs_trace_write(struct file *file,232const char __user *buffer,233size_t count, loff_t *ppos)234{235struct seq_file *f = (struct seq_file *)file->private_data;236VCHIQ_INSTANCE_T instance = f->private;237char firstchar;238239if (copy_from_user(&firstchar, buffer, 1) != 0)240return -EFAULT;241242switch (firstchar) {243case 'Y':244case 'y':245case '1':246vchiq_instance_set_trace(instance, 1);247break;248case 'N':249case 'n':250case '0':251vchiq_instance_set_trace(instance, 0);252break;253default:254break;255}256257*ppos += count;258259return count;260}261262static const struct file_operations debugfs_trace_fops = {263.owner = THIS_MODULE,264.open = debugfs_trace_open,265.write = debugfs_trace_write,266.read = seq_read,267.llseek = seq_lseek,268.release = single_release,269};270271/* add an instance (process) to the debugfs entries */272int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)273{274char pidstr[16];275struct dentry *top, *use_count, *trace;276struct dentry *clients = vchiq_clients_top();277278snprintf(pidstr, sizeof(pidstr), "%d",279vchiq_instance_get_pid(instance));280281top = debugfs_create_dir(pidstr, clients);282if (!top)283goto fail_top;284285use_count = debugfs_create_file("use_count",2860444, top,287instance,288&debugfs_usecount_fops);289if (!use_count)290goto fail_use_count;291292trace = debugfs_create_file("trace",2930644, top,294instance,295&debugfs_trace_fops);296if (!trace)297goto fail_trace;298299vchiq_instance_get_debugfs_node(instance)->dentry = top;300301return 0;302303fail_trace:304debugfs_remove(use_count);305fail_use_count:306debugfs_remove(top);307fail_top:308return -ENOMEM;309}310311void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)312{313VCHIQ_DEBUGFS_NODE_T *node = vchiq_instance_get_debugfs_node(instance);314debugfs_remove_recursive(node->dentry);315}316317318int vchiq_debugfs_init(void)319{320BUG_ON(debugfs_info.vchiq_cfg_dir != NULL);321322debugfs_info.vchiq_cfg_dir = debugfs_create_dir("vchiq", NULL);323if (debugfs_info.vchiq_cfg_dir == NULL)324goto fail;325326debugfs_info.clients = debugfs_create_dir("clients",327vchiq_debugfs_top());328if (!debugfs_info.clients)329goto fail;330331if (vchiq_debugfs_create_log_entries(vchiq_debugfs_top()) != 0)332goto fail;333334return 0;335336fail:337vchiq_debugfs_deinit();338vchiq_log_error(vchiq_arm_log_level,339"%s: failed to create debugfs directory",340__func__);341342return -ENOMEM;343}344345/* remove all the debugfs entries */346void vchiq_debugfs_deinit(void)347{348debugfs_remove_recursive(vchiq_debugfs_top());349}350351static struct dentry *vchiq_clients_top(void)352{353return debugfs_info.clients;354}355356static struct dentry *vchiq_debugfs_top(void)357{358BUG_ON(debugfs_info.vchiq_cfg_dir == NULL);359return debugfs_info.vchiq_cfg_dir;360}361362#else /* CONFIG_DEBUG_FS */363364int vchiq_debugfs_init(void)365{366return 0;367}368369void vchiq_debugfs_deinit(void)370{371}372373int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)374{375return 0;376}377378void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)379{380}381382#endif /* CONFIG_DEBUG_FS */383384385