diff mbox

drm/msm: return -EBUSY if bo still active

Message ID 1378936009-31287-1-git-send-email-robdclark@gmail.com (mailing list archive)
State Accepted
Headers show

Commit Message

Rob Clark Sept. 11, 2013, 9:46 p.m. UTC
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 | 50 ++++++++++++++++++++++++++++---------------
 drivers/gpu/drm/msm/msm_drv.h |  6 ++++++
 drivers/gpu/drm/msm/msm_gem.c |  6 +++++-
 3 files changed, 44 insertions(+), 18 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 864c977..008d772 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -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;
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 1ea9d46..df8f1d0 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -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;
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 5999b67..583286f 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -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);
 	}