Commit 6236451d83a720072053855fa63d51934024a707

Authored by Terje Bergstrom
Committed by Thierry Reding
1 parent 6579324a41

gpu: host1x: Add debug support

Add support for host1x debugging. Adds debugfs entries, and dumps
channel state to UART in case of stuck job.

Signed-off-by: Arto Merilainen <amerilainen@nvidia.com>
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-by: Thierry Reding <thierry.reding@avionic-design.de>
Tested-by: Thierry Reding <thierry.reding@avionic-design.de>
Tested-by: Erik Faye-Lund <kusmabite@gmail.com>
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>

Showing 15 changed files with 807 additions and 0 deletions Side-by-side Diff

drivers/gpu/host1x/Makefile
... ... @@ -7,6 +7,7 @@
7 7 cdma.o \
8 8 channel.o \
9 9 job.o \
  10 + debug.o \
10 11 hw/host1x01.o
11 12  
12 13 obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
drivers/gpu/host1x/cdma.c
... ... @@ -439,6 +439,10 @@
439 439 struct push_buffer *pb = &cdma->push_buffer;
440 440 u32 slots_free = cdma->slots_free;
441 441  
  442 + if (host1x_debug_trace_cmdbuf)
  443 + trace_host1x_cdma_push(dev_name(cdma_to_channel(cdma)->dev),
  444 + op1, op2);
  445 +
442 446 if (slots_free == 0) {
443 447 host1x_hw_cdma_flush(host1x, cdma);
444 448 slots_free = host1x_cdma_wait_locked(cdma,
drivers/gpu/host1x/debug.c
  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 +
  28 +unsigned int host1x_debug_trace_cmdbuf;
  29 +
  30 +static pid_t host1x_debug_force_timeout_pid;
  31 +static u32 host1x_debug_force_timeout_val;
  32 +static u32 host1x_debug_force_timeout_channel;
  33 +
  34 +void 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 + o->fn(o->ctx, o->buf, len);
  43 +}
  44 +
  45 +static int show_channels(struct host1x_channel *ch, void *data, bool show_fifo)
  46 +{
  47 + struct host1x *m = dev_get_drvdata(ch->dev->parent);
  48 + struct output *o = data;
  49 +
  50 + mutex_lock(&ch->reflock);
  51 + if (ch->refcount) {
  52 + mutex_lock(&ch->cdma.lock);
  53 + if (show_fifo)
  54 + host1x_hw_show_channel_fifo(m, ch, o);
  55 + host1x_hw_show_channel_cdma(m, ch, o);
  56 + mutex_unlock(&ch->cdma.lock);
  57 + }
  58 + mutex_unlock(&ch->reflock);
  59 +
  60 + return 0;
  61 +}
  62 +
  63 +static void show_syncpts(struct host1x *m, struct output *o)
  64 +{
  65 + int i;
  66 + host1x_debug_output(o, "---- syncpts ----\n");
  67 + for (i = 0; i < host1x_syncpt_nb_pts(m); i++) {
  68 + u32 max = host1x_syncpt_read_max(m->syncpt + i);
  69 + u32 min = host1x_syncpt_load(m->syncpt + i);
  70 + if (!min && !max)
  71 + continue;
  72 + host1x_debug_output(o, "id %d (%s) min %d max %d\n",
  73 + i, m->syncpt[i].name, min, max);
  74 + }
  75 +
  76 + for (i = 0; i < host1x_syncpt_nb_bases(m); i++) {
  77 + u32 base_val;
  78 + base_val = host1x_syncpt_load_wait_base(m->syncpt + i);
  79 + if (base_val)
  80 + host1x_debug_output(o, "waitbase id %d val %d\n", i,
  81 + base_val);
  82 + }
  83 +
  84 + host1x_debug_output(o, "\n");
  85 +}
  86 +
  87 +static void show_all(struct host1x *m, struct output *o)
  88 +{
  89 + struct host1x_channel *ch;
  90 +
  91 + host1x_hw_show_mlocks(m, o);
  92 + show_syncpts(m, o);
  93 + host1x_debug_output(o, "---- channels ----\n");
  94 +
  95 + host1x_for_each_channel(m, ch)
  96 + show_channels(ch, o, true);
  97 +}
  98 +
  99 +#ifdef CONFIG_DEBUG_FS
  100 +static void show_all_no_fifo(struct host1x *host1x, struct output *o)
  101 +{
  102 + struct host1x_channel *ch;
  103 +
  104 + host1x_hw_show_mlocks(host1x, o);
  105 + show_syncpts(host1x, o);
  106 + host1x_debug_output(o, "---- channels ----\n");
  107 +
  108 + host1x_for_each_channel(host1x, ch)
  109 + show_channels(ch, o, false);
  110 +}
  111 +
  112 +static int host1x_debug_show_all(struct seq_file *s, void *unused)
  113 +{
  114 + struct output o = {
  115 + .fn = write_to_seqfile,
  116 + .ctx = s
  117 + };
  118 + show_all(s->private, &o);
  119 + return 0;
  120 +}
  121 +
  122 +static int host1x_debug_show(struct seq_file *s, void *unused)
  123 +{
  124 + struct output o = {
  125 + .fn = write_to_seqfile,
  126 + .ctx = s
  127 + };
  128 + show_all_no_fifo(s->private, &o);
  129 + return 0;
  130 +}
  131 +
  132 +static int host1x_debug_open_all(struct inode *inode, struct file *file)
  133 +{
  134 + return single_open(file, host1x_debug_show_all, inode->i_private);
  135 +}
  136 +
  137 +static const struct file_operations host1x_debug_all_fops = {
  138 + .open = host1x_debug_open_all,
  139 + .read = seq_read,
  140 + .llseek = seq_lseek,
  141 + .release = single_release,
  142 +};
  143 +
  144 +static int host1x_debug_open(struct inode *inode, struct file *file)
  145 +{
  146 + return single_open(file, host1x_debug_show, inode->i_private);
  147 +}
  148 +
  149 +static const struct file_operations host1x_debug_fops = {
  150 + .open = host1x_debug_open,
  151 + .read = seq_read,
  152 + .llseek = seq_lseek,
  153 + .release = single_release,
  154 +};
  155 +
  156 +void host1x_debug_init(struct host1x *host1x)
  157 +{
  158 + struct dentry *de = debugfs_create_dir("tegra-host1x", NULL);
  159 +
  160 + if (!de)
  161 + return;
  162 +
  163 + /* Store the created entry */
  164 + host1x->debugfs = de;
  165 +
  166 + debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops);
  167 + debugfs_create_file("status_all", S_IRUGO, de, host1x,
  168 + &host1x_debug_all_fops);
  169 +
  170 + debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,
  171 + &host1x_debug_trace_cmdbuf);
  172 +
  173 + host1x_hw_debug_init(host1x, de);
  174 +
  175 + debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,
  176 + &host1x_debug_force_timeout_pid);
  177 + debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de,
  178 + &host1x_debug_force_timeout_val);
  179 + debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de,
  180 + &host1x_debug_force_timeout_channel);
  181 +}
  182 +
  183 +void host1x_debug_deinit(struct host1x *host1x)
  184 +{
  185 + debugfs_remove_recursive(host1x->debugfs);
  186 +}
  187 +#else
  188 +void host1x_debug_init(struct host1x *host1x)
  189 +{
  190 +}
  191 +void host1x_debug_deinit(struct host1x *host1x)
  192 +{
  193 +}
  194 +#endif
  195 +
  196 +void host1x_debug_dump(struct host1x *host1x)
  197 +{
  198 + struct output o = {
  199 + .fn = write_to_printk
  200 + };
  201 + show_all(host1x, &o);
  202 +}
  203 +
  204 +void host1x_debug_dump_syncpts(struct host1x *host1x)
  205 +{
  206 + struct output o = {
  207 + .fn = write_to_printk
  208 + };
  209 + show_syncpts(host1x, &o);
  210 +}
