1/*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright �� 2014-2016 Intel Corporation
5 */
6
7#include <linux/jiffies.h>
8
9#include <drm/drm_file.h>
10
11#include "i915_drv.h"
12#include "i915_file_private.h"
13#include "i915_gem_context.h"
14#include "i915_gem_ioctls.h"
15#include "i915_gem_object.h"
16
17/*
18 * 20ms is a fairly arbitrary limit (greater than the average frame time)
19 * chosen to prevent the CPU getting more than a frame ahead of the GPU
20 * (when using lax throttling for the frontbuffer). We also use it to
21 * offer free GPU waitboosts for severely congested workloads.
22 */
23#define DRM_I915_THROTTLE_JIFFIES msecs_to_jiffies(20)
24
25/*
26 * Throttle our rendering by waiting until the ring has completed our requests
27 * emitted over 20 msec ago.
28 *
29 * Note that if we were to use the current jiffies each time around the loop,
30 * we wouldn't escape the function with any frames outstanding if the time to
31 * render a frame was over 20ms.
32 *
33 * This should get us reasonable parallelism between CPU and GPU but also
34 * relatively low latency when blocking on a particular request to finish.
35 */
36int
37i915_gem_throttle_ioctl(struct drm_device *dev, void *data,
38			struct drm_file *file)
39{
40	const unsigned long recent_enough = jiffies - DRM_I915_THROTTLE_JIFFIES;
41	struct drm_i915_file_private *file_priv = file->driver_priv;
42	struct drm_i915_private *i915 = to_i915(dev);
43	struct i915_gem_context *ctx;
44	unsigned long idx;
45	long ret;
46
47	/* ABI: return -EIO if already wedged */
48	ret = intel_gt_terminally_wedged(to_gt(i915));
49	if (ret)
50		return ret;
51
52	rcu_read_lock();
53	xa_for_each(&file_priv->context_xa, idx, ctx) {
54		struct i915_gem_engines_iter it;
55		struct intel_context *ce;
56
57		if (!kref_get_unless_zero(&ctx->ref))
58			continue;
59		rcu_read_unlock();
60
61		for_each_gem_engine(ce,
62				    i915_gem_context_lock_engines(ctx),
63				    it) {
64			struct i915_request *rq, *target = NULL;
65
66			if (!ce->timeline)
67				continue;
68
69			mutex_lock(&ce->timeline->mutex);
70			list_for_each_entry_reverse(rq,
71						    &ce->timeline->requests,
72						    link) {
73				if (i915_request_completed(rq))
74					break;
75
76				if (time_after(rq->emitted_jiffies,
77					       recent_enough))
78					continue;
79
80				target = i915_request_get(rq);
81				break;
82			}
83			mutex_unlock(&ce->timeline->mutex);
84			if (!target)
85				continue;
86
87			ret = i915_request_wait(target,
88						I915_WAIT_INTERRUPTIBLE,
89						MAX_SCHEDULE_TIMEOUT);
90			i915_request_put(target);
91			if (ret < 0)
92				break;
93		}
94		i915_gem_context_unlock_engines(ctx);
95		i915_gem_context_put(ctx);
96
97		rcu_read_lock();
98	}
99	rcu_read_unlock();
100
101	return ret < 0 ? ret : 0;
102}
103