From d9fd0c7d259e6e041890764f21f3033d248e0ac8 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 7 Jan 2016 12:43:15 +0100 Subject: [PATCH 01/12] drm/etnaviv: move runtime PM balance into retire worker The retire worker is kicked for each fence, either the normal way by signaling the fence from the event completion interrupt or by the recover worker if the GPU got stuck. Moving the RPM put into the retire worker allows us to have it in a single place for both cases. This also shaves off quite a bit of the CPU time spent in hardirq context, as arming the autosuspend timer when the RPM refcount drops to 0 is a relatively costly operation. Tested-by: Russell King Acked-by: Russell King Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index a33162cf4f4c..40f2a37f56e3 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -871,11 +871,6 @@ static void recover_worker(struct work_struct *work) gpu->event[i].fence = NULL; gpu->event[i].used = false; complete(&gpu->event_free); - /* - * Decrement the PM count for each stuck event. This is safe - * even in atomic context as we use ASYNC RPM here. - */ - pm_runtime_put_autosuspend(gpu->dev); } spin_unlock_irqrestore(&gpu->event_spinlock, flags); gpu->completed_fence = gpu->active_fence; @@ -1158,6 +1153,14 @@ static void retire_worker(struct work_struct *work) } etnaviv_gpu_cmdbuf_free(cmdbuf); + /* + * We need to balance the runtime PM count caused by + * each submission. Upon submission, we increment + * the runtime PM counter, and allocate one event. + * So here, we put the runtime PM count for each + * completed event. + */ + pm_runtime_put_autosuspend(gpu->dev); } gpu->retired_fence = fence; @@ -1378,15 +1381,6 @@ static irqreturn_t irq_handler(int irq, void *data) gpu->completed_fence = fence->seqno; event_free(gpu, event); - - /* - * We need to balance the runtime PM count caused by - * each submission. Upon submission, we increment - * the runtime PM counter, and allocate one event. - * So here, we put the runtime PM count for each - * completed event. - */ - pm_runtime_put_autosuspend(gpu->dev); } /* Retire the buffer objects in a work */ From 471070abd2f53e579ebeb362e78ce62d04287f49 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 25 Jan 2016 17:03:09 +0100 Subject: [PATCH 02/12] drm/etnaviv: move GPU linear window to end of DMA window If the end of the system DMA window is farther away from the start of physical RAM than the size of the GPU linear window, move the linear window so that it ends at the same address than the system DMA window. This allows to map command buffer from CMA, which is likely to reside at the end of the system DMA window, while also overlapping as much RAM as possible, in order to optimize regular buffer mappings through the linear window. Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 40f2a37f56e3..e9e66b99ab7c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1563,6 +1563,7 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct etnaviv_gpu *gpu; + u32 dma_mask; int err = 0; gpu = devm_kzalloc(dev, sizeof(*gpu), GFP_KERNEL); @@ -1573,12 +1574,16 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev) mutex_init(&gpu->lock); /* - * Set the GPU base address to the start of physical memory. This - * ensures that if we have up to 2GB, the v1 MMU can address the - * highest memory. This is important as command buffers may be - * allocated outside of this limit. + * Set the GPU linear window to be at the end of the DMA window, where + * the CMA area is likely to reside. This ensures that we are able to + * map the command buffers while having the linear window overlap as + * much RAM as possible, so we can optimize mappings for other buffers. */ - gpu->memory_base = PHYS_OFFSET; + dma_mask = (u32)dma_get_required_mask(dev); + if (dma_mask < PHYS_OFFSET + SZ_2G) + gpu->memory_base = PHYS_OFFSET; + else + gpu->memory_base = dma_mask - SZ_2G + 1; /* Map registers: */ gpu->mmio = etnaviv_ioremap(pdev, NULL, dev_name(gpu->dev)); From 584a13c6e65d9f986424594e41c6a7114d37391b Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jan 2016 15:20:04 +0000 Subject: [PATCH 03/12] drm: etnaviv: extract command ring reservation Provide a helper etnaviv_buffer_reserve() to ensure that we can fit a set of commands into the ring buffer without wrapping by moving code out of etnaviv_buffer_queue(). Signed-off-by: Russell King Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c index 332c55ebba6d..7f935e58e4b3 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c @@ -131,6 +131,19 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, ptr, len * 4, 0); } +/* + * Ensure that there is space in the command buffer to contiguously write + * 'cmd_dwords' 64-bit words into the buffer, wrapping if necessary. + */ +static u32 etnaviv_buffer_reserve(struct etnaviv_gpu *gpu, + struct etnaviv_cmdbuf *buffer, unsigned int cmd_dwords) +{ + if (buffer->user_size + cmd_dwords * sizeof(u64) > buffer->size) + buffer->user_size = 0; + + return gpu_va(gpu, buffer) + buffer->user_size; +} + u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu) { struct etnaviv_cmdbuf *buffer = gpu->buffer; @@ -183,15 +196,10 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, reserve_size = (6 + extra_size) * 4; - /* - * if we are going to completely overflow the buffer, we need to wrap. - */ - if (buffer->user_size + reserve_size > buffer->size) - buffer->user_size = 0; + link_target = etnaviv_buffer_reserve(gpu, buffer, reserve_size / 8); /* save offset back into main buffer */ back = buffer->user_size + reserve_size - 6 * 4; - link_target = gpu_va(gpu, buffer) + buffer->user_size; link_size = 6; /* Skip over any extra instructions */ @@ -207,8 +215,6 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, link_target = gpu_va(gpu, cmdbuf); link_size = cmdbuf->size / 8; - - if (drm_debug & DRM_UT_DRIVER) { print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4, cmdbuf->vaddr, cmdbuf->size, 0); From 6e138f76b676b8c6dfa744db183776b0668ec272 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jan 2016 15:20:09 +0000 Subject: [PATCH 04/12] drm: etnaviv: extract replacement of WAIT command Extract out the replacement of the WAIT command with some other command. Signed-off-by: Russell King Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 32 +++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c index 7f935e58e4b3..975c11b7fb38 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c @@ -131,6 +131,23 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, ptr, len * 4, 0); } +/* + * Safely replace the WAIT of a waitlink with a new command and argument. + * The GPU may be executing this WAIT while we're modifying it, so we have + * to write it in a specific order to avoid the GPU branching to somewhere + * else. 'wl_offset' is the offset to the first byte of the WAIT command. + */ +static void etnaviv_buffer_replace_wait(struct etnaviv_cmdbuf *buffer, + unsigned int wl_offset, u32 cmd, u32 arg) +{ + u32 *lw = buffer->vaddr + wl_offset; + + lw[1] = arg; + mb(); + lw[0] = cmd; + mb(); +} + /* * Ensure that there is space in the command buffer to contiguously write * 'cmd_dwords' 64-bit words into the buffer, wrapping if necessary. @@ -172,7 +189,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, struct etnaviv_cmdbuf *cmdbuf) { struct etnaviv_cmdbuf *buffer = gpu->buffer; - u32 *lw = buffer->vaddr + buffer->user_size - 16; + unsigned int waitlink_offset = buffer->user_size - 16; u32 back, link_target, link_size, reserve_size, extra_size = 0; if (drm_debug & DRM_UT_DRIVER) @@ -219,8 +236,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4, cmdbuf->vaddr, cmdbuf->size, 0); - pr_info("link op: %p\n", lw); - pr_info("link addr: %p\n", lw + 1); + pr_info("link op: %p\n", buffer->vaddr + waitlink_offset); pr_info("addr: 0x%08x\n", link_target); pr_info("back: 0x%08x\n", gpu_va(gpu, buffer) + back); pr_info("event: %d\n", event); @@ -262,12 +278,10 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, CMD_WAIT(buffer); CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + (buffer->user_size - 4)); - /* Change WAIT into a LINK command; write the address first. */ - *(lw + 1) = link_target; - mb(); - *(lw) = VIV_FE_LINK_HEADER_OP_LINK | - VIV_FE_LINK_HEADER_PREFETCH(link_size); - mb(); + etnaviv_buffer_replace_wait(buffer, waitlink_offset, + VIV_FE_LINK_HEADER_OP_LINK | + VIV_FE_LINK_HEADER_PREFETCH(link_size), + link_target); if (drm_debug & DRM_UT_DRIVER) etnaviv_buffer_dump(gpu, buffer, 0, 0x50); From 18060f4d87665e974950cb36133bbbf5e1b350f3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jan 2016 15:20:14 +0000 Subject: [PATCH 05/12] drm: etnaviv: extract arming of semaphore Extract out the arming of a semaphore from the pipe select code. Signed-off-by: Russell King Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c index 975c11b7fb38..cfd08ef33eab 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c @@ -85,10 +85,16 @@ static inline void CMD_STALL(struct etnaviv_cmdbuf *buffer, OUT(buffer, VIV_FE_STALL_TOKEN_FROM(from) | VIV_FE_STALL_TOKEN_TO(to)); } +static inline void CMD_SEM(struct etnaviv_cmdbuf *buffer, u32 from, u32 to) +{ + CMD_LOAD_STATE(buffer, VIVS_GL_SEMAPHORE_TOKEN, + VIVS_GL_SEMAPHORE_TOKEN_FROM(from) | + VIVS_GL_SEMAPHORE_TOKEN_TO(to)); +} + static void etnaviv_cmd_select_pipe(struct etnaviv_cmdbuf *buffer, u8 pipe) { u32 flush; - u32 stall; /* * This assumes that if we're switching to 2D, we're switching @@ -101,12 +107,8 @@ static void etnaviv_cmd_select_pipe(struct etnaviv_cmdbuf *buffer, u8 pipe) else flush = VIVS_GL_FLUSH_CACHE_PE2D; - stall = VIVS_GL_SEMAPHORE_TOKEN_FROM(SYNC_RECIPIENT_FE) | - VIVS_GL_SEMAPHORE_TOKEN_TO(SYNC_RECIPIENT_PE); - CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE, flush); - CMD_LOAD_STATE(buffer, VIVS_GL_SEMAPHORE_TOKEN, stall); - + CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); CMD_LOAD_STATE(buffer, VIVS_GL_PIPE_SELECT, From f60863116b4026713fba1810927f8639bfd6ae80 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jan 2016 15:20:19 +0000 Subject: [PATCH 06/12] drm: etnaviv: track current execution state Add tracking of the current execution state (iow, active GPU pipe). Signed-off-by: Russell King Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 1 + drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 3 +++ drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 1 + 3 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c index cfd08ef33eab..950db38c1324 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c @@ -261,6 +261,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, if (gpu->switch_context) { etnaviv_cmd_select_pipe(buffer, cmdbuf->exec_state); + gpu->exec_state = cmdbuf->exec_state; gpu->switch_context = false; } diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index e9e66b99ab7c..2adee13058df 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -628,6 +628,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) /* Now program the hardware */ mutex_lock(&gpu->lock); etnaviv_gpu_hw_init(gpu); + gpu->exec_state = -1; mutex_unlock(&gpu->lock); pm_runtime_mark_last_busy(gpu->dev); @@ -877,6 +878,7 @@ static void recover_worker(struct work_struct *work) etnaviv_gpu_hw_init(gpu); gpu->switch_context = true; + gpu->exec_state = -1; mutex_unlock(&gpu->lock); pm_runtime_mark_last_busy(gpu->dev); @@ -1475,6 +1477,7 @@ static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu) etnaviv_gpu_hw_init(gpu); gpu->switch_context = true; + gpu->exec_state = -1; mutex_unlock(&gpu->lock); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index f233ac4c7c1c..0523f73f9fec 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -103,6 +103,7 @@ struct etnaviv_gpu { /* 'ring'-buffer: */ struct etnaviv_cmdbuf *buffer; + int exec_state; /* bus base address of memory */ u32 memory_base; From 8581d8149750e19fc363ad93327f4382b26959f9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jan 2016 15:20:25 +0000 Subject: [PATCH 07/12] drm: etnaviv: flush all GPU caches when stopping GPU Flush the GPU caches to ensure that any dirty data is pushed out before stopping the front end. Signed-off-by: Russell King Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 39 +++++++++++++++++++++--- drivers/gpu/drm/etnaviv/state_3d.xml.h | 9 ++++++ 2 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/etnaviv/state_3d.xml.h diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c index 950db38c1324..6ff10d76a601 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c @@ -21,6 +21,7 @@ #include "common.xml.h" #include "state.xml.h" +#include "state_3d.xml.h" #include "cmdstream.xml.h" /* @@ -179,12 +180,42 @@ u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu) void etnaviv_buffer_end(struct etnaviv_gpu *gpu) { struct etnaviv_cmdbuf *buffer = gpu->buffer; + unsigned int waitlink_offset = buffer->user_size - 16; + u32 link_target, flush = 0; - /* Replace the last WAIT with an END */ - buffer->user_size -= 16; + if (gpu->exec_state == ETNA_PIPE_2D) + flush = VIVS_GL_FLUSH_CACHE_PE2D; + else if (gpu->exec_state == ETNA_PIPE_3D) + flush = VIVS_GL_FLUSH_CACHE_DEPTH | + VIVS_GL_FLUSH_CACHE_COLOR | + VIVS_GL_FLUSH_CACHE_TEXTURE | + VIVS_GL_FLUSH_CACHE_TEXTUREVS | + VIVS_GL_FLUSH_CACHE_SHADER_L2; - CMD_END(buffer); - mb(); + if (flush) { + unsigned int dwords = 7; + + link_target = etnaviv_buffer_reserve(gpu, buffer, dwords); + + CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); + CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); + CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE, flush); + if (gpu->exec_state == ETNA_PIPE_3D) + CMD_LOAD_STATE(buffer, VIVS_TS_FLUSH_CACHE, + VIVS_TS_FLUSH_CACHE_FLUSH); + CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); + CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); + CMD_END(buffer); + + etnaviv_buffer_replace_wait(buffer, waitlink_offset, + VIV_FE_LINK_HEADER_OP_LINK | + VIV_FE_LINK_HEADER_PREFETCH(dwords), + link_target); + } else { + /* Replace the last link-wait with an "END" command */ + etnaviv_buffer_replace_wait(buffer, waitlink_offset, + VIV_FE_END_HEADER_OP_END, 0); + } } void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, diff --git a/drivers/gpu/drm/etnaviv/state_3d.xml.h b/drivers/gpu/drm/etnaviv/state_3d.xml.h new file mode 100644 index 000000000000..d7146fd13943 --- /dev/null +++ b/drivers/gpu/drm/etnaviv/state_3d.xml.h @@ -0,0 +1,9 @@ +#ifndef STATE_3D_XML +#define STATE_3D_XML + +/* This is a cut-down version of the state_3d.xml.h file */ + +#define VIVS_TS_FLUSH_CACHE 0x00001650 +#define VIVS_TS_FLUSH_CACHE_FLUSH 0x00000001 + +#endif /* STATE_3D_XML */ From 90747b9511d14a2eb6c7dbd78ea9251e3b2b092a Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jan 2016 15:20:30 +0000 Subject: [PATCH 08/12] drm: etnaviv: use previous GPU pipe state when pipe switching Use the previous GPU pipe state when deciding which GPU caches should be flushed prior to switching the current pipe. This avoids infering what the previously selected pipe was, and potentially flushing the wrong caches. Signed-off-by: Russell King Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c index 6ff10d76a601..22b3bfa75cfa 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c @@ -93,9 +93,10 @@ static inline void CMD_SEM(struct etnaviv_cmdbuf *buffer, u32 from, u32 to) VIVS_GL_SEMAPHORE_TOKEN_TO(to)); } -static void etnaviv_cmd_select_pipe(struct etnaviv_cmdbuf *buffer, u8 pipe) +static void etnaviv_cmd_select_pipe(struct etnaviv_gpu *gpu, + struct etnaviv_cmdbuf *buffer, u8 pipe) { - u32 flush; + u32 flush = 0; /* * This assumes that if we're switching to 2D, we're switching @@ -103,10 +104,10 @@ static void etnaviv_cmd_select_pipe(struct etnaviv_cmdbuf *buffer, u8 pipe) * the 2D core, we need to flush the 3D depth and color caches, * otherwise we need to flush the 2D pixel engine cache. */ - if (pipe == ETNA_PIPE_2D) - flush = VIVS_GL_FLUSH_CACHE_DEPTH | VIVS_GL_FLUSH_CACHE_COLOR; - else + if (gpu->exec_state == ETNA_PIPE_2D) flush = VIVS_GL_FLUSH_CACHE_PE2D; + else if (gpu->exec_state == ETNA_PIPE_3D) + flush = VIVS_GL_FLUSH_CACHE_DEPTH | VIVS_GL_FLUSH_CACHE_COLOR; CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE, flush); CMD_SEM(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); @@ -291,7 +292,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, } if (gpu->switch_context) { - etnaviv_cmd_select_pipe(buffer, cmdbuf->exec_state); + etnaviv_cmd_select_pipe(gpu, buffer, cmdbuf->exec_state); gpu->exec_state = cmdbuf->exec_state; gpu->switch_context = false; } From 33b1be99fb4cfd0d7d483a9947f9c95d6d17ede9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jan 2016 15:20:35 +0000 Subject: [PATCH 09/12] drm: etnaviv: clean up GPU command submission Clean up the GPU command submission path to prepare for the next change. This makes the next change easier to read and understand. Signed-off-by: Russell King Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c index 22b3bfa75cfa..2a10463a8790 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c @@ -224,7 +224,8 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, { struct etnaviv_cmdbuf *buffer = gpu->buffer; unsigned int waitlink_offset = buffer->user_size - 16; - u32 back, link_target, link_size, reserve_size, extra_size = 0; + u32 back, reserve_size, extra_size = 0; + u32 link_target, link_dwords; if (drm_debug & DRM_UT_DRIVER) etnaviv_buffer_dump(gpu, buffer, 0, 0x50); @@ -251,7 +252,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, /* save offset back into main buffer */ back = buffer->user_size + reserve_size - 6 * 4; - link_size = 6; + link_dwords = 6; /* Skip over any extra instructions */ link_target += extra_size * sizeof(u32); @@ -261,10 +262,10 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, link_target, gpu_va(gpu, cmdbuf), cmdbuf->vaddr); /* jump back from cmd to main buffer */ - CMD_LINK(cmdbuf, link_size, link_target); + CMD_LINK(cmdbuf, link_dwords, link_target); link_target = gpu_va(gpu, cmdbuf); - link_size = cmdbuf->size / 8; + link_dwords = cmdbuf->size / 8; if (drm_debug & DRM_UT_DRIVER) { print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4, @@ -297,12 +298,12 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, gpu->switch_context = false; } - /* And the link to the first buffer */ - CMD_LINK(buffer, link_size, link_target); + /* And the link to the submitted buffer */ + CMD_LINK(buffer, link_dwords, link_target); /* Update the link target to point to above instructions */ link_target = new_target; - link_size = extra_size; + link_dwords = extra_size; } /* trigger event */ @@ -315,7 +316,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, etnaviv_buffer_replace_wait(buffer, waitlink_offset, VIV_FE_LINK_HEADER_OP_LINK | - VIV_FE_LINK_HEADER_PREFETCH(link_size), + VIV_FE_LINK_HEADER_PREFETCH(link_dwords), link_target); if (drm_debug & DRM_UT_DRIVER) From 41db12df64ace13c98865340b5c076cdf9a99a93 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jan 2016 15:20:40 +0000 Subject: [PATCH 10/12] drm: etnaviv: improve readability of command insertion to ring buffer Improve the readibility of the function which inserts command buffers and other maintanence commands into the GPUs ring buffer. We do this by splitting the ring buffer reservation in two: one chunk for any commands that need to be issued prior to the command buffer, and a separate chunk for commands issued after the buffer. The result is a much more obvious code flow in this function, and localisation of the conditional maintanence commands prior to the command buffer. Signed-off-by: Russell King Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 107 ++++++++++++----------- 1 file changed, 55 insertions(+), 52 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c index 2a10463a8790..d8d556457427 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c @@ -219,66 +219,41 @@ void etnaviv_buffer_end(struct etnaviv_gpu *gpu) } } +/* Append a command buffer to the ring buffer. */ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, struct etnaviv_cmdbuf *cmdbuf) { struct etnaviv_cmdbuf *buffer = gpu->buffer; unsigned int waitlink_offset = buffer->user_size - 16; - u32 back, reserve_size, extra_size = 0; + u32 return_target, return_dwords; u32 link_target, link_dwords; if (drm_debug & DRM_UT_DRIVER) etnaviv_buffer_dump(gpu, buffer, 0, 0x50); - /* - * If we need to flush the MMU prior to submitting this buffer, we - * will need to append a mmu flush load state, followed by a new - * link to this buffer - a total of four additional words. - */ - if (gpu->mmu->need_flush || gpu->switch_context) { - /* link command */ - extra_size += 2; - /* flush command */ - if (gpu->mmu->need_flush) - extra_size += 2; - /* pipe switch commands */ - if (gpu->switch_context) - extra_size += 8; - } - - reserve_size = (6 + extra_size) * 4; - - link_target = etnaviv_buffer_reserve(gpu, buffer, reserve_size / 8); - - /* save offset back into main buffer */ - back = buffer->user_size + reserve_size - 6 * 4; - link_dwords = 6; - - /* Skip over any extra instructions */ - link_target += extra_size * sizeof(u32); - - if (drm_debug & DRM_UT_DRIVER) - pr_info("stream link to 0x%08x @ 0x%08x %p\n", - link_target, gpu_va(gpu, cmdbuf), cmdbuf->vaddr); - - /* jump back from cmd to main buffer */ - CMD_LINK(cmdbuf, link_dwords, link_target); - link_target = gpu_va(gpu, cmdbuf); link_dwords = cmdbuf->size / 8; - if (drm_debug & DRM_UT_DRIVER) { - print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4, - cmdbuf->vaddr, cmdbuf->size, 0); - - pr_info("link op: %p\n", buffer->vaddr + waitlink_offset); - pr_info("addr: 0x%08x\n", link_target); - pr_info("back: 0x%08x\n", gpu_va(gpu, buffer) + back); - pr_info("event: %d\n", event); - } - + /* + * If we need maintanence prior to submitting this buffer, we will + * need to append a mmu flush load state, followed by a new + * link to this buffer - a total of four additional words. + */ if (gpu->mmu->need_flush || gpu->switch_context) { - u32 new_target = gpu_va(gpu, buffer) + buffer->user_size; + u32 target, extra_dwords; + + /* link command */ + extra_dwords = 1; + + /* flush command */ + if (gpu->mmu->need_flush) + extra_dwords += 1; + + /* pipe switch commands */ + if (gpu->switch_context) + extra_dwords += 4; + + target = etnaviv_buffer_reserve(gpu, buffer, extra_dwords); if (gpu->mmu->need_flush) { /* Add the MMU flush */ @@ -302,18 +277,46 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, CMD_LINK(buffer, link_dwords, link_target); /* Update the link target to point to above instructions */ - link_target = new_target; - link_dwords = extra_size; + link_target = target; + link_dwords = extra_dwords; } - /* trigger event */ + /* + * Append a LINK to the submitted command buffer to return to + * the ring buffer. return_target is the ring target address. + * We need three dwords: event, wait, link. + */ + return_dwords = 3; + return_target = etnaviv_buffer_reserve(gpu, buffer, return_dwords); + CMD_LINK(cmdbuf, return_dwords, return_target); + + /* + * Append event, wait and link pointing back to the wait + * command to the ring buffer. + */ CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) | VIVS_GL_EVENT_FROM_PE); - - /* append WAIT/LINK to main buffer */ CMD_WAIT(buffer); - CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + (buffer->user_size - 4)); + CMD_LINK(buffer, 2, return_target + 8); + if (drm_debug & DRM_UT_DRIVER) + pr_info("stream link to 0x%08x @ 0x%08x %p\n", + return_target, gpu_va(gpu, cmdbuf), cmdbuf->vaddr); + + if (drm_debug & DRM_UT_DRIVER) { + print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4, + cmdbuf->vaddr, cmdbuf->size, 0); + + pr_info("link op: %p\n", buffer->vaddr + waitlink_offset); + pr_info("addr: 0x%08x\n", link_target); + pr_info("back: 0x%08x\n", return_target); + pr_info("event: %d\n", event); + } + + /* + * Kick off the submitted command by replacing the previous + * WAIT with a link to the address in the ring buffer. + */ etnaviv_buffer_replace_wait(buffer, waitlink_offset, VIV_FE_LINK_HEADER_OP_LINK | VIV_FE_LINK_HEADER_PREFETCH(link_dwords), From b6325f409959c7e1065ef1537f2e54cf4d7ab465 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jan 2016 15:20:50 +0000 Subject: [PATCH 11/12] drm: etnaviv: clean up vram_mapping submission/retire path Currently, we scan the list of mappings each time we want to operate on the vram_mapping struct. Rather than repeatedly scanning these, look them up once in the submission path, and then use _reference and _unreference methods as necessary to manage this object. Signed-off-by: Russell King Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_drv.h | 3 -- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 54 +++++++++++--------- drivers/gpu/drm/etnaviv/etnaviv_gem.h | 6 +++ drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 18 ++++--- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 14 ++--- drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 3 +- drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 2 +- 7 files changed, 57 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h index 1cd6046e76b1..115c5bc6d7c8 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h @@ -75,9 +75,6 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma); int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset); -int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, - struct drm_gem_object *obj, u32 *iova); -void etnaviv_gem_put_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj); struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj); void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj); void etnaviv_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 4b519e4309b2..937a77520f58 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -260,8 +260,32 @@ etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj, return NULL; } -int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, - struct drm_gem_object *obj, u32 *iova) +void etnaviv_gem_mapping_reference(struct etnaviv_vram_mapping *mapping) +{ + struct etnaviv_gem_object *etnaviv_obj = mapping->object; + + drm_gem_object_reference(&etnaviv_obj->base); + + mutex_lock(&etnaviv_obj->lock); + WARN_ON(mapping->use == 0); + mapping->use += 1; + mutex_unlock(&etnaviv_obj->lock); +} + +void etnaviv_gem_mapping_unreference(struct etnaviv_vram_mapping *mapping) +{ + struct etnaviv_gem_object *etnaviv_obj = mapping->object; + + mutex_lock(&etnaviv_obj->lock); + WARN_ON(mapping->use == 0); + mapping->use -= 1; + mutex_unlock(&etnaviv_obj->lock); + + drm_gem_object_unreference_unlocked(&etnaviv_obj->base); +} + +struct etnaviv_vram_mapping *etnaviv_gem_mapping_get( + struct drm_gem_object *obj, struct etnaviv_gpu *gpu) { struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); struct etnaviv_vram_mapping *mapping; @@ -329,28 +353,12 @@ int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, out: mutex_unlock(&etnaviv_obj->lock); - if (!ret) { - /* Take a reference on the object */ - drm_gem_object_reference(obj); - *iova = mapping->iova; - } + if (ret) + return ERR_PTR(ret); - return ret; -} - -void etnaviv_gem_put_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj) -{ - struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); - struct etnaviv_vram_mapping *mapping; - - mutex_lock(&etnaviv_obj->lock); - mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu); - - WARN_ON(mapping->use == 0); - mapping->use -= 1; - mutex_unlock(&etnaviv_obj->lock); - - drm_gem_object_unreference_unlocked(obj); + /* Take a reference on the object */ + drm_gem_object_reference(obj); + return mapping; } void *etnaviv_gem_vmap(struct drm_gem_object *obj) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h index ab5df8147a5f..22f350b2e824 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h @@ -102,6 +102,7 @@ struct etnaviv_gem_submit { struct { u32 flags; struct etnaviv_gem_object *obj; + struct etnaviv_vram_mapping *mapping; u32 iova; } bos[0]; }; @@ -115,4 +116,9 @@ int etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj); struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *obj); void etnaviv_gem_put_pages(struct etnaviv_gem_object *obj); +struct etnaviv_vram_mapping *etnaviv_gem_mapping_get( + struct drm_gem_object *obj, struct etnaviv_gpu *gpu); +void etnaviv_gem_mapping_reference(struct etnaviv_vram_mapping *mapping); +void etnaviv_gem_mapping_unreference(struct etnaviv_vram_mapping *mapping); + #endif /* __ETNAVIV_GEM_H__ */ diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 1aba01a999df..a5c7f79b1d3c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -187,12 +187,11 @@ static void submit_unpin_objects(struct etnaviv_gem_submit *submit) int i; for (i = 0; i < submit->nr_bos; i++) { - struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; - if (submit->bos[i].flags & BO_PINNED) - etnaviv_gem_put_iova(submit->gpu, &etnaviv_obj->base); + etnaviv_gem_mapping_unreference(submit->bos[i].mapping); submit->bos[i].iova = 0; + submit->bos[i].mapping = NULL; submit->bos[i].flags &= ~BO_PINNED; } } @@ -203,15 +202,18 @@ static int submit_pin_objects(struct etnaviv_gem_submit *submit) for (i = 0; i < submit->nr_bos; i++) { struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; - u32 iova; + struct etnaviv_vram_mapping *mapping; - ret = etnaviv_gem_get_iova(submit->gpu, &etnaviv_obj->base, - &iova); - if (ret) + mapping = etnaviv_gem_mapping_get(&etnaviv_obj->base, + submit->gpu); + if (IS_ERR(mapping)) { + ret = PTR_ERR(mapping); break; + } submit->bos[i].flags |= BO_PINNED; - submit->bos[i].iova = iova; + submit->bos[i].mapping = mapping; + submit->bos[i].iova = mapping->iova; } return ret; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 2adee13058df..d13303ce530d 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1103,7 +1103,7 @@ struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size, size_t nr_bos) { struct etnaviv_cmdbuf *cmdbuf; - size_t sz = size_vstruct(nr_bos, sizeof(cmdbuf->bo[0]), + size_t sz = size_vstruct(nr_bos, sizeof(cmdbuf->bo_map[0]), sizeof(*cmdbuf)); cmdbuf = kzalloc(sz, GFP_KERNEL); @@ -1147,11 +1147,12 @@ static void retire_worker(struct work_struct *work) fence_put(cmdbuf->fence); for (i = 0; i < cmdbuf->nr_bos; i++) { - struct etnaviv_gem_object *etnaviv_obj = cmdbuf->bo[i]; + struct etnaviv_vram_mapping *mapping = cmdbuf->bo_map[i]; + struct etnaviv_gem_object *etnaviv_obj = mapping->object; atomic_dec(&etnaviv_obj->gpu_active); /* drop the refcount taken in etnaviv_gpu_submit */ - etnaviv_gem_put_iova(gpu, &etnaviv_obj->base); + etnaviv_gem_mapping_unreference(mapping); } etnaviv_gpu_cmdbuf_free(cmdbuf); @@ -1309,11 +1310,10 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, for (i = 0; i < submit->nr_bos; i++) { struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; - u32 iova; - /* Each cmdbuf takes a refcount on the iova */ - etnaviv_gem_get_iova(gpu, &etnaviv_obj->base, &iova); - cmdbuf->bo[i] = etnaviv_obj; + /* Each cmdbuf takes a refcount on the mapping */ + etnaviv_gem_mapping_reference(submit->bos[i].mapping); + cmdbuf->bo_map[i] = submit->bos[i].mapping; atomic_inc(&etnaviv_obj->gpu_active); if (submit->bos[i].flags & ETNA_SUBMIT_BO_WRITE) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 0523f73f9fec..f5321e2f25ff 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -23,6 +23,7 @@ #include "etnaviv_drv.h" struct etnaviv_gem_submit; +struct etnaviv_vram_mapping; struct etnaviv_chip_identity { /* Chip model. */ @@ -167,7 +168,7 @@ struct etnaviv_cmdbuf { struct list_head node; /* BOs attached to this command buffer */ unsigned int nr_bos; - struct etnaviv_gem_object *bo[0]; + struct etnaviv_vram_mapping *bo_map[0]; }; static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c index 6743bc648dc8..29a723fabc17 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c @@ -193,7 +193,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu, /* * Unmap the blocks which need to be reaped from the MMU. - * Clear the mmu pointer to prevent the get_iova finding + * Clear the mmu pointer to prevent the mapping_get finding * this mapping. */ list_for_each_entry_safe(m, n, &list, scan_node) { From 8779aa8f8b7fa397a0abe9e6af3334ea41e15836 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Jan 2016 15:20:55 +0000 Subject: [PATCH 12/12] drm: etnaviv: clean up submit_bo() As we now store the etnaviv_vram_mapping, we no longer need to store the iova itself: we can get this directly from the mapping structure. Arrange for submit_bo() to return a pointer to etnaviv_gem_submit_bo, and directly access mapping->iova when applying relocations. Signed-off-by: Russell King Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gem.h | 13 +++++++------ drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 20 +++++++------------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h index 22f350b2e824..02665d8c10ee 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h @@ -88,6 +88,12 @@ static inline bool is_active(struct etnaviv_gem_object *etnaviv_obj) #define MAX_CMDS 4 +struct etnaviv_gem_submit_bo { + u32 flags; + struct etnaviv_gem_object *obj; + struct etnaviv_vram_mapping *mapping; +}; + /* Created per submit-ioctl, to track bo's and cmdstream bufs, etc, * associated with the cmdstream submission for synchronization (and * make it easier to unwind when things go wrong, etc). This only @@ -99,12 +105,7 @@ struct etnaviv_gem_submit { struct ww_acquire_ctx ticket; u32 fence; unsigned int nr_bos; - struct { - u32 flags; - struct etnaviv_gem_object *obj; - struct etnaviv_vram_mapping *mapping; - u32 iova; - } bos[0]; + struct etnaviv_gem_submit_bo bos[0]; }; int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index a5c7f79b1d3c..236ada93df53 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -190,7 +190,6 @@ static void submit_unpin_objects(struct etnaviv_gem_submit *submit) if (submit->bos[i].flags & BO_PINNED) etnaviv_gem_mapping_unreference(submit->bos[i].mapping); - submit->bos[i].iova = 0; submit->bos[i].mapping = NULL; submit->bos[i].flags &= ~BO_PINNED; } @@ -213,14 +212,13 @@ static int submit_pin_objects(struct etnaviv_gem_submit *submit) submit->bos[i].flags |= BO_PINNED; submit->bos[i].mapping = mapping; - submit->bos[i].iova = mapping->iova; } return ret; } static int submit_bo(struct etnaviv_gem_submit *submit, u32 idx, - struct etnaviv_gem_object **obj, u32 *iova) + struct etnaviv_gem_submit_bo **bo) { if (idx >= submit->nr_bos) { DRM_ERROR("invalid buffer index: %u (out of %u)\n", @@ -228,10 +226,7 @@ static int submit_bo(struct etnaviv_gem_submit *submit, u32 idx, return -EINVAL; } - if (obj) - *obj = submit->bos[idx].obj; - if (iova) - *iova = submit->bos[idx].iova; + *bo = &submit->bos[idx]; return 0; } @@ -247,8 +242,8 @@ static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream, for (i = 0; i < nr_relocs; i++) { const struct drm_etnaviv_gem_submit_reloc *r = relocs + i; - struct etnaviv_gem_object *bobj; - u32 iova, off; + struct etnaviv_gem_submit_bo *bo; + u32 off; if (unlikely(r->flags)) { DRM_ERROR("invalid reloc flags\n"); @@ -270,17 +265,16 @@ static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream, return -EINVAL; } - ret = submit_bo(submit, r->reloc_idx, &bobj, &iova); + ret = submit_bo(submit, r->reloc_idx, &bo); if (ret) return ret; - if (r->reloc_offset >= - bobj->base.size - sizeof(*ptr)) { + if (r->reloc_offset >= bo->obj->base.size - sizeof(*ptr)) { DRM_ERROR("relocation %u outside object", i); return -EINVAL; } - ptr[off] = iova + r->reloc_offset; + ptr[off] = bo->mapping->iova + r->reloc_offset; last_offset = off; }