drivers/gpu/host1x/debug.h
  1 +/*
  2 + * Tegra host1x Debug
  3 + *
  4 + * Copyright (c) 2011-2013 NVIDIA Corporation.
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify it
  7 + * under the terms and conditions of the GNU General Public License,
  8 + * version 2, as published by the Free Software Foundation.
  9 + *
  10 + * This program is distributed in the hope it will be useful, but WITHOUT
  11 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13 + * more details.
  14 + *
  15 + * You should have received a copy of the GNU General Public License
  16 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17 + */
  18 +#ifndef __HOST1X_DEBUG_H
  19 +#define __HOST1X_DEBUG_H
  20 +
  21 +#include <linux/debugfs.h>
  22 +#include <linux/seq_file.h>
  23 +
  24 +struct host1x;
  25 +
  26 +struct output {
  27 + void (*fn)(void *ctx, const char *str, size_t len);
  28 + void *ctx;
  29 + char buf[256];
  30 +};
  31 +
  32 +static inline void write_to_seqfile(void *ctx, const char *str, size_t len)
  33 +{
  34 + seq_write((struct seq_file *)ctx, str, len);
  35 +}
  36 +
  37 +static inline void write_to_printk(void *ctx, const char *str, size_t len)
  38 +{
  39 + pr_info("%s", str);
  40 +}
  41 +
  42 +void __printf(2, 3) host1x_debug_output(struct output *o, const char *fmt, ...);
  43 +
  44 +extern unsigned int host1x_debug_trace_cmdbuf;
  45 +
  46 +void host1x_debug_init(struct host1x *host1x);
  47 +void host1x_debug_deinit(struct host1x *host1x);
  48 +void host1x_debug_dump(struct host1x *host1x);
  49 +void host1x_debug_dump_syncpts(struct host1x *host1x);
  50 +
  51 +#endif
