#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
+#include <linux/gk20a.h>
#include <linux/io.h>
.fn = write_to_printk
};
show_all_no_fifo(master, &o, locked_id);
+ gk20a_debug_dump_device(NULL);
}
void nvhost_debug_dump(struct nvhost_master *master)
.fn = write_to_printk
};
show_all_no_fifo(master, &o, -1);
+ gk20a_debug_dump_device(NULL);
}
+
+void nvhost_debug_dump_device(struct platform_device *pdev)
+{
+ struct nvhost_master *master = nvhost_get_host(pdev);
+ struct output o = {
+ .fn = write_to_printk
+ };
+
+ if (!master)
+ return;
+
+ show_all_no_fifo(master, &o, -1);
+}
+EXPORT_SYMBOL(nvhost_debug_dump_device);
#endif
#include <linux/io.h>
-#include "dev.h"
-#include "debug.h"
-#include "nvhost_cdma.h"
-#include "nvhost_acm.h"
-
#include "gk20a.h"
+#include "debug_gk20a.h"
+
#include "hw_ram_gk20a.h"
#include "hw_fifo_gk20a.h"
#include "hw_ccsr_gk20a.h"
#include "hw_pbdma_gk20a.h"
+unsigned int gk20a_debug_trace_cmdbuf;
+struct platform_device *gk20a_device;
+
+struct gk20a_debug_output {
+ void (*fn)(void *ctx, const char *str, size_t len);
+ void *ctx;
+ char buf[256];
+};
+
static const char * const ccsr_chan_status_str[] = {
"idle",
"pending",
"ctxsw_switch",
};
-static void gk20a_debug_show_channel(struct output *o,
- struct gk20a *g, struct channel_gk20a *ch)
+static inline void gk20a_debug_write_printk(void *ctx, const char *str,
+ size_t len)
+{
+ pr_info("%s", str);
+}
+
+static inline void gk20a_debug_write_to_seqfile(void *ctx, const char *str,
+ size_t len)
+{
+ seq_write((struct seq_file *)ctx, str, len);
+}
+
+void gk20a_debug_output(struct gk20a_debug_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);
+}
+
+static void gk20a_debug_show_channel(struct gk20a *g,
+ struct gk20a_debug_output *o,
+ struct channel_gk20a *ch)
{
u32 channel = gk20a_readl(g, ccsr_channel_r(ch->hw_chid));
u32 status = ccsr_channel_status_v(channel);
if (!inst_ptr)
return;
- nvhost_debug_output(o, "%d-%s, pid %d: ", ch->hw_chid,
+ gk20a_debug_output(o, "%d-%s, pid %d: ", ch->hw_chid,
ch->g->dev->name,
ch->pid);
- nvhost_debug_output(o, "%s in use %s %s\n",
+ gk20a_debug_output(o, "%s in use %s %s\n",
ccsr_channel_enable_v(channel) ? "" : "not",
ccsr_chan_status_str[status],
ccsr_channel_busy_v(channel) ? "busy" : "not busy");
- nvhost_debug_output(o, "TOP: %016llx PUT: %016llx GET: %016llx "
+ gk20a_debug_output(o, "TOP: %016llx PUT: %016llx GET: %016llx "
"FETCH: %016llx\nHEADER: %08x COUNT: %08x\n"
"SYNCPOINT %08x %08x SEMAPHORE %08x %08x %08x %08x\n",
(u64)mem_rd32(inst_ptr, ram_fc_pb_top_level_get_w()) +
mem_rd32(inst_ptr, ram_fc_semaphorec_w()),
mem_rd32(inst_ptr, ram_fc_semaphored_w()));
- nvhost_debug_output(o, "\n");
+ gk20a_debug_output(o, "\n");
}
-void gk20a_debug_show_channel_cdma(struct nvhost_master *m,
- struct nvhost_channel *ch, struct output *o, int _chid)
+void gk20a_debug_show_dump(struct platform_device *pdev,
+ struct gk20a_debug_output *o)
{
- struct gk20a *g = get_gk20a(ch->dev);
+ struct gk20a_platform *platform = gk20a_get_platform(pdev);
+ struct gk20a *g = platform->g;
struct fifo_gk20a *f = &g->fifo;
u32 chid;
int i;
- gk20a_busy(ch->dev);
+ gk20a_busy(g->dev);
for (i = 0; i < fifo_pbdma_status__size_1_v(); i++) {
u32 status = gk20a_readl(g, fifo_pbdma_status_r(i));
u32 chan_status = fifo_pbdma_status_chan_status_v(status);
- nvhost_debug_output(o, "%s pbdma %d: ", ch->dev->name, i);
- nvhost_debug_output(o,
+ gk20a_debug_output(o, "%s pbdma %d: ", g->dev->name, i);
+ gk20a_debug_output(o,
"id: %d (%s), next_id: %d (%s) status: %s\n",
fifo_pbdma_status_id_v(status),
fifo_pbdma_status_id_type_v(status) ?
fifo_pbdma_status_next_id_type_v(status) ?
"tsg" : "channel",
chan_status_str[chan_status]);
- nvhost_debug_output(o, "PUT: %016llx GET: %016llx "
+ gk20a_debug_output(o, "PUT: %016llx GET: %016llx "
"FETCH: %08x HEADER: %08x\n",
(u64)gk20a_readl(g, pbdma_put_r(i)) +
((u64)gk20a_readl(g, pbdma_put_hi_r(i)) << 32ULL),
gk20a_readl(g, pbdma_gp_fetch_r(i)),
gk20a_readl(g, pbdma_pb_header_r(i)));
}
- nvhost_debug_output(o, "\n");
+ gk20a_debug_output(o, "\n");
for (i = 0; i < fifo_engine_status__size_1_v(); i++) {
u32 status = gk20a_readl(g, fifo_engine_status_r(i));
u32 ctx_status = fifo_engine_status_ctx_status_v(status);
- nvhost_debug_output(o, "%s eng %d: ",
- ch->dev->name, i);
- nvhost_debug_output(o,
+ gk20a_debug_output(o, "%s eng %d: ", g->dev->name, i);
+ gk20a_debug_output(o,
"id: %d (%s), next_id: %d (%s), ctx: %s ",
fifo_engine_status_id_v(status),
fifo_engine_status_id_type_v(status) ?
ctx_status_str[ctx_status]);
if (fifo_engine_status_faulted_v(status))
- nvhost_debug_output(o, "faulted ");
+ gk20a_debug_output(o, "faulted ");
if (fifo_engine_status_engine_v(status))
- nvhost_debug_output(o, "busy ");
- nvhost_debug_output(o, "\n");
+ gk20a_debug_output(o, "busy ");
+ gk20a_debug_output(o, "\n");
}
- nvhost_debug_output(o, "\n");
+ gk20a_debug_output(o, "\n");
for (chid = 0; chid < f->num_channels; chid++) {
if (f->channel[chid].in_use) {
struct channel_gk20a *gpu_ch = &f->channel[chid];
- gk20a_debug_show_channel(o, g, gpu_ch);
+ gk20a_debug_show_channel(g, o, gpu_ch);
}
}
- gk20a_idle(ch->dev);
+ gk20a_idle(g->dev);
+}
+
+void gk20a_debug_dump(struct platform_device *pdev)
+{
+ struct gk20a_platform *platform = gk20a_get_platform(pdev);
+ struct gk20a_debug_output o = {
+ .fn = gk20a_debug_write_printk
+ };
+
+ if (platform->dump_platform_dependencies)
+ platform->dump_platform_dependencies(pdev);
+
+ gk20a_debug_show_dump(pdev, &o);
+}
+
+void gk20a_debug_dump_device(struct platform_device *pdev)
+{
+ struct gk20a_debug_output o = {
+ .fn = gk20a_debug_write_printk
+ };
+
+ /* Dump the first device if no info is provided */
+ if (!pdev && gk20a_device)
+ pdev = gk20a_device;
+
+ gk20a_debug_show_dump(pdev, &o);
+}
+EXPORT_SYMBOL(gk20a_debug_dump_device);
+
+static int gk20a_debug_show(struct seq_file *s, void *unused)
+{
+ struct platform_device *pdev = s->private;
+ struct gk20a_debug_output o = {
+ .fn = gk20a_debug_write_to_seqfile,
+ .ctx = s,
+ };
+ gk20a_debug_show_dump(pdev, &o);
+ return 0;
}
-void gk20a_debug_show_channel_fifo(struct nvhost_master *m,
- struct nvhost_channel *ch, struct output *o, int chid)
+static int gk20a_debug_open(struct inode *inode, struct file *file)
{
+ return single_open(file, gk20a_debug_show, inode->i_private);
+}
+
+static const struct file_operations gk20a_debug_fops = {
+ .open = gk20a_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void gk20a_debug_init(struct platform_device *pdev)
+{
+ struct gk20a_platform *platform = platform_get_drvdata(pdev);
+
+ /* Store the first device */
+ if (!gk20a_device)
+ gk20a_device = pdev;
+
+ platform->debugfs = debugfs_create_dir(pdev->name, NULL);
+
+#if defined(NVHOST_DEBUG)
+ debugfs_create_file("status", S_IRUGO, platform->debugfs,
+ pdev, &gk20a_debug_fops);
+ debugfs_create_u32("dbg_mask", S_IRUGO|S_IWUSR, platform->debugfs,
+ &gk20a_dbg_mask);
+ debugfs_create_u32("dbg_ftrace", S_IRUGO|S_IWUSR, platform->debugfs,
+ &gk20a_dbg_ftrace);
+#endif
}
/*
- * drivers/video/tegra/host/gk20a/debug_gk20a.h
+ * GK20A Debug functionality
*
- * Copyright (C) 2011 NVIDIA Corporation
+ * Copyright (C) 2011-2014 NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
*
*/
-void gk20a_debug_show_channel_cdma(struct nvhost_master *m,
- struct nvhost_channel *ch,
- struct output *o, int chid);
-void gk20a_debug_show_channel_fifo(struct nvhost_master *m,
- struct nvhost_channel *ch,
- struct output *o, int chid);
+#ifndef _DEBUG_GK20A_H_
+#define _DEBUG_GK20A_H_
+
+void gk20a_debug_dump(struct platform_device *pdev);
+void gk20a_debug_init(struct platform_device *pdev);
+
+#endif
#include "../dev.h"
+#include "debug_gk20a.h"
#include "gk20a.h"
#include "hw_fifo_gk20a.h"
#include "hw_pbdma_gk20a.h"
} else {
fault_id = gk20a_readl(g, fifo_intr_mmu_fault_id_r());
fake_fault = false;
- nvhost_debug_dump(g->host);
+ gk20a_debug_dump(g->dev);
}
/* lock all runlists. Note that locks are are released in
int ret;
if (verbose)
- nvhost_debug_dump(g->host);
+ gk20a_debug_dump(g->dev);
/* store faulted engines in advance */
g->fifo.mmu_fault_engines = 0;
#include "nvhost_acm.h"
#include "gk20a.h"
+#include "debug_gk20a.h"
#include "ctrl_gk20a.h"
#include "hw_mc_gk20a.h"
#include "hw_timer_gk20a.h"
#define GK20A_NUM_CDEVS 5
+#if defined(GK20A_DEBUG)
+u32 gk20a_dbg_mask = GK20A_DEFAULT_DBG_MASK;
+u32 gk20a_dbg_ftrace;
+#endif
+
static int gk20a_pm_finalize_poweron(struct device *dev);
static int gk20a_pm_prepare_poweroff(struct device *dev);
}
}
+ gk20a_debug_init(dev);
+
/* Set DMA parameters to allow larger sgt lists */
dev->dev.dma_parms = &gk20a->dma_parms;
dma_set_max_seg_size(&dev->dev, UINT_MAX);
u64 data;
};
+/* debug accessories */
+
+#ifdef CONFIG_DEBUG_FS
+ /* debug info, default is compiled-in but effectively disabled (0 mask) */
+ #define GK20A_DEBUG
+ /*e.g: echo 1 > /d/tegra_host/dbg_mask */
+ #define GK20A_DEFAULT_DBG_MASK 0
+#else
+ /* manually enable and turn it on the mask */
+ /*#define NVHOST_DEBUG*/
+ #define GK20A_DEFAULT_DBG_MASK (dbg_info)
+#endif
+
+enum gk20a_dbg_categories {
+ gpu_dbg_info = BIT(0), /* lightly verbose info */
+ gpu_dbg_fn = BIT(2), /* fn name tracing */
+ gpu_dbg_reg = BIT(3), /* register accesses, very verbose */
+ gpu_dbg_pte = BIT(4), /* gmmu ptes */
+ gpu_dbg_intr = BIT(5), /* interrupts */
+ gpu_dbg_pmu = BIT(6), /* gk20a pmu */
+ gpu_dbg_clk = BIT(7), /* gk20a clk */
+ gpu_dbg_map = BIT(8), /* mem mappings */
+ gpu_dbg_gpu_dbg = BIT(9), /* gpu debugger/profiler */
+ gpu_dbg_mem = BIT(31), /* memory accesses, very verbose */
+};
+
+#if defined(GK20A_DEBUG)
+extern u32 gk20a_dbg_mask;
+extern u32 gk20a_dbg_ftrace;
+#define gk20a_dbg(dbg_mask, format, arg...) \
+do { \
+ if (unlikely((dbg_mask) & gk20a_dbg_mask)) { \
+ if (nvhost_dbg_ftrace) \
+ trace_printk(format "\n", ##arg); \
+ else \
+ pr_info("gk20a %s: " format "\n", \
+ __func__, ##arg); \
+ } \
+} while (0)
+
+#else /* GK20A_DEBUG */
+#define gk20a_dbg(dbg_mask, format, arg...) \
+do { \
+ if (0) \
+ pr_info("gk20a %s: " format "\n", __func__, ##arg);\
+} while (0)
+
+#endif
+
+#define gk20a_err(d, fmt, arg...) \
+ dev_err(d, "%s: " fmt "\n", __func__, ##arg)
+
+#define gk20a_warn(d, fmt, arg...) \
+ dev_warn(d, "%s: " fmt "\n", __func__, ##arg)
+
+#define gk20a_dbg_fn(fmt, arg...) \
+ gk20a_dbg(gpu_dbg_fn, fmt, ##arg)
+
+#define gk20a_dbg_info(fmt, arg...) \
+ gk20a_dbg(gpu_dbg_info, fmt, ##arg)
+
+/* mem access with dbg_mem logging */
+static inline u8 gk20a_mem_rd08(void *ptr, int b)
+{
+ u8 _b = ((const u8 *)ptr)[b];
+#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
+ gk20a_dbg(gpu_dbg_mem, " %p = 0x%x", ptr+sizeof(u8)*b, _b);
+#endif
+ return _b;
+}
+static inline u16 gk20a_mem_rd16(void *ptr, int s)
+{
+ u16 _s = ((const u16 *)ptr)[s];
+#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
+ gk20a_dbg(gpu_dbg_mem, " %p = 0x%x", ptr+sizeof(u16)*s, _s);
+#endif
+ return _s;
+}
+static inline u32 gk20a_mem_rd32(void *ptr, int w)
+{
+ u32 _w = ((const u32 *)ptr)[w];
+#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
+ gk20a_dbg(gpu_dbg_mem, " %p = 0x%x", ptr + sizeof(u32)*w, _w);
+#endif
+ return _w;
+}
+static inline void gk20a_mem_wr08(void *ptr, int b, u8 data)
+{
+#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
+ gk20a_dbg(gpu_dbg_mem, " %p = 0x%x", ptr+sizeof(u8)*b, data);
+#endif
+ ((u8 *)ptr)[b] = data;
+}
+static inline void gk20a_mem_wr16(void *ptr, int s, u16 data)
+{
+#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
+ gk20a_dbg(gpu_dbg_mem, " %p = 0x%x", ptr+sizeof(u16)*s, data);
+#endif
+ ((u16 *)ptr)[s] = data;
+}
+static inline void gk20a_mem_wr32(void *ptr, int w, u32 data)
+{
+#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
+ gk20a_dbg(gpu_dbg_mem, " %p = 0x%x", ptr+sizeof(u32)*w, data);
+#endif
+ ((u32 *)ptr)[w] = data;
+}
+
/* register accessors */
static inline void gk20a_writel(struct gk20a *g, u32 r, u32 v)
{
* will register a callback to id. Each time we receive a new value,
* the postscale callback gets called. */
int qos_id;
+
+ /* Called as part of debug dump. If the gpu gets hung, this function
+ * is responsible for delivering all necessary debug data of other
+ * hw units which may interact with the gpu without direct supervision
+ * of the CPU.
+ */
+ void (*dump_platform_dependencies)(struct platform_device *dev);
};
static inline struct gk20a_platform *gk20a_get_platform(
profile->private_data = emc_params;
}
+static void gk20a_tegra_debug_dump(struct platform_device *pdev)
+{
+ struct gk20a_platform *platform = gk20a_get_platform(pdev);
+ struct gk20a *g = platform->g;
+ nvhost_debug_dump_device(g->dev);
+}
+
static int gk20a_tegra_probe(struct platform_device *dev)
{
struct gk20a_platform *platform = gk20a_get_platform(dev);
/* Make gk20a power domain a subdomain of mc */
tegra_pd_add_sd(&platform->g->pd);
-
/* Initialise tegra specific scaling quirks */
gk20a_tegra_scale_init(dev);
- platform->debugfs = debugfs_create_dir(dev->name, NULL);
-
return 0;
}
.channel_busy = gk20a_tegra_channel_busy,
.channel_idle = gk20a_tegra_channel_idle,
.secure_alloc = gk20a_tegra_secure_alloc,
+ .dump_platform_dependencies = gk20a_tegra_debug_dump,
};
struct gk20a_platform gk20a_tegra_platform = {
.channel_busy = gk20a_tegra_channel_busy,
.channel_idle = gk20a_tegra_channel_idle,
.secure_alloc = gk20a_tegra_secure_alloc,
+ .dump_platform_dependencies = gk20a_tegra_debug_dump,
};
struct platform_device tegra_gk20a_device = {
ccflags-y += -Werror
nvhost-t124-objs = \
- t124.o \
- debug_t124.o
+ t124.o
obj-$(CONFIG_TEGRA_GRHOST) += nvhost-t124.o
+++ /dev/null
-/*
- * drivers/video/tegra/host/t124/debug_t124.c
- *
- * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-#include <linux/io.h>
-
-#include "dev.h"
-#include "debug.h"
-#include "nvhost_cdma.h"
-
-#include "t124.h"
-#include "hardware_t124.h"
-#include "gk20a/gk20a.h"
-#include "gk20a/debug_gk20a.h"
-
-#include "chip_support.h"
-
-#include "host1x/host1x_debug.c"
-
-static void t124_debug_show_channel_cdma(struct nvhost_master *m,
- struct nvhost_channel *ch, struct output *o, int chid)
-{
- nvhost_dbg_fn("");
-
-#if defined(CONFIG_TEGRA_GK20A)
- if (is_gk20a_module(ch->dev))
- gk20a_debug_show_channel_cdma(m, ch, o, chid);
- else
-#endif
- t20_debug_show_channel_cdma(m, ch, o, chid);
-}
-
-void t124_debug_show_channel_fifo(struct nvhost_master *m,
- struct nvhost_channel *ch, struct output *o, int chid)
-{
- nvhost_dbg_fn("");
-
- if (!ch || !ch->dev) {
- pr_warn("%s: Channel un-mapped\n", __func__);
- return;
- }
-#if defined(CONFIG_TEGRA_GK20A)
- if (is_gk20a_module(ch->dev))
- gk20a_debug_show_channel_fifo(m, ch, o, chid);
- else
-#endif
- t20_debug_show_channel_fifo(m, ch, o, chid);
-}
-
-static void t124_debug_show_mlocks(struct nvhost_master *m, struct output *o)
-{
- u32 __iomem *mlo_regs = m->sync_aperture +
- host1x_sync_mlock_owner_0_r();
- int i;
-
- nvhost_debug_output(o, "---- mlocks ----\n");
- for (i = 0; i < NV_HOST1X_NB_MLOCKS; i++) {
- u32 owner = readl(mlo_regs + i * 4);
- if (owner & 0x1)
- nvhost_debug_output(o, "%d: locked by channel %d\n",
- i, (owner >> 8) & 0xf);
- else if (owner & 0x2)
- nvhost_debug_output(o, "%d: locked by cpu\n", i);
- else
- nvhost_debug_output(o, "%d: unlocked\n", i);
- }
- nvhost_debug_output(o, "\n");
-}
-
-int nvhost_init_t124_debug_support(struct nvhost_chip_support *op)
-{
- op->debug.show_channel_cdma = t124_debug_show_channel_cdma;
- op->debug.show_channel_fifo = t124_debug_show_channel_fifo;
- op->debug.show_mlocks = t124_debug_show_mlocks;
-
- return 0;
-}
}
#include "host1x/host1x_cdma.c"
+#include "host1x/host1x_debug.c"
#include "host1x/host1x_syncpt.c"
#include "host1x/host1x_intr.c"
#include "host1x/host1x_actmon_t124.c"
op->cdma = host1x_cdma_ops;
op->push_buffer = host1x_pushbuffer_ops;
-
- err = nvhost_init_t124_debug_support(op);
- if (err)
- return err;
-
+ op->debug = host1x_debug_ops;
host->sync_aperture = host->aperture + HOST1X_CHANNEL_SYNC_REG_BASE;
op->syncpt = host1x_syncpt_ops;
op->intr = host1x_intr_ops;
*
* Tegra Graphics Chip support for T124
*
- * Copyright (c) 2011-2013, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2011-2014, NVIDIA Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
int nvhost_init_t124_channel_support(struct nvhost_master *,
struct nvhost_chip_support *);
int nvhost_init_t124_cdma_support(struct nvhost_chip_support *);
-int nvhost_init_t124_debug_support(struct nvhost_chip_support *);
int nvhost_init_t124_syncpt_support(struct nvhost_master *,
struct nvhost_chip_support *);
int nvhost_init_t124_intr_support(struct nvhost_chip_support *);
#define __GK20A_H
struct channel_gk20a;
+struct platform_device;
#ifdef CONFIG_GK20A
void gk20a_channel_update(struct channel_gk20a *c, int nr_completed);
+void gk20a_debug_dump_device(struct platform_device *pdev);
#else
static inline void gk20a_channel_update(struct channel_gk20a *c,
- int nr_completed)
-{
-}
+ int nr_completed) {}
+static inline void gk20a_debug_dump_device(struct platform_device *pdev) {}
#endif
#endif
}
#endif
+#ifdef CONFIG_TEGRA_GRHOST
+void nvhost_debug_dump_device(struct platform_device *pdev);
+#else
+static inline void nvhost_debug_dump_device(struct platform_device *pdev) {}
+#endif
+
/* Hacky way to get access to struct nvhost_device_data for VI device. */
extern struct nvhost_device_data t20_vi_info;
extern struct nvhost_device_data t30_vi_info;