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
This commit is contained in:
parent
c67a3d4f68
commit
b78edd46f6
@ -344,6 +344,12 @@ int lima_device_init(struct lima_device *ldev)
|
|||||||
if (err)
|
if (err)
|
||||||
goto err_out5;
|
goto err_out5;
|
||||||
|
|
||||||
|
ldev->dump.magic = LIMA_DUMP_MAGIC;
|
||||||
|
ldev->dump.version_major = LIMA_DUMP_MAJOR;
|
||||||
|
ldev->dump.version_minor = LIMA_DUMP_MINOR;
|
||||||
|
INIT_LIST_HEAD(&ldev->error_task_list);
|
||||||
|
mutex_init(&ldev->error_task_list_lock);
|
||||||
|
|
||||||
dev_info(ldev->dev, "bus rate = %lu\n", clk_get_rate(ldev->clk_bus));
|
dev_info(ldev->dev, "bus rate = %lu\n", clk_get_rate(ldev->clk_bus));
|
||||||
dev_info(ldev->dev, "mod rate = %lu", clk_get_rate(ldev->clk_gpu));
|
dev_info(ldev->dev, "mod rate = %lu", clk_get_rate(ldev->clk_gpu));
|
||||||
|
|
||||||
@ -370,6 +376,13 @@ err_out0:
|
|||||||
void lima_device_fini(struct lima_device *ldev)
|
void lima_device_fini(struct lima_device *ldev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
struct lima_sched_error_task *et, *tmp;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(et, tmp, &ldev->error_task_list, list) {
|
||||||
|
list_del(&et->list);
|
||||||
|
kvfree(et);
|
||||||
|
}
|
||||||
|
mutex_destroy(&ldev->error_task_list_lock);
|
||||||
|
|
||||||
lima_fini_pp_pipe(ldev);
|
lima_fini_pp_pipe(ldev);
|
||||||
lima_fini_gp_pipe(ldev);
|
lima_fini_gp_pipe(ldev);
|
||||||
|
@ -6,8 +6,11 @@
|
|||||||
|
|
||||||
#include <drm/drm_device.h>
|
#include <drm/drm_device.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
|
||||||
#include "lima_sched.h"
|
#include "lima_sched.h"
|
||||||
|
#include "lima_dump.h"
|
||||||
|
|
||||||
enum lima_gpu_id {
|
enum lima_gpu_id {
|
||||||
lima_gpu_mali400 = 0,
|
lima_gpu_mali400 = 0,
|
||||||
@ -94,6 +97,11 @@ struct lima_device {
|
|||||||
|
|
||||||
u32 *dlbu_cpu;
|
u32 *dlbu_cpu;
|
||||||
dma_addr_t dlbu_dma;
|
dma_addr_t dlbu_dma;
|
||||||
|
|
||||||
|
/* debug info */
|
||||||
|
struct lima_dump_head dump;
|
||||||
|
struct list_head error_task_list;
|
||||||
|
struct mutex error_task_list_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct lima_device *
|
static inline struct lima_device *
|
||||||
|
77
drivers/gpu/drm/lima/lima_dump.h
Normal file
77
drivers/gpu/drm/lima/lima_dump.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
|
||||||
|
/* Copyright 2020 Qiang Yu <yuq825@gmail.com> */
|
||||||
|
|
||||||
|
#ifndef __LIMA_DUMP_H__
|
||||||
|
#define __LIMA_DUMP_H__
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dump file format for all the information to start a lima task
|
||||||
|
*
|
||||||
|
* top level format
|
||||||
|
* | magic code "LIMA" | format version | num tasks | data size |
|
||||||
|
* | reserved | reserved | reserved | reserved |
|
||||||
|
* | task 1 ID | task 1 size | num chunks | reserved | task 1 data |
|
||||||
|
* | task 2 ID | task 2 size | num chunks | reserved | task 2 data |
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* task data format
|
||||||
|
* | chunk 1 ID | chunk 1 size | reserved | reserved | chunk 1 data |
|
||||||
|
* | chunk 2 ID | chunk 2 size | reserved | reserved | chunk 2 data |
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LIMA_DUMP_MAJOR 1
|
||||||
|
#define LIMA_DUMP_MINOR 0
|
||||||
|
|
||||||
|
#define LIMA_DUMP_MAGIC 0x414d494c
|
||||||
|
|
||||||
|
struct lima_dump_head {
|
||||||
|
__u32 magic;
|
||||||
|
__u16 version_major;
|
||||||
|
__u16 version_minor;
|
||||||
|
__u32 num_tasks;
|
||||||
|
__u32 size;
|
||||||
|
__u32 reserved[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LIMA_DUMP_TASK_GP 0
|
||||||
|
#define LIMA_DUMP_TASK_PP 1
|
||||||
|
#define LIMA_DUMP_TASK_NUM 2
|
||||||
|
|
||||||
|
struct lima_dump_task {
|
||||||
|
__u32 id;
|
||||||
|
__u32 size;
|
||||||
|
__u32 num_chunks;
|
||||||
|
__u32 reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LIMA_DUMP_CHUNK_FRAME 0
|
||||||
|
#define LIMA_DUMP_CHUNK_BUFFER 1
|
||||||
|
#define LIMA_DUMP_CHUNK_PROCESS_NAME 2
|
||||||
|
#define LIMA_DUMP_CHUNK_PROCESS_ID 3
|
||||||
|
#define LIMA_DUMP_CHUNK_NUM 4
|
||||||
|
|
||||||
|
struct lima_dump_chunk {
|
||||||
|
__u32 id;
|
||||||
|
__u32 size;
|
||||||
|
__u32 reserved[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lima_dump_chunk_buffer {
|
||||||
|
__u32 id;
|
||||||
|
__u32 size;
|
||||||
|
__u32 va;
|
||||||
|
__u32 reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lima_dump_chunk_pid {
|
||||||
|
__u32 id;
|
||||||
|
__u32 size;
|
||||||
|
__u32 pid;
|
||||||
|
__u32 reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -4,6 +4,7 @@
|
|||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/xarray.h>
|
#include <linux/xarray.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
|
||||||
#include "lima_drv.h"
|
#include "lima_drv.h"
|
||||||
#include "lima_sched.h"
|
#include "lima_sched.h"
|
||||||
@ -256,6 +257,133 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job)
|
|||||||
return task->fence;
|
return task->fence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lima_sched_build_error_task_list(struct lima_sched_task *task)
|
||||||
|
{
|
||||||
|
struct lima_sched_error_task *et;
|
||||||
|
struct lima_sched_pipe *pipe = to_lima_pipe(task->base.sched);
|
||||||
|
struct lima_ip *ip = pipe->processor[0];
|
||||||
|
int pipe_id = ip->id == lima_ip_gp ? lima_pipe_gp : lima_pipe_pp;
|
||||||
|
struct lima_device *dev = ip->dev;
|
||||||
|
struct lima_sched_context *sched_ctx =
|
||||||
|
container_of(task->base.entity,
|
||||||
|
struct lima_sched_context, base);
|
||||||
|
struct lima_ctx *ctx =
|
||||||
|
container_of(sched_ctx, struct lima_ctx, context[pipe_id]);
|
||||||
|
struct lima_dump_task *dt;
|
||||||
|
struct lima_dump_chunk *chunk;
|
||||||
|
struct lima_dump_chunk_pid *pid_chunk;
|
||||||
|
struct lima_dump_chunk_buffer *buffer_chunk;
|
||||||
|
u32 size, task_size, mem_size;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
mutex_lock(&dev->error_task_list_lock);
|
||||||
|
|
||||||
|
if (dev->dump.num_tasks >= lima_max_error_tasks) {
|
||||||
|
dev_info(dev->dev, "fail to save task state: error task list is full\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* frame chunk */
|
||||||
|
size = sizeof(struct lima_dump_chunk) + pipe->frame_size;
|
||||||
|
/* process name chunk */
|
||||||
|
size += sizeof(struct lima_dump_chunk) + sizeof(ctx->pname);
|
||||||
|
/* pid chunk */
|
||||||
|
size += sizeof(struct lima_dump_chunk);
|
||||||
|
/* buffer chunks */
|
||||||
|
for (i = 0; i < task->num_bos; i++) {
|
||||||
|
struct lima_bo *bo = task->bos[i];
|
||||||
|
|
||||||
|
size += sizeof(struct lima_dump_chunk);
|
||||||
|
size += bo->heap_size ? bo->heap_size : lima_bo_size(bo);
|
||||||
|
}
|
||||||
|
|
||||||
|
task_size = size + sizeof(struct lima_dump_task);
|
||||||
|
mem_size = task_size + sizeof(*et);
|
||||||
|
et = kvmalloc(mem_size, GFP_KERNEL);
|
||||||
|
if (!et) {
|
||||||
|
dev_err(dev->dev, "fail to alloc task dump buffer of size %x\n",
|
||||||
|
mem_size);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
et->data = et + 1;
|
||||||
|
et->size = task_size;
|
||||||
|
|
||||||
|
dt = et->data;
|
||||||
|
memset(dt, 0, sizeof(*dt));
|
||||||
|
dt->id = pipe_id;
|
||||||
|
dt->size = size;
|
||||||
|
|
||||||
|
chunk = (struct lima_dump_chunk *)(dt + 1);
|
||||||
|
memset(chunk, 0, sizeof(*chunk));
|
||||||
|
chunk->id = LIMA_DUMP_CHUNK_FRAME;
|
||||||
|
chunk->size = pipe->frame_size;
|
||||||
|
memcpy(chunk + 1, task->frame, pipe->frame_size);
|
||||||
|
dt->num_chunks++;
|
||||||
|
|
||||||
|
chunk = (void *)(chunk + 1) + chunk->size;
|
||||||
|
memset(chunk, 0, sizeof(*chunk));
|
||||||
|
chunk->id = LIMA_DUMP_CHUNK_PROCESS_NAME;
|
||||||
|
chunk->size = sizeof(ctx->pname);
|
||||||
|
memcpy(chunk + 1, ctx->pname, sizeof(ctx->pname));
|
||||||
|
dt->num_chunks++;
|
||||||
|
|
||||||
|
pid_chunk = (void *)(chunk + 1) + chunk->size;
|
||||||
|
memset(pid_chunk, 0, sizeof(*pid_chunk));
|
||||||
|
pid_chunk->id = LIMA_DUMP_CHUNK_PROCESS_ID;
|
||||||
|
pid_chunk->pid = ctx->pid;
|
||||||
|
dt->num_chunks++;
|
||||||
|
|
||||||
|
buffer_chunk = (void *)(pid_chunk + 1) + pid_chunk->size;
|
||||||
|
for (i = 0; i < task->num_bos; i++) {
|
||||||
|
struct lima_bo *bo = task->bos[i];
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
memset(buffer_chunk, 0, sizeof(*buffer_chunk));
|
||||||
|
buffer_chunk->id = LIMA_DUMP_CHUNK_BUFFER;
|
||||||
|
buffer_chunk->va = lima_vm_get_va(task->vm, bo);
|
||||||
|
|
||||||
|
if (bo->heap_size) {
|
||||||
|
buffer_chunk->size = bo->heap_size;
|
||||||
|
|
||||||
|
data = vmap(bo->base.pages, bo->heap_size >> PAGE_SHIFT,
|
||||||
|
VM_MAP, pgprot_writecombine(PAGE_KERNEL));
|
||||||
|
if (!data) {
|
||||||
|
kvfree(et);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer_chunk + 1, data, buffer_chunk->size);
|
||||||
|
|
||||||
|
vunmap(data);
|
||||||
|
} else {
|
||||||
|
buffer_chunk->size = lima_bo_size(bo);
|
||||||
|
|
||||||
|
data = drm_gem_shmem_vmap(&bo->base.base);
|
||||||
|
if (IS_ERR_OR_NULL(data)) {
|
||||||
|
kvfree(et);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer_chunk + 1, data, buffer_chunk->size);
|
||||||
|
|
||||||
|
drm_gem_shmem_vunmap(&bo->base.base, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_chunk = (void *)(buffer_chunk + 1) + buffer_chunk->size;
|
||||||
|
dt->num_chunks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add(&et->list, &dev->error_task_list);
|
||||||
|
dev->dump.size += et->size;
|
||||||
|
dev->dump.num_tasks++;
|
||||||
|
|
||||||
|
dev_info(dev->dev, "save error task state success\n");
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&dev->error_task_list_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static void lima_sched_timedout_job(struct drm_sched_job *job)
|
static void lima_sched_timedout_job(struct drm_sched_job *job)
|
||||||
{
|
{
|
||||||
struct lima_sched_pipe *pipe = to_lima_pipe(job->sched);
|
struct lima_sched_pipe *pipe = to_lima_pipe(job->sched);
|
||||||
@ -268,6 +396,8 @@ static void lima_sched_timedout_job(struct drm_sched_job *job)
|
|||||||
|
|
||||||
drm_sched_increase_karma(&task->base);
|
drm_sched_increase_karma(&task->base);
|
||||||
|
|
||||||
|
lima_sched_build_error_task_list(task);
|
||||||
|
|
||||||
pipe->task_error(pipe);
|
pipe->task_error(pipe);
|
||||||
|
|
||||||
if (pipe->bcast_mmu)
|
if (pipe->bcast_mmu)
|
||||||
|
@ -5,9 +5,16 @@
|
|||||||
#define __LIMA_SCHED_H__
|
#define __LIMA_SCHED_H__
|
||||||
|
|
||||||
#include <drm/gpu_scheduler.h>
|
#include <drm/gpu_scheduler.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
|
||||||
struct lima_vm;
|
struct lima_vm;
|
||||||
|
|
||||||
|
struct lima_sched_error_task {
|
||||||
|
struct list_head list;
|
||||||
|
void *data;
|
||||||
|
u32 size;
|
||||||
|
};
|
||||||
|
|
||||||
struct lima_sched_task {
|
struct lima_sched_task {
|
||||||
struct drm_sched_job base;
|
struct drm_sched_job base;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user