/* Attempt to reap some mmap space from dead objects */
        do {
-               err = i915_gem_wait_for_idle(dev_priv, I915_WAIT_INTERRUPTIBLE);
+               err = i915_gem_wait_for_idle(dev_priv,
+                                            I915_WAIT_INTERRUPTIBLE,
+                                            MAX_SCHEDULE_TIMEOUT);
                if (err)
                        break;
 
        return ret;
 }
 
-static int wait_for_timeline(struct i915_timeline *tl, unsigned int flags)
+static long wait_for_timeline(struct i915_timeline *tl,
+                             unsigned int flags, long timeout)
 {
        struct i915_request *rq;
-       long ret;
 
        rq = i915_gem_active_get_unlocked(&tl->last_request);
        if (!rq)
-               return 0;
+               return timeout;
 
        /*
         * "Race-to-idle".
        if (flags & I915_WAIT_FOR_IDLE_BOOST)
                gen6_rps_boost(rq, NULL);
 
-       ret = i915_request_wait(rq, flags, MAX_SCHEDULE_TIMEOUT);
+       timeout = i915_request_wait(rq, flags, timeout);
        i915_request_put(rq);
 
-       return ret < 0 ? ret : 0;
+       return timeout;
 }
 
 static int wait_for_engines(struct drm_i915_private *i915)
        return 0;
 }
 
-int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
+int i915_gem_wait_for_idle(struct drm_i915_private *i915,
+                          unsigned int flags, long timeout)
 {
-       GEM_TRACE("flags=%x (%s)\n",
-                 flags, flags & I915_WAIT_LOCKED ? "locked" : "unlocked");
+       GEM_TRACE("flags=%x (%s), timeout=%ld%s\n",
+                 flags, flags & I915_WAIT_LOCKED ? "locked" : "unlocked",
+                 timeout, timeout == MAX_SCHEDULE_TIMEOUT ? " (forever)" : "");
 
        /* If the device is asleep, we have no requests outstanding */
        if (!READ_ONCE(i915->gt.awake))
                lockdep_assert_held(&i915->drm.struct_mutex);
 
                list_for_each_entry(tl, &i915->gt.timelines, link) {
-                       err = wait_for_timeline(tl, flags);
-                       if (err)
-                               return err;
+                       timeout = wait_for_timeline(tl, flags, timeout);
+                       if (timeout < 0)
+                               return timeout;
                }
 
                err = wait_for_engines(i915);
        } else {
                struct intel_engine_cs *engine;
                enum intel_engine_id id;
-               int err;
 
                for_each_engine(engine, i915, id) {
-                       err = wait_for_timeline(&engine->timeline, flags);
-                       if (err)
-                               return err;
+                       struct i915_timeline *tl = &engine->timeline;
+
+                       timeout = wait_for_timeline(tl, flags, timeout);
+                       if (timeout < 0)
+                               return timeout;
                }
        }
 
                ret = i915_gem_wait_for_idle(dev_priv,
                                             I915_WAIT_INTERRUPTIBLE |
                                             I915_WAIT_LOCKED |
-                                            I915_WAIT_FOR_IDLE_BOOST);
+                                            I915_WAIT_FOR_IDLE_BOOST,
+                                            MAX_SCHEDULE_TIMEOUT);
                if (ret && ret != -EIO)
                        goto err_unlock;
 
        if (err)
                goto err_active;
 
-       err = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED);
+       err = i915_gem_wait_for_idle(i915,
+                                    I915_WAIT_LOCKED,
+                                    MAX_SCHEDULE_TIMEOUT);
        if (err)
                goto err_active;
 
        if (WARN_ON(i915_gem_switch_to_kernel_context(i915)))
                goto out_ctx;
 
-       if (WARN_ON(i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED)))
+       if (WARN_ON(i915_gem_wait_for_idle(i915,
+                                          I915_WAIT_LOCKED,
+                                          MAX_SCHEDULE_TIMEOUT)))
                goto out_ctx;
 
        i915_gem_contexts_lost(i915);
 
         * we will free as much as we can and hope to get a second chance.
         */
        if (flags & I915_SHRINK_ACTIVE)
-               i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED);
+               i915_gem_wait_for_idle(i915,
+                                      I915_WAIT_LOCKED,
+                                      MAX_SCHEDULE_TIMEOUT);
 
        trace_i915_gem_shrink(i915, target, flags);
        i915_retire_requests(i915);
        unsigned long timeout = jiffies + msecs_to_jiffies_timeout(timeout_ms);
 
        do {
-               if (i915_gem_wait_for_idle(i915, 0) == 0 &&
+               if (i915_gem_wait_for_idle(i915,
+                                          0, MAX_SCHEDULE_TIMEOUT) == 0 &&
                    shrinker_lock(i915, unlock))
                        break;
 
                return NOTIFY_DONE;
 
        /* Force everything onto the inactive lists */
-       ret = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED);
+       ret = i915_gem_wait_for_idle(i915,
+                                    I915_WAIT_LOCKED,
+                                    MAX_SCHEDULE_TIMEOUT);
        if (ret)
                goto out;