Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2010 Google, Inc.
0004  * Author: Erik Gilling <konkers@android.com>
0005  *
0006  * Copyright (C) 2011-2013 NVIDIA Corporation
0007  */
0008 
0009 #include <linux/debugfs.h>
0010 #include <linux/pm_runtime.h>
0011 #include <linux/seq_file.h>
0012 #include <linux/uaccess.h>
0013 
0014 #include <linux/io.h>
0015 
0016 #include "dev.h"
0017 #include "debug.h"
0018 #include "channel.h"
0019 
0020 static DEFINE_MUTEX(debug_lock);
0021 
0022 unsigned int host1x_debug_trace_cmdbuf;
0023 
0024 static pid_t host1x_debug_force_timeout_pid;
0025 static u32 host1x_debug_force_timeout_val;
0026 static u32 host1x_debug_force_timeout_channel;
0027 
0028 void host1x_debug_output(struct output *o, const char *fmt, ...)
0029 {
0030     va_list args;
0031     int len;
0032 
0033     va_start(args, fmt);
0034     len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
0035     va_end(args);
0036 
0037     o->fn(o->ctx, o->buf, len, false);
0038 }
0039 
0040 void host1x_debug_cont(struct output *o, const char *fmt, ...)
0041 {
0042     va_list args;
0043     int len;
0044 
0045     va_start(args, fmt);
0046     len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
0047     va_end(args);
0048 
0049     o->fn(o->ctx, o->buf, len, true);
0050 }
0051 
0052 static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo)
0053 {
0054     struct host1x *m = dev_get_drvdata(ch->dev->parent);
0055     struct output *o = data;
0056     int err;
0057 
0058     err = pm_runtime_resume_and_get(m->dev);
0059     if (err < 0)
0060         return err;
0061 
0062     mutex_lock(&ch->cdma.lock);
0063     mutex_lock(&debug_lock);
0064 
0065     if (show_fifo)
0066         host1x_hw_show_channel_fifo(m, ch, o);
0067 
0068     host1x_hw_show_channel_cdma(m, ch, o);
0069 
0070     mutex_unlock(&debug_lock);
0071     mutex_unlock(&ch->cdma.lock);
0072 
0073     pm_runtime_put(m->dev);
0074 
0075     return 0;
0076 }
0077 
0078 static void show_syncpts(struct host1x *m, struct output *o, bool show_all)
0079 {
0080     struct list_head *pos;
0081     unsigned int i;
0082     int err;
0083 
0084     host1x_debug_output(o, "---- syncpts ----\n");
0085 
0086     err = pm_runtime_resume_and_get(m->dev);
0087     if (err < 0)
0088         return;
0089 
0090     for (i = 0; i < host1x_syncpt_nb_pts(m); i++) {
0091         u32 max = host1x_syncpt_read_max(m->syncpt + i);
0092         u32 min = host1x_syncpt_load(m->syncpt + i);
0093         unsigned int waiters = 0;
0094 
0095         spin_lock(&m->syncpt[i].intr.lock);
0096         list_for_each(pos, &m->syncpt[i].intr.wait_head)
0097             waiters++;
0098         spin_unlock(&m->syncpt[i].intr.lock);
0099 
0100         if (!kref_read(&m->syncpt[i].ref))
0101             continue;
0102 
0103         if (!show_all && !min && !max && !waiters)
0104             continue;
0105 
0106         host1x_debug_output(o,
0107                     "id %u (%s) min %d max %d (%d waiters)\n",
0108                     i, m->syncpt[i].name, min, max, waiters);
0109     }
0110 
0111     for (i = 0; i < host1x_syncpt_nb_bases(m); i++) {
0112         u32 base_val;
0113 
0114         base_val = host1x_syncpt_load_wait_base(m->syncpt + i);
0115         if (base_val)
0116             host1x_debug_output(o, "waitbase id %u val %d\n", i,
0117                         base_val);
0118     }
0119 
0120     pm_runtime_put(m->dev);
0121 
0122     host1x_debug_output(o, "\n");
0123 }
0124 
0125 static void show_all(struct host1x *m, struct output *o, bool show_fifo)
0126 {
0127     unsigned int i;
0128 
0129     host1x_hw_show_mlocks(m, o);
0130     show_syncpts(m, o, true);
0131     host1x_debug_output(o, "---- channels ----\n");
0132 
0133     for (i = 0; i < m->info->nb_channels; ++i) {
0134         struct host1x_channel *ch = host1x_channel_get_index(m, i);
0135 
0136         if (ch) {
0137             show_channel(ch, o, show_fifo);
0138             host1x_channel_put(ch);
0139         }
0140     }
0141 }
0142 
0143 static int host1x_debug_show_all(struct seq_file *s, void *unused)
0144 {
0145     struct output o = {
0146         .fn = write_to_seqfile,
0147         .ctx = s
0148     };
0149 
0150     show_all(s->private, &o, true);
0151 
0152     return 0;
0153 }
0154 
0155 static int host1x_debug_show(struct seq_file *s, void *unused)
0156 {
0157     struct output o = {
0158         .fn = write_to_seqfile,
0159         .ctx = s
0160     };
0161 
0162     show_all(s->private, &o, false);
0163 
0164     return 0;
0165 }
0166 
0167 static int host1x_debug_open_all(struct inode *inode, struct file *file)
0168 {
0169     return single_open(file, host1x_debug_show_all, inode->i_private);
0170 }
0171 
0172 static const struct file_operations host1x_debug_all_fops = {
0173     .open = host1x_debug_open_all,
0174     .read = seq_read,
0175     .llseek = seq_lseek,
0176     .release = single_release,
0177 };
0178 
0179 static int host1x_debug_open(struct inode *inode, struct file *file)
0180 {
0181     return single_open(file, host1x_debug_show, inode->i_private);
0182 }
0183 
0184 static const struct file_operations host1x_debug_fops = {
0185     .open = host1x_debug_open,
0186     .read = seq_read,
0187     .llseek = seq_lseek,
0188     .release = single_release,
0189 };
0190 
0191 static void host1x_debugfs_init(struct host1x *host1x)
0192 {
0193     struct dentry *de = debugfs_create_dir("tegra-host1x", NULL);
0194 
0195     /* Store the created entry */
0196     host1x->debugfs = de;
0197 
0198     debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops);
0199     debugfs_create_file("status_all", S_IRUGO, de, host1x,
0200                 &host1x_debug_all_fops);
0201 
0202     debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,
0203                &host1x_debug_trace_cmdbuf);
0204 
0205     host1x_hw_debug_init(host1x, de);
0206 
0207     debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,
0208                &host1x_debug_force_timeout_pid);
0209     debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de,
0210                &host1x_debug_force_timeout_val);
0211     debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de,
0212                &host1x_debug_force_timeout_channel);
0213 }
0214 
0215 static void host1x_debugfs_exit(struct host1x *host1x)
0216 {
0217     debugfs_remove_recursive(host1x->debugfs);
0218 }
0219 
0220 void host1x_debug_init(struct host1x *host1x)
0221 {
0222     if (IS_ENABLED(CONFIG_DEBUG_FS))
0223         host1x_debugfs_init(host1x);
0224 }
0225 
0226 void host1x_debug_deinit(struct host1x *host1x)
0227 {
0228     if (IS_ENABLED(CONFIG_DEBUG_FS))
0229         host1x_debugfs_exit(host1x);
0230 }
0231 
0232 void host1x_debug_dump(struct host1x *host1x)
0233 {
0234     struct output o = {
0235         .fn = write_to_printk
0236     };
0237 
0238     show_all(host1x, &o, true);
0239 }
0240 
0241 void host1x_debug_dump_syncpts(struct host1x *host1x)
0242 {
0243     struct output o = {
0244         .fn = write_to_printk
0245     };
0246 
0247     show_syncpts(host1x, &o, false);
0248 }