]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
drm: Fix syncobj handing of schedule() returning 0
authorChris Wilson <chris@chris-wilson.co.uk>
Thu, 20 Sep 2018 20:05:30 +0000 (21:05 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Fri, 21 Sep 2018 09:31:12 +0000 (10:31 +0100)
After schedule() returns 0, we must do one last check of COND to
determine the reason for the wakeup with 0 jiffies remaining before
reporting the timeout -- otherwise we may lose the signal due to
scheduler delays.

References: https://bugs.freedesktop.org/show_bug.cgi?id=106690
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180920200530.2836-2-chris@chris-wilson.co.uk
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/drm_syncobj.c

index e254f97fed7d3d87305a5a127d1dee6002a31a2f..5bcb3ef9b2566ec8fb44d0deacdb55ddbf15dbbc 100644 (file)
@@ -672,7 +672,6 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
 {
        struct syncobj_wait_entry *entries;
        struct dma_fence *fence;
-       signed long ret;
        uint32_t signaled_count, i;
 
        entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
@@ -692,7 +691,7 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
                        if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
                                continue;
                        } else {
-                               ret = -EINVAL;
+                               timeout = -EINVAL;
                                goto cleanup_entries;
                        }
                }
@@ -704,12 +703,6 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
                }
        }
 
-       /* Initialize ret to the max of timeout and 1.  That way, the
-        * default return value indicates a successful wait and not a
-        * timeout.
-        */
-       ret = max_t(signed long, timeout, 1);
-
        if (signaled_count == count ||
            (signaled_count > 0 &&
             !(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL)))
@@ -760,18 +753,17 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
                        goto done_waiting;
 
                if (timeout == 0) {
-                       /* If we are doing a 0 timeout wait and we got
-                        * here, then we just timed out.
-                        */
-                       ret = 0;
+                       timeout = -ETIME;
                        goto done_waiting;
                }
 
-               ret = schedule_timeout(ret);
+               if (signal_pending(current)) {
+                       timeout = -ERESTARTSYS;
+                       goto done_waiting;
+               }
 
-               if (ret > 0 && signal_pending(current))
-                       ret = -ERESTARTSYS;
-       } while (ret > 0);
+               timeout = schedule_timeout(timeout);
+       } while (1);
 
 done_waiting:
        __set_current_state(TASK_RUNNING);
@@ -788,7 +780,7 @@ cleanup_entries:
        }
        kfree(entries);
 
-       return ret;
+       return timeout;
 }
 
 /**
@@ -829,19 +821,16 @@ static int drm_syncobj_array_wait(struct drm_device *dev,
                                  struct drm_syncobj **syncobjs)
 {
        signed long timeout = drm_timeout_abs_to_jiffies(wait->timeout_nsec);
-       signed long ret = 0;
        uint32_t first = ~0;
 
-       ret = drm_syncobj_array_wait_timeout(syncobjs,
-                                            wait->count_handles,
-                                            wait->flags,
-                                            timeout, &first);
-       if (ret < 0)
-               return ret;
+       timeout = drm_syncobj_array_wait_timeout(syncobjs,
+                                                wait->count_handles,
+                                                wait->flags,
+                                                timeout, &first);
+       if (timeout < 0)
+               return timeout;
 
        wait->first_signaled = first;
-       if (ret == 0)
-               return -ETIME;
        return 0;
 }