summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2015-01-18 09:19:31 +1300
committerEric Anholt <eric@anholt.net>2015-06-04 14:15:31 -0700
commitcf24e99f0ac4918658db934ff0ab027bc41b646b (patch)
treeef8c495016bfa67edd65d8dcc75dc40eb007ba3a
parent19d37d01bc3ff4545149cfce00992fc58b28377e (diff)
downloadlinux-cf24e99f0ac4918658db934ff0ab027bc41b646b.tar.gz
drm/vc4: Make sure that waits that get interrupted don't wait forever.
danvet's talk recommended avoiding relative waits entirely, but his example was of relative waits with units (vblank numbers) that were potentially longer than the interval between signals coming in, so you couldn't adjust the ioctl arguments appropriately. This change also has a wait unit that might be too large (jiffies), but given that the other argument (an emitted seqno) is guaranteed to eventually result in a nonblocking successful return, this isn't really a big deal. Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c22
1 files changed, 20 insertions, 2 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 9343f36272c0..34036c3f0f50 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -505,13 +505,31 @@ vc4_job_done_work(struct work_struct *work)
mutex_unlock(&dev->struct_mutex);
}
+static int
+vc4_wait_for_seqno_ioctl_helper(struct drm_device *dev,
+ uint64_t seqno,
+ uint64_t *timeout_ns)
+{
+ unsigned long start = jiffies;
+ int ret = vc4_wait_for_seqno(dev, seqno, *timeout_ns);
+
+ if (ret == -EINTR || ret == -ERESTARTSYS) {
+ uint64_t delta = jiffies_to_nsecs(jiffies - start);
+ if (*timeout_ns >= delta)
+ *timeout_ns -= delta;
+ }
+
+ return ret;
+}
+
int
vc4_wait_seqno_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_vc4_wait_seqno *args = data;
- return vc4_wait_for_seqno(dev, args->seqno, args->timeout_ns);
+ return vc4_wait_for_seqno_ioctl_helper(dev, args->seqno,
+ &args->timeout_ns);
}
int
@@ -530,7 +548,7 @@ vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
}
bo = to_vc4_bo(gem_obj);
- ret = vc4_wait_for_seqno(dev, bo->seqno, args->timeout_ns);
+ ret = vc4_wait_for_seqno_ioctl_helper(dev, bo->seqno, &args->timeout_ns);
drm_gem_object_unreference(gem_obj);
return ret;