Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : *
4 : : * Copyright © 2016 Intel Corporation
5 : : */
6 : :
7 : : #include <linux/dma-fence-array.h>
8 : : #include <linux/jiffies.h>
9 : :
10 : : #include "gt/intel_engine.h"
11 : :
12 : : #include "i915_gem_ioctls.h"
13 : : #include "i915_gem_object.h"
14 : :
15 : : static long
16 : 0 : i915_gem_object_wait_fence(struct dma_fence *fence,
17 : : unsigned int flags,
18 : : long timeout)
19 : : {
20 : 0 : BUILD_BUG_ON(I915_WAIT_INTERRUPTIBLE != 0x1);
21 : :
22 [ # # ]: 0 : if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
23 : : return timeout;
24 : :
25 [ # # ]: 0 : if (dma_fence_is_i915(fence))
26 : 0 : return i915_request_wait(to_request(fence), flags, timeout);
27 : :
28 : 0 : return dma_fence_wait_timeout(fence,
29 : : flags & I915_WAIT_INTERRUPTIBLE,
30 : : timeout);
31 : : }
32 : :
33 : : static long
34 : 0 : i915_gem_object_wait_reservation(struct dma_resv *resv,
35 : : unsigned int flags,
36 : : long timeout)
37 : : {
38 : 0 : struct dma_fence *excl;
39 : 0 : bool prune_fences = false;
40 : :
41 [ # # ]: 0 : if (flags & I915_WAIT_ALL) {
42 : 0 : struct dma_fence **shared;
43 : 0 : unsigned int count, i;
44 : 0 : int ret;
45 : :
46 : 0 : ret = dma_resv_get_fences_rcu(resv,
47 : : &excl, &count, &shared);
48 [ # # ]: 0 : if (ret)
49 : 0 : return ret;
50 : :
51 [ # # ]: 0 : for (i = 0; i < count; i++) {
52 : 0 : timeout = i915_gem_object_wait_fence(shared[i],
53 : : flags, timeout);
54 [ # # ]: 0 : if (timeout < 0)
55 : : break;
56 : :
57 : 0 : dma_fence_put(shared[i]);
58 : : }
59 : :
60 [ # # ]: 0 : for (; i < count; i++)
61 : 0 : dma_fence_put(shared[i]);
62 : 0 : kfree(shared);
63 : :
64 : : /*
65 : : * If both shared fences and an exclusive fence exist,
66 : : * then by construction the shared fences must be later
67 : : * than the exclusive fence. If we successfully wait for
68 : : * all the shared fences, we know that the exclusive fence
69 : : * must all be signaled. If all the shared fences are
70 : : * signaled, we can prune the array and recover the
71 : : * floating references on the fences/requests.
72 : : */
73 [ # # # # ]: 0 : prune_fences = count && timeout >= 0;
74 : : } else {
75 [ # # ]: 0 : excl = dma_resv_get_excl_rcu(resv);
76 : : }
77 : :
78 [ # # # # ]: 0 : if (excl && timeout >= 0)
79 : 0 : timeout = i915_gem_object_wait_fence(excl, flags, timeout);
80 : :
81 : 0 : dma_fence_put(excl);
82 : :
83 : : /*
84 : : * Opportunistically prune the fences iff we know they have *all* been
85 : : * signaled.
86 : : */
87 [ # # # # ]: 0 : if (prune_fences && dma_resv_trylock(resv)) {
88 [ # # ]: 0 : if (dma_resv_test_signaled_rcu(resv, true))
89 : 0 : dma_resv_add_excl_fence(resv, NULL);
90 : 0 : dma_resv_unlock(resv);
91 : : }
92 : :
93 : : return timeout;
94 : : }
95 : :
96 : 0 : static void __fence_set_priority(struct dma_fence *fence,
97 : : const struct i915_sched_attr *attr)
98 : : {
99 : 0 : struct i915_request *rq;
100 : 0 : struct intel_engine_cs *engine;
101 : :
102 [ # # # # ]: 0 : if (dma_fence_is_signaled(fence) || !dma_fence_is_i915(fence))
103 : : return;
104 : :
105 : 0 : rq = to_request(fence);
106 : 0 : engine = rq->engine;
107 : :
108 : 0 : local_bh_disable();
109 : 0 : rcu_read_lock(); /* RCU serialisation for set-wedged protection */
110 [ # # ]: 0 : if (engine->schedule)
111 : 0 : engine->schedule(rq, attr);
112 : 0 : rcu_read_unlock();
113 : 0 : local_bh_enable(); /* kick the tasklets if queues were reprioritised */
114 : : }
115 : :
116 : 0 : static void fence_set_priority(struct dma_fence *fence,
117 : : const struct i915_sched_attr *attr)
118 : : {
119 : : /* Recurse once into a fence-array */
120 [ # # ]: 0 : if (dma_fence_is_array(fence)) {
121 : : struct dma_fence_array *array = to_dma_fence_array(fence);
122 : : int i;
123 : :
124 [ # # ]: 0 : for (i = 0; i < array->num_fences; i++)
125 : 0 : __fence_set_priority(array->fences[i], attr);
126 : : } else {
127 : 0 : __fence_set_priority(fence, attr);
128 : : }
129 : 0 : }
130 : :
131 : : int
132 : 0 : i915_gem_object_wait_priority(struct drm_i915_gem_object *obj,
133 : : unsigned int flags,
134 : : const struct i915_sched_attr *attr)
135 : : {
136 : 0 : struct dma_fence *excl;
137 : :
138 [ # # ]: 0 : if (flags & I915_WAIT_ALL) {
139 : 0 : struct dma_fence **shared;
140 : 0 : unsigned int count, i;
141 : 0 : int ret;
142 : :
143 : 0 : ret = dma_resv_get_fences_rcu(obj->base.resv,
144 : : &excl, &count, &shared);
145 [ # # ]: 0 : if (ret)
146 : 0 : return ret;
147 : :
148 [ # # ]: 0 : for (i = 0; i < count; i++) {
149 : 0 : fence_set_priority(shared[i], attr);
150 : 0 : dma_fence_put(shared[i]);
151 : : }
152 : :
153 : 0 : kfree(shared);
154 : : } else {
155 [ # # ]: 0 : excl = dma_resv_get_excl_rcu(obj->base.resv);
156 : : }
157 : :
158 [ # # ]: 0 : if (excl) {
159 : 0 : fence_set_priority(excl, attr);
160 : 0 : dma_fence_put(excl);
161 : : }
162 : : return 0;
163 : : }
164 : :
165 : : /**
166 : : * Waits for rendering to the object to be completed
167 : : * @obj: i915 gem object
168 : : * @flags: how to wait (under a lock, for all rendering or just for writes etc)
169 : : * @timeout: how long to wait
170 : : */
171 : : int
172 : 0 : i915_gem_object_wait(struct drm_i915_gem_object *obj,
173 : : unsigned int flags,
174 : : long timeout)
175 : : {
176 : 0 : might_sleep();
177 : 0 : GEM_BUG_ON(timeout < 0);
178 : :
179 : 0 : timeout = i915_gem_object_wait_reservation(obj->base.resv,
180 : : flags, timeout);
181 : 0 : return timeout < 0 ? timeout : 0;
182 : : }
183 : :
184 : 0 : static inline unsigned long nsecs_to_jiffies_timeout(const u64 n)
185 : : {
186 : : /* nsecs_to_jiffies64() does not guard against overflow */
187 : 0 : if (NSEC_PER_SEC % HZ &&
188 : : div_u64(n, NSEC_PER_SEC) >= MAX_JIFFY_OFFSET / HZ)
189 : : return MAX_JIFFY_OFFSET;
190 : :
191 : 0 : return min_t(u64, MAX_JIFFY_OFFSET, nsecs_to_jiffies64(n) + 1);
192 : : }
193 : :
194 : 0 : static unsigned long to_wait_timeout(s64 timeout_ns)
195 : : {
196 : 0 : if (timeout_ns < 0)
197 : : return MAX_SCHEDULE_TIMEOUT;
198 : :
199 [ # # ]: 0 : if (timeout_ns == 0)
200 : : return 0;
201 : :
202 : 0 : return nsecs_to_jiffies_timeout(timeout_ns);
203 : : }
204 : :
205 : : /**
206 : : * i915_gem_wait_ioctl - implements DRM_IOCTL_I915_GEM_WAIT
207 : : * @dev: drm device pointer
208 : : * @data: ioctl data blob
209 : : * @file: drm file pointer
210 : : *
211 : : * Returns 0 if successful, else an error is returned with the remaining time in
212 : : * the timeout parameter.
213 : : * -ETIME: object is still busy after timeout
214 : : * -ERESTARTSYS: signal interrupted the wait
215 : : * -ENONENT: object doesn't exist
216 : : * Also possible, but rare:
217 : : * -EAGAIN: incomplete, restart syscall
218 : : * -ENOMEM: damn
219 : : * -ENODEV: Internal IRQ fail
220 : : * -E?: The add request failed
221 : : *
222 : : * The wait ioctl with a timeout of 0 reimplements the busy ioctl. With any
223 : : * non-zero timeout parameter the wait ioctl will wait for the given number of
224 : : * nanoseconds on an object becoming unbusy. Since the wait itself does so
225 : : * without holding struct_mutex the object may become re-busied before this
226 : : * function completes. A similar but shorter * race condition exists in the busy
227 : : * ioctl
228 : : */
229 : : int
230 : 0 : i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
231 : : {
232 : 0 : struct drm_i915_gem_wait *args = data;
233 : 0 : struct drm_i915_gem_object *obj;
234 : 0 : ktime_t start;
235 : 0 : long ret;
236 : :
237 [ # # ]: 0 : if (args->flags != 0)
238 : : return -EINVAL;
239 : :
240 : 0 : obj = i915_gem_object_lookup(file, args->bo_handle);
241 [ # # ]: 0 : if (!obj)
242 : : return -ENOENT;
243 : :
244 : 0 : start = ktime_get();
245 : :
246 : 0 : ret = i915_gem_object_wait(obj,
247 : : I915_WAIT_INTERRUPTIBLE |
248 : : I915_WAIT_PRIORITY |
249 : : I915_WAIT_ALL,
250 [ # # ]: 0 : to_wait_timeout(args->timeout_ns));
251 : :
252 [ # # ]: 0 : if (args->timeout_ns > 0) {
253 : 0 : args->timeout_ns -= ktime_to_ns(ktime_sub(ktime_get(), start));
254 [ # # ]: 0 : if (args->timeout_ns < 0)
255 : 0 : args->timeout_ns = 0;
256 : :
257 : : /*
258 : : * Apparently ktime isn't accurate enough and occasionally has a
259 : : * bit of mismatch in the jiffies<->nsecs<->ktime loop. So patch
260 : : * things up to make the test happy. We allow up to 1 jiffy.
261 : : *
262 : : * This is a regression from the timespec->ktime conversion.
263 : : */
264 [ # # # # ]: 0 : if (ret == -ETIME && !nsecs_to_jiffies(args->timeout_ns))
265 : 0 : args->timeout_ns = 0;
266 : :
267 : : /* Asked to wait beyond the jiffie/scheduler precision? */
268 [ # # # # ]: 0 : if (ret == -ETIME && args->timeout_ns)
269 : 0 : ret = -EAGAIN;
270 : : }
271 : :
272 : 0 : i915_gem_object_put(obj);
273 : 0 : return ret;
274 : : }
|