Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/lima: save task info dump when task fail

Save all information to start a task which can be exported to user
for debug usage. Dump file data format is specified in lima_dump.h

v2:
Add include header to address build robot complain.

Tested-by: Andreas Baierl <ichgeh@imkreisrum.de>
Reviewed-by: Vasily Khoruzhick <anarsoul@gmail.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200307134423.24329-1-yuq825@gmail.com

Qiang Yu b78edd46 c67a3d4f

+235
+13
drivers/gpu/drm/lima/lima_device.c
··· 344 344 if (err) 345 345 goto err_out5; 346 346 347 + ldev->dump.magic = LIMA_DUMP_MAGIC; 348 + ldev->dump.version_major = LIMA_DUMP_MAJOR; 349 + ldev->dump.version_minor = LIMA_DUMP_MINOR; 350 + INIT_LIST_HEAD(&ldev->error_task_list); 351 + mutex_init(&ldev->error_task_list_lock); 352 + 347 353 dev_info(ldev->dev, "bus rate = %lu\n", clk_get_rate(ldev->clk_bus)); 348 354 dev_info(ldev->dev, "mod rate = %lu", clk_get_rate(ldev->clk_gpu)); 349 355 ··· 376 370 void lima_device_fini(struct lima_device *ldev) 377 371 { 378 372 int i; 373 + struct lima_sched_error_task *et, *tmp; 374 + 375 + list_for_each_entry_safe(et, tmp, &ldev->error_task_list, list) { 376 + list_del(&et->list); 377 + kvfree(et); 378 + } 379 + mutex_destroy(&ldev->error_task_list_lock); 379 380 380 381 lima_fini_pp_pipe(ldev); 381 382 lima_fini_gp_pipe(ldev);
+8
drivers/gpu/drm/lima/lima_device.h
··· 6 6 7 7 #include <drm/drm_device.h> 8 8 #include <linux/delay.h> 9 + #include <linux/list.h> 10 + #include <linux/mutex.h> 9 11 10 12 #include "lima_sched.h" 13 + #include "lima_dump.h" 11 14 12 15 enum lima_gpu_id { 13 16 lima_gpu_mali400 = 0, ··· 97 94 98 95 u32 *dlbu_cpu; 99 96 dma_addr_t dlbu_dma; 97 + 98 + /* debug info */ 99 + struct lima_dump_head dump; 100 + struct list_head error_task_list; 101 + struct mutex error_task_list_lock; 100 102 }; 101 103 102 104 static inline struct lima_device *
+77
drivers/gpu/drm/lima/lima_dump.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 + /* Copyright 2020 Qiang Yu <yuq825@gmail.com> */ 3 + 4 + #ifndef __LIMA_DUMP_H__ 5 + #define __LIMA_DUMP_H__ 6 + 7 + #include <linux/types.h> 8 + 9 + /** 10 + * dump file format for all the information to start a lima task 11 + * 12 + * top level format 13 + * | magic code "LIMA" | format version | num tasks | data size | 14 + * | reserved | reserved | reserved | reserved | 15 + * | task 1 ID | task 1 size | num chunks | reserved | task 1 data | 16 + * | task 2 ID | task 2 size | num chunks | reserved | task 2 data | 17 + * ... 18 + * 19 + * task data format 20 + * | chunk 1 ID | chunk 1 size | reserved | reserved | chunk 1 data | 21 + * | chunk 2 ID | chunk 2 size | reserved | reserved | chunk 2 data | 22 + * ... 23 + * 24 + */ 25 + 26 + #define LIMA_DUMP_MAJOR 1 27 + #define LIMA_DUMP_MINOR 0 28 + 29 + #define LIMA_DUMP_MAGIC 0x414d494c 30 + 31 + struct lima_dump_head { 32 + __u32 magic; 33 + __u16 version_major; 34 + __u16 version_minor; 35 + __u32 num_tasks; 36 + __u32 size; 37 + __u32 reserved[4]; 38 + }; 39 + 40 + #define LIMA_DUMP_TASK_GP 0 41 + #define LIMA_DUMP_TASK_PP 1 42 + #define LIMA_DUMP_TASK_NUM 2 43 + 44 + struct lima_dump_task { 45 + __u32 id; 46 + __u32 size; 47 + __u32 num_chunks; 48 + __u32 reserved; 49 + }; 50 + 51 + #define LIMA_DUMP_CHUNK_FRAME 0 52 + #define LIMA_DUMP_CHUNK_BUFFER 1 53 + #define LIMA_DUMP_CHUNK_PROCESS_NAME 2 54 + #define LIMA_DUMP_CHUNK_PROCESS_ID 3 55 + #define LIMA_DUMP_CHUNK_NUM 4 56 + 57 + struct lima_dump_chunk { 58 + __u32 id; 59 + __u32 size; 60 + __u32 reserved[2]; 61 + }; 62 + 63 + struct lima_dump_chunk_buffer { 64 + __u32 id; 65 + __u32 size; 66 + __u32 va; 67 + __u32 reserved; 68 + }; 69 + 70 + struct lima_dump_chunk_pid { 71 + __u32 id; 72 + __u32 size; 73 + __u32 pid; 74 + __u32 reserved; 75 + }; 76 + 77 + #endif
+130
drivers/gpu/drm/lima/lima_sched.c
··· 4 4 #include <linux/kthread.h> 5 5 #include <linux/slab.h> 6 6 #include <linux/xarray.h> 7 + #include <linux/vmalloc.h> 7 8 8 9 #include "lima_drv.h" 9 10 #include "lima_sched.h" ··· 257 256 return task->fence; 258 257 } 259 258 259 + static void lima_sched_build_error_task_list(struct lima_sched_task *task) 260 + { 261 + struct lima_sched_error_task *et; 262 + struct lima_sched_pipe *pipe = to_lima_pipe(task->base.sched); 263 + struct lima_ip *ip = pipe->processor[0]; 264 + int pipe_id = ip->id == lima_ip_gp ? lima_pipe_gp : lima_pipe_pp; 265 + struct lima_device *dev = ip->dev; 266 + struct lima_sched_context *sched_ctx = 267 + container_of(task->base.entity, 268 + struct lima_sched_context, base); 269 + struct lima_ctx *ctx = 270 + container_of(sched_ctx, struct lima_ctx, context[pipe_id]); 271 + struct lima_dump_task *dt; 272 + struct lima_dump_chunk *chunk; 273 + struct lima_dump_chunk_pid *pid_chunk; 274 + struct lima_dump_chunk_buffer *buffer_chunk; 275 + u32 size, task_size, mem_size; 276 + int i; 277 + 278 + mutex_lock(&dev->error_task_list_lock); 279 + 280 + if (dev->dump.num_tasks >= lima_max_error_tasks) { 281 + dev_info(dev->dev, "fail to save task state: error task list is full\n"); 282 + goto out; 283 + } 284 + 285 + /* frame chunk */ 286 + size = sizeof(struct lima_dump_chunk) + pipe->frame_size; 287 + /* process name chunk */ 288 + size += sizeof(struct lima_dump_chunk) + sizeof(ctx->pname); 289 + /* pid chunk */ 290 + size += sizeof(struct lima_dump_chunk); 291 + /* buffer chunks */ 292 + for (i = 0; i < task->num_bos; i++) { 293 + struct lima_bo *bo = task->bos[i]; 294 + 295 + size += sizeof(struct lima_dump_chunk); 296 + size += bo->heap_size ? bo->heap_size : lima_bo_size(bo); 297 + } 298 + 299 + task_size = size + sizeof(struct lima_dump_task); 300 + mem_size = task_size + sizeof(*et); 301 + et = kvmalloc(mem_size, GFP_KERNEL); 302 + if (!et) { 303 + dev_err(dev->dev, "fail to alloc task dump buffer of size %x\n", 304 + mem_size); 305 + goto out; 306 + } 307 + 308 + et->data = et + 1; 309 + et->size = task_size; 310 + 311 + dt = et->data; 312 + memset(dt, 0, sizeof(*dt)); 313 + dt->id = pipe_id; 314 + dt->size = size; 315 + 316 + chunk = (struct lima_dump_chunk *)(dt + 1); 317 + memset(chunk, 0, sizeof(*chunk)); 318 + chunk->id = LIMA_DUMP_CHUNK_FRAME; 319 + chunk->size = pipe->frame_size; 320 + memcpy(chunk + 1, task->frame, pipe->frame_size); 321 + dt->num_chunks++; 322 + 323 + chunk = (void *)(chunk + 1) + chunk->size; 324 + memset(chunk, 0, sizeof(*chunk)); 325 + chunk->id = LIMA_DUMP_CHUNK_PROCESS_NAME; 326 + chunk->size = sizeof(ctx->pname); 327 + memcpy(chunk + 1, ctx->pname, sizeof(ctx->pname)); 328 + dt->num_chunks++; 329 + 330 + pid_chunk = (void *)(chunk + 1) + chunk->size; 331 + memset(pid_chunk, 0, sizeof(*pid_chunk)); 332 + pid_chunk->id = LIMA_DUMP_CHUNK_PROCESS_ID; 333 + pid_chunk->pid = ctx->pid; 334 + dt->num_chunks++; 335 + 336 + buffer_chunk = (void *)(pid_chunk + 1) + pid_chunk->size; 337 + for (i = 0; i < task->num_bos; i++) { 338 + struct lima_bo *bo = task->bos[i]; 339 + void *data; 340 + 341 + memset(buffer_chunk, 0, sizeof(*buffer_chunk)); 342 + buffer_chunk->id = LIMA_DUMP_CHUNK_BUFFER; 343 + buffer_chunk->va = lima_vm_get_va(task->vm, bo); 344 + 345 + if (bo->heap_size) { 346 + buffer_chunk->size = bo->heap_size; 347 + 348 + data = vmap(bo->base.pages, bo->heap_size >> PAGE_SHIFT, 349 + VM_MAP, pgprot_writecombine(PAGE_KERNEL)); 350 + if (!data) { 351 + kvfree(et); 352 + goto out; 353 + } 354 + 355 + memcpy(buffer_chunk + 1, data, buffer_chunk->size); 356 + 357 + vunmap(data); 358 + } else { 359 + buffer_chunk->size = lima_bo_size(bo); 360 + 361 + data = drm_gem_shmem_vmap(&bo->base.base); 362 + if (IS_ERR_OR_NULL(data)) { 363 + kvfree(et); 364 + goto out; 365 + } 366 + 367 + memcpy(buffer_chunk + 1, data, buffer_chunk->size); 368 + 369 + drm_gem_shmem_vunmap(&bo->base.base, data); 370 + } 371 + 372 + buffer_chunk = (void *)(buffer_chunk + 1) + buffer_chunk->size; 373 + dt->num_chunks++; 374 + } 375 + 376 + list_add(&et->list, &dev->error_task_list); 377 + dev->dump.size += et->size; 378 + dev->dump.num_tasks++; 379 + 380 + dev_info(dev->dev, "save error task state success\n"); 381 + 382 + out: 383 + mutex_unlock(&dev->error_task_list_lock); 384 + } 385 + 260 386 static void lima_sched_timedout_job(struct drm_sched_job *job) 261 387 { 262 388 struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); ··· 395 267 drm_sched_stop(&pipe->base, &task->base); 396 268 397 269 drm_sched_increase_karma(&task->base); 270 + 271 + lima_sched_build_error_task_list(task); 398 272 399 273 pipe->task_error(pipe); 400 274
+7
drivers/gpu/drm/lima/lima_sched.h
··· 5 5 #define __LIMA_SCHED_H__ 6 6 7 7 #include <drm/gpu_scheduler.h> 8 + #include <linux/list.h> 8 9 9 10 struct lima_vm; 11 + 12 + struct lima_sched_error_task { 13 + struct list_head list; 14 + void *data; 15 + u32 size; 16 + }; 10 17 11 18 struct lima_sched_task { 12 19 struct drm_sched_job base;