Tue Feb 15 22:51:03 2022 UTC ()
drm: Use KM_SLEEP to allocate reservation fence arrays.

Except as a fast path in an RCU reader.

The array sizes appear to be reasonably small and not trivially
controlled by userland, from what I can tell, so if my impression is
accurate, it is reasonable to sleep for allocation here.


(riastradh)
diff -r1.21 -r1.22 src/sys/external/bsd/drm2/linux/linux_dma_resv.c

cvs diff -r1.21 -r1.22 src/sys/external/bsd/drm2/linux/linux_dma_resv.c (expand / switch to unified diff)

--- src/sys/external/bsd/drm2/linux/linux_dma_resv.c 2021/12/19 12:36:02 1.21
+++ src/sys/external/bsd/drm2/linux/linux_dma_resv.c 2022/02/15 22:51:03 1.22
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: linux_dma_resv.c,v 1.21 2021/12/19 12:36:02 riastradh Exp $ */ 1/* $NetBSD: linux_dma_resv.c,v 1.22 2022/02/15 22:51:03 riastradh Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2018 The NetBSD Foundation, Inc. 4 * Copyright (c) 2018 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Taylor R. Campbell. 8 * by Taylor R. Campbell.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -20,52 +20,63 @@ @@ -20,52 +20,63 @@
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: linux_dma_resv.c,v 1.21 2021/12/19 12:36:02 riastradh Exp $"); 33__KERNEL_RCSID(0, "$NetBSD: linux_dma_resv.c,v 1.22 2022/02/15 22:51:03 riastradh Exp $");
34 34
35#include <sys/param.h> 35#include <sys/param.h>
36#include <sys/poll.h> 36#include <sys/poll.h>
37#include <sys/select.h> 37#include <sys/select.h>
38 38
39#include <linux/dma-fence.h> 39#include <linux/dma-fence.h>
40#include <linux/dma-resv.h> 40#include <linux/dma-resv.h>
41#include <linux/seqlock.h> 41#include <linux/seqlock.h>
42#include <linux/ww_mutex.h> 42#include <linux/ww_mutex.h>
43 43
44DEFINE_WW_CLASS(reservation_ww_class __cacheline_aligned); 44DEFINE_WW_CLASS(reservation_ww_class __cacheline_aligned);
45 45
46static struct dma_resv_list * 46static struct dma_resv_list *
47objlist_tryalloc(uint32_t n) 47objlist_tryalloc(uint32_t n)
48{ 48{
49 struct dma_resv_list *list; 49 struct dma_resv_list *list;
50 50
51 list = kmem_alloc(offsetof(typeof(*list), shared[n]), KM_NOSLEEP); 51 list = kmem_alloc(offsetof(typeof(*list), shared[n]), KM_NOSLEEP);
52 if (list == NULL) 52 if (list == NULL)
53 return NULL; 53 return NULL;
54 list->shared_max = n; 54 list->shared_max = n;
55 55
56 return list; 56 return list;
57} 57}
58 58
 59static struct dma_resv_list *
 60objlist_alloc(uint32_t n)
 61{
 62 struct dma_resv_list *list;
 63
 64 list = kmem_alloc(offsetof(typeof(*list), shared[n]), KM_SLEEP);
 65 list->shared_max = n;
 66
 67 return list;
 68}
 69
59static void 70static void
60objlist_free(struct dma_resv_list *list) 71objlist_free(struct dma_resv_list *list)
61{ 72{
62 uint32_t n = list->shared_max; 73 uint32_t n = list->shared_max;
63 74
64 kmem_free(list, offsetof(typeof(*list), shared[n])); 75 kmem_free(list, offsetof(typeof(*list), shared[n]));
65} 76}
66 77
67static void 78static void
68objlist_free_cb(struct rcu_head *rcu) 79objlist_free_cb(struct rcu_head *rcu)
69{ 80{
70 struct dma_resv_list *list = container_of(rcu, 81 struct dma_resv_list *list = container_of(rcu,
71 struct dma_resv_list, rol_rcu); 82 struct dma_resv_list, rol_rcu);
@@ -336,39 +347,36 @@ dma_resv_reserve_shared(struct dma_resv  @@ -336,39 +347,36 @@ dma_resv_reserve_shared(struct dma_resv
336 } else { 347 } else {
337 /* No list already. We need space for num_fences. */ 348 /* No list already. We need space for num_fences. */
338 n = num_fences; 349 n = num_fences;
339 } 350 }
340 351
341 /* If not, maybe there's a preallocated list ready. */ 352 /* If not, maybe there's a preallocated list ready. */
342 if (prealloc != NULL) { 353 if (prealloc != NULL) {
343 /* If there's enough room in it, stop here. */ 354 /* If there's enough room in it, stop here. */
344 if (n <= prealloc->shared_max) 355 if (n <= prealloc->shared_max)
345 return 0; 356 return 0;
346 357
347 /* Try to double its capacity. */ 358 /* Try to double its capacity. */
348 nalloc = n > UINT32_MAX/2 ? UINT32_MAX : 2*n; 359 nalloc = n > UINT32_MAX/2 ? UINT32_MAX : 2*n;
349 prealloc = objlist_tryalloc(nalloc); 360 prealloc = objlist_alloc(nalloc);
350 if (prealloc == NULL) 
351 return -ENOMEM; 
352 361
353 /* Swap the new preallocated list and free the old one. */ 362 /* Swap the new preallocated list and free the old one. */
354 objlist_free(robj->robj_prealloc); 363 objlist_free(robj->robj_prealloc);
355 robj->robj_prealloc = prealloc; 364 robj->robj_prealloc = prealloc;
356 } else { 365 } else {
357 /* Start with some spare. */ 366 /* Start with some spare. */
358 nalloc = n > UINT32_MAX/2 ? UINT32_MAX : MAX(2*n, 4); 367 nalloc = n > UINT32_MAX/2 ? UINT32_MAX : MAX(2*n, 4);
359 prealloc = objlist_tryalloc(nalloc); 368 prealloc = objlist_alloc(nalloc);
360 if (prealloc == NULL) 369
361 return -ENOMEM; 
362 /* Save the new preallocated list. */ 370 /* Save the new preallocated list. */
363 robj->robj_prealloc = prealloc; 371 robj->robj_prealloc = prealloc;
364 } 372 }
365 373
366 /* Success! */ 374 /* Success! */
367 return 0; 375 return 0;
368} 376}
369 377
370struct dma_resv_write_ticket { 378struct dma_resv_write_ticket {
371}; 379};
372 380
373/* 381/*
374 * dma_resv_write_begin(robj, ticket) 382 * dma_resv_write_begin(robj, ticket)
@@ -679,28 +687,30 @@ dma_resv_add_shared_fence(struct dma_res @@ -679,28 +687,30 @@ dma_resv_add_shared_fence(struct dma_res
679 */ 687 */
680 for (i = 0; i < shared_count; i++) { 688 for (i = 0; i < shared_count; i++) {
681 if (replace == NULL && 689 if (replace == NULL &&
682 list->shared[i]->context == fence->context) { 690 list->shared[i]->context == fence->context) {
683 replace = list->shared[i]; 691 replace = list->shared[i];
684 prealloc->shared[i] = fence; 692 prealloc->shared[i] = fence;
685 } else { 693 } else {
686 prealloc->shared[i] = list->shared[i]; 694 prealloc->shared[i] = list->shared[i];
687 } 695 }
688 } 696 }
689 prealloc->shared_count = shared_count; 697 prealloc->shared_count = shared_count;
690 698
691 /* If we didn't find one, add it at the end. */ 699 /* If we didn't find one, add it at the end. */
692 if (replace == NULL) 700 if (replace == NULL) {
 701 KASSERT(prealloc->shared_count < prealloc->shared_max);
693 prealloc->shared[prealloc->shared_count++] = fence; 702 prealloc->shared[prealloc->shared_count++] = fence;
 703 }
