/* called under struct_mutex */ void msm_rd_dump_submit(struct msm_gem_submit *submit) { struct drm_device *dev = submit->dev; struct msm_drm_private *priv = dev->dev_private; struct msm_rd_state *rd = priv->rd; char msg[128]; int i, n; if (!rd->open) return; /* writing into fifo is serialized by caller, and * rd->read_lock is used to serialize the reads */ WARN_ON(!mutex_is_locked(&dev->struct_mutex)); n = snprintf(msg, sizeof(msg), "%.*s/%d: fence=%u", TASK_COMM_LEN, current->comm, task_pid_nr(current), submit->fence->seqno); rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4)); /* could be nice to have an option (module-param?) to snapshot * all the bo's associated with the submit. Handy to see vtx * buffers, etc. For now just the cmdstream bo's is enough. */ for (i = 0; i < submit->nr_cmds; i++) { uint32_t idx = submit->cmd[i].idx; uint32_t iova = submit->cmd[i].iova; uint32_t szd = submit->cmd[i].size; /* in dwords */ struct msm_gem_object *obj = submit->bos[idx].obj; const char *buf = msm_gem_vaddr_locked(&obj->base); buf += iova - submit->bos[idx].iova; rd_write_section(rd, RD_GPUADDR, (uint32_t[2]) { iova, szd * 4 }, 8); rd_write_section(rd, RD_BUFFER_CONTENTS, buf, szd * 4); switch (submit->cmd[i].type) { case MSM_SUBMIT_CMD_IB_TARGET_BUF: /* ignore IB-targets, we've logged the buffer, the * parser tool will follow the IB based on the logged * buffer/gpuaddr, so nothing more to do. */ break; case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: case MSM_SUBMIT_CMD_BUF: rd_write_section(rd, RD_CMDSTREAM_ADDR, (uint32_t[2]) { iova, szd }, 8); break; } } }
void rd_start(const char *name, const char *fmt, ...) { char buf[256]; static int cnt = 0; int n = cnt++; const char *testnum; va_list args; testnum = getenv("TESTNUM"); if (testnum) n = strtol(testnum, NULL, 0); sprintf(buf, "%s-%04d.rd", name, n); fd = open(buf, O_WRONLY| O_TRUNC | O_CREAT, 0644); va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); rd_write_section(RD_TEST, buf, strlen(buf)); if (gpu_id) { /* no guarantee that blob driver will again get devinfo property, * so we could miss the GPU_ID section in the new rd file.. so * just hack around it: */ rd_write_section(RD_GPU_ID, &gpu_id, sizeof(gpu_id)); } }
/* called under struct_mutex */ void msm_rd_dump_submit(struct msm_gem_submit *submit) { struct drm_device *dev = submit->dev; struct msm_drm_private *priv = dev->dev_private; struct msm_rd_state *rd = priv->rd; char msg[128]; int i, n; if (!rd->open) return; /* writing into fifo is serialized by caller, and * rd->read_lock is used to serialize the reads */ WARN_ON(!mutex_is_locked(&dev->struct_mutex)); n = snprintf(msg, sizeof(msg), "%.*s/%d: fence=%u", TASK_COMM_LEN, current->comm, task_pid_nr(current), submit->fence->seqno); rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4)); if (rd_full) { for (i = 0; i < submit->nr_bos; i++) { /* buffers that are written to probably don't start out * with anything interesting: */ if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE) continue; snapshot_buf(rd, submit, i, 0, 0); } } for (i = 0; i < submit->nr_cmds; i++) { uint32_t iova = submit->cmd[i].iova; uint32_t szd = submit->cmd[i].size; /* in dwords */ /* snapshot cmdstream bo's (if we haven't already): */ if (!rd_full) { snapshot_buf(rd, submit, submit->cmd[i].idx, submit->cmd[i].iova, szd * 4); } switch (submit->cmd[i].type) { case MSM_SUBMIT_CMD_IB_TARGET_BUF: /* ignore IB-targets, we've logged the buffer, the * parser tool will follow the IB based on the logged * buffer/gpuaddr, so nothing more to do. */ break; case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: case MSM_SUBMIT_CMD_BUF: rd_write_section(rd, RD_CMDSTREAM_ADDR, (uint32_t[2]){ iova, szd }, 8); break; } } }
static int rd_open(struct inode *inode, struct file *file) { struct msm_rd_state *rd = inode->i_private; struct drm_device *dev = rd->dev; struct msm_drm_private *priv = dev->dev_private; struct msm_gpu *gpu = priv->gpu; uint64_t val; uint32_t gpu_id; int ret = 0; mutex_lock(&dev->struct_mutex); if (rd->open || !gpu) { ret = -EBUSY; goto out; } file->private_data = rd; rd->open = true; /* the parsing tools need to know gpu-id to know which * register database to load. */ gpu->funcs->get_param(gpu, MSM_PARAM_GPU_ID, &val); gpu_id = val; rd_write_section(rd, RD_GPU_ID, &gpu_id, sizeof(gpu_id)); out: mutex_unlock(&dev->struct_mutex); return ret; }
static void snapshot_buf(struct msm_rd_state *rd, struct msm_gem_submit *submit, int idx, uint32_t iova, uint32_t size) { struct msm_gem_object *obj = submit->bos[idx].obj; const char *buf; buf = msm_gem_get_vaddr_locked(&obj->base); if (IS_ERR(buf)) return; if (iova) { buf += iova - submit->bos[idx].iova; } else { iova = submit->bos[idx].iova; size = obj->base.size; } rd_write_section(rd, RD_GPUADDR, (uint32_t[2]){ iova, size }, 8); rd_write_section(rd, RD_BUFFER_CONTENTS, buf, size); msm_gem_put_vaddr_locked(&obj->base); }