xref: /openbmc/linux/drivers/gpu/host1x/debug.c (revision 6b6776e2ab8ac7086cf31ad339411df7681715b7)
19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26236451dSTerje Bergstrom /*
36236451dSTerje Bergstrom  * Copyright (C) 2010 Google, Inc.
46236451dSTerje Bergstrom  * Author: Erik Gilling <konkers@android.com>
56236451dSTerje Bergstrom  *
66236451dSTerje Bergstrom  * Copyright (C) 2011-2013 NVIDIA Corporation
76236451dSTerje Bergstrom  */
86236451dSTerje Bergstrom 
96236451dSTerje Bergstrom #include <linux/debugfs.h>
10*6b6776e2SDmitry Osipenko #include <linux/pm_runtime.h>
116236451dSTerje Bergstrom #include <linux/seq_file.h>
126236451dSTerje Bergstrom #include <linux/uaccess.h>
136236451dSTerje Bergstrom 
146236451dSTerje Bergstrom #include <linux/io.h>
156236451dSTerje Bergstrom 
166236451dSTerje Bergstrom #include "dev.h"
176236451dSTerje Bergstrom #include "debug.h"
186236451dSTerje Bergstrom #include "channel.h"
196236451dSTerje Bergstrom 
2035681862SDmitry Osipenko static DEFINE_MUTEX(debug_lock);
2135681862SDmitry Osipenko 
226236451dSTerje Bergstrom unsigned int host1x_debug_trace_cmdbuf;
236236451dSTerje Bergstrom 
246236451dSTerje Bergstrom static pid_t host1x_debug_force_timeout_pid;
256236451dSTerje Bergstrom static u32 host1x_debug_force_timeout_val;
266236451dSTerje Bergstrom static u32 host1x_debug_force_timeout_channel;
276236451dSTerje Bergstrom 
286236451dSTerje Bergstrom void host1x_debug_output(struct output *o, const char *fmt, ...)
296236451dSTerje Bergstrom {
306236451dSTerje Bergstrom 	va_list args;
316236451dSTerje Bergstrom 	int len;
326236451dSTerje Bergstrom 
336236451dSTerje Bergstrom 	va_start(args, fmt);
346236451dSTerje Bergstrom 	len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
356236451dSTerje Bergstrom 	va_end(args);
360b8070d1SThierry Reding 
37eb2ee1a2SMikko Perttunen 	o->fn(o->ctx, o->buf, len, false);
38eb2ee1a2SMikko Perttunen }
39eb2ee1a2SMikko Perttunen 
40eb2ee1a2SMikko Perttunen void host1x_debug_cont(struct output *o, const char *fmt, ...)
41eb2ee1a2SMikko Perttunen {
42eb2ee1a2SMikko Perttunen 	va_list args;
43eb2ee1a2SMikko Perttunen 	int len;
44eb2ee1a2SMikko Perttunen 
45eb2ee1a2SMikko Perttunen 	va_start(args, fmt);
46eb2ee1a2SMikko Perttunen 	len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
47eb2ee1a2SMikko Perttunen 	va_end(args);
48eb2ee1a2SMikko Perttunen 
49eb2ee1a2SMikko Perttunen 	o->fn(o->ctx, o->buf, len, true);
506236451dSTerje Bergstrom }
516236451dSTerje Bergstrom 
528474b025SMikko Perttunen static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo)
536236451dSTerje Bergstrom {
546236451dSTerje Bergstrom 	struct host1x *m = dev_get_drvdata(ch->dev->parent);
556236451dSTerje Bergstrom 	struct output *o = data;
56*6b6776e2SDmitry Osipenko 	int err;
57*6b6776e2SDmitry Osipenko 
58*6b6776e2SDmitry Osipenko 	err = pm_runtime_resume_and_get(m->dev);
59*6b6776e2SDmitry Osipenko 	if (err < 0)
60*6b6776e2SDmitry Osipenko 		return err;
616236451dSTerje Bergstrom 
626236451dSTerje Bergstrom 	mutex_lock(&ch->cdma.lock);
6335681862SDmitry Osipenko 	mutex_lock(&debug_lock);
640b8070d1SThierry Reding 
656236451dSTerje Bergstrom 	if (show_fifo)
666236451dSTerje Bergstrom 		host1x_hw_show_channel_fifo(m, ch, o);
670b8070d1SThierry Reding 
686236451dSTerje Bergstrom 	host1x_hw_show_channel_cdma(m, ch, o);
690b8070d1SThierry Reding 
7035681862SDmitry Osipenko 	mutex_unlock(&debug_lock);
718474b025SMikko Perttunen 	mutex_unlock(&ch->cdma.lock);
726236451dSTerje Bergstrom 
73*6b6776e2SDmitry Osipenko 	pm_runtime_put(m->dev);
74*6b6776e2SDmitry Osipenko 
756236451dSTerje Bergstrom 	return 0;
766236451dSTerje Bergstrom }
776236451dSTerje Bergstrom 
786236451dSTerje Bergstrom static void show_syncpts(struct host1x *m, struct output *o)
796236451dSTerje Bergstrom {
8049a5fb16SMikko Perttunen 	struct list_head *pos;
8114c95fc8SThierry Reding 	unsigned int i;
82*6b6776e2SDmitry Osipenko 	int err;
836df633d0SThierry Reding 
846236451dSTerje Bergstrom 	host1x_debug_output(o, "---- syncpts ----\n");
850b8070d1SThierry Reding 
86*6b6776e2SDmitry Osipenko 	err = pm_runtime_resume_and_get(m->dev);
87*6b6776e2SDmitry Osipenko 	if (err < 0)
88*6b6776e2SDmitry Osipenko 		return;
89*6b6776e2SDmitry Osipenko 
906236451dSTerje Bergstrom 	for (i = 0; i < host1x_syncpt_nb_pts(m); i++) {
916236451dSTerje Bergstrom 		u32 max = host1x_syncpt_read_max(m->syncpt + i);
926236451dSTerje Bergstrom 		u32 min = host1x_syncpt_load(m->syncpt + i);
9349a5fb16SMikko Perttunen 		unsigned int waiters = 0;
946df633d0SThierry Reding 
9549a5fb16SMikko Perttunen 		spin_lock(&m->syncpt[i].intr.lock);
9649a5fb16SMikko Perttunen 		list_for_each(pos, &m->syncpt[i].intr.wait_head)
9749a5fb16SMikko Perttunen 			waiters++;
9849a5fb16SMikko Perttunen 		spin_unlock(&m->syncpt[i].intr.lock);
9949a5fb16SMikko Perttunen 
10049a5fb16SMikko Perttunen 		if (!min && !max && !waiters)
1016236451dSTerje Bergstrom 			continue;
10214c95fc8SThierry Reding 
10349a5fb16SMikko Perttunen 		host1x_debug_output(o,
10449a5fb16SMikko Perttunen 				    "id %u (%s) min %d max %d (%d waiters)\n",
10549a5fb16SMikko Perttunen 				    i, m->syncpt[i].name, min, max, waiters);
1066236451dSTerje Bergstrom 	}
1076236451dSTerje Bergstrom 
1086236451dSTerje Bergstrom 	for (i = 0; i < host1x_syncpt_nb_bases(m); i++) {
1096236451dSTerje Bergstrom 		u32 base_val;
1106df633d0SThierry Reding 
1116236451dSTerje Bergstrom 		base_val = host1x_syncpt_load_wait_base(m->syncpt + i);
1126236451dSTerje Bergstrom 		if (base_val)
11314c95fc8SThierry Reding 			host1x_debug_output(o, "waitbase id %u val %d\n", i,
1146236451dSTerje Bergstrom 					    base_val);
1156236451dSTerje Bergstrom 	}
1166236451dSTerje Bergstrom 
117*6b6776e2SDmitry Osipenko 	pm_runtime_put(m->dev);
118*6b6776e2SDmitry Osipenko 
1196236451dSTerje Bergstrom 	host1x_debug_output(o, "\n");
1206236451dSTerje Bergstrom }
1216236451dSTerje Bergstrom 
1228474b025SMikko Perttunen static void show_all(struct host1x *m, struct output *o, bool show_fifo)
1236236451dSTerje Bergstrom {
124d4ad3ad9SThierry Reding 	unsigned int i;
1256236451dSTerje Bergstrom 
1266236451dSTerje Bergstrom 	host1x_hw_show_mlocks(m, o);
1276236451dSTerje Bergstrom 	show_syncpts(m, o);
1286236451dSTerje Bergstrom 	host1x_debug_output(o, "---- channels ----\n");
1296236451dSTerje Bergstrom 
1308474b025SMikko Perttunen 	for (i = 0; i < m->info->nb_channels; ++i) {
1318474b025SMikko Perttunen 		struct host1x_channel *ch = host1x_channel_get_index(m, i);
1328474b025SMikko Perttunen 
1338474b025SMikko Perttunen 		if (ch) {
1348474b025SMikko Perttunen 			show_channel(ch, o, show_fifo);
1358474b025SMikko Perttunen 			host1x_channel_put(ch);
1366236451dSTerje Bergstrom 		}
1378474b025SMikko Perttunen 	}
1386236451dSTerje Bergstrom }
1396236451dSTerje Bergstrom 
1406236451dSTerje Bergstrom static int host1x_debug_show_all(struct seq_file *s, void *unused)
1416236451dSTerje Bergstrom {
1426236451dSTerje Bergstrom 	struct output o = {
1436236451dSTerje Bergstrom 		.fn = write_to_seqfile,
1446236451dSTerje Bergstrom 		.ctx = s
1456236451dSTerje Bergstrom 	};
1460b8070d1SThierry Reding 
1478474b025SMikko Perttunen 	show_all(s->private, &o, true);
1480b8070d1SThierry Reding 
1496236451dSTerje Bergstrom 	return 0;
1506236451dSTerje Bergstrom }
1516236451dSTerje Bergstrom 
1526236451dSTerje Bergstrom static int host1x_debug_show(struct seq_file *s, void *unused)
1536236451dSTerje Bergstrom {
1546236451dSTerje Bergstrom 	struct output o = {
1556236451dSTerje Bergstrom 		.fn = write_to_seqfile,
1566236451dSTerje Bergstrom 		.ctx = s
1576236451dSTerje Bergstrom 	};
1580b8070d1SThierry Reding 
1598474b025SMikko Perttunen 	show_all(s->private, &o, false);
1600b8070d1SThierry Reding 
1616236451dSTerje Bergstrom 	return 0;
1626236451dSTerje Bergstrom }
1636236451dSTerje Bergstrom 
1646236451dSTerje Bergstrom static int host1x_debug_open_all(struct inode *inode, struct file *file)
1656236451dSTerje Bergstrom {
1666236451dSTerje Bergstrom 	return single_open(file, host1x_debug_show_all, inode->i_private);
1676236451dSTerje Bergstrom }
1686236451dSTerje Bergstrom 
1696236451dSTerje Bergstrom static const struct file_operations host1x_debug_all_fops = {
1706236451dSTerje Bergstrom 	.open = host1x_debug_open_all,
1716236451dSTerje Bergstrom 	.read = seq_read,
1726236451dSTerje Bergstrom 	.llseek = seq_lseek,
1736236451dSTerje Bergstrom 	.release = single_release,
1746236451dSTerje Bergstrom };
1756236451dSTerje Bergstrom 
1766236451dSTerje Bergstrom static int host1x_debug_open(struct inode *inode, struct file *file)
1776236451dSTerje Bergstrom {
1786236451dSTerje Bergstrom 	return single_open(file, host1x_debug_show, inode->i_private);
1796236451dSTerje Bergstrom }
1806236451dSTerje Bergstrom 
1816236451dSTerje Bergstrom static const struct file_operations host1x_debug_fops = {
1826236451dSTerje Bergstrom 	.open = host1x_debug_open,
1836236451dSTerje Bergstrom 	.read = seq_read,
1846236451dSTerje Bergstrom 	.llseek = seq_lseek,
1856236451dSTerje Bergstrom 	.release = single_release,
1866236451dSTerje Bergstrom };
1876236451dSTerje Bergstrom 
1888e0d788cSThierry Reding static void host1x_debugfs_init(struct host1x *host1x)
1896236451dSTerje Bergstrom {
1906236451dSTerje Bergstrom 	struct dentry *de = debugfs_create_dir("tegra-host1x", NULL);
1916236451dSTerje Bergstrom 
1926236451dSTerje Bergstrom 	/* Store the created entry */
1936236451dSTerje Bergstrom 	host1x->debugfs = de;
1946236451dSTerje Bergstrom 
1956236451dSTerje Bergstrom 	debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops);
1966236451dSTerje Bergstrom 	debugfs_create_file("status_all", S_IRUGO, de, host1x,
1976236451dSTerje Bergstrom 			    &host1x_debug_all_fops);
1986236451dSTerje Bergstrom 
1996236451dSTerje Bergstrom 	debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,
2006236451dSTerje Bergstrom 			   &host1x_debug_trace_cmdbuf);
2016236451dSTerje Bergstrom 
2026236451dSTerje Bergstrom 	host1x_hw_debug_init(host1x, de);
2036236451dSTerje Bergstrom 
2046236451dSTerje Bergstrom 	debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,
2056236451dSTerje Bergstrom 			   &host1x_debug_force_timeout_pid);
2066236451dSTerje Bergstrom 	debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de,
2076236451dSTerje Bergstrom 			   &host1x_debug_force_timeout_val);
2086236451dSTerje Bergstrom 	debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de,
2096236451dSTerje Bergstrom 			   &host1x_debug_force_timeout_channel);
2106236451dSTerje Bergstrom }
2116236451dSTerje Bergstrom 
2128e0d788cSThierry Reding static void host1x_debugfs_exit(struct host1x *host1x)
2136236451dSTerje Bergstrom {
2146236451dSTerje Bergstrom 	debugfs_remove_recursive(host1x->debugfs);
2156236451dSTerje Bergstrom }
2168e0d788cSThierry Reding 
2176236451dSTerje Bergstrom void host1x_debug_init(struct host1x *host1x)
2186236451dSTerje Bergstrom {
2198e0d788cSThierry Reding 	if (IS_ENABLED(CONFIG_DEBUG_FS))
2208e0d788cSThierry Reding 		host1x_debugfs_init(host1x);
2216236451dSTerje Bergstrom }
2228e0d788cSThierry Reding 
2236236451dSTerje Bergstrom void host1x_debug_deinit(struct host1x *host1x)
2246236451dSTerje Bergstrom {
2258e0d788cSThierry Reding 	if (IS_ENABLED(CONFIG_DEBUG_FS))
2268e0d788cSThierry Reding 		host1x_debugfs_exit(host1x);
2276236451dSTerje Bergstrom }
2286236451dSTerje Bergstrom 
2296236451dSTerje Bergstrom void host1x_debug_dump(struct host1x *host1x)
2306236451dSTerje Bergstrom {
2316236451dSTerje Bergstrom 	struct output o = {
2326236451dSTerje Bergstrom 		.fn = write_to_printk
2336236451dSTerje Bergstrom 	};
2340b8070d1SThierry Reding 
2358474b025SMikko Perttunen 	show_all(host1x, &o, true);
2366236451dSTerje Bergstrom }
2376236451dSTerje Bergstrom 
2386236451dSTerje Bergstrom void host1x_debug_dump_syncpts(struct host1x *host1x)
2396236451dSTerje Bergstrom {
2406236451dSTerje Bergstrom 	struct output o = {
2416236451dSTerje Bergstrom 		.fn = write_to_printk
2426236451dSTerje Bergstrom 	};
2430b8070d1SThierry Reding 
2446236451dSTerje Bergstrom 	show_syncpts(host1x, &o);
2456236451dSTerje Bergstrom }
246