694 704
695 /* 705 /*
696 * Now ready to replace the list. Begin an update. 706 * Now ready to replace the list. Begin an update.
697 * Implies membar_producer for fence and prealloc. 707 * Implies membar_producer for fence and prealloc.
698 */ 708 */
699 dma_resv_write_begin(robj, &ticket); 709 dma_resv_write_begin(robj, &ticket);
700 710
701 /* Replace the list. */ 711 /* Replace the list. */
702 atomic_store_relaxed(&robj->fence, prealloc); 712 atomic_store_relaxed(&robj->fence, prealloc);
703 robj->robj_prealloc = NULL; 713 robj->robj_prealloc = NULL;
704 714
705 /* Commit the update. */ 715 /* Commit the update. */
706 dma_resv_write_commit(robj, &ticket); 716 dma_resv_write_commit(robj, &ticket);
@@ -909,31 +919,40 @@ dma_resv_copy_fences(struct dma_resv *ds @@ -909,31 +919,40 @@ dma_resv_copy_fences(struct dma_resv *ds
909 919
910 KASSERT(dma_resv_held(dst_robj)); 920 KASSERT(dma_resv_held(dst_robj));
911 921
912top: KASSERT(fence == NULL); 922top: KASSERT(fence == NULL);
913 923
914 /* Enter an RCU read section and get a read ticket. */ 924 /* Enter an RCU read section and get a read ticket. */
915 rcu_read_lock(); 925 rcu_read_lock();
916 dma_resv_read_begin(src_robj, &read_ticket); 926 dma_resv_read_begin(src_robj, &read_ticket);
917 927
918 /* Get the shared list. */ 928 /* Get the shared list. */
919 if (!dma_resv_get_shared_reader(src_robj, &src_list, &shared_count, 929 if (!dma_resv_get_shared_reader(src_robj, &src_list, &shared_count,
920 &read_ticket)) 930 &read_ticket))
921 goto restart; 931 goto restart;
922 if (src_list != NULL) { 932 if (src_list) {
923 /* Allocate a new list. */ 933 /* Allocate a new list, if necessary. */
924 dst_list = objlist_tryalloc(shared_count); 
925 if (dst_list == NULL) 934 if (dst_list == NULL)
926 return -ENOMEM; 935 dst_list = objlist_tryalloc(shared_count);
 936 if (dst_list == NULL || dst_list->shared_max < shared_count) {
 937 rcu_read_unlock();
 938 if (dst_list) {
 939 objlist_free(dst_list);
 940 dst_list = NULL;
 941 }
 942 dst_list = objlist_alloc(shared_count);
 943 dst_list->shared_count = 0; /* paranoia */
 944 goto top;
 945 }
927 946
928 /* Copy over all fences that are not yet signalled. */ 947 /* Copy over all fences that are not yet signalled. */
929 dst_list->shared_count = 0; 948 dst_list->shared_count = 0;
930 for (i = 0; i < shared_count; i++) { 949 for (i = 0; i < shared_count; i++) {
931 KASSERT(fence == NULL); 950 KASSERT(fence == NULL);
932 fence = atomic_load_relaxed(&src_list->shared[i]); 951 fence = atomic_load_relaxed(&src_list->shared[i]);
933 if ((fence = dma_fence_get_rcu(fence)) == NULL) 952 if ((fence = dma_fence_get_rcu(fence)) == NULL)
934 goto restart; 953 goto restart;
935 if (dma_fence_is_signaled(fence)) { 954 if (dma_fence_is_signaled(fence)) {
936 dma_fence_put(fence); 955 dma_fence_put(fence);
937 fence = NULL; 956 fence = NULL;
938 continue; 957 continue;
939 } 958 }
@@ -995,28 +1014,27 @@ top: KASSERT(fence == NULL); @@ -995,28 +1014,27 @@ top: KASSERT(fence == NULL);
995 } 1014 }
996 1015
997 /* Success! */ 1016 /* Success! */
998 return 0; 1017 return 0;
999 1018
1000restart: 1019restart:
1001 KASSERT(fence == NULL); 1020 KASSERT(fence == NULL);
1002 rcu_read_unlock(); 1021 rcu_read_unlock();
1003 if (dst_list) { 1022 if (dst_list) {
1004 for (i = dst_list->shared_count; i --> 0;) { 1023 for (i = dst_list->shared_count; i --> 0;) {
1005 dma_fence_put(dst_list->shared[i]); 1024 dma_fence_put(dst_list->shared[i]);
1006 dst_list->shared[i] = NULL; /* paranoia */ 1025 dst_list->shared[i] = NULL; /* paranoia */
1007 } 1026 }
1008 objlist_free(dst_list); 1027 /* reuse dst_list allocation for the next attempt */
1009 dst_list = NULL; 
1010 } 1028 }
1011 goto top; 1029 goto top;
1012} 1030}
1013 1031
1014/* 1032/*
1015 * dma_resv_test_signaled_rcu(robj, shared) 1033 * dma_resv_test_signaled_rcu(robj, shared)
1016 * 1034 *
1017 * If shared is true, test whether all of the shared fences are 1035 * If shared is true, test whether all of the shared fences are
1018 * signalled, or if there are none, test whether the exclusive 1036 * signalled, or if there are none, test whether the exclusive
1019 * fence is signalled. If shared is false, test only whether the 1037 * fence is signalled. If shared is false, test only whether the
1020 * exclusive fence is signalled. 1038 * exclusive fence is signalled.
1021 * 1039 *
1022 * XXX Why does this _not_ test the exclusive fence if shared is 1040 * XXX Why does this _not_ test the exclusive fence if shared is