From 34ff636f322c6d5e4f0a52338fa63a7dff09a495 Mon Sep 17 00:00:00 2001 From: Joel Fernandes Date: Sat, 18 Jul 2026 13:15:36 -0400 Subject: scftorture: Count single_rpc offline failures in statistics output scf_torture_stats_print() aggregates each invoker thread's counters into a local scf_statistics structure before printing, but the n_single_rpc_ofl field is missing from the aggregation loop. As a result, the "single_rpc_ofl" value printed in the statistics line is always zero, even when smp_call_function_single() invocations for the RPC test have failed due to offline CPUs and been counted by the invoker threads. Add the missing accumulation so that the printed value reflects the actual counts. Signed-off-by: Joel Fernandes Signed-off-by: Paul E. McKenney --- drivers/gpu/host1x/debug.c | 218 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 drivers/gpu/host1x/debug.c (limited to 'drivers/gpu/host1x/debug.c') diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c new file mode 100644 index 000000000..6433c00d5 --- /dev/null +++ b/drivers/gpu/host1x/debug.c @@ -0,0 +1,218 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2010 Google, Inc. + * Author: Erik Gilling + * + * Copyright (C) 2011-2013 NVIDIA Corporation + */ + +#include +#include +#include +#include + +#include + +#include "dev.h" +#include "debug.h" +#include "channel.h" + +static DEFINE_MUTEX(debug_lock); + +unsigned int host1x_debug_trace_cmdbuf; + +static pid_t host1x_debug_force_timeout_pid; +static u32 host1x_debug_force_timeout_val; +static u32 host1x_debug_force_timeout_channel; + +void host1x_debug_output(struct output *o, const char *fmt, ...) +{ + va_list args; + int len; + + va_start(args, fmt); + len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); + va_end(args); + + o->fn(o->ctx, o->buf, len, false); +} + +void host1x_debug_cont(struct output *o, const char *fmt, ...) +{ + va_list args; + int len; + + va_start(args, fmt); + len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); + va_end(args); + + o->fn(o->ctx, o->buf, len, true); +} + +static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) +{ + struct host1x *m = dev_get_drvdata(ch->dev->parent); + struct output *o = data; + int err; + + err = pm_runtime_resume_and_get(m->dev); + if (err < 0) + return err; + + mutex_lock(&ch->cdma.lock); + mutex_lock(&debug_lock); + + if (show_fifo) + host1x_hw_show_channel_fifo(m, ch, o); + + host1x_hw_show_channel_cdma(m, ch, o); + + mutex_unlock(&debug_lock); + mutex_unlock(&ch->cdma.lock); + + pm_runtime_put(m->dev); + + return 0; +} + +static void show_syncpts(struct host1x *m, struct output *o, bool show_all) +{ + unsigned long irqflags; + struct list_head *pos; + unsigned int i; + int err; + + host1x_debug_output(o, "---- syncpts ----\n"); + + err = pm_runtime_resume_and_get(m->dev); + if (err < 0) + return; + + for (i = 0; i < host1x_syncpt_nb_pts(m); i++) { + u32 max = host1x_syncpt_read_max(m->syncpt + i); + u32 min = host1x_syncpt_load(m->syncpt + i); + unsigned int waiters = 0; + + spin_lock_irqsave(&m->syncpt[i].fences.lock, irqflags); + list_for_each(pos, &m->syncpt[i].fences.list) + waiters++; + spin_unlock_irqrestore(&m->syncpt[i].fences.lock, irqflags); + + if (!kref_read(&m->syncpt[i].ref)) + continue; + + if (!show_all && !min && !max && !waiters) + continue; + + host1x_debug_output(o, + "id %u (%s) min %d max %d (%d waiters)\n", + i, m->syncpt[i].name, min, max, waiters); + } + + for (i = 0; i < host1x_syncpt_nb_bases(m); i++) { + u32 base_val; + + base_val = host1x_syncpt_load_wait_base(m->syncpt + i); + if (base_val) + host1x_debug_output(o, "waitbase id %u val %d\n", i, + base_val); + } + + pm_runtime_put(m->dev); + + host1x_debug_output(o, "\n"); +} + +static void show_all(struct host1x *m, struct output *o, bool show_fifo) +{ + unsigned int i; + + host1x_hw_show_mlocks(m, o); + show_syncpts(m, o, true); + host1x_debug_output(o, "---- channels ----\n"); + + for (i = 0; i < m->info->nb_channels; ++i) { + struct host1x_channel *ch = host1x_channel_get_index(m, i); + + if (ch) { + show_channel(ch, o, show_fifo); + host1x_channel_put(ch); + } + } +} + +static int host1x_debug_all_show(struct seq_file *s, void *unused) +{ + struct output o = { + .fn = write_to_seqfile, + .ctx = s + }; + + show_all(s->private, &o, true); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(host1x_debug_all); + +static int host1x_debug_show(struct seq_file *s, void *unused) +{ + struct output o = { + .fn = write_to_seqfile, + .ctx = s + }; + + show_all(s->private, &o, false); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(host1x_debug); + +static void host1x_debugfs_init(struct host1x *host1x) +{ + struct dentry *de = debugfs_create_dir("tegra-host1x", NULL); + + /* Store the created entry */ + host1x->debugfs = de; + + debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops); + debugfs_create_file("status_all", S_IRUGO, de, host1x, + &host1x_debug_all_fops); + + debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de, + &host1x_debug_trace_cmdbuf); + + host1x_hw_debug_init(host1x, de); + + debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de, + &host1x_debug_force_timeout_pid); + debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de, + &host1x_debug_force_timeout_val); + debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de, + &host1x_debug_force_timeout_channel); +} + +static void host1x_debugfs_exit(struct host1x *host1x) +{ + debugfs_remove_recursive(host1x->debugfs); +} + +void host1x_debug_init(struct host1x *host1x) +{ + if (IS_ENABLED(CONFIG_DEBUG_FS)) + host1x_debugfs_init(host1x); +} + +void host1x_debug_deinit(struct host1x *host1x) +{ + if (IS_ENABLED(CONFIG_DEBUG_FS)) + host1x_debugfs_exit(host1x); +} + +void host1x_debug_dump(struct host1x *host1x) +{ + struct output o = { + .fn = write_to_printk + }; + + show_all(host1x, &o, true); +} -- cgit v1.3.1