Commit 2165e2b9 authored by Rob Clark's avatar Rob Clark

drm/msm: split rd debugfs file

Split into two instances, the existing $debugfs/rd which continues to
dump all submits, and $debugfs/hangrd which will be used to dump just
submits that cause gpu hangs (and eventually faults, but that will
require some iommu framework enhancements).
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent fad33f4b
...@@ -108,7 +108,8 @@ struct msm_drm_private { ...@@ -108,7 +108,8 @@ struct msm_drm_private {
struct drm_fb_helper *fbdev; struct drm_fb_helper *fbdev;
struct msm_rd_state *rd; struct msm_rd_state *rd; /* debugfs to dump all submits */
struct msm_rd_state *hangrd; /* debugfs to dump hanging submits */
struct msm_perf_state *perf; struct msm_perf_state *perf;
/* list of GEM objects: */ /* list of GEM objects: */
...@@ -298,7 +299,7 @@ void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m); ...@@ -298,7 +299,7 @@ void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m);
int msm_debugfs_late_init(struct drm_device *dev); int msm_debugfs_late_init(struct drm_device *dev);
int msm_rd_debugfs_init(struct drm_minor *minor); int msm_rd_debugfs_init(struct drm_minor *minor);
void msm_rd_debugfs_cleanup(struct msm_drm_private *priv); void msm_rd_debugfs_cleanup(struct msm_drm_private *priv);
void msm_rd_dump_submit(struct msm_gem_submit *submit); void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit);
int msm_perf_debugfs_init(struct drm_minor *minor); int msm_perf_debugfs_init(struct drm_minor *minor);
void msm_perf_debugfs_cleanup(struct msm_drm_private *priv); void msm_perf_debugfs_cleanup(struct msm_drm_private *priv);
#else #else
......
...@@ -557,7 +557,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, ...@@ -557,7 +557,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
list_add_tail(&submit->node, &ring->submits); list_add_tail(&submit->node, &ring->submits);
msm_rd_dump_submit(submit); msm_rd_dump_submit(priv->rd, submit);
update_sw_cntrs(gpu); update_sw_cntrs(gpu);
......
...@@ -19,11 +19,17 @@ ...@@ -19,11 +19,17 @@
* *
* tail -f /sys/kernel/debug/dri/<minor>/rd > logfile.rd * tail -f /sys/kernel/debug/dri/<minor>/rd > logfile.rd
* *
* To log the cmdstream in a format that is understood by freedreno/cffdump * to log the cmdstream in a format that is understood by freedreno/cffdump
* utility. By comparing the last successfully completed fence #, to the * utility. By comparing the last successfully completed fence #, to the
* cmdstream for the next fence, you can narrow down which process and submit * cmdstream for the next fence, you can narrow down which process and submit
* caused the gpu crash/lockup. * caused the gpu crash/lockup.
* *
* Additionally:
*
* tail -f /sys/kernel/debug/dri/<minor>/hangrd > logfile.rd
*
* will capture just the cmdstream from submits which triggered a GPU hang.
*
* This bypasses drm_debugfs_create_files() mainly because we need to use * This bypasses drm_debugfs_create_files() mainly because we need to use
* our own fops for a bit more control. In particular, we don't want to * our own fops for a bit more control. In particular, we don't want to
* do anything if userspace doesn't have the debugfs file open. * do anything if userspace doesn't have the debugfs file open.
...@@ -212,53 +218,89 @@ static const struct file_operations rd_debugfs_fops = { ...@@ -212,53 +218,89 @@ static const struct file_operations rd_debugfs_fops = {
.release = rd_release, .release = rd_release,
}; };
int msm_rd_debugfs_init(struct drm_minor *minor)
static void rd_cleanup(struct msm_rd_state *rd)
{
if (!rd)
return;
mutex_destroy(&rd->read_lock);
kfree(rd);
}
static struct msm_rd_state *rd_init(struct drm_minor *minor, const char *name)
{ {
struct msm_drm_private *priv = minor->dev->dev_private;
struct msm_rd_state *rd; struct msm_rd_state *rd;
struct dentry *ent; struct dentry *ent;
int ret = 0;
/* only create on first minor: */
if (priv->rd)
return 0;
rd = kzalloc(sizeof(*rd), GFP_KERNEL); rd = kzalloc(sizeof(*rd), GFP_KERNEL);
if (!rd) if (!rd)
return -ENOMEM; return ERR_PTR(-ENOMEM);
rd->dev = minor->dev; rd->dev = minor->dev;
rd->fifo.buf = rd->buf; rd->fifo.buf = rd->buf;
mutex_init(&rd->read_lock); mutex_init(&rd->read_lock);
priv->rd = rd;
init_waitqueue_head(&rd->fifo_event); init_waitqueue_head(&rd->fifo_event);
ent = debugfs_create_file("rd", S_IFREG | S_IRUGO, ent = debugfs_create_file(name, S_IFREG | S_IRUGO,
minor->debugfs_root, rd, &rd_debugfs_fops); minor->debugfs_root, rd, &rd_debugfs_fops);
if (!ent) { if (!ent) {
DRM_ERROR("Cannot create /sys/kernel/debug/dri/%pd/rd\n", DRM_ERROR("Cannot create /sys/kernel/debug/dri/%pd/%s\n",
minor->debugfs_root); minor->debugfs_root, name);
ret = -ENOMEM;
goto fail; goto fail;
} }
return rd;
fail:
rd_cleanup(rd);
return ERR_PTR(ret);
}
int msm_rd_debugfs_init(struct drm_minor *minor)
{
struct msm_drm_private *priv = minor->dev->dev_private;
struct msm_rd_state *rd;
int ret;
/* only create on first minor: */
if (priv->rd)
return 0;
rd = rd_init(minor, "rd");
if (IS_ERR(rd)) {
ret = PTR_ERR(rd);
goto fail;
}
priv->rd = rd;
rd = rd_init(minor, "hangrd");
if (IS_ERR(rd)) {
ret = PTR_ERR(rd);
goto fail;
}
priv->hangrd = rd;
return 0; return 0;
fail: fail:
msm_rd_debugfs_cleanup(priv); msm_rd_debugfs_cleanup(priv);
return -1; return ret;
} }
void msm_rd_debugfs_cleanup(struct msm_drm_private *priv) void msm_rd_debugfs_cleanup(struct msm_drm_private *priv)
{ {
struct msm_rd_state *rd = priv->rd; rd_cleanup(priv->rd);
if (!rd)
return;
priv->rd = NULL; priv->rd = NULL;
mutex_destroy(&rd->read_lock);
kfree(rd); rd_cleanup(priv->hangrd);
priv->hangrd = NULL;
} }
static void snapshot_buf(struct msm_rd_state *rd, static void snapshot_buf(struct msm_rd_state *rd,
...@@ -296,11 +338,10 @@ static void snapshot_buf(struct msm_rd_state *rd, ...@@ -296,11 +338,10 @@ static void snapshot_buf(struct msm_rd_state *rd,
} }
/* called under struct_mutex */ /* called under struct_mutex */
void msm_rd_dump_submit(struct msm_gem_submit *submit) void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit)
{ {
struct drm_device *dev = submit->dev; struct drm_device *dev = submit->dev;
struct msm_drm_private *priv = dev->dev_private; struct task_struct *task;
struct msm_rd_state *rd = priv->rd;
char msg[128]; char msg[128];
int i, n; int i, n;
...@@ -312,9 +353,17 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit) ...@@ -312,9 +353,17 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit)
*/ */
WARN_ON(!mutex_is_locked(&dev->struct_mutex)); WARN_ON(!mutex_is_locked(&dev->struct_mutex));
rcu_read_lock();
task = pid_task(submit->pid, PIDTYPE_PID);
if (task) {
n = snprintf(msg, sizeof(msg), "%.*s/%d: fence=%u", n = snprintf(msg, sizeof(msg), "%.*s/%d: fence=%u",
TASK_COMM_LEN, current->comm, task_pid_nr(current), TASK_COMM_LEN, task->comm,
submit->fence->seqno); pid_nr(submit->pid), submit->seqno);
} else {
n = snprintf(msg, sizeof(msg), "???/%d: fence=%u",
pid_nr(submit->pid), submit->seqno);
}
rcu_read_unlock();
rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4)); rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment