xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/i915/gem/i915_gem_throttle.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
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