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