Module Name: src Committed By: riastradh Date: Sun Dec 19 01:50:33 UTC 2021
Modified Files: src/sys/external/bsd/drm2/linux: linux_reservation.c Log Message: Draft implementation of reservation_object_copy_fences. To generate a diff of this commit: cvs rdiff -u -r1.23 -r1.24 \ src/sys/external/bsd/drm2/linux/linux_reservation.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/external/bsd/drm2/linux/linux_reservation.c diff -u src/sys/external/bsd/drm2/linux/linux_reservation.c:1.23 src/sys/external/bsd/drm2/linux/linux_reservation.c:1.24 --- src/sys/external/bsd/drm2/linux/linux_reservation.c:1.23 Sun Dec 19 01:50:25 2021 +++ src/sys/external/bsd/drm2/linux/linux_reservation.c Sun Dec 19 01:50:33 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: linux_reservation.c,v 1.23 2021/12/19 01:50:25 riastradh Exp $ */ +/* $NetBSD: linux_reservation.c,v 1.24 2021/12/19 01:50:33 riastradh Exp $ */ /*- * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: linux_reservation.c,v 1.23 2021/12/19 01:50:25 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: linux_reservation.c,v 1.24 2021/12/19 01:50:33 riastradh Exp $"); #include <sys/param.h> #include <sys/poll.h> @@ -694,6 +694,154 @@ restart: } /* + * reservation_object_copy_fences(dst, src) + * + * Copy the exclusive fence and all the shared fences from src to + * dst. + * + * Caller must have dst locked. + */ +int +reservation_object_copy_fences(struct reservation_object *dst_robj, + const struct reservation_object *src_robj) +{ + const struct reservation_object_list *src_list; + struct reservation_object_list *dst_list = NULL; + struct reservation_object_list *old_list; + struct dma_fence *fence = NULL; + struct dma_fence *old_fence; + uint32_t shared_count, i; + struct reservation_object_read_ticket read_ticket; + struct reservation_object_write_ticket write_ticket; + + KASSERT(reservation_object_held(dst_robj)); + +top: + /* Enter an RCU read section and get a read ticket. */ + rcu_read_lock(); + reservation_object_read_begin(src_robj, &read_ticket); + + /* Get the shared list. */ + src_list = src_robj->fence; + __insn_barrier(); + if (src_list) { + /* Make sure the content of the list has been published. */ + membar_datadep_consumer(); + + /* Find out how long it is. */ + shared_count = src_list->shared_count; + + /* + * Make sure we saw a consistent snapshot of the list + * pointer and length. + */ + if (!reservation_object_read_valid(src_robj, &read_ticket)) + goto restart; + + /* Allocate a new list. */ + dst_list = objlist_tryalloc(shared_count); + if (dst_list == NULL) + return -ENOMEM; + + /* Copy over all fences that are not yet signalled. */ + dst_list->shared_count = 0; + for (i = 0; i < shared_count; i++) { + if ((fence = dma_fence_get_rcu(src_list->shared[i])) + != NULL) + goto restart; + if (dma_fence_is_signaled(fence)) { + dma_fence_put(fence); + fence = NULL; + continue; + } + dst_list->shared[dst_list->shared_count++] = fence; + fence = NULL; + } + } + + /* Get the exclusive fence. */ + fence = src_robj->fence_excl; + __insn_barrier(); + if (fence != NULL) { + /* Make sure the content of the fence has been published. */ + membar_datadep_consumer(); + + /* + * Make sure we saw a consistent snapshot of the fence. + * + * XXX I'm not actually sure this is necessary since + * pointer writes are supposed to be atomic. + */ + if (!reservation_object_read_valid(src_robj, &read_ticket)) { + fence = NULL; + goto restart; + } + + /* + * If it is going away, restart. Otherwise, acquire a + * reference to it. + */ + if (!dma_fence_get_rcu(fence)) { + fence = NULL; + goto restart; + } + } + + /* All done with src; exit the RCU read section. */ + rcu_read_unlock(); + + /* + * We now have a snapshot of the shared and exclusive fences of + * src_robj and we have acquired references to them so they + * won't go away. Transfer them over to dst_robj, releasing + * references to any that were there. + */ + + /* Get the old shared and exclusive fences, if any. */ + old_list = dst_robj->fence; + old_fence = dst_robj->fence_excl; + + /* Begin an update. */ + reservation_object_write_begin(dst_robj, &write_ticket); + + /* Replace the fences. */ + dst_robj->fence = dst_list; + dst_robj->fence_excl = fence; + + /* Commit the update. */ + reservation_object_write_commit(dst_robj, &write_ticket); + + /* Release the old exclusive fence, if any. */ + if (old_fence) + dma_fence_put(old_fence); + + /* Release any old shared fences. */ + if (old_list) { + for (i = old_list->shared_count; i --> 0;) + dma_fence_put(old_list->shared[i]); + } + + /* Success! */ + return 0; + +restart: + rcu_read_unlock(); + if (dst_list) { + for (i = dst_list->shared_count; i --> 0;) { + dma_fence_put(dst_list->shared[i]); + dst_list->shared[i] = NULL; + } + objlist_free(dst_list); + dst_list = NULL; + } + if (fence) { + dma_fence_put(fence); + fence = NULL; + } + goto top; +} + +/* * reservation_object_test_signaled_rcu(robj, shared) * * If shared is true, test whether all of the shared fences are