1/* 2 * Copyright (C) 2013 Red Hat 3 * Author: Rob Clark <robdclark@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18/* For debugging crashes, userspace can: 19 * 20 * tail -f /sys/kernel/debug/dri/<minor>/rd > logfile.rd 21 * 22 * To log the cmdstream in a format that is understood by freedreno/cffdump 23 * utility. By comparing the last successfully completed fence #, to the 24 * cmdstream for the next fence, you can narrow down which process and submit 25 * caused the gpu crash/lockup. 26 * 27 * This bypasses drm_debugfs_create_files() mainly because we need to use 28 * our own fops for a bit more control. In particular, we don't want to 29 * do anything if userspace doesn't have the debugfs file open. 30 */ 31 32#ifdef CONFIG_DEBUG_FS 33 34#include <linux/kfifo.h> 35#include <linux/debugfs.h> 36#include <linux/circ_buf.h> 37#include <linux/wait.h> 38 39#include "msm_drv.h" 40#include "msm_gpu.h" 41#include "msm_gem.h" 42 43enum rd_sect_type { 44 RD_NONE, 45 RD_TEST, /* ascii text */ 46 RD_CMD, /* ascii text */ 47 RD_GPUADDR, /* u32 gpuaddr, u32 size */ 48 RD_CONTEXT, /* raw dump */ 49 RD_CMDSTREAM, /* raw dump */ 50 RD_CMDSTREAM_ADDR, /* gpu addr of cmdstream */ 51 RD_PARAM, /* u32 param_type, u32 param_val, u32 bitlen */ 52 RD_FLUSH, /* empty, clear previous params */ 53 RD_PROGRAM, /* shader program, raw dump */ 54 RD_VERT_SHADER, 55 RD_FRAG_SHADER, 56 RD_BUFFER_CONTENTS, 57 RD_GPU_ID, 58}; 59 60#define BUF_SZ 512 /* should be power of 2 */ 61 62/* space used: */ 63#define circ_count(circ) \ 64 (CIRC_CNT((circ)->head, (circ)->tail, BUF_SZ)) 65#define circ_count_to_end(circ) \ 66 (CIRC_CNT_TO_END((circ)->head, (circ)->tail, BUF_SZ)) 67/* space available: */ 68#define circ_space(circ) \ 69 (CIRC_SPACE((circ)->head, (circ)->tail, BUF_SZ)) 70#define circ_space_to_end(circ) \ 71 (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, BUF_SZ)) 72 73struct msm_rd_state { 74 struct drm_device *dev; 75 76 bool open; 77 78 struct dentry *ent; 79 struct drm_info_node *node; 80 81 /* current submit to read out: */ 82 struct msm_gem_submit *submit; 83 84 /* fifo access is synchronized on the producer side by 85 * struct_mutex held by submit code (otherwise we could 86 * end up w/ cmds logged in different order than they 87 * were executed). And read_lock synchronizes the reads 88 */ 89 struct mutex read_lock; 90 91 wait_queue_head_t fifo_event; 92 struct circ_buf fifo; 93 94 char buf[BUF_SZ]; 95}; 96 97static void rd_write(struct msm_rd_state *rd, const void *buf, int sz) 98{ 99 struct circ_buf *fifo = &rd->fifo; 100 const char *ptr = buf; 101 102 while (sz > 0) { 103 char *fptr = &fifo->buf[fifo->head]; 104 int n; 105 106 wait_event(rd->fifo_event, circ_space(&rd->fifo) > 0); 107 108 n = min(sz, circ_space_to_end(&rd->fifo)); 109 memcpy(fptr, ptr, n); 110 111 fifo->head = (fifo->head + n) & (BUF_SZ - 1); 112 sz -= n; 113 ptr += n; 114 115 wake_up_all(&rd->fifo_event); 116 } 117} 118 119static void rd_write_section(struct msm_rd_state *rd, 120 enum rd_sect_type type, const void *buf, int sz) 121{ 122 rd_write(rd, &type, 4); 123 rd_write(rd, &sz, 4); 124 rd_write(rd, buf, sz); 125} 126 127static ssize_t rd_read(struct file *file, char __user *buf, 128 size_t sz, loff_t *ppos) 129{ 130 struct msm_rd_state *rd = file->private_data; 131 struct circ_buf *fifo = &rd->fifo; 132 const char *fptr = &fifo->buf[fifo->tail]; 133 int n = 0, ret = 0; 134 135 mutex_lock(&rd->read_lock); 136 137 ret = wait_event_interruptible(rd->fifo_event, 138 circ_count(&rd->fifo) > 0); 139 if (ret) 140 goto out; 141 142 n = min_t(int, sz, circ_count_to_end(&rd->fifo)); 143 ret = copy_to_user(buf, fptr, n); 144 if (ret) 145 goto out; 146 147 fifo->tail = (fifo->tail + n) & (BUF_SZ - 1); 148 *ppos += n; 149 150 wake_up_all(&rd->fifo_event); 151 152out: 153 mutex_unlock(&rd->read_lock); 154 if (ret) 155 return ret; 156 return n; 157} 158 159static int rd_open(struct inode *inode, struct file *file) 160{ 161 struct msm_rd_state *rd = inode->i_private; 162 struct drm_device *dev = rd->dev; 163 struct msm_drm_private *priv = dev->dev_private; 164 struct msm_gpu *gpu = priv->gpu; 165 uint64_t val; 166 uint32_t gpu_id; 167 int ret = 0; 168 169 mutex_lock(&dev->struct_mutex); 170 171 if (rd->open || !gpu) { 172 ret = -EBUSY; 173 goto out; 174 } 175 176 file->private_data = rd; 177 rd->open = true; 178 179 /* the parsing tools need to know gpu-id to know which 180 * register database to load. 181 */ 182 gpu->funcs->get_param(gpu, MSM_PARAM_GPU_ID, &val); 183 gpu_id = val; 184 185 rd_write_section(rd, RD_GPU_ID, &gpu_id, sizeof(gpu_id)); 186 187out: 188 mutex_unlock(&dev->struct_mutex); 189 return ret; 190} 191 192static int rd_release(struct inode *inode, struct file *file) 193{ 194 struct msm_rd_state *rd = inode->i_private; 195 rd->open = false; 196 return 0; 197} 198 199 200static const struct file_operations rd_debugfs_fops = { 201 .owner = THIS_MODULE, 202 .open = rd_open, 203 .read = rd_read, 204 .llseek = no_llseek, 205 .release = rd_release, 206}; 207 208int msm_rd_debugfs_init(struct drm_minor *minor) 209{ 210 struct msm_drm_private *priv = minor->dev->dev_private; 211 struct msm_rd_state *rd; 212 213 /* only create on first minor: */ 214 if (priv->rd) 215 return 0; 216 217 rd = kzalloc(sizeof(*rd), GFP_KERNEL); 218 if (!rd) 219 return -ENOMEM; 220 221 rd->dev = minor->dev; 222 rd->fifo.buf = rd->buf; 223 224 mutex_init(&rd->read_lock); 225 priv->rd = rd; 226 227 init_waitqueue_head(&rd->fifo_event); 228 229 rd->node = kzalloc(sizeof(*rd->node), GFP_KERNEL); 230 if (!rd->node) 231 goto fail; 232 233 rd->ent = debugfs_create_file("rd", S_IFREG | S_IRUGO, 234 minor->debugfs_root, rd, &rd_debugfs_fops); 235 if (!rd->ent) { 236 DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/rd\n", 237 minor->debugfs_root->d_name.name); 238 goto fail; 239 } 240 241 rd->node->minor = minor; 242 rd->node->dent = rd->ent; 243 rd->node->info_ent = NULL; 244 245 mutex_lock(&minor->debugfs_lock); 246 list_add(&rd->node->list, &minor->debugfs_list); 247 mutex_unlock(&minor->debugfs_lock); 248 249 return 0; 250 251fail: 252 msm_rd_debugfs_cleanup(minor); 253 return -1; 254} 255 256void msm_rd_debugfs_cleanup(struct drm_minor *minor) 257{ 258 struct msm_drm_private *priv = minor->dev->dev_private; 259 struct msm_rd_state *rd = priv->rd; 260 261 if (!rd) 262 return; 263 264 priv->rd = NULL; 265 266 debugfs_remove(rd->ent); 267 268 if (rd->node) { 269 mutex_lock(&minor->debugfs_lock); 270 list_del(&rd->node->list); 271 mutex_unlock(&minor->debugfs_lock); 272 kfree(rd->node); 273 } 274 275 mutex_destroy(&rd->read_lock); 276 277 kfree(rd); 278} 279 280/* called under struct_mutex */ 281void msm_rd_dump_submit(struct msm_gem_submit *submit) 282{ 283 struct drm_device *dev = submit->dev; 284 struct msm_drm_private *priv = dev->dev_private; 285 struct msm_rd_state *rd = priv->rd; 286 char msg[128]; 287 int i, n; 288 289 if (!rd->open) 290 return; 291 292 /* writing into fifo is serialized by caller, and 293 * rd->read_lock is used to serialize the reads 294 */ 295 WARN_ON(!mutex_is_locked(&dev->struct_mutex)); 296 297 n = snprintf(msg, sizeof(msg), "%.*s/%d: fence=%u", 298 TASK_COMM_LEN, current->comm, task_pid_nr(current), 299 submit->fence); 300 301 rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4)); 302 303 /* could be nice to have an option (module-param?) to snapshot 304 * all the bo's associated with the submit. Handy to see vtx 305 * buffers, etc. For now just the cmdstream bo's is enough. 306 */ 307 308 for (i = 0; i < submit->nr_cmds; i++) { 309 uint32_t idx = submit->cmd[i].idx; 310 uint32_t iova = submit->cmd[i].iova; 311 uint32_t szd = submit->cmd[i].size; /* in dwords */ 312 struct msm_gem_object *obj = submit->bos[idx].obj; 313 const char *buf = msm_gem_vaddr_locked(&obj->base); 314 315 buf += iova - submit->bos[idx].iova; 316 317 rd_write_section(rd, RD_GPUADDR, 318 (uint32_t[2]){ iova, szd * 4 }, 8); 319 rd_write_section(rd, RD_BUFFER_CONTENTS, 320 buf, szd * 4); 321 322 switch (submit->cmd[i].type) { 323 case MSM_SUBMIT_CMD_IB_TARGET_BUF: 324 /* ignore IB-targets, we've logged the buffer, the 325 * parser tool will follow the IB based on the logged 326 * buffer/gpuaddr, so nothing more to do. 327 */ 328 break; 329 case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: 330 case MSM_SUBMIT_CMD_BUF: 331 rd_write_section(rd, RD_CMDSTREAM_ADDR, 332 (uint32_t[2]){ iova, szd }, 8); 333 break; 334 } 335 } 336} 337#endif 338