drivers/gpu/host1x/dev.c
... ... @@ -30,6 +30,7 @@
30 30 #include "dev.h"
31 31 #include "intr.h"
32 32 #include "channel.h"
  33 +#include "debug.h"
33 34 #include "hw/host1x01.h"
34 35  
35 36 void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
... ... @@ -146,6 +147,8 @@
146 147 dev_err(&pdev->dev, "failed to initialize interrupts\n");
147 148 goto fail_deinit_syncpt;
148 149 }
  150 +
  151 + host1x_debug_init(host);
149 152  
150 153 return 0;
151 154  
drivers/gpu/host1x/dev.h
... ... @@ -31,6 +31,8 @@
31 31 struct host1x_cdma;
32 32 struct host1x_job;
33 33 struct push_buffer;
  34 +struct output;
  35 +struct dentry;
34 36  
35 37 struct host1x_channel_ops {
36 38 int (*init)(struct host1x_channel *channel, struct host1x *host,
... ... @@ -54,6 +56,18 @@
54 56 void (*init)(struct push_buffer *pb);
55 57 };
56 58  
  59 +struct host1x_debug_ops {
  60 + void (*debug_init)(struct dentry *de);
  61 + void (*show_channel_cdma)(struct host1x *host,
  62 + struct host1x_channel *ch,
  63 + struct output *o);
  64 + void (*show_channel_fifo)(struct host1x *host,
  65 + struct host1x_channel *ch,
  66 + struct output *o);
  67 + void (*show_mlocks)(struct host1x *host, struct output *output);
  68 +
  69 +};
  70 +
57 71 struct host1x_syncpt_ops {
58 72 void (*restore)(struct host1x_syncpt *syncpt);
59 73 void (*restore_wait_base)(struct host1x_syncpt *syncpt);
... ... @@ -100,6 +114,7 @@
100 114 const struct host1x_channel_ops *channel_op;
101 115 const struct host1x_cdma_ops *cdma_op;
102 116 const struct host1x_pushbuffer_ops *cdma_pb_op;
  117 + const struct host1x_debug_ops *debug_op;
103 118  
104 119 struct host1x_syncpt *nop_sp;
105 120  
... ... @@ -107,6 +122,8 @@
107 122 struct host1x_channel chlist;
108 123 unsigned long allocated_channels;
109 124 unsigned int num_allocated_channels;
  125 +
  126 + struct dentry *debugfs;
110 127 };
111 128  
112 129 void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v);
... ... @@ -255,6 +272,31 @@
255 272 struct push_buffer *pb)
256 273 {
257 274 host->cdma_pb_op->init(pb);
  275 +}
  276 +
  277 +static inline void host1x_hw_debug_init(struct host1x *host, struct dentry *de)
  278 +{
  279 + if (host->debug_op && host->debug_op->debug_init)
  280 + host->debug_op->debug_init(de);
  281 +}
  282 +
  283 +static inline void host1x_hw_show_channel_cdma(struct host1x *host,
  284 + struct host1x_channel *channel,
  285 + struct output *o)
  286 +{
  287 + host->debug_op->show_channel_cdma(host, channel, o);
  288 +}
  289 +
  290 +static inline void host1x_hw_show_channel_fifo(struct host1x *host,
  291 + struct host1x_channel *channel,
  292 + struct output *o)
  293 +{
  294 + host->debug_op->show_channel_fifo(host, channel, o);
  295 +}
  296 +
  297 +static inline void host1x_hw_show_mlocks(struct host1x *host, struct output *o)
  298 +{
  299 + host->debug_op->show_mlocks(host, o);
258 300 }
259 301  
260 302 #endif
drivers/gpu/host1x/hw/cdma_hw.c
... ... @@ -244,6 +244,8 @@
244 244 host1x = cdma_to_host1x(cdma);
245 245 ch = cdma_to_channel(cdma);
246 246  
  247 + host1x_debug_dump(cdma_to_host1x(cdma));
  248 +
247 249 mutex_lock(&cdma->lock);
248 250  
249 251 if (!cdma->timeout.client) {
drivers/gpu/host1x/hw/channel_hw.c
... ... @@ -29,6 +29,30 @@
29 29 #define HOST1X_CHANNEL_SIZE 16384
30 30 #define TRACE_MAX_LENGTH 128U
31 31  
  32 +static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo,
  33 + u32 offset, u32 words)
  34 +{
  35 + void *mem = NULL;
  36 +
  37 + if (host1x_debug_trace_cmdbuf)
  38 + mem = host1x_bo_mmap(bo);
  39 +
  40 + if (mem) {
  41 + u32 i;
  42 + /*
  43 + * Write in batches of 128 as there seems to be a limit
  44 + * of how much you can output to ftrace at once.
  45 + */
  46 + for (i = 0; i < words; i += TRACE_MAX_LENGTH) {
  47 + trace_host1x_cdma_push_gather(
  48 + dev_name(cdma_to_channel(cdma)->dev),
  49 + (u32)bo, min(words - i, TRACE_MAX_LENGTH),
  50 + offset + i * sizeof(u32), mem);
  51 + }
  52 + host1x_bo_munmap(bo, mem);
  53 + }
  54 +}
  55 +
