Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2012-2014 Canonical Ltd (Maarten Lankhorst)
3 : : *
4 : : * Based on bo.c which bears the following copyright notice,
5 : : * but is dual licensed:
6 : : *
7 : : * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
8 : : * All Rights Reserved.
9 : : *
10 : : * Permission is hereby granted, free of charge, to any person obtaining a
11 : : * copy of this software and associated documentation files (the
12 : : * "Software"), to deal in the Software without restriction, including
13 : : * without limitation the rights to use, copy, modify, merge, publish,
14 : : * distribute, sub license, and/or sell copies of the Software, and to
15 : : * permit persons to whom the Software is furnished to do so, subject to
16 : : * the following conditions:
17 : : *
18 : : * The above copyright notice and this permission notice (including the
19 : : * next paragraph) shall be included in all copies or substantial portions
20 : : * of the Software.
21 : : *
22 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : : * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
25 : : * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
26 : : * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
27 : : * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
28 : : * USE OR OTHER DEALINGS IN THE SOFTWARE.
29 : : *
30 : : **************************************************************************/
31 : : /*
32 : : * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
33 : : */
34 : :
35 : : #include <linux/dma-resv.h>
36 : : #include <linux/export.h>
37 : : #include <linux/sched/mm.h>
38 : :
39 : : /**
40 : : * DOC: Reservation Object Overview
41 : : *
42 : : * The reservation object provides a mechanism to manage shared and
43 : : * exclusive fences associated with a buffer. A reservation object
44 : : * can have attached one exclusive fence (normally associated with
45 : : * write operations) or N shared fences (read operations). The RCU
46 : : * mechanism is used to protect read access to fences from locked
47 : : * write-side updates.
48 : : */
49 : :
50 : : DEFINE_WD_CLASS(reservation_ww_class);
51 : : EXPORT_SYMBOL(reservation_ww_class);
52 : :
53 : : struct lock_class_key reservation_seqcount_class;
54 : : EXPORT_SYMBOL(reservation_seqcount_class);
55 : :
56 : : const char reservation_seqcount_string[] = "reservation_seqcount";
57 : : EXPORT_SYMBOL(reservation_seqcount_string);
58 : :
59 : : /**
60 : : * dma_resv_list_alloc - allocate fence list
61 : : * @shared_max: number of fences we need space for
62 : : *
63 : : * Allocate a new dma_resv_list and make sure to correctly initialize
64 : : * shared_max.
65 : : */
66 : 0 : static struct dma_resv_list *dma_resv_list_alloc(unsigned int shared_max)
67 : : {
68 : 0 : struct dma_resv_list *list;
69 : :
70 [ # # ]: 0 : list = kmalloc(offsetof(typeof(*list), shared[shared_max]), GFP_KERNEL);
71 [ # # ]: 0 : if (!list)
72 : : return NULL;
73 : :
74 : 0 : list->shared_max = (ksize(list) - offsetof(typeof(*list), shared)) /
75 : : sizeof(*list->shared);
76 : :
77 : 0 : return list;
78 : : }
79 : :
80 : : /**
81 : : * dma_resv_list_free - free fence list
82 : : * @list: list to free
83 : : *
84 : : * Free a dma_resv_list and make sure to drop all references.
85 : : */
86 : 0 : static void dma_resv_list_free(struct dma_resv_list *list)
87 : : {
88 : 0 : unsigned int i;
89 : :
90 [ # # ]: 0 : if (!list)
91 : : return;
92 : :
93 [ # # ]: 0 : for (i = 0; i < list->shared_count; ++i)
94 : 0 : dma_fence_put(rcu_dereference_protected(list->shared[i], true));
95 : :
96 : 0 : kfree_rcu(list, rcu);
97 : : }
98 : :
99 : : #if IS_ENABLED(CONFIG_LOCKDEP)
100 : : static int __init dma_resv_lockdep(void)
101 : : {
102 : : struct mm_struct *mm = mm_alloc();
103 : : struct ww_acquire_ctx ctx;
104 : : struct dma_resv obj;
105 : : int ret;
106 : :
107 : : if (!mm)
108 : : return -ENOMEM;
109 : :
110 : : dma_resv_init(&obj);
111 : :
112 : : down_read(&mm->mmap_sem);
113 : : ww_acquire_init(&ctx, &reservation_ww_class);
114 : : ret = dma_resv_lock(&obj, &ctx);
115 : : if (ret == -EDEADLK)
116 : : dma_resv_lock_slow(&obj, &ctx);
117 : : fs_reclaim_acquire(GFP_KERNEL);
118 : : fs_reclaim_release(GFP_KERNEL);
119 : : ww_mutex_unlock(&obj.lock);
120 : : ww_acquire_fini(&ctx);
121 : : up_read(&mm->mmap_sem);
122 : :
123 : : mmput(mm);
124 : :
125 : : return 0;
126 : : }
127 : : subsys_initcall(dma_resv_lockdep);
128 : : #endif
129 : :
130 : : /**
131 : : * dma_resv_init - initialize a reservation object
132 : : * @obj: the reservation object
133 : : */
134 : 0 : void dma_resv_init(struct dma_resv *obj)
135 : : {
136 : 0 : ww_mutex_init(&obj->lock, &reservation_ww_class);
137 : :
138 : 0 : __seqcount_init(&obj->seq, reservation_seqcount_string,
139 : : &reservation_seqcount_class);
140 : 0 : RCU_INIT_POINTER(obj->fence, NULL);
141 : 0 : RCU_INIT_POINTER(obj->fence_excl, NULL);
142 : 0 : }
143 : : EXPORT_SYMBOL(dma_resv_init);
144 : :
145 : : /**
146 : : * dma_resv_fini - destroys a reservation object
147 : : * @obj: the reservation object
148 : : */
149 : 0 : void dma_resv_fini(struct dma_resv *obj)
150 : : {
151 : 0 : struct dma_resv_list *fobj;
152 : 0 : struct dma_fence *excl;
153 : :
154 : : /*
155 : : * This object should be dead and all references must have
156 : : * been released to it, so no need to be protected with rcu.
157 : : */
158 : 0 : excl = rcu_dereference_protected(obj->fence_excl, 1);
159 [ # # ]: 0 : if (excl)
160 : 0 : dma_fence_put(excl);
161 : :
162 : 0 : fobj = rcu_dereference_protected(obj->fence, 1);
163 : 0 : dma_resv_list_free(fobj);
164 : 0 : ww_mutex_destroy(&obj->lock);
165 : 0 : }
166 : : EXPORT_SYMBOL(dma_resv_fini);
167 : :
168 : : /**
169 : : * dma_resv_reserve_shared - Reserve space to add shared fences to
170 : : * a dma_resv.
171 : : * @obj: reservation object
172 : : * @num_fences: number of fences we want to add
173 : : *
174 : : * Should be called before dma_resv_add_shared_fence(). Must
175 : : * be called with obj->lock held.
176 : : *
177 : : * RETURNS
178 : : * Zero for success, or -errno
179 : : */
180 : 0 : int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
181 : : {
182 : 0 : struct dma_resv_list *old, *new;
183 : 0 : unsigned int i, j, k, max;
184 : :
185 : 0 : dma_resv_assert_held(obj);
186 : :
187 [ # # ]: 0 : old = dma_resv_get_list(obj);
188 : :
189 [ # # # # ]: 0 : if (old && old->shared_max) {
190 [ # # ]: 0 : if ((old->shared_count + num_fences) <= old->shared_max)
191 : : return 0;
192 : : else
193 : 0 : max = max(old->shared_count + num_fences,
194 : : old->shared_max * 2);
195 : : } else {
196 : : max = 4;
197 : : }
198 : :
199 : 0 : new = dma_resv_list_alloc(max);
200 [ # # ]: 0 : if (!new)
201 : : return -ENOMEM;
202 : :
203 : : /*
204 : : * no need to bump fence refcounts, rcu_read access
205 : : * requires the use of kref_get_unless_zero, and the
206 : : * references from the old struct are carried over to
207 : : * the new.
208 : : */
209 [ # # # # ]: 0 : for (i = 0, j = 0, k = max; i < (old ? old->shared_count : 0); ++i) {
210 : 0 : struct dma_fence *fence;
211 : :
212 : 0 : fence = rcu_dereference_protected(old->shared[i],
213 : : dma_resv_held(obj));
214 [ # # ]: 0 : if (dma_fence_is_signaled(fence))
215 : 0 : RCU_INIT_POINTER(new->shared[--k], fence);
216 : : else
217 : 0 : RCU_INIT_POINTER(new->shared[j++], fence);
218 : : }
219 : 0 : new->shared_count = j;
220 : :
221 : : /*
222 : : * We are not changing the effective set of fences here so can
223 : : * merely update the pointer to the new array; both existing
224 : : * readers and new readers will see exactly the same set of
225 : : * active (unsignaled) shared fences. Individual fences and the
226 : : * old array are protected by RCU and so will not vanish under
227 : : * the gaze of the rcu_read_lock() readers.
228 : : */
229 [ # # ]: 0 : rcu_assign_pointer(obj->fence, new);
230 : :
231 [ # # ]: 0 : if (!old)
232 : : return 0;
233 : :
234 : : /* Drop the references to the signaled fences */
235 [ # # ]: 0 : for (i = k; i < max; ++i) {
236 : 0 : struct dma_fence *fence;
237 : :
238 : 0 : fence = rcu_dereference_protected(new->shared[i],
239 : : dma_resv_held(obj));
240 : 0 : dma_fence_put(fence);
241 : : }
242 : 0 : kfree_rcu(old, rcu);
243 : :
244 : 0 : return 0;
245 : : }
246 : : EXPORT_SYMBOL(dma_resv_reserve_shared);
247 : :
248 : : /**
249 : : * dma_resv_add_shared_fence - Add a fence to a shared slot
250 : : * @obj: the reservation object
251 : : * @fence: the shared fence to add
252 : : *
253 : : * Add a fence to a shared slot, obj->lock must be held, and
254 : : * dma_resv_reserve_shared() has been called.
255 : : */
256 : 0 : void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
257 : : {
258 : 0 : struct dma_resv_list *fobj;
259 : 0 : struct dma_fence *old;
260 : 0 : unsigned int i, count;
261 : :
262 [ # # ]: 0 : dma_fence_get(fence);
263 : :
264 : 0 : dma_resv_assert_held(obj);
265 : :
266 : 0 : fobj = dma_resv_get_list(obj);
267 : 0 : count = fobj->shared_count;
268 : :
269 : 0 : preempt_disable();
270 : 0 : write_seqcount_begin(&obj->seq);
271 : :
272 [ # # ]: 0 : for (i = 0; i < count; ++i) {
273 : :
274 : 0 : old = rcu_dereference_protected(fobj->shared[i],
275 : : dma_resv_held(obj));
276 [ # # # # ]: 0 : if (old->context == fence->context ||
277 : 0 : dma_fence_is_signaled(old))
278 : 0 : goto replace;
279 : : }
280 : :
281 [ # # ]: 0 : BUG_ON(fobj->shared_count >= fobj->shared_max);
282 : 0 : old = NULL;
283 : 0 : count++;
284 : :
285 : 0 : replace:
286 : 0 : RCU_INIT_POINTER(fobj->shared[i], fence);
287 : : /* pointer update must be visible before we extend the shared_count */
288 : 0 : smp_store_mb(fobj->shared_count, count);
289 : :
290 : 0 : write_seqcount_end(&obj->seq);
291 : 0 : preempt_enable();
292 : 0 : dma_fence_put(old);
293 : 0 : }
294 : : EXPORT_SYMBOL(dma_resv_add_shared_fence);
295 : :
296 : : /**
297 : : * dma_resv_add_excl_fence - Add an exclusive fence.
298 : : * @obj: the reservation object
299 : : * @fence: the shared fence to add
300 : : *
301 : : * Add a fence to the exclusive slot. The obj->lock must be held.
302 : : */
303 : 0 : void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
304 : : {
305 [ # # ]: 0 : struct dma_fence *old_fence = dma_resv_get_excl(obj);
306 : 0 : struct dma_resv_list *old;
307 : 0 : u32 i = 0;
308 : :
309 : 0 : dma_resv_assert_held(obj);
310 : :
311 [ # # ]: 0 : old = dma_resv_get_list(obj);
312 [ # # ]: 0 : if (old)
313 : 0 : i = old->shared_count;
314 : :
315 [ # # ]: 0 : if (fence)
316 : 0 : dma_fence_get(fence);
317 : :
318 : 0 : preempt_disable();
319 : 0 : write_seqcount_begin(&obj->seq);
320 : : /* write_seqcount_begin provides the necessary memory barrier */
321 [ # # ]: 0 : RCU_INIT_POINTER(obj->fence_excl, fence);
322 [ # # ]: 0 : if (old)
323 : 0 : old->shared_count = 0;
324 : 0 : write_seqcount_end(&obj->seq);
325 : 0 : preempt_enable();
326 : :
327 : : /* inplace update, no shared fences */
328 [ # # ]: 0 : while (i--)
329 : 0 : dma_fence_put(rcu_dereference_protected(old->shared[i],
330 : : dma_resv_held(obj)));
331 : :
332 : 0 : dma_fence_put(old_fence);
333 : 0 : }
334 : : EXPORT_SYMBOL(dma_resv_add_excl_fence);
335 : :
336 : : /**
337 : : * dma_resv_copy_fences - Copy all fences from src to dst.
338 : : * @dst: the destination reservation object
339 : : * @src: the source reservation object
340 : : *
341 : : * Copy all fences from src to dst. dst-lock must be held.
342 : : */
343 : 0 : int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src)
344 : : {
345 : 0 : struct dma_resv_list *src_list, *dst_list;
346 : 0 : struct dma_fence *old, *new;
347 : 0 : unsigned i;
348 : :
349 : 0 : dma_resv_assert_held(dst);
350 : :
351 : 0 : rcu_read_lock();
352 : 0 : src_list = rcu_dereference(src->fence);
353 : :
354 : : retry:
355 [ # # ]: 0 : if (src_list) {
356 : 0 : unsigned shared_count = src_list->shared_count;
357 : :
358 : 0 : rcu_read_unlock();
359 : :
360 : 0 : dst_list = dma_resv_list_alloc(shared_count);
361 [ # # ]: 0 : if (!dst_list)
362 : : return -ENOMEM;
363 : :
364 : 0 : rcu_read_lock();
365 [ # # ]: 0 : src_list = rcu_dereference(src->fence);
366 [ # # # # ]: 0 : if (!src_list || src_list->shared_count > shared_count) {
367 : 0 : kfree(dst_list);
368 : 0 : goto retry;
369 : : }
370 : :
371 : 0 : dst_list->shared_count = 0;
372 [ # # ]: 0 : for (i = 0; i < src_list->shared_count; ++i) {
373 : 0 : struct dma_fence *fence;
374 : :
375 : 0 : fence = rcu_dereference(src_list->shared[i]);
376 [ # # ]: 0 : if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
377 : 0 : &fence->flags))
378 : 0 : continue;
379 : :
380 [ # # ]: 0 : if (!dma_fence_get_rcu(fence)) {
381 : 0 : dma_resv_list_free(dst_list);
382 : 0 : src_list = rcu_dereference(src->fence);
383 : 0 : goto retry;
384 : : }
385 : :
386 [ # # ]: 0 : if (dma_fence_is_signaled(fence)) {
387 : 0 : dma_fence_put(fence);
388 : 0 : continue;
389 : : }
390 : :
391 : 0 : rcu_assign_pointer(dst_list->shared[dst_list->shared_count++], fence);
392 : : }
393 : : } else {
394 : : dst_list = NULL;
395 : : }
396 : :
397 : 0 : new = dma_fence_get_rcu_safe(&src->fence_excl);
398 : 0 : rcu_read_unlock();
399 : :
400 : 0 : src_list = dma_resv_get_list(dst);
401 : 0 : old = dma_resv_get_excl(dst);
402 : :
403 : 0 : preempt_disable();
404 : 0 : write_seqcount_begin(&dst->seq);
405 : : /* write_seqcount_begin provides the necessary memory barrier */
406 : 0 : RCU_INIT_POINTER(dst->fence_excl, new);
407 : 0 : RCU_INIT_POINTER(dst->fence, dst_list);
408 : 0 : write_seqcount_end(&dst->seq);
409 : 0 : preempt_enable();
410 : :
411 : 0 : dma_resv_list_free(src_list);
412 : 0 : dma_fence_put(old);
413 : :
414 : 0 : return 0;
415 : : }
416 : : EXPORT_SYMBOL(dma_resv_copy_fences);
417 : :
418 : : /**
419 : : * dma_resv_get_fences_rcu - Get an object's shared and exclusive
420 : : * fences without update side lock held
421 : : * @obj: the reservation object
422 : : * @pfence_excl: the returned exclusive fence (or NULL)
423 : : * @pshared_count: the number of shared fences returned
424 : : * @pshared: the array of shared fence ptrs returned (array is krealloc'd to
425 : : * the required size, and must be freed by caller)
426 : : *
427 : : * Retrieve all fences from the reservation object. If the pointer for the
428 : : * exclusive fence is not specified the fence is put into the array of the
429 : : * shared fences as well. Returns either zero or -ENOMEM.
430 : : */
431 : 0 : int dma_resv_get_fences_rcu(struct dma_resv *obj,
432 : : struct dma_fence **pfence_excl,
433 : : unsigned *pshared_count,
434 : : struct dma_fence ***pshared)
435 : : {
436 : 0 : struct dma_fence **shared = NULL;
437 : 0 : struct dma_fence *fence_excl;
438 : 0 : unsigned int shared_count;
439 : 0 : int ret = 1;
440 : :
441 : 0 : do {
442 : 0 : struct dma_resv_list *fobj;
443 : 0 : unsigned int i, seq;
444 : 0 : size_t sz = 0;
445 : :
446 : 0 : shared_count = i = 0;
447 : :
448 : 0 : rcu_read_lock();
449 : 0 : seq = read_seqcount_begin(&obj->seq);
450 : :
451 [ # # ]: 0 : fence_excl = rcu_dereference(obj->fence_excl);
452 [ # # ]: 0 : if (fence_excl && !dma_fence_get_rcu(fence_excl))
453 : 0 : goto unlock;
454 : :
455 [ # # ]: 0 : fobj = rcu_dereference(obj->fence);
456 [ # # ]: 0 : if (fobj)
457 : 0 : sz += sizeof(*shared) * fobj->shared_max;
458 : :
459 [ # # ]: 0 : if (!pfence_excl && fence_excl)
460 : 0 : sz += sizeof(*shared);
461 : :
462 [ # # ]: 0 : if (sz) {
463 : 0 : struct dma_fence **nshared;
464 : :
465 : 0 : nshared = krealloc(shared, sz,
466 : : GFP_NOWAIT | __GFP_NOWARN);
467 [ # # ]: 0 : if (!nshared) {
468 : 0 : rcu_read_unlock();
469 : :
470 : 0 : dma_fence_put(fence_excl);
471 : 0 : fence_excl = NULL;
472 : :
473 : 0 : nshared = krealloc(shared, sz, GFP_KERNEL);
474 [ # # ]: 0 : if (nshared) {
475 : 0 : shared = nshared;
476 : 0 : continue;
477 : : }
478 : :
479 : : ret = -ENOMEM;
480 : : break;
481 : : }
482 : 0 : shared = nshared;
483 [ # # ]: 0 : shared_count = fobj ? fobj->shared_count : 0;
484 [ # # ]: 0 : for (i = 0; i < shared_count; ++i) {
485 : 0 : shared[i] = rcu_dereference(fobj->shared[i]);
486 [ # # ]: 0 : if (!dma_fence_get_rcu(shared[i]))
487 : : break;
488 : : }
489 : : }
490 : :
491 [ # # # # ]: 0 : if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) {
492 [ # # ]: 0 : while (i--)
493 : 0 : dma_fence_put(shared[i]);
494 : 0 : dma_fence_put(fence_excl);
495 : 0 : goto unlock;
496 : : }
497 : :
498 : : ret = 0;
499 : 0 : unlock:
500 : 0 : rcu_read_unlock();
501 [ # # ]: 0 : } while (ret);
502 : :
503 [ # # ]: 0 : if (pfence_excl)
504 : 0 : *pfence_excl = fence_excl;
505 [ # # ]: 0 : else if (fence_excl)
506 : 0 : shared[shared_count++] = fence_excl;
507 : :
508 [ # # ]: 0 : if (!shared_count) {
509 : 0 : kfree(shared);
510 : 0 : shared = NULL;
511 : : }
512 : :
513 : 0 : *pshared_count = shared_count;
514 : 0 : *pshared = shared;
515 : 0 : return ret;
516 : : }
517 : : EXPORT_SYMBOL_GPL(dma_resv_get_fences_rcu);
518 : :
519 : : /**
520 : : * dma_resv_wait_timeout_rcu - Wait on reservation's objects
521 : : * shared and/or exclusive fences.
522 : : * @obj: the reservation object
523 : : * @wait_all: if true, wait on all fences, else wait on just exclusive fence
524 : : * @intr: if true, do interruptible wait
525 : : * @timeout: timeout value in jiffies or zero to return immediately
526 : : *
527 : : * RETURNS
528 : : * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
529 : : * greater than zer on success.
530 : : */
531 : 0 : long dma_resv_wait_timeout_rcu(struct dma_resv *obj,
532 : : bool wait_all, bool intr,
533 : : unsigned long timeout)
534 : : {
535 : 0 : struct dma_fence *fence;
536 : 0 : unsigned seq, shared_count;
537 : 0 : long ret = timeout ? timeout : 1;
538 : 0 : int i;
539 : :
540 : : retry:
541 : 0 : shared_count = 0;
542 : 0 : seq = read_seqcount_begin(&obj->seq);
543 : 0 : rcu_read_lock();
544 : 0 : i = -1;
545 : :
546 [ # # ]: 0 : fence = rcu_dereference(obj->fence_excl);
547 [ # # # # ]: 0 : if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
548 : 0 : if (!dma_fence_get_rcu(fence))
549 : 0 : goto unlock_retry;
550 : :
551 [ # # ]: 0 : if (dma_fence_is_signaled(fence)) {
552 : 0 : dma_fence_put(fence);
553 : 0 : fence = NULL;
554 : : }
555 : :
556 : : } else {
557 : : fence = NULL;
558 : : }
559 : :
560 [ # # ]: 0 : if (wait_all) {
561 [ # # ]: 0 : struct dma_resv_list *fobj = rcu_dereference(obj->fence);
562 : :
563 [ # # ]: 0 : if (fobj)
564 : 0 : shared_count = fobj->shared_count;
565 : :
566 [ # # ]: 0 : for (i = 0; !fence && i < shared_count; ++i) {
567 : 0 : struct dma_fence *lfence = rcu_dereference(fobj->shared[i]);
568 : :
569 [ # # ]: 0 : if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
570 : 0 : &lfence->flags))
571 : 0 : continue;
572 : :
573 [ # # ]: 0 : if (!dma_fence_get_rcu(lfence))
574 : 0 : goto unlock_retry;
575 : :
576 [ # # ]: 0 : if (dma_fence_is_signaled(lfence)) {
577 : 0 : dma_fence_put(lfence);
578 : 0 : continue;
579 : : }
580 : :
581 : : fence = lfence;
582 : : break;
583 : : }
584 : : }
585 : :
586 : 0 : rcu_read_unlock();
587 [ # # ]: 0 : if (fence) {
588 [ # # ]: 0 : if (read_seqcount_retry(&obj->seq, seq)) {
589 : 0 : dma_fence_put(fence);
590 : 0 : goto retry;
591 : : }
592 : :
593 : 0 : ret = dma_fence_wait_timeout(fence, intr, ret);
594 : 0 : dma_fence_put(fence);
595 [ # # # # ]: 0 : if (ret > 0 && wait_all && (i + 1 < shared_count))
596 : 0 : goto retry;
597 : : }
598 : 0 : return ret;
599 : :
600 : 0 : unlock_retry:
601 : 0 : rcu_read_unlock();
602 : 0 : goto retry;
603 : : }
604 : : EXPORT_SYMBOL_GPL(dma_resv_wait_timeout_rcu);
605 : :
606 : :
607 : 0 : static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence)
608 : : {
609 : 0 : struct dma_fence *fence, *lfence = passed_fence;
610 : 0 : int ret = 1;
611 : :
612 [ # # ]: 0 : if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) {
613 : 0 : fence = dma_fence_get_rcu(lfence);
614 [ # # ]: 0 : if (!fence)
615 : : return -1;
616 : :
617 : 0 : ret = !!dma_fence_is_signaled(fence);
618 : 0 : dma_fence_put(fence);
619 : : }
620 : : return ret;
621 : : }
622 : :
623 : : /**
624 : : * dma_resv_test_signaled_rcu - Test if a reservation object's
625 : : * fences have been signaled.
626 : : * @obj: the reservation object
627 : : * @test_all: if true, test all fences, otherwise only test the exclusive
628 : : * fence
629 : : *
630 : : * RETURNS
631 : : * true if all fences signaled, else false
632 : : */
633 : 0 : bool dma_resv_test_signaled_rcu(struct dma_resv *obj, bool test_all)
634 : : {
635 : 0 : unsigned seq, shared_count;
636 : 0 : int ret;
637 : :
638 : 0 : rcu_read_lock();
639 : : retry:
640 : 0 : ret = true;
641 : 0 : shared_count = 0;
642 : 0 : seq = read_seqcount_begin(&obj->seq);
643 : :
644 [ # # ]: 0 : if (test_all) {
645 : 0 : unsigned i;
646 : :
647 [ # # ]: 0 : struct dma_resv_list *fobj = rcu_dereference(obj->fence);
648 : :
649 [ # # ]: 0 : if (fobj)
650 : 0 : shared_count = fobj->shared_count;
651 : :
652 [ # # ]: 0 : for (i = 0; i < shared_count; ++i) {
653 : 0 : struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
654 : :
655 : 0 : ret = dma_resv_test_signaled_single(fence);
656 [ # # ]: 0 : if (ret < 0)
657 : 0 : goto retry;
658 [ # # ]: 0 : else if (!ret)
659 : : break;
660 : : }
661 : :
662 [ # # ]: 0 : if (read_seqcount_retry(&obj->seq, seq))
663 : 0 : goto retry;
664 : : }
665 : :
666 [ # # ]: 0 : if (!shared_count) {
667 [ # # ]: 0 : struct dma_fence *fence_excl = rcu_dereference(obj->fence_excl);
668 : :
669 [ # # ]: 0 : if (fence_excl) {
670 : 0 : ret = dma_resv_test_signaled_single(fence_excl);
671 [ # # ]: 0 : if (ret < 0)
672 : 0 : goto retry;
673 : :
674 [ # # ]: 0 : if (read_seqcount_retry(&obj->seq, seq))
675 : 0 : goto retry;
676 : : }
677 : : }
678 : :
679 : 0 : rcu_read_unlock();
680 : 0 : return ret;
681 : : }
682 : : EXPORT_SYMBOL_GPL(dma_resv_test_signaled_rcu);
|