linux/drivers/gpu/host1x/debug.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010 Google, Inc.
   3 * Author: Erik Gilling <konkers@android.com>
   4 *
   5 * Copyright (C) 2011-2013 NVIDIA Corporation
   6 *
   7 * This software is licensed under the terms of the GNU General Public
   8 * License version 2, as published by the Free Software Foundation, and
   9 * may be copied, distributed, and modified under those terms.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 */
  17
  18#include <linux/debugfs.h>
  19#include <linux/seq_file.h>
  20#include <linux/uaccess.h>
  21
  22#include <linux/io.h>
  23
  24#include "dev.h"
  25#include "debug.h"
  26#include "channel.h"
  27
  28unsigned int host1x_debug_trace_cmdbuf;
  29
  30static pid_t host1x_debug_force_timeout_pid;
  31static u32 host1x_debug_force_timeout_val;
  32static u32 host1x_debug_force_timeout_channel;
  33
  34void host1x_debug_output(struct output *o, const char *fmt, ...)
  35{
  36        va_list args;
  37        int len;
  38
  39        va_start(args, fmt);
  40        len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
  41        va_end(args);
  42
  43        o->fn(o->ctx, o->buf, len, false);
  44}
  45
  46void host1x_debug_cont(struct output *o, const char *fmt, ...)
  47{
  48        va_list args;
  49        int len;
  50
  51        va_start(args, fmt);
  52        len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
  53        va_end(args);
  54
  55        o->fn(o->ctx, o->buf, len, true);
  56}
  57
  58static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo)
  59{
  60        struct host1x *m = dev_get_drvdata(ch->dev->parent);
  61        struct output *o = data;
  62
  63        mutex_lock(&ch->cdma.lock);
  64
  65        if (show_fifo)
  66                host1x_hw_show_channel_fifo(m, ch, o);
  67
  68        host1x_hw_show_channel_cdma(m, ch, o);
  69
  70        mutex_unlock(&ch->cdma.lock);
  71
  72        return 0;
  73}
  74
  75static void show_syncpts(struct host1x *m, struct output *o)
  76{
  77        unsigned int i;
  78
  79        host1x_debug_output(o, "---- syncpts ----\n");
  80
  81        for (i = 0; i < host1x_syncpt_nb_pts(m); i++) {
  82                u32 max = host1x_syncpt_read_max(m->syncpt + i);
  83                u32 min = host1x_syncpt_load(m->syncpt + i);
  84
  85                if (!min && !max)
  86                        continue;
  87
  88                host1x_debug_output(o, "id %u (%s) min %d max %d\n",
  89                                    i, m->syncpt[i].name, min, max);
  90        }
  91
  92        for (i = 0; i < host1x_syncpt_nb_bases(m); i++) {
  93                u32 base_val;
  94
  95                base_val = host1x_syncpt_load_wait_base(m->syncpt + i);
  96                if (base_val)
  97                        host1x_debug_output(o, "waitbase id %u val %d\n", i,
  98                                            base_val);
  99        }
 100
 101        host1x_debug_output(o, "\n");
 102}
 103
 104static void show_all(struct host1x *m, struct output *o, bool show_fifo)
 105{
 106        unsigned int i;
 107
 108        host1x_hw_show_mlocks(m, o);
 109        show_syncpts(m, o);
 110        host1x_debug_output(o, "---- channels ----\n");
 111
 112        for (i = 0; i < m->info->nb_channels; ++i) {
 113                struct host1x_channel *ch = host1x_channel_get_index(m, i);
 114
 115                if (ch) {
 116                        show_channel(ch, o, show_fifo);
 117                        host1x_channel_put(ch);
 118                }
 119        }
 120}
 121
 122static int host1x_debug_show_all(struct seq_file *s, void *unused)
 123{
 124        struct output o = {
 125                .fn = write_to_seqfile,
 126                .ctx = s
 127        };
 128
 129        show_all(s->private, &o, true);
 130
 131        return 0;
 132}
 133
 134static int host1x_debug_show(struct seq_file *s, void *unused)
 135{
 136        struct output o = {
 137                .fn = write_to_seqfile,
 138                .ctx = s
 139        };
 140
 141        show_all(s->private, &o, false);
 142
 143        return 0;
 144}
 145
 146static int host1x_debug_open_all(struct inode *inode, struct file *file)
 147{
 148        return single_open(file, host1x_debug_show_all, inode->i_private);
 149}
 150
 151static const struct file_operations host1x_debug_all_fops = {
 152        .open = host1x_debug_open_all,
 153        .read = seq_read,
 154        .llseek = seq_lseek,
 155        .release = single_release,
 156};
 157
 158static int host1x_debug_open(struct inode *inode, struct file *file)
 159{
 160        return single_open(file, host1x_debug_show, inode->i_private);
 161}
 162
 163static const struct file_operations host1x_debug_fops = {
 164        .open = host1x_debug_open,
 165        .read = seq_read,
 166        .llseek = seq_lseek,
 167        .release = single_release,
 168};
 169
 170static void host1x_debugfs_init(struct host1x *host1x)
 171{
 172        struct dentry *de = debugfs_create_dir("tegra-host1x", NULL);
 173
 174        if (!de)
 175                return;
 176
 177        /* Store the created entry */
 178        host1x->debugfs = de;
 179
 180        debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops);
 181        debugfs_create_file("status_all", S_IRUGO, de, host1x,
 182                            &host1x_debug_all_fops);
 183
 184        debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,
 185                           &host1x_debug_trace_cmdbuf);
 186
 187        host1x_hw_debug_init(host1x, de);
 188
 189        debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,
 190                           &host1x_debug_force_timeout_pid);
 191        debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de,
 192                           &host1x_debug_force_timeout_val);
 193        debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de,
 194                           &host1x_debug_force_timeout_channel);
 195}
 196
 197static void host1x_debugfs_exit(struct host1x *host1x)
 198{
 199        debugfs_remove_recursive(host1x->debugfs);
 200}
 201
 202void host1x_debug_init(struct host1x *host1x)
 203{
 204        if (IS_ENABLED(CONFIG_DEBUG_FS))
 205                host1x_debugfs_init(host1x);
 206}
 207
 208void host1x_debug_deinit(struct host1x *host1x)
 209{
 210        if (IS_ENABLED(CONFIG_DEBUG_FS))
 211                host1x_debugfs_exit(host1x);
 212}
 213
 214void host1x_debug_dump(struct host1x *host1x)
 215{
 216        struct output o = {
 217                .fn = write_to_printk
 218        };
 219
 220        show_all(host1x, &o, true);
 221}
 222
 223void host1x_debug_dump_syncpts(struct host1x *host1x)
 224{
 225        struct output o = {
 226                .fn = write_to_printk
 227        };
 228
 229        show_syncpts(host1x, &o);
 230}
 231