brintos

brintos / linux-shallow public Read only

0
0
Text · 4.8 KiB · a18cc8d Raw
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