18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2010 Google, Inc. 48c2ecf20Sopenharmony_ci * Author: Erik Gilling <konkers@android.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2011-2013 NVIDIA Corporation 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 108c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 118c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "dev.h" 168c2ecf20Sopenharmony_ci#include "debug.h" 178c2ecf20Sopenharmony_ci#include "channel.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(debug_lock); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ciunsigned int host1x_debug_trace_cmdbuf; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic pid_t host1x_debug_force_timeout_pid; 248c2ecf20Sopenharmony_cistatic u32 host1x_debug_force_timeout_val; 258c2ecf20Sopenharmony_cistatic u32 host1x_debug_force_timeout_channel; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_civoid host1x_debug_output(struct output *o, const char *fmt, ...) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci va_list args; 308c2ecf20Sopenharmony_ci int len; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci va_start(args, fmt); 338c2ecf20Sopenharmony_ci len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); 348c2ecf20Sopenharmony_ci va_end(args); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci o->fn(o->ctx, o->buf, len, false); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_civoid host1x_debug_cont(struct output *o, const char *fmt, ...) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci va_list args; 428c2ecf20Sopenharmony_ci int len; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci va_start(args, fmt); 458c2ecf20Sopenharmony_ci len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); 468c2ecf20Sopenharmony_ci va_end(args); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci o->fn(o->ctx, o->buf, len, true); 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct host1x *m = dev_get_drvdata(ch->dev->parent); 548c2ecf20Sopenharmony_ci struct output *o = data; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci mutex_lock(&ch->cdma.lock); 578c2ecf20Sopenharmony_ci mutex_lock(&debug_lock); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (show_fifo) 608c2ecf20Sopenharmony_ci host1x_hw_show_channel_fifo(m, ch, o); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci host1x_hw_show_channel_cdma(m, ch, o); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci mutex_unlock(&debug_lock); 658c2ecf20Sopenharmony_ci mutex_unlock(&ch->cdma.lock); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic void show_syncpts(struct host1x *m, struct output *o) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci unsigned int i; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci host1x_debug_output(o, "---- syncpts ----\n"); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci for (i = 0; i < host1x_syncpt_nb_pts(m); i++) { 778c2ecf20Sopenharmony_ci u32 max = host1x_syncpt_read_max(m->syncpt + i); 788c2ecf20Sopenharmony_ci u32 min = host1x_syncpt_load(m->syncpt + i); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (!min && !max) 818c2ecf20Sopenharmony_ci continue; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci host1x_debug_output(o, "id %u (%s) min %d max %d\n", 848c2ecf20Sopenharmony_ci i, m->syncpt[i].name, min, max); 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci for (i = 0; i < host1x_syncpt_nb_bases(m); i++) { 888c2ecf20Sopenharmony_ci u32 base_val; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci base_val = host1x_syncpt_load_wait_base(m->syncpt + i); 918c2ecf20Sopenharmony_ci if (base_val) 928c2ecf20Sopenharmony_ci host1x_debug_output(o, "waitbase id %u val %d\n", i, 938c2ecf20Sopenharmony_ci base_val); 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci host1x_debug_output(o, "\n"); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void show_all(struct host1x *m, struct output *o, bool show_fifo) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci unsigned int i; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci host1x_hw_show_mlocks(m, o); 1048c2ecf20Sopenharmony_ci show_syncpts(m, o); 1058c2ecf20Sopenharmony_ci host1x_debug_output(o, "---- channels ----\n"); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci for (i = 0; i < m->info->nb_channels; ++i) { 1088c2ecf20Sopenharmony_ci struct host1x_channel *ch = host1x_channel_get_index(m, i); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (ch) { 1118c2ecf20Sopenharmony_ci show_channel(ch, o, show_fifo); 1128c2ecf20Sopenharmony_ci host1x_channel_put(ch); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int host1x_debug_show_all(struct seq_file *s, void *unused) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct output o = { 1208c2ecf20Sopenharmony_ci .fn = write_to_seqfile, 1218c2ecf20Sopenharmony_ci .ctx = s 1228c2ecf20Sopenharmony_ci }; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci show_all(s->private, &o, true); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int host1x_debug_show(struct seq_file *s, void *unused) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct output o = { 1328c2ecf20Sopenharmony_ci .fn = write_to_seqfile, 1338c2ecf20Sopenharmony_ci .ctx = s 1348c2ecf20Sopenharmony_ci }; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci show_all(s->private, &o, false); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int host1x_debug_open_all(struct inode *inode, struct file *file) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci return single_open(file, host1x_debug_show_all, inode->i_private); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic const struct file_operations host1x_debug_all_fops = { 1478c2ecf20Sopenharmony_ci .open = host1x_debug_open_all, 1488c2ecf20Sopenharmony_ci .read = seq_read, 1498c2ecf20Sopenharmony_ci .llseek = seq_lseek, 1508c2ecf20Sopenharmony_ci .release = single_release, 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic int host1x_debug_open(struct inode *inode, struct file *file) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci return single_open(file, host1x_debug_show, inode->i_private); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic const struct file_operations host1x_debug_fops = { 1598c2ecf20Sopenharmony_ci .open = host1x_debug_open, 1608c2ecf20Sopenharmony_ci .read = seq_read, 1618c2ecf20Sopenharmony_ci .llseek = seq_lseek, 1628c2ecf20Sopenharmony_ci .release = single_release, 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void host1x_debugfs_init(struct host1x *host1x) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct dentry *de = debugfs_create_dir("tegra-host1x", NULL); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* Store the created entry */ 1708c2ecf20Sopenharmony_ci host1x->debugfs = de; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops); 1738c2ecf20Sopenharmony_ci debugfs_create_file("status_all", S_IRUGO, de, host1x, 1748c2ecf20Sopenharmony_ci &host1x_debug_all_fops); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de, 1778c2ecf20Sopenharmony_ci &host1x_debug_trace_cmdbuf); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci host1x_hw_debug_init(host1x, de); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de, 1828c2ecf20Sopenharmony_ci &host1x_debug_force_timeout_pid); 1838c2ecf20Sopenharmony_ci debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de, 1848c2ecf20Sopenharmony_ci &host1x_debug_force_timeout_val); 1858c2ecf20Sopenharmony_ci debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de, 1868c2ecf20Sopenharmony_ci &host1x_debug_force_timeout_channel); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic void host1x_debugfs_exit(struct host1x *host1x) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci debugfs_remove_recursive(host1x->debugfs); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_civoid host1x_debug_init(struct host1x *host1x) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_FS)) 1978c2ecf20Sopenharmony_ci host1x_debugfs_init(host1x); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_civoid host1x_debug_deinit(struct host1x *host1x) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_DEBUG_FS)) 2038c2ecf20Sopenharmony_ci host1x_debugfs_exit(host1x); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_civoid host1x_debug_dump(struct host1x *host1x) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct output o = { 2098c2ecf20Sopenharmony_ci .fn = write_to_printk 2108c2ecf20Sopenharmony_ci }; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci show_all(host1x, &o, true); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_civoid host1x_debug_dump_syncpts(struct host1x *host1x) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct output o = { 2188c2ecf20Sopenharmony_ci .fn = write_to_printk 2198c2ecf20Sopenharmony_ci }; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci show_syncpts(host1x, &o); 2228c2ecf20Sopenharmony_ci} 223