32 56 static void submit_gathers(struct host1x_job *job)
33 57 {
34 58 struct host1x_cdma *cdma = &job->channel->cdma;
... ... @@ -38,6 +62,7 @@
38 62 struct host1x_job_gather *g = &job->gathers[i];
39 63 u32 op1 = host1x_opcode_gather(g->words);
40 64 u32 op2 = g->base + g->offset;
  65 + trace_write_gather(cdma, g->bo, g->offset, op1 & 0xffff);
41 66 host1x_cdma_push(cdma, op1, op2);
42 67 }
43 68 }
drivers/gpu/host1x/hw/debug_hw.c
  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/mm.h>
  21 +#include <linux/scatterlist.h>
  22 +
  23 +#include <linux/io.h>
  24 +
  25 +#include "dev.h"
  26 +#include "debug.h"
  27 +#include "cdma.h"
  28 +#include "channel.h"
  29 +#include "host1x_bo.h"
  30 +
  31 +#define HOST1X_DEBUG_MAX_PAGE_OFFSET 102400
  32 +
  33 +enum {
  34 + HOST1X_OPCODE_SETCLASS = 0x00,
  35 + HOST1X_OPCODE_INCR = 0x01,
  36 + HOST1X_OPCODE_NONINCR = 0x02,
  37 + HOST1X_OPCODE_MASK = 0x03,
  38 + HOST1X_OPCODE_IMM = 0x04,
  39 + HOST1X_OPCODE_RESTART = 0x05,
  40 + HOST1X_OPCODE_GATHER = 0x06,
  41 + HOST1X_OPCODE_EXTEND = 0x0e,
  42 +};
  43 +
  44 +enum {
  45 + HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK = 0x00,
  46 + HOST1X_OPCODE_EXTEND_RELEASE_MLOCK = 0x01,
  47 +};
  48 +
  49 +static unsigned int show_channel_command(struct output *o, u32 val)
  50 +{
  51 + unsigned mask;
  52 + unsigned subop;
  53 +
  54 + switch (val >> 28) {
  55 + case HOST1X_OPCODE_SETCLASS:
  56 + mask = val & 0x3f;
  57 + if (mask) {
  58 + host1x_debug_output(o, "SETCL(class=%03x, offset=%03x, mask=%02x, [",
  59 + val >> 6 & 0x3ff,
  60 + val >> 16 & 0xfff, mask);
  61 + return hweight8(mask);
  62 + } else {
  63 + host1x_debug_output(o, "SETCL(class=%03x)\n",
  64 + val >> 6 & 0x3ff);
  65 + return 0;
  66 + }
  67 +
  68 + case HOST1X_OPCODE_INCR:
  69 + host1x_debug_output(o, "INCR(offset=%03x, [",
  70 + val >> 16 & 0xfff);
  71 + return val & 0xffff;
  72 +
  73 + case HOST1X_OPCODE_NONINCR:
  74 + host1x_debug_output(o, "NONINCR(offset=%03x, [",
  75 + val >> 16 & 0xfff);
  76 + return val & 0xffff;
  77 +
  78 + case HOST1X_OPCODE_MASK:
  79 + mask = val & 0xffff;
  80 + host1x_debug_output(o, "MASK(offset=%03x, mask=%03x, [",
  81 + val >> 16 & 0xfff, mask);
  82 + return hweight16(mask);
  83 +
  84 + case HOST1X_OPCODE_IMM:
  85 + host1x_debug_output(o, "IMM(offset=%03x, data=%03x)\n",
  86 + val >> 16 & 0xfff, val & 0xffff);
  87 + return 0;
  88 +
  89 + case HOST1X_OPCODE_RESTART:
  90 + host1x_debug_output(o, "RESTART(offset=%08x)\n", val << 4);
  91 + return 0;
  92 +
  93 + case HOST1X_OPCODE_GATHER:
  94 + host1x_debug_output(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[",
  95 + val >> 16 & 0xfff, val >> 15 & 0x1,
  96 + val >> 14 & 0x1, val & 0x3fff);
  97 + return 1;
  98 +
  99 + case HOST1X_OPCODE_EXTEND:
  100 + subop = val >> 24 & 0xf;
  101 + if (subop == HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK)
  102 + host1x_debug_output(o, "ACQUIRE_MLOCK(index=%d)\n",
  103 + val & 0xff);
  104 + else if (subop == HOST1X_OPCODE_EXTEND_RELEASE_MLOCK)
  105 + host1x_debug_output(o, "RELEASE_MLOCK(index=%d)\n",
  106 + val & 0xff);
  107 + else
  108 + host1x_debug_output(o, "EXTEND_UNKNOWN(%08x)\n", val);
  109 + return 0;
  110 +
  111 + default:
  112 + return 0;
  113 + }
  114 +}
  115 +
  116 +static void show_gather(struct output *o, phys_addr_t phys_addr,
  117 + unsigned int words, struct host1x_cdma *cdma,
  118 + phys_addr_t pin_addr, u32 *map_addr)
  119 +{
  120 + /* Map dmaget cursor to corresponding mem handle */
  121 + u32 offset = phys_addr - pin_addr;
  122 + unsigned int data_count = 0, i;
  123 +
  124 + /*
  125 + * Sometimes we're given different hardware address to the same
  126 + * page - in these cases the offset will get an invalid number and
  127 + * we just have to bail out.
  128 + */
  129 + if (offset > HOST1X_DEBUG_MAX_PAGE_OFFSET) {
  130 + host1x_debug_output(o, "[address mismatch]\n");
  131 + return;
  132 + }
  133 +
  134 + for (i = 0; i < words; i++) {
  135 + u32 addr = phys_addr + i * 4;
  136 + u32 val = *(map_addr + offset / 4 + i);
  137 +
  138 + if (!data_count) {
  139 + host1x_debug_output(o, "%08x: %08x:", addr, val);
  140 + data_count = show_channel_command(o, val);
  141 + } else {
  142 + host1x_debug_output(o, "%08x%s", val,
  143 + data_count > 0 ? ", " : "])\n");
  144 + data_count--;
  145 + }
  146 + }
  147 +}
  148 +
  149 +static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma)
  150 +{
  151 + struct host1x_job *job;
  152 +
  153 + list_for_each_entry(job, &cdma->sync_queue, list) {
  154 + int i;
  155 + host1x_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d, first_get=%08x, timeout=%d num_slots=%d, num_handles=%d\n",
  156 + job, job->syncpt_id, job->syncpt_end,
  157 + job->first_get, job->timeout,
  158 + job->num_slots, job->num_unpins);
  159 +
  160 + for (i = 0; i < job->num_gathers; i++) {
  161 + struct host1x_job_gather *g = &job->gathers[i];
  162 + u32 *mapped;
  163 +
  164 + if (job->gather_copy_mapped)
  165 + mapped = (u32 *)job->gather_copy_mapped;
  166 + else
  167 + mapped = host1x_bo_mmap(g->bo);
  168 +
  169 + if (!mapped) {
  170 + host1x_debug_output(o, "[could not mmap]\n");
  171 + continue;
  172 + }
  173 +
  174 + host1x_debug_output(o, " GATHER at %08x+%04x, %d words\n",
  175 + g->base, g->offset, g->words);
  176 +
  177 + show_gather(o, g->base + g->offset, g->words, cdma,
  178 + g->base, mapped);
  179 +
  180 + if (!job->gather_copy_mapped)
  181 + host1x_bo_munmap(g->bo, mapped);
  182 + }
  183 + }
  184 +}
  185 +
  186 +static void host1x_debug_show_channel_cdma(struct host1x *host,
  187 + struct host1x_channel *ch,
  188 + struct output *o)
  189 +{
  190 + struct host1x_cdma *cdma = &ch->cdma;
  191 + u32 dmaput, dmaget, dmactrl;
  192 + u32 cbstat, cbread;
  193 + u32 val, base, baseval;
  194 +
  195 + dmaput = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT);
  196 + dmaget = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET);
  197 + dmactrl = host1x_ch_readl(ch, HOST1X_CHANNEL_DMACTRL);
  198 + cbread = host1x_sync_readl(host, HOST1X_SYNC_CBREAD(ch->id));
  199 + cbstat = host1x_sync_readl(host, HOST1X_SYNC_CBSTAT(ch->id));
  200 +
  201 + host1x_debug_output(o, "%d-%s: ", ch->id, dev_name(ch->dev));
  202 +
  203 + if (HOST1X_CHANNEL_DMACTRL_DMASTOP_V(dmactrl) ||
  204 + !ch->cdma.push_buffer.mapped) {
  205 + host1x_debug_output(o, "inactive\n\n");
  206 + return;
  207 + }
  208 +
  209 + if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) == HOST1X_CLASS_HOST1X &&
  210 + HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) ==
  211 + HOST1X_UCLASS_WAIT_SYNCPT)
  212 + host1x_debug_output(o, "waiting on syncpt %d val %d\n",
  213 + cbread >> 24, cbread & 0xffffff);
  214 + else if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) ==
  215 + HOST1X_CLASS_HOST1X &&
  216 + HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) ==
  217 + HOST1X_UCLASS_WAIT_SYNCPT_BASE) {
  218 +
  219 + base = (cbread >> 16) & 0xff;
  220 + baseval =
  221 + host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(base));
  222 + val = cbread & 0xffff;
  223 + host1x_debug_output(o, "waiting on syncpt %d val %d (base %d = %d; offset = %d)\n",
  224 + cbread >> 24, baseval + val, base,
  225 + baseval, val);
  226 + } else
  227 + host1x_debug_output(o, "active class %02x, offset %04x, val %08x\n",
  228 + HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat),
  229 + HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat),
  230 + cbread);
  231 +
  232 + host1x_debug_output(o, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n",
  233 + dmaput, dmaget, dmactrl);
  234 + host1x_debug_output(o, "CBREAD %08x, CBSTAT %08x\n", cbread, cbstat);
  235 +
  236 + show_channel_gathers(o, cdma);
  237 + host1x_debug_output(o, "\n");
  238 +}
  239 +
  240 +static void host1x_debug_show_channel_fifo(struct host1x *host,
  241 + struct host1x_channel *ch,
  242 + struct output *o)
  243 +{
  244 + u32 val, rd_ptr, wr_ptr, start, end;
  245 + unsigned int data_count = 0;
  246 +
  247 + host1x_debug_output(o, "%d: fifo:\n", ch->id);
  248 +
  249 + val = host1x_ch_readl(ch, HOST1X_CHANNEL_FIFOSTAT);
  250 + host1x_debug_output(o, "FIFOSTAT %08x\n", val);
  251 + if (HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(val)) {
  252 + host1x_debug_output(o, "[empty]\n");
  253 + return;
  254 + }
  255 +
  256 + host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL);
  257 + host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) |
  258 + HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id),
  259 + HOST1X_SYNC_CFPEEK_CTRL);
  260 +
  261 + val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_PTRS);
  262 + rd_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(val);
  263 + wr_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(val);
  264 +
  265 + val = host1x_sync_readl(host, HOST1X_SYNC_CF_SETUP(ch->id));
  266 + start = HOST1X_SYNC_CF_SETUP_BASE_V(val);
  267 + end = HOST1X_SYNC_CF_SETUP_LIMIT_V(val);
  268 +
  269 + do {
  270 + host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL);
  271 + host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) |
  272 + HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id) |
  273 + HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(rd_ptr),
  274 + HOST1X_SYNC_CFPEEK_CTRL);
  275 + val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_READ);
  276 +
  277 + if (!data_count) {
  278 + host1x_debug_output(o, "%08x:", val);
  279 + data_count = show_channel_command(o, val);
  280 + } else {
  281 + host1x_debug_output(o, "%08x%s", val,
  282 + data_count > 0 ? ", " : "])\n");
  283 + data_count--;
  284 + }
  285 +
  286 + if (rd_ptr == end)
  287 + rd_ptr = start;
  288 + else
  289 + rd_ptr++;
  290 + } while (rd_ptr != wr_ptr);
  291 +
  292 + if (data_count)
  293 + host1x_debug_output(o, ", ...])\n");
  294 + host1x_debug_output(o, "\n");
  295 +
  296 + host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL);
  297 +}
  298 +
  299 +static void host1x_debug_show_mlocks(struct host1x *host, struct output *o)
  300 +{
  301 + int i;
  302 +
  303 + host1x_debug_output(o, "---- mlocks ----\n");
  304 + for (i = 0; i < host1x_syncpt_nb_mlocks(host); i++) {
  305 + u32 owner =
  306 + host1x_sync_readl(host, HOST1X_SYNC_MLOCK_OWNER(i));
  307 + if (HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(owner))
  308 + host1x_debug_output(o, "%d: locked by channel %d\n",
  309 + i, HOST1X_SYNC_MLOCK_OWNER_CHID_F(owner));
  310 + else if (HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(owner))
  311 + host1x_debug_output(o, "%d: locked by cpu\n", i);
  312 + else
  313 + host1x_debug_output(o, "%d: unlocked\n", i);
  314 + }
  315 + host1x_debug_output(o, "\n");
  316 +}
  317 +
  318 +static const struct host1x_debug_ops host1x_debug_ops = {
  319 + .show_channel_cdma = host1x_debug_show_channel_cdma,
  320 + .show_channel_fifo = host1x_debug_show_channel_fifo,
  321 + .show_mlocks = host1x_debug_show_mlocks,
  322 +};
