From: Russell King <rmk+kernel@xxxxxxxxxxxxxxxx> If we queue up a large command buffer (32K) containing about 164 1080p blit operations, it can take the GPU several seconds to complete before raising the next event. Our existing hangcheck code decides after a second that the GPU is stuck, and provokes a retirement of the events. This can lead to errors as the GPU isn't stuck - we could end up overwriting the buffers which the GPU is currently executing. Resolve this by also checking the current DMA address register, and monitoring it for progress. We have to be careful here, because if we get stuck in a WAIT LINK, the DMA address will change by 16 bytes (inclusive) while the GPU spins in the loop - even though we may not have received the last event from the GPU (eg, because the PE is busy.) Signed-off-by: Russell King <rmk+kernel@xxxxxxxxxxxxxxxx> --- drivers/staging/etnaviv/etnaviv_gpu.c | 19 +++++++++++++++---- drivers/staging/etnaviv/etnaviv_gpu.h | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c index 24ed14804ebd..cd308976dec9 100644 --- a/drivers/staging/etnaviv/etnaviv_gpu.c +++ b/drivers/staging/etnaviv/etnaviv_gpu.c @@ -689,13 +689,24 @@ static void hangcheck_handler(unsigned long data) struct drm_device *dev = gpu->drm; struct etnaviv_drm_private *priv = dev->dev_private; uint32_t fence = gpu->retired_fence; + bool progress = false; if (fence != gpu->hangcheck_fence) { - /* some progress has been made.. ya! */ - gpu->hangcheck_fence = fence; - } else if (fence_after(gpu->submitted_fence, fence)) { - /* no progress and not done.. hung! */ gpu->hangcheck_fence = fence; + progress = true; + } + + if (!progress) { + uint32_t dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); + int change = dma_addr - gpu->hangcheck_dma_addr; + + if (change < 0 || change > 16) { + gpu->hangcheck_dma_addr = dma_addr; + progress = true; + } + } + + if (!progress && fence_after(gpu->submitted_fence, fence)) { dev_err(gpu->dev, "hangcheck detected gpu lockup!\n"); dev_err(gpu->dev, " completed fence: %u\n", fence); dev_err(gpu->dev, " submitted fence: %u\n", diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h b/drivers/staging/etnaviv/etnaviv_gpu.h index 885eddf9fb1c..59dc9c1a048f 100644 --- a/drivers/staging/etnaviv/etnaviv_gpu.h +++ b/drivers/staging/etnaviv/etnaviv_gpu.h @@ -123,6 +123,7 @@ struct etnaviv_gpu { #define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD) struct timer_list hangcheck_timer; uint32_t hangcheck_fence; + uint32_t hangcheck_dma_addr; struct work_struct recover_work; }; -- 2.1.4 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel