cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

debug.c (5367B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2010 Google, Inc.
      4 * Author: Erik Gilling <konkers@android.com>
      5 *
      6 * Copyright (C) 2011-2013 NVIDIA Corporation
      7 */
      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	struct list_head *pos;
     81	unsigned int i;
     82	int err;
     83
     84	host1x_debug_output(o, "---- syncpts ----\n");
     85
     86	err = pm_runtime_resume_and_get(m->dev);
     87	if (err < 0)
     88		return;
     89
     90	for (i = 0; i < host1x_syncpt_nb_pts(m); i++) {
     91		u32 max = host1x_syncpt_read_max(m->syncpt + i);
     92		u32 min = host1x_syncpt_load(m->syncpt + i);
     93		unsigned int waiters = 0;
     94
     95		spin_lock(&m->syncpt[i].intr.lock);
     96		list_for_each(pos, &m->syncpt[i].intr.wait_head)
     97			waiters++;
     98		spin_unlock(&m->syncpt[i].intr.lock);
     99
    100		if (!kref_read(&m->syncpt[i].ref))
    101			continue;
    102
    103		if (!show_all && !min && !max && !waiters)
    104			continue;
    105
    106		host1x_debug_output(o,
    107				    "id %u (%s) min %d max %d (%d waiters)\n",
    108				    i, m->syncpt[i].name, min, max, waiters);
    109	}
    110
    111	for (i = 0; i < host1x_syncpt_nb_bases(m); i++) {
    112		u32 base_val;
    113
    114		base_val = host1x_syncpt_load_wait_base(m->syncpt + i);
    115		if (base_val)
    116			host1x_debug_output(o, "waitbase id %u val %d\n", i,
    117					    base_val);
    118	}
    119
    120	pm_runtime_put(m->dev);
    121
    122	host1x_debug_output(o, "\n");
    123}
    124
    125static void show_all(struct host1x *m, struct output *o, bool show_fifo)
    126{
    127	unsigned int i;
    128
    129	host1x_hw_show_mlocks(m, o);
    130	show_syncpts(m, o, true);
    131	host1x_debug_output(o, "---- channels ----\n");
    132
    133	for (i = 0; i < m->info->nb_channels; ++i) {
    134		struct host1x_channel *ch = host1x_channel_get_index(m, i);
    135
    136		if (ch) {
    137			show_channel(ch, o, show_fifo);
    138			host1x_channel_put(ch);
    139		}
    140	}
    141}
    142
    143static int host1x_debug_show_all(struct seq_file *s, void *unused)
    144{
    145	struct output o = {
    146		.fn = write_to_seqfile,
    147		.ctx = s
    148	};
    149
    150	show_all(s->private, &o, true);
    151
    152	return 0;
    153}
    154
    155static int host1x_debug_show(struct seq_file *s, void *unused)
    156{
    157	struct output o = {
    158		.fn = write_to_seqfile,
    159		.ctx = s
    160	};
    161
    162	show_all(s->private, &o, false);
    163
    164	return 0;
    165}
    166
    167static int host1x_debug_open_all(struct inode *inode, struct file *file)
    168{
    169	return single_open(file, host1x_debug_show_all, inode->i_private);
    170}
    171
    172static const struct file_operations host1x_debug_all_fops = {
    173	.open = host1x_debug_open_all,
    174	.read = seq_read,
    175	.llseek = seq_lseek,
    176	.release = single_release,
    177};
    178
    179static int host1x_debug_open(struct inode *inode, struct file *file)
    180{
    181	return single_open(file, host1x_debug_show, inode->i_private);
    182}
    183
    184static const struct file_operations host1x_debug_fops = {
    185	.open = host1x_debug_open,
    186	.read = seq_read,
    187	.llseek = seq_lseek,
    188	.release = single_release,
    189};
    190
    191static void host1x_debugfs_init(struct host1x *host1x)
    192{
    193	struct dentry *de = debugfs_create_dir("tegra-host1x", NULL);
    194
    195	/* Store the created entry */
    196	host1x->debugfs = de;
    197
    198	debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops);
    199	debugfs_create_file("status_all", S_IRUGO, de, host1x,
    200			    &host1x_debug_all_fops);
    201
    202	debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,
    203			   &host1x_debug_trace_cmdbuf);
    204
    205	host1x_hw_debug_init(host1x, de);
    206
    207	debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,
    208			   &host1x_debug_force_timeout_pid);
    209	debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de,
    210			   &host1x_debug_force_timeout_val);
    211	debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de,
    212			   &host1x_debug_force_timeout_channel);
    213}
    214
    215static void host1x_debugfs_exit(struct host1x *host1x)
    216{
    217	debugfs_remove_recursive(host1x->debugfs);
    218}
    219
    220void host1x_debug_init(struct host1x *host1x)
    221{
    222	if (IS_ENABLED(CONFIG_DEBUG_FS))
    223		host1x_debugfs_init(host1x);
    224}
    225
    226void host1x_debug_deinit(struct host1x *host1x)
    227{
    228	if (IS_ENABLED(CONFIG_DEBUG_FS))
    229		host1x_debugfs_exit(host1x);
    230}
    231
    232void host1x_debug_dump(struct host1x *host1x)
    233{
    234	struct output o = {
    235		.fn = write_to_printk
    236	};
    237
    238	show_all(host1x, &o, true);
    239}
    240
    241void host1x_debug_dump_syncpts(struct host1x *host1x)
    242{
    243	struct output o = {
    244		.fn = write_to_printk
    245	};
    246
    247	show_syncpts(host1x, &o, false);
    248}