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>
106b6776e2SDmitry 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
host1x_debug_output(struct output * o,const char * fmt,...)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
host1x_debug_cont(struct output * o,const char * fmt,...)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
show_channel(struct host1x_channel * ch,void * data,bool show_fifo)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;
566b6776e2SDmitry Osipenko int err;
576b6776e2SDmitry Osipenko
586b6776e2SDmitry Osipenko err = pm_runtime_resume_and_get(m->dev);
596b6776e2SDmitry Osipenko if (err < 0)
606b6776e2SDmitry 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
736b6776e2SDmitry Osipenko pm_runtime_put(m->dev);
746b6776e2SDmitry Osipenko
756236451dSTerje Bergstrom return 0;
766236451dSTerje Bergstrom }
776236451dSTerje Bergstrom
show_syncpts(struct host1x * m,struct output * o,bool show_all)7874bb98ddSJon Hunter static void show_syncpts(struct host1x *m, struct output *o, bool show_all)
796236451dSTerje Bergstrom {
80*625d4ffbSMikko Perttunen unsigned long irqflags;
8149a5fb16SMikko Perttunen struct list_head *pos;
8214c95fc8SThierry Reding unsigned int i;
836b6776e2SDmitry Osipenko int err;
846df633d0SThierry Reding
856236451dSTerje Bergstrom host1x_debug_output(o, "---- syncpts ----\n");
860b8070d1SThierry Reding
876b6776e2SDmitry Osipenko err = pm_runtime_resume_and_get(m->dev);
886b6776e2SDmitry Osipenko if (err < 0)
896b6776e2SDmitry Osipenko return;
906b6776e2SDmitry Osipenko
916236451dSTerje Bergstrom for (i = 0; i < host1x_syncpt_nb_pts(m); i++) {
926236451dSTerje Bergstrom u32 max = host1x_syncpt_read_max(m->syncpt + i);
936236451dSTerje Bergstrom u32 min = host1x_syncpt_load(m->syncpt + i);
9449a5fb16SMikko Perttunen unsigned int waiters = 0;
956df633d0SThierry Reding
96*625d4ffbSMikko Perttunen spin_lock_irqsave(&m->syncpt[i].fences.lock, irqflags);
97*625d4ffbSMikko Perttunen list_for_each(pos, &m->syncpt[i].fences.list)
9849a5fb16SMikko Perttunen waiters++;
99*625d4ffbSMikko Perttunen spin_unlock_irqrestore(&m->syncpt[i].fences.lock, irqflags);
10049a5fb16SMikko Perttunen
10174bb98ddSJon Hunter if (!kref_read(&m->syncpt[i].ref))
10274bb98ddSJon Hunter continue;
10374bb98ddSJon Hunter
10474bb98ddSJon Hunter if (!show_all && !min && !max && !waiters)
1056236451dSTerje Bergstrom continue;
10614c95fc8SThierry Reding
10749a5fb16SMikko Perttunen host1x_debug_output(o,
10849a5fb16SMikko Perttunen "id %u (%s) min %d max %d (%d waiters)\n",
10949a5fb16SMikko Perttunen i, m->syncpt[i].name, min, max, waiters);
1106236451dSTerje Bergstrom }
1116236451dSTerje Bergstrom
1126236451dSTerje Bergstrom for (i = 0; i < host1x_syncpt_nb_bases(m); i++) {
1136236451dSTerje Bergstrom u32 base_val;
1146df633d0SThierry Reding
1156236451dSTerje Bergstrom base_val = host1x_syncpt_load_wait_base(m->syncpt + i);
1166236451dSTerje Bergstrom if (base_val)
11714c95fc8SThierry Reding host1x_debug_output(o, "waitbase id %u val %d\n", i,
1186236451dSTerje Bergstrom base_val);
1196236451dSTerje Bergstrom }
1206236451dSTerje Bergstrom
1216b6776e2SDmitry Osipenko pm_runtime_put(m->dev);
1226b6776e2SDmitry Osipenko
1236236451dSTerje Bergstrom host1x_debug_output(o, "\n");
1246236451dSTerje Bergstrom }
1256236451dSTerje Bergstrom
show_all(struct host1x * m,struct output * o,bool show_fifo)1268474b025SMikko Perttunen static void show_all(struct host1x *m, struct output *o, bool show_fifo)
1276236451dSTerje Bergstrom {
128d4ad3ad9SThierry Reding unsigned int i;
1296236451dSTerje Bergstrom
1306236451dSTerje Bergstrom host1x_hw_show_mlocks(m, o);
13174bb98ddSJon Hunter show_syncpts(m, o, true);
1326236451dSTerje Bergstrom host1x_debug_output(o, "---- channels ----\n");
1336236451dSTerje Bergstrom
1348474b025SMikko Perttunen for (i = 0; i < m->info->nb_channels; ++i) {
1358474b025SMikko Perttunen struct host1x_channel *ch = host1x_channel_get_index(m, i);
1368474b025SMikko Perttunen
1378474b025SMikko Perttunen if (ch) {
1388474b025SMikko Perttunen show_channel(ch, o, show_fifo);
1398474b025SMikko Perttunen host1x_channel_put(ch);
1406236451dSTerje Bergstrom }
1418474b025SMikko Perttunen }
1426236451dSTerje Bergstrom }
1436236451dSTerje Bergstrom
host1x_debug_all_show(struct seq_file * s,void * unused)144a624bd9cSLiu Shixin static int host1x_debug_all_show(struct seq_file *s, void *unused)
1456236451dSTerje Bergstrom {
1466236451dSTerje Bergstrom struct output o = {
1476236451dSTerje Bergstrom .fn = write_to_seqfile,
1486236451dSTerje Bergstrom .ctx = s
1496236451dSTerje Bergstrom };
1500b8070d1SThierry Reding
1518474b025SMikko Perttunen show_all(s->private, &o, true);
1520b8070d1SThierry Reding
1536236451dSTerje Bergstrom return 0;
1546236451dSTerje Bergstrom }
155a624bd9cSLiu Shixin DEFINE_SHOW_ATTRIBUTE(host1x_debug_all);
1566236451dSTerje Bergstrom
host1x_debug_show(struct seq_file * s,void * unused)1576236451dSTerje Bergstrom static int host1x_debug_show(struct seq_file *s, void *unused)
1586236451dSTerje Bergstrom {
1596236451dSTerje Bergstrom struct output o = {
1606236451dSTerje Bergstrom .fn = write_to_seqfile,
1616236451dSTerje Bergstrom .ctx = s
1626236451dSTerje Bergstrom };
1630b8070d1SThierry Reding
1648474b025SMikko Perttunen show_all(s->private, &o, false);
1650b8070d1SThierry Reding
1666236451dSTerje Bergstrom return 0;
1676236451dSTerje Bergstrom }
168a624bd9cSLiu Shixin DEFINE_SHOW_ATTRIBUTE(host1x_debug);
1696236451dSTerje Bergstrom
host1x_debugfs_init(struct host1x * host1x)1708e0d788cSThierry Reding static void host1x_debugfs_init(struct host1x *host1x)
1716236451dSTerje Bergstrom {
1726236451dSTerje Bergstrom struct dentry *de = debugfs_create_dir("tegra-host1x", NULL);
1736236451dSTerje Bergstrom
1746236451dSTerje Bergstrom /* Store the created entry */
1756236451dSTerje Bergstrom host1x->debugfs = de;
1766236451dSTerje Bergstrom
1776236451dSTerje Bergstrom debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops);
1786236451dSTerje Bergstrom debugfs_create_file("status_all", S_IRUGO, de, host1x,
1796236451dSTerje Bergstrom &host1x_debug_all_fops);
1806236451dSTerje Bergstrom
1816236451dSTerje Bergstrom debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,
1826236451dSTerje Bergstrom &host1x_debug_trace_cmdbuf);
1836236451dSTerje Bergstrom
1846236451dSTerje Bergstrom host1x_hw_debug_init(host1x, de);
1856236451dSTerje Bergstrom
1866236451dSTerje Bergstrom debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,
1876236451dSTerje Bergstrom &host1x_debug_force_timeout_pid);
1886236451dSTerje Bergstrom debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de,
1896236451dSTerje Bergstrom &host1x_debug_force_timeout_val);
1906236451dSTerje Bergstrom debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de,
1916236451dSTerje Bergstrom &host1x_debug_force_timeout_channel);
1926236451dSTerje Bergstrom }
1936236451dSTerje Bergstrom
host1x_debugfs_exit(struct host1x * host1x)1948e0d788cSThierry Reding static void host1x_debugfs_exit(struct host1x *host1x)
1956236451dSTerje Bergstrom {
1966236451dSTerje Bergstrom debugfs_remove_recursive(host1x->debugfs);
1976236451dSTerje Bergstrom }
1988e0d788cSThierry Reding
host1x_debug_init(struct host1x * host1x)1996236451dSTerje Bergstrom void host1x_debug_init(struct host1x *host1x)
2006236451dSTerje Bergstrom {
2018e0d788cSThierry Reding if (IS_ENABLED(CONFIG_DEBUG_FS))
2028e0d788cSThierry Reding host1x_debugfs_init(host1x);
2036236451dSTerje Bergstrom }
2048e0d788cSThierry Reding
host1x_debug_deinit(struct host1x * host1x)2056236451dSTerje Bergstrom void host1x_debug_deinit(struct host1x *host1x)
2066236451dSTerje Bergstrom {
2078e0d788cSThierry Reding if (IS_ENABLED(CONFIG_DEBUG_FS))
2088e0d788cSThierry Reding host1x_debugfs_exit(host1x);
2096236451dSTerje Bergstrom }
2106236451dSTerje Bergstrom
host1x_debug_dump(struct host1x * host1x)2116236451dSTerje Bergstrom void host1x_debug_dump(struct host1x *host1x)
2126236451dSTerje Bergstrom {
2136236451dSTerje Bergstrom struct output o = {
2146236451dSTerje Bergstrom .fn = write_to_printk
2156236451dSTerje Bergstrom };
2160b8070d1SThierry Reding
2178474b025SMikko Perttunen show_all(host1x, &o, true);
2186236451dSTerje Bergstrom }
2196236451dSTerje Bergstrom
host1x_debug_dump_syncpts(struct host1x * host1x)2206236451dSTerje Bergstrom void host1x_debug_dump_syncpts(struct host1x *host1x)
2216236451dSTerje Bergstrom {
2226236451dSTerje Bergstrom struct output o = {
2236236451dSTerje Bergstrom .fn = write_to_printk
2246236451dSTerje Bergstrom };
2250b8070d1SThierry Reding
22674bb98ddSJon Hunter show_syncpts(host1x, &o, false);
2276236451dSTerje Bergstrom }
228