1 /* $NetBSD: i915_gem_throttle.c,v 1.2 2021/12/18 23:45:30 riastradh Exp $ */
2
3 /*
4 * SPDX-License-Identifier: MIT
5 *
6 * Copyright © 2014-2016 Intel Corporation
7 */
8
9 #include <sys/cdefs.h>
10 __KERNEL_RCSID(0, "$NetBSD: i915_gem_throttle.c,v 1.2 2021/12/18 23:45:30 riastradh Exp $");
11
12 #include <linux/jiffies.h>
13
14 #include <drm/drm_file.h>
15
16 #include "i915_drv.h"
17 #include "i915_gem_ioctls.h"
18 #include "i915_gem_object.h"
19
20 /*
21 * 20ms is a fairly arbitrary limit (greater than the average frame time)
22 * chosen to prevent the CPU getting more than a frame ahead of the GPU
23 * (when using lax throttling for the frontbuffer). We also use it to
24 * offer free GPU waitboosts for severely congested workloads.
25 */
26 #define DRM_I915_THROTTLE_JIFFIES msecs_to_jiffies(20)
27
28 /*
29 * Throttle our rendering by waiting until the ring has completed our requests
30 * emitted over 20 msec ago.
31 *
32 * Note that if we were to use the current jiffies each time around the loop,
33 * we wouldn't escape the function with any frames outstanding if the time to
34 * render a frame was over 20ms.
35 *
36 * This should get us reasonable parallelism between CPU and GPU but also
37 * relatively low latency when blocking on a particular request to finish.
38 */
39 int
i915_gem_throttle_ioctl(struct drm_device * dev,void * data,struct drm_file * file)40 i915_gem_throttle_ioctl(struct drm_device *dev, void *data,
41 struct drm_file *file)
42 {
43 struct drm_i915_file_private *file_priv = file->driver_priv;
44 unsigned long recent_enough = jiffies - DRM_I915_THROTTLE_JIFFIES;
45 struct i915_request *request, *target = NULL;
46 long ret;
47
48 /* ABI: return -EIO if already wedged */
49 ret = intel_gt_terminally_wedged(&to_i915(dev)->gt);
50 if (ret)
51 return ret;
52
53 spin_lock(&file_priv->mm.lock);
54 list_for_each_entry(request, &file_priv->mm.request_list, client_link) {
55 if (time_after_eq(request->emitted_jiffies, recent_enough))
56 break;
57
58 if (target && xchg(&target->file_priv, NULL))
59 list_del(&target->client_link);
60
61 target = request;
62 }
63 if (target)
64 i915_request_get(target);
65 spin_unlock(&file_priv->mm.lock);
66
67 if (!target)
68 return 0;
69
70 ret = i915_request_wait(target,
71 I915_WAIT_INTERRUPTIBLE,
72 MAX_SCHEDULE_TIMEOUT);
73 i915_request_put(target);
74
75 return ret < 0 ? ret : 0;
76 }
77