drivers/gpu/host1x/hw/host1x01.c
... ... @@ -23,6 +23,7 @@
23 23 /* include code */
24 24 #include "hw/cdma_hw.c"
25 25 #include "hw/channel_hw.c"
  26 +#include "hw/debug_hw.c"
26 27 #include "hw/intr_hw.c"
27 28 #include "hw/syncpt_hw.c"
28 29  
... ... @@ -35,6 +36,7 @@
35 36 host->cdma_pb_op = &host1x_pushbuffer_ops;
36 37 host->syncpt_op = &host1x_syncpt_ops;
37 38 host->intr_op = &host1x_intr_ops;
  39 + host->debug_op = &host1x_debug_ops;
38 40  
39 41 return 0;
40 42 }
drivers/gpu/host1x/hw/hw_host1x01_channel.h
... ... @@ -51,6 +51,18 @@
51 51 #ifndef __hw_host1x_channel_host1x_h__
52 52 #define __hw_host1x_channel_host1x_h__
53 53  
  54 +static inline u32 host1x_channel_fifostat_r(void)
  55 +{
  56 + return 0x0;
  57 +}
  58 +#define HOST1X_CHANNEL_FIFOSTAT \
  59 + host1x_channel_fifostat_r()
  60 +static inline u32 host1x_channel_fifostat_cfempty_v(u32 r)
  61 +{
  62 + return (r >> 10) & 0x1;
  63 +}
  64 +#define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(r) \
  65 + host1x_channel_fifostat_cfempty_v(r)
