mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 17:36:20 +03:00
gpu: nvgpu: Dump offending push buffer fragment
When outputting debug dump, print the contents of current push buffer segment. Also changes the debug dump to use pr_cont when applicable, and dumps state before recovering in case channel was not loaded to an engine. Bug 1498688 Change-Id: I5ca12f64bae8f12333d82350278c700645d5007e Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/422198
This commit is contained in:
committed by
Dan Willemsen
parent
aa3e3aaaa0
commit
c32ac10b0b
@@ -929,6 +929,21 @@ static void channel_gk20a_free_priv_cmdbuf(struct channel_gk20a *c)
|
|||||||
memset(q, 0, sizeof(struct priv_cmd_queue));
|
memset(q, 0, sizeof(struct priv_cmd_queue));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int gk20a_find_from_priv_cmdbuf(struct channel_gk20a *c,
|
||||||
|
u64 gpu_va, u32 **cpu_va)
|
||||||
|
{
|
||||||
|
struct priv_cmd_queue *q = &c->priv_cmd_q;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (gpu_va >= q->base_gpuva && gpu_va < (q->base_gpuva + q->size)) {
|
||||||
|
*cpu_va = gpu_va - q->base_gpuva + q->mem.base_cpuva;
|
||||||
|
ret = 0;
|
||||||
|
} else
|
||||||
|
ret = -EINVAL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* allocate a cmd buffer with given size. size is number of u32 entries */
|
/* allocate a cmd buffer with given size. size is number of u32 entries */
|
||||||
int gk20a_channel_alloc_priv_cmdbuf(struct channel_gk20a *c, u32 orig_size,
|
int gk20a_channel_alloc_priv_cmdbuf(struct channel_gk20a *c, u32 orig_size,
|
||||||
struct priv_cmd_entry **entry)
|
struct priv_cmd_entry **entry)
|
||||||
|
|||||||
@@ -159,6 +159,8 @@ void gk20a_set_error_notifier(struct channel_gk20a *ch, __u32 error);
|
|||||||
void gk20a_channel_semaphore_wakeup(struct gk20a *g);
|
void gk20a_channel_semaphore_wakeup(struct gk20a *g);
|
||||||
int gk20a_channel_alloc_priv_cmdbuf(struct channel_gk20a *c, u32 size,
|
int gk20a_channel_alloc_priv_cmdbuf(struct channel_gk20a *c, u32 size,
|
||||||
struct priv_cmd_entry **entry);
|
struct priv_cmd_entry **entry);
|
||||||
|
int gk20a_find_from_priv_cmdbuf(struct channel_gk20a *c,
|
||||||
|
u64 addr, u32 **cpu_va);
|
||||||
|
|
||||||
int gk20a_channel_suspend(struct gk20a *g);
|
int gk20a_channel_suspend(struct gk20a *g);
|
||||||
int gk20a_channel_resume(struct gk20a *g);
|
int gk20a_channel_resume(struct gk20a *g);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
|
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/dma-buf.h>
|
||||||
|
|
||||||
#include "gk20a.h"
|
#include "gk20a.h"
|
||||||
#include "debug_gk20a.h"
|
#include "debug_gk20a.h"
|
||||||
@@ -33,6 +34,7 @@ struct platform_device *gk20a_device;
|
|||||||
|
|
||||||
struct gk20a_debug_output {
|
struct gk20a_debug_output {
|
||||||
void (*fn)(void *ctx, const char *str, size_t len);
|
void (*fn)(void *ctx, const char *str, size_t len);
|
||||||
|
void (*cont)(void *ctx, const char *str, size_t len);
|
||||||
void *ctx;
|
void *ctx;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
};
|
};
|
||||||
@@ -80,6 +82,12 @@ static inline void gk20a_debug_write_printk(void *ctx, const char *str,
|
|||||||
pr_info("%s", str);
|
pr_info("%s", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void gk20a_debug_cont_printk(void *ctx, const char *str,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
pr_cont("%s", str);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void gk20a_debug_write_to_seqfile(void *ctx, const char *str,
|
static inline void gk20a_debug_write_to_seqfile(void *ctx, const char *str,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
@@ -97,6 +105,17 @@ void gk20a_debug_output(struct gk20a_debug_output *o, const char *fmt, ...)
|
|||||||
o->fn(o->ctx, o->buf, len);
|
o->fn(o->ctx, o->buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gk20a_debug_output_cont(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->cont(o->ctx, o->buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
static void gk20a_debug_show_channel(struct gk20a *g,
|
static void gk20a_debug_show_channel(struct gk20a *g,
|
||||||
struct gk20a_debug_output *o,
|
struct gk20a_debug_output *o,
|
||||||
struct channel_gk20a *ch)
|
struct channel_gk20a *ch)
|
||||||
@@ -113,14 +132,14 @@ static void gk20a_debug_show_channel(struct gk20a *g,
|
|||||||
syncpointa = gk20a_mem_rd32(inst_ptr, ram_fc_syncpointa_w());
|
syncpointa = gk20a_mem_rd32(inst_ptr, ram_fc_syncpointa_w());
|
||||||
syncpointb = gk20a_mem_rd32(inst_ptr, ram_fc_syncpointb_w());
|
syncpointb = gk20a_mem_rd32(inst_ptr, ram_fc_syncpointb_w());
|
||||||
|
|
||||||
gk20a_debug_output(o, "%d-%s, pid %d: ", ch->hw_chid,
|
gk20a_debug_output_cont(o, "%d-%s, pid %d: ", ch->hw_chid,
|
||||||
ch->g->dev->name,
|
ch->g->dev->name,
|
||||||
ch->pid);
|
ch->pid);
|
||||||
gk20a_debug_output(o, "%s in use %s %s\n",
|
gk20a_debug_output_cont(o, "%s in use %s %s\n",
|
||||||
ccsr_channel_enable_v(channel) ? "" : "not",
|
ccsr_channel_enable_v(channel) ? "" : "not",
|
||||||
ccsr_chan_status_str[status],
|
ccsr_chan_status_str[status],
|
||||||
ccsr_channel_busy_v(channel) ? "busy" : "not busy");
|
ccsr_channel_busy_v(channel) ? "busy" : "not busy");
|
||||||
gk20a_debug_output(o, "TOP: %016llx PUT: %016llx GET: %016llx "
|
gk20a_debug_output_cont(o, "TOP: %016llx PUT: %016llx GET: %016llx "
|
||||||
"FETCH: %016llx\nHEADER: %08x COUNT: %08x\n"
|
"FETCH: %016llx\nHEADER: %08x COUNT: %08x\n"
|
||||||
"SYNCPOINT %08x %08x SEMAPHORE %08x %08x %08x %08x\n",
|
"SYNCPOINT %08x %08x SEMAPHORE %08x %08x %08x %08x\n",
|
||||||
(u64)gk20a_mem_rd32(inst_ptr, ram_fc_pb_top_level_get_w()) +
|
(u64)gk20a_mem_rd32(inst_ptr, ram_fc_pb_top_level_get_w()) +
|
||||||
@@ -144,14 +163,81 @@ static void gk20a_debug_show_channel(struct gk20a *g,
|
|||||||
if ((pbdma_syncpointb_op_v(syncpointb) == pbdma_syncpointb_op_wait_v())
|
if ((pbdma_syncpointb_op_v(syncpointb) == pbdma_syncpointb_op_wait_v())
|
||||||
&& (pbdma_syncpointb_wait_switch_v(syncpointb) ==
|
&& (pbdma_syncpointb_wait_switch_v(syncpointb) ==
|
||||||
pbdma_syncpointb_wait_switch_en_v()))
|
pbdma_syncpointb_wait_switch_en_v()))
|
||||||
gk20a_debug_output(o, "%s on syncpt %u (%s) val %u\n",
|
gk20a_debug_output_cont(o, "%s on syncpt %u (%s) val %u\n",
|
||||||
(status == 3 || status == 8) ? "Waiting" : "Waited",
|
(status == 3 || status == 8) ? "Waiting" : "Waited",
|
||||||
pbdma_syncpointb_syncpt_index_v(syncpointb),
|
pbdma_syncpointb_syncpt_index_v(syncpointb),
|
||||||
nvhost_syncpt_get_name(g->host1x_dev,
|
nvhost_syncpt_get_name(g->host1x_dev,
|
||||||
pbdma_syncpointb_syncpt_index_v(syncpointb)),
|
pbdma_syncpointb_syncpt_index_v(syncpointb)),
|
||||||
pbdma_syncpointa_payload_v(syncpointa));
|
pbdma_syncpointa_payload_v(syncpointa));
|
||||||
|
|
||||||
gk20a_debug_output(o, "\n");
|
gk20a_debug_output_cont(o, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gk20a_dump_gpfifo(struct channel_gk20a *ch,
|
||||||
|
struct gpfifo *g, struct gk20a_debug_output *o)
|
||||||
|
{
|
||||||
|
struct dma_buf *pb = NULL;
|
||||||
|
u32 *pb_cpu_va = NULL;
|
||||||
|
u64 pb_offset = 0;
|
||||||
|
int i, err = 0;
|
||||||
|
|
||||||
|
u64 gpu_va = (u64)g->entry0
|
||||||
|
| (u64)pbdma_gp_entry1_get_hi_v(g->entry1) << 32ULL;
|
||||||
|
u32 length = pbdma_gp_entry1_length_v(g->entry1);
|
||||||
|
|
||||||
|
if (gk20a_find_from_priv_cmdbuf(ch, gpu_va, &pb_cpu_va)) {
|
||||||
|
gk20a_debug_output_cont(o, "U: ");
|
||||||
|
err = gk20a_vm_find_buffer(ch->vm, gpu_va, &pb, &pb_offset);
|
||||||
|
}
|
||||||
|
if (err) {
|
||||||
|
gk20a_debug_output_cont(o, "Couldn't find push buffer\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pb)
|
||||||
|
pb_cpu_va = dma_buf_vmap(pb);
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
if (i && i % 8 == 0)
|
||||||
|
gk20a_debug_output_cont(o, "\n");
|
||||||
|
gk20a_debug_output_cont(o, "%08x ", *(pb_cpu_va + (pb_offset/4) + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pb)
|
||||||
|
dma_buf_vunmap(pb, pb_cpu_va);
|
||||||
|
|
||||||
|
gk20a_debug_output_cont(o, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gk20a_dump_pb(struct gk20a *g,
|
||||||
|
u32 pbdma_id, struct gk20a_debug_output *o)
|
||||||
|
{
|
||||||
|
u32 gp_get = gk20a_readl(g, pbdma_gp_get_r(pbdma_id));
|
||||||
|
u32 status = gk20a_readl(g, fifo_pbdma_status_r(pbdma_id));
|
||||||
|
u32 chan_status = fifo_pbdma_status_chan_status_v(status);
|
||||||
|
u32 hw_chid = fifo_pbdma_status_id_v(status);
|
||||||
|
struct channel_gk20a *ch = g->fifo.channel+ hw_chid;
|
||||||
|
|
||||||
|
gk20a_debug_output_cont(o, "%s pbdma %d: ", g->dev->name, pbdma_id);
|
||||||
|
gk20a_debug_output_cont(o,
|
||||||
|
"id: %d (%s), next_id: %d (%s) status: %s\n",
|
||||||
|
fifo_pbdma_status_id_v(status),
|
||||||
|
fifo_pbdma_status_id_type_v(status) ?
|
||||||
|
"tsg" : "channel",
|
||||||
|
fifo_pbdma_status_next_id_v(status),
|
||||||
|
fifo_pbdma_status_next_id_type_v(status) ?
|
||||||
|
"tsg" : "channel",
|
||||||
|
chan_status_str[chan_status]);
|
||||||
|
gk20a_debug_output_cont(o, "PUT: %08x GET: %08x "
|
||||||
|
"FETCH: %08x HEADER: %08x\n",
|
||||||
|
gk20a_readl(g, pbdma_gp_put_r(pbdma_id)),
|
||||||
|
gk20a_readl(g, pbdma_gp_get_r(pbdma_id)),
|
||||||
|
gk20a_readl(g, pbdma_gp_fetch_r(pbdma_id)),
|
||||||
|
gk20a_readl(g, pbdma_pb_header_r(pbdma_id)));
|
||||||
|
|
||||||
|
if (ch->in_use) {
|
||||||
|
gk20a_dump_gpfifo(ch, &ch->gpfifo.cpu_va[(gp_get-2) % ch->gpfifo.entry_num], o);
|
||||||
|
gk20a_dump_gpfifo(ch, &ch->gpfifo.cpu_va[(gp_get-1) % ch->gpfifo.entry_num], o);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gk20a_debug_show_dump(struct platform_device *pdev,
|
void gk20a_debug_show_dump(struct platform_device *pdev,
|
||||||
@@ -164,12 +250,13 @@ void gk20a_debug_show_dump(struct platform_device *pdev,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
gk20a_busy(g->dev);
|
gk20a_busy(g->dev);
|
||||||
|
gk20a_debug_output(o, "");
|
||||||
for (i = 0; i < fifo_pbdma_status__size_1_v(); i++) {
|
for (i = 0; i < fifo_pbdma_status__size_1_v(); i++) {
|
||||||
u32 status = gk20a_readl(g, fifo_pbdma_status_r(i));
|
u32 status = gk20a_readl(g, fifo_pbdma_status_r(i));
|
||||||
u32 chan_status = fifo_pbdma_status_chan_status_v(status);
|
u32 chan_status = fifo_pbdma_status_chan_status_v(status);
|
||||||
|
|
||||||
gk20a_debug_output(o, "%s pbdma %d: ", g->dev->name, i);
|
gk20a_debug_output_cont(o, "%s pbdma %d: ", g->dev->name, i);
|
||||||
gk20a_debug_output(o,
|
gk20a_debug_output_cont(o,
|
||||||
"id: %d (%s), next_id: %d (%s) status: %s\n",
|
"id: %d (%s), next_id: %d (%s) status: %s\n",
|
||||||
fifo_pbdma_status_id_v(status),
|
fifo_pbdma_status_id_v(status),
|
||||||
fifo_pbdma_status_id_type_v(status) ?
|
fifo_pbdma_status_id_type_v(status) ?
|
||||||
@@ -178,23 +265,23 @@ void gk20a_debug_show_dump(struct platform_device *pdev,
|
|||||||
fifo_pbdma_status_next_id_type_v(status) ?
|
fifo_pbdma_status_next_id_type_v(status) ?
|
||||||
"tsg" : "channel",
|
"tsg" : "channel",
|
||||||
chan_status_str[chan_status]);
|
chan_status_str[chan_status]);
|
||||||
gk20a_debug_output(o, "PUT: %016llx GET: %016llx "
|
gk20a_debug_output_cont(o, "PUT: %08x GET: %08x "
|
||||||
"FETCH: %08x HEADER: %08x\n",
|
"FETCH: %08x HEADER: %08x\n",
|
||||||
(u64)gk20a_readl(g, pbdma_put_r(i)) +
|
gk20a_readl(g, pbdma_gp_put_r(i)),
|
||||||
((u64)gk20a_readl(g, pbdma_put_hi_r(i)) << 32ULL),
|
gk20a_readl(g, pbdma_gp_get_r(i)),
|
||||||
(u64)gk20a_readl(g, pbdma_get_r(i)) +
|
|
||||||
((u64)gk20a_readl(g, pbdma_get_hi_r(i)) << 32ULL),
|
|
||||||
gk20a_readl(g, pbdma_gp_fetch_r(i)),
|
gk20a_readl(g, pbdma_gp_fetch_r(i)),
|
||||||
gk20a_readl(g, pbdma_pb_header_r(i)));
|
gk20a_readl(g, pbdma_pb_header_r(i)));
|
||||||
|
|
||||||
|
gk20a_dump_pb(g, i, o);
|
||||||
}
|
}
|
||||||
gk20a_debug_output(o, "\n");
|
gk20a_debug_output_cont(o, "\n");
|
||||||
|
|
||||||
for (i = 0; i < fifo_engine_status__size_1_v(); i++) {
|
for (i = 0; i < fifo_engine_status__size_1_v(); i++) {
|
||||||
u32 status = gk20a_readl(g, fifo_engine_status_r(i));
|
u32 status = gk20a_readl(g, fifo_engine_status_r(i));
|
||||||
u32 ctx_status = fifo_engine_status_ctx_status_v(status);
|
u32 ctx_status = fifo_engine_status_ctx_status_v(status);
|
||||||
|
|
||||||
gk20a_debug_output(o, "%s eng %d: ", g->dev->name, i);
|
gk20a_debug_output_cont(o, "%s eng %d: ", g->dev->name, i);
|
||||||
gk20a_debug_output(o,
|
gk20a_debug_output_cont(o,
|
||||||
"id: %d (%s), next_id: %d (%s), ctx: %s ",
|
"id: %d (%s), next_id: %d (%s), ctx: %s ",
|
||||||
fifo_engine_status_id_v(status),
|
fifo_engine_status_id_v(status),
|
||||||
fifo_engine_status_id_type_v(status) ?
|
fifo_engine_status_id_type_v(status) ?
|
||||||
@@ -205,12 +292,12 @@ void gk20a_debug_show_dump(struct platform_device *pdev,
|
|||||||
ctx_status_str[ctx_status]);
|
ctx_status_str[ctx_status]);
|
||||||
|
|
||||||
if (fifo_engine_status_faulted_v(status))
|
if (fifo_engine_status_faulted_v(status))
|
||||||
gk20a_debug_output(o, "faulted ");
|
gk20a_debug_output_cont(o, "faulted ");
|
||||||
if (fifo_engine_status_engine_v(status))
|
if (fifo_engine_status_engine_v(status))
|
||||||
gk20a_debug_output(o, "busy ");
|
gk20a_debug_output_cont(o, "busy ");
|
||||||
gk20a_debug_output(o, "\n");
|
gk20a_debug_output_cont(o, "\n");
|
||||||
}
|
}
|
||||||
gk20a_debug_output(o, "\n");
|
gk20a_debug_output_cont(o, "\n");
|
||||||
|
|
||||||
for (chid = 0; chid < f->num_channels; chid++) {
|
for (chid = 0; chid < f->num_channels; chid++) {
|
||||||
if (f->channel[chid].in_use) {
|
if (f->channel[chid].in_use) {
|
||||||
@@ -225,7 +312,8 @@ void gk20a_debug_dump(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct gk20a_platform *platform = gk20a_get_platform(pdev);
|
struct gk20a_platform *platform = gk20a_get_platform(pdev);
|
||||||
struct gk20a_debug_output o = {
|
struct gk20a_debug_output o = {
|
||||||
.fn = gk20a_debug_write_printk
|
.fn = gk20a_debug_write_printk,
|
||||||
|
.cont = gk20a_debug_cont_printk
|
||||||
};
|
};
|
||||||
|
|
||||||
if (platform->dump_platform_dependencies)
|
if (platform->dump_platform_dependencies)
|
||||||
@@ -237,7 +325,8 @@ void gk20a_debug_dump(struct platform_device *pdev)
|
|||||||
void gk20a_debug_dump_device(struct platform_device *pdev)
|
void gk20a_debug_dump_device(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct gk20a_debug_output o = {
|
struct gk20a_debug_output o = {
|
||||||
.fn = gk20a_debug_write_printk
|
.fn = gk20a_debug_write_printk,
|
||||||
|
.cont = gk20a_debug_cont_printk
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Dump the first device if no info is provided */
|
/* Dump the first device if no info is provided */
|
||||||
@@ -253,6 +342,7 @@ static int gk20a_debug_show(struct seq_file *s, void *unused)
|
|||||||
struct platform_device *pdev = s->private;
|
struct platform_device *pdev = s->private;
|
||||||
struct gk20a_debug_output o = {
|
struct gk20a_debug_output o = {
|
||||||
.fn = gk20a_debug_write_to_seqfile,
|
.fn = gk20a_debug_write_to_seqfile,
|
||||||
|
.cont = gk20a_debug_write_to_seqfile,
|
||||||
.ctx = s,
|
.ctx = s,
|
||||||
};
|
};
|
||||||
gk20a_debug_show_dump(pdev, &o);
|
gk20a_debug_show_dump(pdev, &o);
|
||||||
|
|||||||
@@ -1180,13 +1180,15 @@ void gk20a_fifo_recover_ch(struct gk20a *g, u32 hw_chid, bool verbose)
|
|||||||
struct channel_gk20a *ch =
|
struct channel_gk20a *ch =
|
||||||
g->fifo.channel + hw_chid;
|
g->fifo.channel + hw_chid;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
gk20a_debug_dump(g->dev);
|
||||||
|
|
||||||
gk20a_channel_abort(ch);
|
gk20a_channel_abort(ch);
|
||||||
for (i = 0; i < g->fifo.max_runlists; i++)
|
for (i = 0; i < g->fifo.max_runlists; i++)
|
||||||
gk20a_fifo_update_runlist(g, i,
|
gk20a_fifo_update_runlist(g, i,
|
||||||
hw_chid, false, false);
|
hw_chid, false, false);
|
||||||
|
|
||||||
if (gk20a_fifo_set_ctx_mmu_error(g, ch))
|
gk20a_fifo_set_ctx_mmu_error(g, ch);
|
||||||
gk20a_debug_dump(g->dev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user