Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * SPDX-License-Identifier: MIT
0003  *
0004  * Copyright © 2014-2016 Intel Corporation
0005  */
0006 
0007 #include <linux/jiffies.h>
0008 
0009 #include <drm/drm_file.h>
0010 
0011 #include "i915_drv.h"
0012 #include "i915_file_private.h"
0013 #include "i915_gem_context.h"
0014 #include "i915_gem_ioctls.h"
0015 #include "i915_gem_object.h"
0016 
0017 /*
0018  * 20ms is a fairly arbitrary limit (greater than the average frame time)
0019  * chosen to prevent the CPU getting more than a frame ahead of the GPU
0020  * (when using lax throttling for the frontbuffer). We also use it to
0021  * offer free GPU waitboosts for severely congested workloads.
0022  */
0023 #define DRM_I915_THROTTLE_JIFFIES msecs_to_jiffies(20)
0024 
0025 /*
0026  * Throttle our rendering by waiting until the ring has completed our requests
0027  * emitted over 20 msec ago.
0028  *
0029  * Note that if we were to use the current jiffies each time around the loop,
0030  * we wouldn't escape the function with any frames outstanding if the time to
0031  * render a frame was over 20ms.
0032  *
0033  * This should get us reasonable parallelism between CPU and GPU but also
0034  * relatively low latency when blocking on a particular request to finish.
0035  */
0036 int
0037 i915_gem_throttle_ioctl(struct drm_device *dev, void *data,
0038             struct drm_file *file)
0039 {
0040     const unsigned long recent_enough = jiffies - DRM_I915_THROTTLE_JIFFIES;
0041     struct drm_i915_file_private *file_priv = file->driver_priv;
0042     struct drm_i915_private *i915 = to_i915(dev);
0043     struct i915_gem_context *ctx;
0044     unsigned long idx;
0045     long ret;
0046 
0047     /* ABI: return -EIO if already wedged */
0048     ret = intel_gt_terminally_wedged(to_gt(i915));
0049     if (ret)
0050         return ret;
0051 
0052     rcu_read_lock();
0053     xa_for_each(&file_priv->context_xa, idx, ctx) {
0054         struct i915_gem_engines_iter it;
0055         struct intel_context *ce;
0056 
0057         if (!kref_get_unless_zero(&ctx->ref))
0058             continue;
0059         rcu_read_unlock();
0060 
0061         for_each_gem_engine(ce,
0062                     i915_gem_context_lock_engines(ctx),
0063                     it) {
0064             struct i915_request *rq, *target = NULL;
0065 
0066             if (!ce->timeline)
0067                 continue;
0068 
0069             mutex_lock(&ce->timeline->mutex);
0070             list_for_each_entry_reverse(rq,
0071                             &ce->timeline->requests,
0072                             link) {
0073                 if (i915_request_completed(rq))
0074                     break;
0075 
0076                 if (time_after(rq->emitted_jiffies,
0077                            recent_enough))
0078                     continue;
0079 
0080                 target = i915_request_get(rq);
0081                 break;
0082             }
0083             mutex_unlock(&ce->timeline->mutex);
0084             if (!target)
0085                 continue;
0086 
0087             ret = i915_request_wait(target,
0088                         I915_WAIT_INTERRUPTIBLE,
0089                         MAX_SCHEDULE_TIMEOUT);
0090             i915_request_put(target);
0091             if (ret < 0)
0092                 break;
0093         }
0094         i915_gem_context_unlock_engines(ctx);
0095         i915_gem_context_put(ctx);
0096 
0097         rcu_read_lock();
0098     }
0099     rcu_read_unlock();
0100 
0101     return ret < 0 ? ret : 0;
0102 }