diff options
Diffstat (limited to 'drivers/gpu/drm/lima/lima_gp.c')
-rw-r--r-- | drivers/gpu/drm/lima/lima_gp.c | 63 |
1 files changed, 61 insertions, 2 deletions
diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c index ccf49faedebf..d8841c870d90 100644 --- a/drivers/gpu/drm/lima/lima_gp.c +++ b/drivers/gpu/drm/lima/lima_gp.c @@ -11,6 +11,8 @@ #include "lima_device.h" #include "lima_gp.h" #include "lima_regs.h" +#include "lima_gem.h" +#include "lima_vm.h" #define gp_write(reg, data) writel(data, ip->iomem + reg) #define gp_read(reg) readl(ip->iomem + reg) @@ -20,6 +22,7 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data) struct lima_ip *ip = data; struct lima_device *dev = ip->dev; struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; + struct lima_sched_task *task = pipe->current_task; u32 state = gp_read(LIMA_GP_INT_STAT); u32 status = gp_read(LIMA_GP_STATUS); bool done = false; @@ -29,8 +32,16 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data) return IRQ_NONE; if (state & LIMA_GP_IRQ_MASK_ERROR) { - dev_err(dev->dev, "gp error irq state=%x status=%x\n", - state, status); + if ((state & LIMA_GP_IRQ_MASK_ERROR) == + LIMA_GP_IRQ_PLBU_OUT_OF_MEM) { + dev_dbg(dev->dev, "gp out of heap irq status=%x\n", + status); + } else { + dev_err(dev->dev, "gp error irq state=%x status=%x\n", + state, status); + if (task) + task->recoverable = false; + } /* mask all interrupts before hard reset */ gp_write(LIMA_GP_INT_MASK, 0); @@ -43,6 +54,7 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data) bool active = status & (LIMA_GP_STATUS_VS_ACTIVE | LIMA_GP_STATUS_PLBU_ACTIVE); done = valid && !active; + pipe->error = false; } gp_write(LIMA_GP_INT_CLEAR, state); @@ -121,6 +133,22 @@ static void lima_gp_task_run(struct lima_sched_pipe *pipe, u32 cmd = 0; int i; + /* update real heap buffer size for GP */ + for (i = 0; i < task->num_bos; i++) { + struct lima_bo *bo = task->bos[i]; + + if (bo->heap_size && + lima_vm_get_va(task->vm, bo) == + f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2]) { + f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] = + f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + + bo->heap_size; + task->recoverable = true; + task->heap = bo; + break; + } + } + if (f[LIMA_GP_VSCL_START_ADDR >> 2] != f[LIMA_GP_VSCL_END_ADDR >> 2]) cmd |= LIMA_GP_CMD_START_VS; @@ -184,6 +212,36 @@ static void lima_gp_task_mmu_error(struct lima_sched_pipe *pipe) lima_sched_pipe_task_done(pipe); } +static int lima_gp_task_recover(struct lima_sched_pipe *pipe) +{ + struct lima_ip *ip = pipe->processor[0]; + struct lima_sched_task *task = pipe->current_task; + struct drm_lima_gp_frame *frame = task->frame; + u32 *f = frame->frame; + size_t fail_size = + f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] - + f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2]; + + if (fail_size == task->heap->heap_size) { + int ret; + + ret = lima_heap_alloc(task->heap, task->vm); + if (ret < 0) + return ret; + } + + gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED); + /* Resume from where we stopped, i.e. new start is old end */ + gp_write(LIMA_GP_PLBU_ALLOC_START_ADDR, + f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]); + f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] = + f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size; + gp_write(LIMA_GP_PLBU_ALLOC_END_ADDR, + f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]); + gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC); + return 0; +} + static void lima_gp_print_version(struct lima_ip *ip) { u32 version, major, minor; @@ -270,6 +328,7 @@ int lima_gp_pipe_init(struct lima_device *dev) pipe->task_fini = lima_gp_task_fini; pipe->task_error = lima_gp_task_error; pipe->task_mmu_error = lima_gp_task_mmu_error; + pipe->task_recover = lima_gp_task_recover; return 0; } |