162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * dma-fence-array: aggregate fences to be waited together 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2016 Collabora Ltd 662306a36Sopenharmony_ci * Copyright (C) 2016 Advanced Micro Devices, Inc. 762306a36Sopenharmony_ci * Authors: 862306a36Sopenharmony_ci * Gustavo Padovan <gustavo@padovan.org> 962306a36Sopenharmony_ci * Christian König <christian.koenig@amd.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/export.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/dma-fence-array.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define PENDING_ERROR 1 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic const char *dma_fence_array_get_driver_name(struct dma_fence *fence) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci return "dma_fence_array"; 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic const char *dma_fence_array_get_timeline_name(struct dma_fence *fence) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci return "unbound"; 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void dma_fence_array_set_pending_error(struct dma_fence_array *array, 2962306a36Sopenharmony_ci int error) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci /* 3262306a36Sopenharmony_ci * Propagate the first error reported by any of our fences, but only 3362306a36Sopenharmony_ci * before we ourselves are signaled. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci if (error) 3662306a36Sopenharmony_ci cmpxchg(&array->base.error, PENDING_ERROR, error); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic void dma_fence_array_clear_pending_error(struct dma_fence_array *array) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci /* Clear the error flag if not actually set. */ 4262306a36Sopenharmony_ci cmpxchg(&array->base.error, PENDING_ERROR, 0); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic void irq_dma_fence_array_work(struct irq_work *wrk) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci struct dma_fence_array *array = container_of(wrk, typeof(*array), work); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci dma_fence_array_clear_pending_error(array); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci dma_fence_signal(&array->base); 5262306a36Sopenharmony_ci dma_fence_put(&array->base); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void dma_fence_array_cb_func(struct dma_fence *f, 5662306a36Sopenharmony_ci struct dma_fence_cb *cb) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct dma_fence_array_cb *array_cb = 5962306a36Sopenharmony_ci container_of(cb, struct dma_fence_array_cb, cb); 6062306a36Sopenharmony_ci struct dma_fence_array *array = array_cb->array; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci dma_fence_array_set_pending_error(array, f->error); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (atomic_dec_and_test(&array->num_pending)) 6562306a36Sopenharmony_ci irq_work_queue(&array->work); 6662306a36Sopenharmony_ci else 6762306a36Sopenharmony_ci dma_fence_put(&array->base); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic bool dma_fence_array_enable_signaling(struct dma_fence *fence) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct dma_fence_array *array = to_dma_fence_array(fence); 7362306a36Sopenharmony_ci struct dma_fence_array_cb *cb = (void *)(&array[1]); 7462306a36Sopenharmony_ci unsigned i; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci for (i = 0; i < array->num_fences; ++i) { 7762306a36Sopenharmony_ci cb[i].array = array; 7862306a36Sopenharmony_ci /* 7962306a36Sopenharmony_ci * As we may report that the fence is signaled before all 8062306a36Sopenharmony_ci * callbacks are complete, we need to take an additional 8162306a36Sopenharmony_ci * reference count on the array so that we do not free it too 8262306a36Sopenharmony_ci * early. The core fence handling will only hold the reference 8362306a36Sopenharmony_ci * until we signal the array as complete (but that is now 8462306a36Sopenharmony_ci * insufficient). 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci dma_fence_get(&array->base); 8762306a36Sopenharmony_ci if (dma_fence_add_callback(array->fences[i], &cb[i].cb, 8862306a36Sopenharmony_ci dma_fence_array_cb_func)) { 8962306a36Sopenharmony_ci int error = array->fences[i]->error; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci dma_fence_array_set_pending_error(array, error); 9262306a36Sopenharmony_ci dma_fence_put(&array->base); 9362306a36Sopenharmony_ci if (atomic_dec_and_test(&array->num_pending)) { 9462306a36Sopenharmony_ci dma_fence_array_clear_pending_error(array); 9562306a36Sopenharmony_ci return false; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return true; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic bool dma_fence_array_signaled(struct dma_fence *fence) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct dma_fence_array *array = to_dma_fence_array(fence); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (atomic_read(&array->num_pending) > 0) 10862306a36Sopenharmony_ci return false; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci dma_fence_array_clear_pending_error(array); 11162306a36Sopenharmony_ci return true; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic void dma_fence_array_release(struct dma_fence *fence) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct dma_fence_array *array = to_dma_fence_array(fence); 11762306a36Sopenharmony_ci unsigned i; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci for (i = 0; i < array->num_fences; ++i) 12062306a36Sopenharmony_ci dma_fence_put(array->fences[i]); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci kfree(array->fences); 12362306a36Sopenharmony_ci dma_fence_free(fence); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void dma_fence_array_set_deadline(struct dma_fence *fence, 12762306a36Sopenharmony_ci ktime_t deadline) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct dma_fence_array *array = to_dma_fence_array(fence); 13062306a36Sopenharmony_ci unsigned i; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci for (i = 0; i < array->num_fences; ++i) 13362306a36Sopenharmony_ci dma_fence_set_deadline(array->fences[i], deadline); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ciconst struct dma_fence_ops dma_fence_array_ops = { 13762306a36Sopenharmony_ci .get_driver_name = dma_fence_array_get_driver_name, 13862306a36Sopenharmony_ci .get_timeline_name = dma_fence_array_get_timeline_name, 13962306a36Sopenharmony_ci .enable_signaling = dma_fence_array_enable_signaling, 14062306a36Sopenharmony_ci .signaled = dma_fence_array_signaled, 14162306a36Sopenharmony_ci .release = dma_fence_array_release, 14262306a36Sopenharmony_ci .set_deadline = dma_fence_array_set_deadline, 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ciEXPORT_SYMBOL(dma_fence_array_ops); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/** 14762306a36Sopenharmony_ci * dma_fence_array_create - Create a custom fence array 14862306a36Sopenharmony_ci * @num_fences: [in] number of fences to add in the array 14962306a36Sopenharmony_ci * @fences: [in] array containing the fences 15062306a36Sopenharmony_ci * @context: [in] fence context to use 15162306a36Sopenharmony_ci * @seqno: [in] sequence number to use 15262306a36Sopenharmony_ci * @signal_on_any: [in] signal on any fence in the array 15362306a36Sopenharmony_ci * 15462306a36Sopenharmony_ci * Allocate a dma_fence_array object and initialize the base fence with 15562306a36Sopenharmony_ci * dma_fence_init(). 15662306a36Sopenharmony_ci * In case of error it returns NULL. 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * The caller should allocate the fences array with num_fences size 15962306a36Sopenharmony_ci * and fill it with the fences it wants to add to the object. Ownership of this 16062306a36Sopenharmony_ci * array is taken and dma_fence_put() is used on each fence on release. 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci * If @signal_on_any is true the fence array signals if any fence in the array 16362306a36Sopenharmony_ci * signals, otherwise it signals when all fences in the array signal. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_cistruct dma_fence_array *dma_fence_array_create(int num_fences, 16662306a36Sopenharmony_ci struct dma_fence **fences, 16762306a36Sopenharmony_ci u64 context, unsigned seqno, 16862306a36Sopenharmony_ci bool signal_on_any) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct dma_fence_array *array; 17162306a36Sopenharmony_ci size_t size = sizeof(*array); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci WARN_ON(!num_fences || !fences); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Allocate the callback structures behind the array. */ 17662306a36Sopenharmony_ci size += num_fences * sizeof(struct dma_fence_array_cb); 17762306a36Sopenharmony_ci array = kzalloc(size, GFP_KERNEL); 17862306a36Sopenharmony_ci if (!array) 17962306a36Sopenharmony_ci return NULL; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci spin_lock_init(&array->lock); 18262306a36Sopenharmony_ci dma_fence_init(&array->base, &dma_fence_array_ops, &array->lock, 18362306a36Sopenharmony_ci context, seqno); 18462306a36Sopenharmony_ci init_irq_work(&array->work, irq_dma_fence_array_work); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci array->num_fences = num_fences; 18762306a36Sopenharmony_ci atomic_set(&array->num_pending, signal_on_any ? 1 : num_fences); 18862306a36Sopenharmony_ci array->fences = fences; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci array->base.error = PENDING_ERROR; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* 19362306a36Sopenharmony_ci * dma_fence_array objects should never contain any other fence 19462306a36Sopenharmony_ci * containers or otherwise we run into recursion and potential kernel 19562306a36Sopenharmony_ci * stack overflow on operations on the dma_fence_array. 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * The correct way of handling this is to flatten out the array by the 19862306a36Sopenharmony_ci * caller instead. 19962306a36Sopenharmony_ci * 20062306a36Sopenharmony_ci * Enforce this here by checking that we don't create a dma_fence_array 20162306a36Sopenharmony_ci * with any container inside. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci while (num_fences--) 20462306a36Sopenharmony_ci WARN_ON(dma_fence_is_container(fences[num_fences])); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci return array; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ciEXPORT_SYMBOL(dma_fence_array_create); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/** 21162306a36Sopenharmony_ci * dma_fence_match_context - Check if all fences are from the given context 21262306a36Sopenharmony_ci * @fence: [in] fence or fence array 21362306a36Sopenharmony_ci * @context: [in] fence context to check all fences against 21462306a36Sopenharmony_ci * 21562306a36Sopenharmony_ci * Checks the provided fence or, for a fence array, all fences in the array 21662306a36Sopenharmony_ci * against the given context. Returns false if any fence is from a different 21762306a36Sopenharmony_ci * context. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_cibool dma_fence_match_context(struct dma_fence *fence, u64 context) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct dma_fence_array *array = to_dma_fence_array(fence); 22262306a36Sopenharmony_ci unsigned i; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (!dma_fence_is_array(fence)) 22562306a36Sopenharmony_ci return fence->context == context; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci for (i = 0; i < array->num_fences; i++) { 22862306a36Sopenharmony_ci if (array->fences[i]->context != context) 22962306a36Sopenharmony_ci return false; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return true; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ciEXPORT_SYMBOL(dma_fence_match_context); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistruct dma_fence *dma_fence_array_first(struct dma_fence *head) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct dma_fence_array *array; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!head) 24162306a36Sopenharmony_ci return NULL; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci array = to_dma_fence_array(head); 24462306a36Sopenharmony_ci if (!array) 24562306a36Sopenharmony_ci return head; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (!array->num_fences) 24862306a36Sopenharmony_ci return NULL; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return array->fences[0]; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ciEXPORT_SYMBOL(dma_fence_array_first); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistruct dma_fence *dma_fence_array_next(struct dma_fence *head, 25562306a36Sopenharmony_ci unsigned int index) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct dma_fence_array *array = to_dma_fence_array(head); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (!array || index >= array->num_fences) 26062306a36Sopenharmony_ci return NULL; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return array->fences[index]; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ciEXPORT_SYMBOL(dma_fence_array_next); 265