Message ID | 20210610210925.642582-3-jason@jlekstrand.net (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | dma-buf: Add an API for exporting sync files (v12) | expand |
Am 10.06.21 um 23:09 schrieb Jason Ekstrand: > Add a helper function to get a single fence representing > all fences in a dma_resv object. > > This fence is either the only one in the object or all not > signaled fences of the object in a flatted out dma_fence_array. > > v2 (Jason Ekstrand): > - Take reference of fences both for creating the dma_fence_array and in > the case where we return one fence. > - Handle the case where dma_resv_get_list() returns NULL > > v3 (Jason Ekstrand): > - Add an _rcu suffix because it is read-only > - Rewrite to use dma_resv_get_fences_rcu so it's RCU-safe > - Add an EXPORT_SYMBOL_GPL declaration > - Re-author the patch to Jason since very little is left of Christian > König's original patch > - Remove the extra fence argument > > v4 (Jason Ekstrand): > - Restore the extra fence argument > > v5 (Daniel Vetter): > - Rename from _rcu to _unlocked since it doesn't leak RCU details to > the caller > - Fix docs > - Use ERR_PTR for error handling rather than an output dma_fence** > > v5 (Jason Ekstrand): > - Drop the extra fence param and leave that to a separate patch > > v6 (Jason Ekstrand): > - Rename to dma_resv_get_singleton to match the new naming convention > for dma_resv helpers which work without taking a lock. > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Christian König <christian.koenig@amd.com> > Cc: Christian König <christian.koenig@amd.com> > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> > --- > drivers/dma-buf/dma-resv.c | 91 ++++++++++++++++++++++++++++++++++++++ > include/linux/dma-resv.h | 1 + > 2 files changed, 92 insertions(+) > > diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c > index f26c71747d43a..1b26aa7e5d81c 100644 > --- a/drivers/dma-buf/dma-resv.c > +++ b/drivers/dma-buf/dma-resv.c > @@ -34,6 +34,8 @@ > */ > > #include <linux/dma-resv.h> > +#include <linux/dma-fence-chain.h> > +#include <linux/dma-fence-array.h> > #include <linux/export.h> > #include <linux/mm.h> > #include <linux/sched/mm.h> > @@ -50,6 +52,10 @@ > * write-side updates. > */ > > +#define dma_fence_deep_dive_for_each(fence, chain, index, head) \ > + dma_fence_chain_for_each(chain, head) \ > + dma_fence_array_for_each(fence, index, chain) > + > DEFINE_WD_CLASS(reservation_ww_class); > EXPORT_SYMBOL(reservation_ww_class); > > @@ -495,6 +501,91 @@ int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl, > } > EXPORT_SYMBOL_GPL(dma_resv_get_fences); > > +/** > + * dma_resv_get_singleton - get a single fence for the dma_resv object > + * @obj: the reservation object > + * > + * Get a single fence representing all unsignaled fences in the dma_resv object > + * plus the given extra fence. If we got only one fence return a new > + * reference to that, otherwise return a dma_fence_array object. > + * > + * RETURNS > + * The singleton dma_fence on success or an ERR_PTR on failure > + */ > +struct dma_fence *dma_resv_get_singleton(struct dma_resv *obj) > +{ > + struct dma_fence *result, **resv_fences, *fence, *chain, **fences; > + struct dma_fence_array *array; > + unsigned int num_resv_fences, num_fences; > + unsigned int err, i, j; > + > + err = dma_resv_get_fences(obj, NULL, &num_resv_fences, &resv_fences); > + if (err) > + return ERR_PTR(err); > + > + if (num_resv_fences == 0) > + return NULL; > + > + num_fences = 0; > + result = NULL; > + > + for (i = 0; i < num_resv_fences; ++i) { > + dma_fence_deep_dive_for_each(fence, chain, j, resv_fences[i]) { > + if (dma_fence_is_signaled(fence)) > + continue; > + > + result = fence; > + ++num_fences; > + } > + } > + > + if (num_fences <= 1) { > + result = dma_fence_get(result); > + goto put_resv_fences; > + } > + > + fences = kmalloc_array(num_fences, sizeof(struct dma_fence *), > + GFP_KERNEL); > + if (!fences) { > + result = ERR_PTR(-ENOMEM); > + goto put_resv_fences; > + } > + > + num_fences = 0; > + for (i = 0; i < num_resv_fences; ++i) { > + dma_fence_deep_dive_for_each(fence, chain, j, resv_fences[i]) { > + if (!dma_fence_is_signaled(fence)) > + fences[num_fences++] = dma_fence_get(fence); > + } > + } > + > + if (num_fences <= 1) { > + result = num_fences ? fences[0] : NULL; > + kfree(fences); > + goto put_resv_fences; > + } > + > + array = dma_fence_array_create(num_fences, fences, > + dma_fence_context_alloc(1), > + 1, false); > + if (array) { > + result = &array->base; > + } else { > + result = ERR_PTR(-ENOMEM); > + while (num_fences--) > + dma_fence_put(fences[num_fences]); > + kfree(fences); > + } > + > +put_resv_fences: > + while (num_resv_fences--) > + dma_fence_put(resv_fences[num_resv_fences]); > + kfree(resv_fences); > + > + return result; > +} > +EXPORT_SYMBOL_GPL(dma_resv_get_singleton); > + > /** > * dma_resv_wait_timeout - Wait on reservation's objects > * shared and/or exclusive fences. > diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h > index 562b885cf9c3d..d60982975a786 100644 > --- a/include/linux/dma-resv.h > +++ b/include/linux/dma-resv.h > @@ -275,6 +275,7 @@ void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence); > int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl, > unsigned *pshared_count, struct dma_fence ***pshared); > int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src); > +struct dma_fence *dma_resv_get_singleton(struct dma_resv *obj); > long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr, > unsigned long timeout); > bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all);
diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index f26c71747d43a..1b26aa7e5d81c 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -34,6 +34,8 @@ */ #include <linux/dma-resv.h> +#include <linux/dma-fence-chain.h> +#include <linux/dma-fence-array.h> #include <linux/export.h> #include <linux/mm.h> #include <linux/sched/mm.h> @@ -50,6 +52,10 @@ * write-side updates. */ +#define dma_fence_deep_dive_for_each(fence, chain, index, head) \ + dma_fence_chain_for_each(chain, head) \ + dma_fence_array_for_each(fence, index, chain) + DEFINE_WD_CLASS(reservation_ww_class); EXPORT_SYMBOL(reservation_ww_class); @@ -495,6 +501,91 @@ int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl, } EXPORT_SYMBOL_GPL(dma_resv_get_fences); +/** + * dma_resv_get_singleton - get a single fence for the dma_resv object + * @obj: the reservation object + * + * Get a single fence representing all unsignaled fences in the dma_resv object + * plus the given extra fence. If we got only one fence return a new + * reference to that, otherwise return a dma_fence_array object. + * + * RETURNS + * The singleton dma_fence on success or an ERR_PTR on failure + */ +struct dma_fence *dma_resv_get_singleton(struct dma_resv *obj) +{ + struct dma_fence *result, **resv_fences, *fence, *chain, **fences; + struct dma_fence_array *array; + unsigned int num_resv_fences, num_fences; + unsigned int err, i, j; + + err = dma_resv_get_fences(obj, NULL, &num_resv_fences, &resv_fences); + if (err) + return ERR_PTR(err); + + if (num_resv_fences == 0) + return NULL; + + num_fences = 0; + result = NULL; + + for (i = 0; i < num_resv_fences; ++i) { + dma_fence_deep_dive_for_each(fence, chain, j, resv_fences[i]) { + if (dma_fence_is_signaled(fence)) + continue; + + result = fence; + ++num_fences; + } + } + + if (num_fences <= 1) { + result = dma_fence_get(result); + goto put_resv_fences; + } + + fences = kmalloc_array(num_fences, sizeof(struct dma_fence *), + GFP_KERNEL); + if (!fences) { + result = ERR_PTR(-ENOMEM); + goto put_resv_fences; + } + + num_fences = 0; + for (i = 0; i < num_resv_fences; ++i) { + dma_fence_deep_dive_for_each(fence, chain, j, resv_fences[i]) { + if (!dma_fence_is_signaled(fence)) + fences[num_fences++] = dma_fence_get(fence); + } + } + + if (num_fences <= 1) { + result = num_fences ? fences[0] : NULL; + kfree(fences); + goto put_resv_fences; + } + + array = dma_fence_array_create(num_fences, fences, + dma_fence_context_alloc(1), + 1, false); + if (array) { + result = &array->base; + } else { + result = ERR_PTR(-ENOMEM); + while (num_fences--) + dma_fence_put(fences[num_fences]); + kfree(fences); + } + +put_resv_fences: + while (num_resv_fences--) + dma_fence_put(resv_fences[num_resv_fences]); + kfree(resv_fences); + + return result; +} +EXPORT_SYMBOL_GPL(dma_resv_get_singleton); + /** * dma_resv_wait_timeout - Wait on reservation's objects * shared and/or exclusive fences. diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h index 562b885cf9c3d..d60982975a786 100644 --- a/include/linux/dma-resv.h +++ b/include/linux/dma-resv.h @@ -275,6 +275,7 @@ void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence); int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl, unsigned *pshared_count, struct dma_fence ***pshared); int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src); +struct dma_fence *dma_resv_get_singleton(struct dma_resv *obj); long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr, unsigned long timeout); bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all);