[PATCH RFC 011/111] staging: etnaviv: fix fence implementation
Lucas Stach
l.stach at pengutronix.de
Thu Apr 2 08:29:13 PDT 2015
From: Russell King <rmk+kernel at 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
More information about the dri-devel
mailing list