drm/msm: return -EBUSY if bo still active
authorRob Clark <robdclark@gmail.com>
Wed, 11 Sep 2013 21:34:07 +0000 (17:34 -0400)
committerRob Clark <robdclark@gmail.com>
Wed, 11 Sep 2013 21:36:28 +0000 (17:36 -0400)
When we CPU_PREP a bo with NOSYNC flag (for example, to implement
PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE), an -EBUSY return indicates to
userspace that the bo is still busy.  Previously it was incorrectly
returning 0 in this case.

And while we're in there throw in an bit of extra sanity checking in
case userspace tries to wait for a bogus fence.

Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_gem.c

index 864c9773636baf6aa7173c6b16a5f81841a2b922..008d772384c7375859aeb51455f9993156ce9c05 100644 (file)
@@ -499,25 +499,41 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
                struct timespec *timeout)
 {
        struct msm_drm_private *priv = dev->dev_private;
-       unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
-       unsigned long start_jiffies = jiffies;
-       unsigned long remaining_jiffies;
        int ret;
 
-       if (time_after(start_jiffies, timeout_jiffies))
-               remaining_jiffies = 0;
-       else
-               remaining_jiffies = timeout_jiffies - start_jiffies;
-
-       ret = wait_event_interruptible_timeout(priv->fence_event,
-                       priv->completed_fence >= fence,
-                       remaining_jiffies);
-       if (ret == 0) {
-               DBG("timeout waiting for fence: %u (completed: %u)",
-                               fence, priv->completed_fence);
-               ret = -ETIMEDOUT;
-       } else if (ret != -ERESTARTSYS) {
-               ret = 0;
+       if (!priv->gpu)
+               return 0;
+
+       if (fence > priv->gpu->submitted_fence) {
+               DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
+                               fence, priv->gpu->submitted_fence);
+               return -EINVAL;
+       }
+
+       if (!timeout) {
+               /* no-wait: */
+               ret = fence_completed(dev, fence) ? 0 : -EBUSY;
+       } else {
+               unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
+               unsigned long start_jiffies = jiffies;
+               unsigned long remaining_jiffies;
+
+               if (time_after(start_jiffies, timeout_jiffies))
+                       remaining_jiffies = 0;
+               else
+                       remaining_jiffies = timeout_jiffies - start_jiffies;
+
+               ret = wait_event_interruptible_timeout(priv->fence_event,
+                               fence_completed(dev, fence),
+                               remaining_jiffies);
+
+               if (ret == 0) {
+                       DBG("timeout waiting for fence: %u (completed: %u)",
+                                       fence, priv->completed_fence);
+                       ret = -ETIMEDOUT;
+               } else if (ret != -ERESTARTSYS) {
+                       ret = 0;
+               }
        }
 
        return ret;
index 1ea9d46e01bc5fea8cc92ba6e8a337fd2c2db6cc..df8f1d084bc1d76d1ee8dc5db948e7ebf9f87771 100644 (file)
@@ -191,6 +191,12 @@ u32 msm_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__)
 
+static inline bool fence_completed(struct drm_device *dev, uint32_t fence)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       return priv->completed_fence >= fence;
+}
+
 static inline int align_pitch(int width, int bpp)
 {
        int bytespp = (bpp + 7) / 8;
index 5999b67ec8f19cf39a16a3e4d1b8b5347cab49b7..583286f392998137b3442cc15b67e73ff81d34db 100644 (file)
@@ -437,12 +437,16 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
        int ret = 0;
 
-       if (is_active(msm_obj) && !(op & MSM_PREP_NOSYNC)) {
+       if (is_active(msm_obj)) {
                uint32_t fence = 0;
+
                if (op & MSM_PREP_READ)
                        fence = msm_obj->write_fence;
                if (op & MSM_PREP_WRITE)
                        fence = max(fence, msm_obj->read_fence);
+               if (op & MSM_PREP_NOSYNC)
+                       timeout = NULL;
+
                ret = msm_wait_fence_interruptable(dev, fence, timeout);
        }