228 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2010 Google, Inc.4 * Author: Erik Gilling <konkers@android.com>5 *6 * Copyright (C) 2011-2013 NVIDIA Corporation7 */8 9#include <linux/debugfs.h>10#include <linux/pm_runtime.h>11#include <linux/seq_file.h>12#include <linux/uaccess.h>13 14#include <linux/io.h>15 16#include "dev.h"17#include "debug.h"18#include "channel.h"19 20static DEFINE_MUTEX(debug_lock);21 22unsigned int host1x_debug_trace_cmdbuf;23 24static pid_t host1x_debug_force_timeout_pid;25static u32 host1x_debug_force_timeout_val;26static u32 host1x_debug_force_timeout_channel;27 28void host1x_debug_output(struct output *o, const char *fmt, ...)29{30 va_list args;31 int len;32 33 va_start(args, fmt);34 len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);35 va_end(args);36 37 o->fn(o->ctx, o->buf, len, false);38}39 40void host1x_debug_cont(struct output *o, const char *fmt, ...)41{42 va_list args;43 int len;44 45 va_start(args, fmt);46 len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);47 va_end(args);48 49 o->fn(o->ctx, o->buf, len, true);50}51 52static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo)53{54 struct host1x *m = dev_get_drvdata(ch->dev->parent);55 struct output *o = data;56 int err;57 58 err = pm_runtime_resume_and_get(m->dev);59 if (err < 0)60 return err;61 62 mutex_lock(&ch->cdma.lock);63 mutex_lock(&debug_lock);64 65 if (show_fifo)66 host1x_hw_show_channel_fifo(m, ch, o);67 68 host1x_hw_show_channel_cdma(m, ch, o);69 70 mutex_unlock(&debug_lock);71 mutex_unlock(&ch->cdma.lock);72 73 pm_runtime_put(m->dev);74 75 return 0;76}77 78static void show_syncpts(struct host1x *m, struct output *o, bool show_all)79{80 unsigned long irqflags;81 struct list_head *pos;82 unsigned int i;83 int err;84 85 host1x_debug_output(o, "---- syncpts ----\n");86 87 err = pm_runtime_resume_and_get(m->dev);88 if (err < 0)89 return;90 91 for (i = 0; i < host1x_syncpt_nb_pts(m); i++) {92 u32 max = host1x_syncpt_read_max(m->syncpt + i);93 u32 min = host1x_syncpt_load(m->syncpt + i);94 unsigned int waiters = 0;95 96 spin_lock_irqsave(&m->syncpt[i].fences.lock, irqflags);97 list_for_each(pos, &m->syncpt[i].fences.list)98 waiters++;99 spin_unlock_irqrestore(&m->syncpt[i].fences.lock, irqflags);100 101 if (!kref_read(&m->syncpt[i].ref))102 continue;103 104 if (!show_all && !min && !max && !waiters)105 continue;106 107 host1x_debug_output(o,108 "id %u (%s) min %d max %d (%d waiters)\n",109 i, m->syncpt[i].name, min, max, waiters);110 }111 112 for (i = 0; i < host1x_syncpt_nb_bases(m); i++) {113 u32 base_val;114 115 base_val = host1x_syncpt_load_wait_base(m->syncpt + i);116 if (base_val)117 host1x_debug_output(o, "waitbase id %u val %d\n", i,118 base_val);119 }120 121 pm_runtime_put(m->dev);122 123 host1x_debug_output(o, "\n");124}125 126static void show_all(struct host1x *m, struct output *o, bool show_fifo)127{128 unsigned int i;129 130 host1x_hw_show_mlocks(m, o);131 show_syncpts(m, o, true);132 host1x_debug_output(o, "---- channels ----\n");133 134 for (i = 0; i < m->info->nb_channels; ++i) {135 struct host1x_channel *ch = host1x_channel_get_index(m, i);136 137 if (ch) {138 show_channel(ch, o, show_fifo);139 host1x_channel_put(ch);140 }141 }142}143 144static int host1x_debug_all_show(struct seq_file *s, void *unused)145{146 struct output o = {147 .fn = write_to_seqfile,148 .ctx = s149 };150 151 show_all(s->private, &o, true);152 153 return 0;154}155DEFINE_SHOW_ATTRIBUTE(host1x_debug_all);156 157static int host1x_debug_show(struct seq_file *s, void *unused)158{159 struct output o = {160 .fn = write_to_seqfile,161 .ctx = s162 };163 164 show_all(s->private, &o, false);165 166 return 0;167}168DEFINE_SHOW_ATTRIBUTE(host1x_debug);169 170static void host1x_debugfs_init(struct host1x *host1x)171{172 struct dentry *de = debugfs_create_dir("tegra-host1x", NULL);173 174 /* Store the created entry */175 host1x->debugfs = de;176 177 debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops);178 debugfs_create_file("status_all", S_IRUGO, de, host1x,179 &host1x_debug_all_fops);180 181 debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,182 &host1x_debug_trace_cmdbuf);183 184 host1x_hw_debug_init(host1x, de);185 186 debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,187 &host1x_debug_force_timeout_pid);188 debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de,189 &host1x_debug_force_timeout_val);190 debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de,191 &host1x_debug_force_timeout_channel);192}193 194static void host1x_debugfs_exit(struct host1x *host1x)195{196 debugfs_remove_recursive(host1x->debugfs);197}198 199void host1x_debug_init(struct host1x *host1x)200{201 if (IS_ENABLED(CONFIG_DEBUG_FS))202 host1x_debugfs_init(host1x);203}204 205void host1x_debug_deinit(struct host1x *host1x)206{207 if (IS_ENABLED(CONFIG_DEBUG_FS))208 host1x_debugfs_exit(host1x);209}210 211void host1x_debug_dump(struct host1x *host1x)212{213 struct output o = {214 .fn = write_to_printk215 };216 217 show_all(host1x, &o, true);218}219 220void host1x_debug_dump_syncpts(struct host1x *host1x)221{222 struct output o = {223 .fn = write_to_printk224 };225 226 show_syncpts(host1x, &o, false);227}228