From: Russell King <rmk+kernel@xxxxxxxxxxxxxxxx> The fence implementation relied upon incrementing a 32-bit number, and using unsigned comparisons. This is a limited number space, which, when exhausted will lead to unpredictable behaviour. Turn this into a circular namespace, and use signed difference comparisons. Signed-off-by: Russell King <rmk+kernel@xxxxxxxxxxxxxxxx> --- drivers/staging/etnaviv/etnaviv_drv.c | 5 +++-- drivers/staging/etnaviv/etnaviv_drv.h | 14 +++++++++++++- drivers/staging/etnaviv/etnaviv_gpu.c | 4 ++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/staging/etnaviv/etnaviv_drv.c b/drivers/staging/etnaviv/etnaviv_drv.c index da7035ce07a2..cc860b63447f 100644 --- a/drivers/staging/etnaviv/etnaviv_drv.c +++ b/drivers/staging/etnaviv/etnaviv_drv.c @@ -303,7 +303,7 @@ int etnaviv_wait_fence_interruptable(struct drm_device *dev, uint32_t pipe, if (!gpu) return -ENXIO; - if (fence > gpu->submitted_fence) { + if (fence_after(fence, gpu->submitted_fence)) { DRM_ERROR("waiting on invalid fence: %u (of %u)\n", fence, gpu->submitted_fence); return -EINVAL; @@ -344,7 +344,8 @@ void etnaviv_update_fence(struct drm_device *dev, uint32_t fence) struct etnaviv_drm_private *priv = dev->dev_private; mutex_lock(&dev->struct_mutex); - priv->completed_fence = max(fence, priv->completed_fence); + if (fence_after(fence, priv->completed_fence)) + priv->completed_fence = fence; mutex_unlock(&dev->struct_mutex); wake_up_all(&priv->fence_event); diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h index 63994f22d8c9..bf5d1d9cc891 100644 --- a/drivers/staging/etnaviv/etnaviv_drv.h +++ b/drivers/staging/etnaviv/etnaviv_drv.h @@ -127,10 +127,22 @@ u32 etnaviv_readl(const void __iomem *addr); #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) +/* returns true if fence a comes after fence b */ +static inline bool fence_after(uint32_t a, uint32_t b) +{ + return (int32_t)(a - b) > 0; +} + +static inline bool fence_after_eq(uint32_t a, uint32_t b) +{ + return (int32_t)(a - b) >= 0; +} + static inline bool fence_completed(struct drm_device *dev, uint32_t fence) { struct etnaviv_drm_private *priv = dev->dev_private; - return priv->completed_fence >= fence; + + return fence_after_eq(priv->completed_fence, fence); } static inline int align_pitch(int width, int bpp) diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c index df5bef16ff4c..859edcccdda6 100644 --- a/drivers/staging/etnaviv/etnaviv_gpu.c +++ b/drivers/staging/etnaviv/etnaviv_gpu.c @@ -648,7 +648,7 @@ static void hangcheck_handler(unsigned long data) if (fence != gpu->hangcheck_fence) { /* some progress has been made.. ya! */ gpu->hangcheck_fence = fence; - } else if (fence < gpu->submitted_fence) { + } else if (fence_after(gpu->submitted_fence, fence)) { /* no progress and not done.. hung! */ gpu->hangcheck_fence = fence; dev_err(dev->dev, "%s: hangcheck detected gpu lockup!\n", @@ -661,7 +661,7 @@ static void hangcheck_handler(unsigned long data) } /* if still more pending work, reset the hangcheck timer: */ - if (gpu->submitted_fence > gpu->hangcheck_fence) + if (fence_after(gpu->submitted_fence, gpu->hangcheck_fence)) hangcheck_timer_reset(gpu); } -- 2.1.4 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel