From: Russell King <rmk+ker...@arm.linux.org.uk>

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 at arm.linux.org.uk>
---
 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

Reply via email to