Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Terje Bergstrom and committed by
Thierry Reding
6236451d 6579324a

+807
+1
drivers/gpu/host1x/Makefile
··· 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
+4
drivers/gpu/host1x/cdma.c
··· 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,
+210
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 + }
+51
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
+3
drivers/gpu/host1x/dev.c
··· 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) ··· 147 146 dev_err(&pdev->dev, "failed to initialize interrupts\n"); 148 147 goto fail_deinit_syncpt; 149 148 } 149 + 150 + host1x_debug_init(host); 150 151 151 152 return 0; 152 153
+42
drivers/gpu/host1x/dev.h
··· 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 52 55 53 struct host1x_pushbuffer_ops { 56 54 void (*init)(struct push_buffer *pb); 55 + }; 56 + 57 + struct host1x_debug_ops { 58 + void (*debug_init)(struct dentry *de); 59 + void (*show_channel_cdma)(struct host1x *host, 60 + struct host1x_channel *ch, 61 + struct output *o); 62 + void (*show_channel_fifo)(struct host1x *host, 63 + struct host1x_channel *ch, 64 + struct output *o); 65 + void (*show_mlocks)(struct host1x *host, struct output *output); 66 + 57 67 }; 58 68 59 69 struct host1x_syncpt_ops { ··· 114 100 const struct host1x_channel_ops *channel_op; 115 101 const struct host1x_cdma_ops *cdma_op; 116 102 const struct host1x_pushbuffer_ops *cdma_pb_op; 103 + const struct host1x_debug_ops *debug_op; 117 104 118 105 struct host1x_syncpt *nop_sp; 119 106 ··· 122 107 struct host1x_channel chlist; 123 108 unsigned long allocated_channels; 124 109 unsigned int num_allocated_channels; 110 + 111 + struct dentry *debugfs; 125 112 }; 126 113 127 114 void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); ··· 272 255 struct push_buffer *pb) 273 256 { 274 257 host->cdma_pb_op->init(pb); 258 + } 259 + 260 + static inline void host1x_hw_debug_init(struct host1x *host, struct dentry *de) 261 + { 262 + if (host->debug_op && host->debug_op->debug_init) 263 + host->debug_op->debug_init(de); 264 + } 265 + 266 + static inline void host1x_hw_show_channel_cdma(struct host1x *host, 267 + struct host1x_channel *channel, 268 + struct output *o) 269 + { 270 + host->debug_op->show_channel_cdma(host, channel, o); 271 + } 272 + 273 + static inline void host1x_hw_show_channel_fifo(struct host1x *host, 274 + struct host1x_channel *channel, 275 + struct output *o) 276 + { 277 + host->debug_op->show_channel_fifo(host, channel, o); 278 + } 279 + 280 + static inline void host1x_hw_show_mlocks(struct host1x *host, struct output *o) 281 + { 282 + host->debug_op->show_mlocks(host, o); 275 283 } 276 284 277 285 #endif
+2
drivers/gpu/host1x/hw/cdma_hw.c
··· 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) {
+25
drivers/gpu/host1x/hw/channel_hw.c
··· 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; ··· 62 38 struct host1x_job_gather *g = &job->gathers[i]; 63 39 u32 op1 = host1x_opcode_gather(g->words); 64 40 u32 op2 = g->base + g->offset; 41 + trace_write_gather(cdma, g->bo, g->offset, op1 & 0xffff); 65 42 host1x_cdma_push(cdma, op1, op2); 66 43 } 67 44 }
+322
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 + };
+2
drivers/gpu/host1x/hw/host1x01.c
··· 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 ··· 36 35 host->cdma_pb_op = &host1x_pushbuffer_ops; 37 36 host->syncpt_op = &host1x_syncpt_ops; 38 37 host->intr_op = &host1x_intr_ops; 38 + host->debug_op = &host1x_debug_ops; 39 39 40 40 return 0; 41 41 }
+18
drivers/gpu/host1x/hw/hw_host1x01_channel.h
··· 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; ··· 99 87 } 100 88 #define HOST1X_CHANNEL_DMACTRL_DMASTOP \ 101 89 host1x_channel_dmactrl_dmastop() 90 + static inline u32 host1x_channel_dmactrl_dmastop_v(u32 r) 91 + { 92 + return (r >> 0) & 0x1; 93 + } 94 + #define HOST1X_CHANNEL_DMACTRL_DMASTOP_V(r) \ 95 + host1x_channel_dmactrl_dmastop_v(r) 102 96 static inline u32 host1x_channel_dmactrl_dmagetrst(void) 103 97 { 104 98 return 1 << 1;
+115
drivers/gpu/host1x/hw/hw_host1x01_sync.h
··· 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; ··· 125 107 } 126 108 #define HOST1X_SYNC_IP_BUSY_TIMEOUT \ 127 109 host1x_sync_ip_busy_timeout_r() 110 + static inline u32 host1x_sync_mlock_owner_r(unsigned int id) 111 + { 112 + return 0x340 + id * REGISTER_STRIDE; 113 + } 114 + #define HOST1X_SYNC_MLOCK_OWNER(id) \ 115 + host1x_sync_mlock_owner_r(id) 116 + static inline u32 host1x_sync_mlock_owner_chid_f(u32 v) 117 + { 118 + return (v & 0xf) << 8; 119 + } 120 + #define HOST1X_SYNC_MLOCK_OWNER_CHID_F(v) \ 121 + host1x_sync_mlock_owner_chid_f(v) 122 + static inline u32 host1x_sync_mlock_owner_cpu_owns_v(u32 r) 123 + { 124 + return (r >> 1) & 0x1; 125 + } 126 + #define HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(r) \ 127 + host1x_sync_mlock_owner_cpu_owns_v(r) 128 + static inline u32 host1x_sync_mlock_owner_ch_owns_v(u32 r) 129 + { 130 + return (r >> 0) & 0x1; 131 + } 132 + #define HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(r) \ 133 + host1x_sync_mlock_owner_ch_owns_v(r) 128 134 static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id) 129 135 { 130 136 return 0x500 + id * REGISTER_STRIDE; ··· 167 125 } 168 126 #define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \ 169 127 host1x_sync_syncpt_cpu_incr_r(id) 128 + static inline u32 host1x_sync_cbread_r(unsigned int channel) 129 + { 130 + return 0x720 + channel * REGISTER_STRIDE; 131 + } 132 + #define HOST1X_SYNC_CBREAD(channel) \ 133 + host1x_sync_cbread_r(channel) 134 + static inline u32 host1x_sync_cfpeek_ctrl_r(void) 135 + { 136 + return 0x74c; 137 + } 138 + #define HOST1X_SYNC_CFPEEK_CTRL \ 139 + host1x_sync_cfpeek_ctrl_r() 140 + static inline u32 host1x_sync_cfpeek_ctrl_addr_f(u32 v) 141 + { 142 + return (v & 0x1ff) << 0; 143 + } 144 + #define HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(v) \ 145 + host1x_sync_cfpeek_ctrl_addr_f(v) 146 + static inline u32 host1x_sync_cfpeek_ctrl_channr_f(u32 v) 147 + { 148 + return (v & 0x7) << 16; 149 + } 150 + #define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(v) \ 151 + host1x_sync_cfpeek_ctrl_channr_f(v) 152 + static inline u32 host1x_sync_cfpeek_ctrl_ena_f(u32 v) 153 + { 154 + return (v & 0x1) << 31; 155 + } 156 + #define HOST1X_SYNC_CFPEEK_CTRL_ENA_F(v) \ 157 + host1x_sync_cfpeek_ctrl_ena_f(v) 158 + static inline u32 host1x_sync_cfpeek_read_r(void) 159 + { 160 + return 0x750; 161 + } 162 + #define HOST1X_SYNC_CFPEEK_READ \ 163 + host1x_sync_cfpeek_read_r() 164 + static inline u32 host1x_sync_cfpeek_ptrs_r(void) 165 + { 166 + return 0x754; 167 + } 168 + #define HOST1X_SYNC_CFPEEK_PTRS \ 169 + host1x_sync_cfpeek_ptrs_r() 170 + static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(u32 r) 171 + { 172 + return (r >> 0) & 0x1ff; 173 + } 174 + #define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(r) \ 175 + host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(r) 176 + static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(u32 r) 177 + { 178 + return (r >> 16) & 0x1ff; 179 + } 180 + #define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(r) \ 181 + host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(r) 182 + static inline u32 host1x_sync_cbstat_r(unsigned int channel) 183 + { 184 + return 0x758 + channel * REGISTER_STRIDE; 185 + } 186 + #define HOST1X_SYNC_CBSTAT(channel) \ 187 + host1x_sync_cbstat_r(channel) 188 + static inline u32 host1x_sync_cbstat_cboffset_v(u32 r) 189 + { 190 + return (r >> 0) & 0xffff; 191 + } 192 + #define HOST1X_SYNC_CBSTAT_CBOFFSET_V(r) \ 193 + host1x_sync_cbstat_cboffset_v(r) 194 + static inline u32 host1x_sync_cbstat_cbclass_v(u32 r) 195 + { 196 + return (r >> 16) & 0x3ff; 197 + } 198 + #define HOST1X_SYNC_CBSTAT_CBCLASS_V(r) \ 199 + host1x_sync_cbstat_cbclass_v(r) 200 + 170 201 #endif /* __hw_host1x01_sync_h__ */
+6
drivers/gpu/host1x/hw/hw_host1x01_uclass.h
··· 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;
+1
drivers/gpu/host1x/hw/syncpt_hw.c
··· 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),
+5
drivers/gpu/host1x/syncpt.c
··· 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 ··· 232 231 "%s: syncpoint id %d (%s) stuck waiting %d, timeout=%ld\n", 233 232 current->comm, sp->id, sp->name, 234 233 thresh, timeout); 234 + 235 + host1x_debug_dump_syncpts(sp->host); 236 + if (check_count == MAX_STUCK_CHECK_COUNT) 237 + host1x_debug_dump(sp->host); 235 238 check_count++; 236 239 } 237 240 }