54 66 static inline u32 host1x_channel_dmastart_r(void)
55 67 {
56 68 return 0x14;
... ... @@ -87,6 +99,12 @@
87 99 }
88 100 #define HOST1X_CHANNEL_DMACTRL_DMASTOP \
89 101 host1x_channel_dmactrl_dmastop()
  102 +static inline u32 host1x_channel_dmactrl_dmastop_v(u32 r)
  103 +{
  104 + return (r >> 0) & 0x1;
  105 +}
  106 +#define HOST1X_CHANNEL_DMACTRL_DMASTOP_V(r) \
  107 + host1x_channel_dmactrl_dmastop_v(r)
90 108 static inline u32 host1x_channel_dmactrl_dmagetrst(void)
91 109 {
92 110 return 1 << 1;
drivers/gpu/host1x/hw/hw_host1x01_sync.h
... ... @@ -77,6 +77,24 @@
77 77 }
78 78 #define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \
79 79 host1x_sync_syncpt_thresh_int_enable_cpu0_r(id)
  80 +static inline u32 host1x_sync_cf_setup_r(unsigned int channel)
  81 +{
  82 + return 0x80 + channel * REGISTER_STRIDE;
  83 +}
  84 +#define HOST1X_SYNC_CF_SETUP(channel) \
  85 + host1x_sync_cf_setup_r(channel)
  86 +static inline u32 host1x_sync_cf_setup_base_v(u32 r)
  87 +{
  88 + return (r >> 0) & 0x1ff;
  89 +}
  90 +#define HOST1X_SYNC_CF_SETUP_BASE_V(r) \
  91 + host1x_sync_cf_setup_base_v(r)
  92 +static inline u32 host1x_sync_cf_setup_limit_v(u32 r)
  93 +{
  94 + return (r >> 16) & 0x1ff;
  95 +}
  96 +#define HOST1X_SYNC_CF_SETUP_LIMIT_V(r) \
  97 + host1x_sync_cf_setup_limit_v(r)
80 98 static inline u32 host1x_sync_cmdproc_stop_r(void)
81 99 {
82 100 return 0xac;
... ... @@ -107,6 +125,30 @@
107 125 }
108 126 #define HOST1X_SYNC_IP_BUSY_TIMEOUT \
109 127 host1x_sync_ip_busy_timeout_r()
  128 +static inline u32 host1x_sync_mlock_owner_r(unsigned int id)
  129 +{
  130 + return 0x340 + id * REGISTER_STRIDE;
  131 +}
  132 +#define HOST1X_SYNC_MLOCK_OWNER(id) \
  133 + host1x_sync_mlock_owner_r(id)
  134 +static inline u32 host1x_sync_mlock_owner_chid_f(u32 v)
  135 +{
  136 + return (v & 0xf) << 8;
  137 +}
  138 +#define HOST1X_SYNC_MLOCK_OWNER_CHID_F(v) \
  139 + host1x_sync_mlock_owner_chid_f(v)
  140 +static inline u32 host1x_sync_mlock_owner_cpu_owns_v(u32 r)
  141 +{
  142 + return (r >> 1) & 0x1;
  143 +}
  144 +#define HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(r) \
  145 + host1x_sync_mlock_owner_cpu_owns_v(r)
  146 +static inline u32 host1x_sync_mlock_owner_ch_owns_v(u32 r)
  147 +{
  148 + return (r >> 0) & 0x1;
  149 +}
  150 +#define HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(r) \
  151 + host1x_sync_mlock_owner_ch_owns_v(r)
110 152 static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id)
111 153 {
112 154 return 0x500 + id * REGISTER_STRIDE;
... ... @@ -125,5 +167,78 @@
125 167 }
126 168 #define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \
127 169 host1x_sync_syncpt_cpu_incr_r(id)
  170 +static inline u32 host1x_sync_cbread_r(unsigned int channel)
  171 +{
  172 + return 0x720 + channel * REGISTER_STRIDE;
  173 +}
  174 +#define HOST1X_SYNC_CBREAD(channel) \
  175 + host1x_sync_cbread_r(channel)
  176 +static inline u32 host1x_sync_cfpeek_ctrl_r(void)
  177 +{
  178 + return 0x74c;
  179 +}
  180 +#define HOST1X_SYNC_CFPEEK_CTRL \
  181 + host1x_sync_cfpeek_ctrl_r()
  182 +static inline u32 host1x_sync_cfpeek_ctrl_addr_f(u32 v)
  183 +{
  184 + return (v & 0x1ff) << 0;
  185 +}
  186 +#define HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(v) \
  187 + host1x_sync_cfpeek_ctrl_addr_f(v)
  188 +static inline u32 host1x_sync_cfpeek_ctrl_channr_f(u32 v)
  189 +{
  190 + return (v & 0x7) << 16;
  191 +}
  192 +#define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(v) \
  193 + host1x_sync_cfpeek_ctrl_channr_f(v)
  194 +static inline u32 host1x_sync_cfpeek_ctrl_ena_f(u32 v)
  195 +{
  196 + return (v & 0x1) << 31;
  197 +}
  198 +#define HOST1X_SYNC_CFPEEK_CTRL_ENA_F(v) \
  199 + host1x_sync_cfpeek_ctrl_ena_f(v)
  200 +static inline u32 host1x_sync_cfpeek_read_r(void)
  201 +{
  202 + return 0x750;
  203 +}
  204 +#define HOST1X_SYNC_CFPEEK_READ \
  205 + host1x_sync_cfpeek_read_r()
  206 +static inline u32 host1x_sync_cfpeek_ptrs_r(void)
  207 +{
  208 + return 0x754;
  209 +}
  210 +#define HOST1X_SYNC_CFPEEK_PTRS \
  211 + host1x_sync_cfpeek_ptrs_r()
  212 +static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(u32 r)
  213 +{
  214 + return (r >> 0) & 0x1ff;
  215 +}
  216 +#define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(r) \
  217 + host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(r)
  218 +static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(u32 r)
  219 +{
  220 + return (r >> 16) & 0x1ff;
  221 +}
  222 +#define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(r) \
  223 + host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(r)
  224 +static inline u32 host1x_sync_cbstat_r(unsigned int channel)
  225 +{
  226 + return 0x758 + channel * REGISTER_STRIDE;
  227 +}
  228 +#define HOST1X_SYNC_CBSTAT(channel) \
  229 + host1x_sync_cbstat_r(channel)
  230 +static inline u32 host1x_sync_cbstat_cboffset_v(u32 r)
  231 +{
  232 + return (r >> 0) & 0xffff;
  233 +}
  234 +#define HOST1X_SYNC_CBSTAT_CBOFFSET_V(r) \
  235 + host1x_sync_cbstat_cboffset_v(r)
  236 +static inline u32 host1x_sync_cbstat_cbclass_v(u32 r)
  237 +{
  238 + return (r >> 16) & 0x3ff;
  239 +}
  240 +#define HOST1X_SYNC_CBSTAT_CBCLASS_V(r) \
  241 + host1x_sync_cbstat_cbclass_v(r)
  242 +
128 243 #endif /* __hw_host1x01_sync_h__ */
drivers/gpu/host1x/hw/hw_host1x01_uclass.h
... ... @@ -87,6 +87,12 @@
87 87 }
88 88 #define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \
89 89 host1x_uclass_wait_syncpt_thresh_f(v)
  90 +static inline u32 host1x_uclass_wait_syncpt_base_r(void)
  91 +{
  92 + return 0x9;
  93 +}
  94 +#define HOST1X_UCLASS_WAIT_SYNCPT_BASE \
  95 + host1x_uclass_wait_syncpt_base_r()
90 96 static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v)
91 97 {
92 98 return (v & 0xff) << 24;
drivers/gpu/host1x/hw/syncpt_hw.c
... ... @@ -86,6 +86,7 @@
86 86 host1x_syncpt_idle(sp)) {
87 87 dev_err(host->dev, "Trying to increment syncpoint id %d beyond max\n",
88 88 sp->id);
  89 + host1x_debug_dump(sp->host);
89 90 return;
90 91 }
91 92 host1x_sync_writel(host, BIT_MASK(sp->id),
drivers/gpu/host1x/syncpt.c
... ... @@ -25,6 +25,7 @@
25 25 #include "syncpt.h"
26 26 #include "dev.h"
27 27 #include "intr.h"
  28 +#include "debug.h"
28 29  
29 30 #define SYNCPT_CHECK_PERIOD (2 * HZ)
30 31 #define MAX_STUCK_CHECK_COUNT 15
... ... @@ -231,6 +232,10 @@
231 232 "%s: syncpoint id %d (%s) stuck waiting %d, timeout=%ld\n",
232 233 current->comm, sp->id, sp->name,
233 234 thresh, timeout);
  235 +
  236 + host1x_debug_dump_syncpts(sp->host);
  237 + if (check_count == MAX_STUCK_CHECK_COUNT)
  238 + host1x_debug_dump(sp->host);
234 239 check_count++;
235 240 }
236 241 }