xref: /openbmc/linux/drivers/dma-buf/dma-fence-unwrap.c (revision 278002edb19bce2c628fafb0af936e77000f3a5b)
101357a5aSChristian König // SPDX-License-Identifier: GPL-2.0-only
201357a5aSChristian König /*
301357a5aSChristian König  * dma-fence-util: misc functions for dma_fence objects
401357a5aSChristian König  *
501357a5aSChristian König  * Copyright (C) 2022 Advanced Micro Devices, Inc.
601357a5aSChristian König  * Authors:
701357a5aSChristian König  *	Christian König <christian.koenig@amd.com>
801357a5aSChristian König  */
901357a5aSChristian König 
1001357a5aSChristian König #include <linux/dma-fence.h>
1101357a5aSChristian König #include <linux/dma-fence-array.h>
1201357a5aSChristian König #include <linux/dma-fence-chain.h>
1301357a5aSChristian König #include <linux/dma-fence-unwrap.h>
14245a4a7bSChristian König #include <linux/slab.h>
15*5ea568e7STvrtko Ursulin #include <linux/sort.h>
1601357a5aSChristian König 
1701357a5aSChristian König /* Internal helper to start new array iteration, don't use directly */
1801357a5aSChristian König static struct dma_fence *
__dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)1901357a5aSChristian König __dma_fence_unwrap_array(struct dma_fence_unwrap *cursor)
2001357a5aSChristian König {
2101357a5aSChristian König 	cursor->array = dma_fence_chain_contained(cursor->chain);
2201357a5aSChristian König 	cursor->index = 0;
2301357a5aSChristian König 	return dma_fence_array_first(cursor->array);
2401357a5aSChristian König }
2501357a5aSChristian König 
2601357a5aSChristian König /**
2701357a5aSChristian König  * dma_fence_unwrap_first - return the first fence from fence containers
2801357a5aSChristian König  * @head: the entrypoint into the containers
2901357a5aSChristian König  * @cursor: current position inside the containers
3001357a5aSChristian König  *
3101357a5aSChristian König  * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
3201357a5aSChristian König  * first fence.
3301357a5aSChristian König  */
dma_fence_unwrap_first(struct dma_fence * head,struct dma_fence_unwrap * cursor)3401357a5aSChristian König struct dma_fence *dma_fence_unwrap_first(struct dma_fence *head,
3501357a5aSChristian König 					 struct dma_fence_unwrap *cursor)
3601357a5aSChristian König {
3701357a5aSChristian König 	cursor->chain = dma_fence_get(head);
3801357a5aSChristian König 	return __dma_fence_unwrap_array(cursor);
3901357a5aSChristian König }
4001357a5aSChristian König EXPORT_SYMBOL_GPL(dma_fence_unwrap_first);
4101357a5aSChristian König 
4201357a5aSChristian König /**
4301357a5aSChristian König  * dma_fence_unwrap_next - return the next fence from a fence containers
4401357a5aSChristian König  * @cursor: current position inside the containers
4501357a5aSChristian König  *
4601357a5aSChristian König  * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
4701357a5aSChristian König  * the next fence from them.
4801357a5aSChristian König  */
dma_fence_unwrap_next(struct dma_fence_unwrap * cursor)4901357a5aSChristian König struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
5001357a5aSChristian König {
5101357a5aSChristian König 	struct dma_fence *tmp;
5201357a5aSChristian König 
5301357a5aSChristian König 	++cursor->index;
5401357a5aSChristian König 	tmp = dma_fence_array_next(cursor->array, cursor->index);
5501357a5aSChristian König 	if (tmp)
5601357a5aSChristian König 		return tmp;
5701357a5aSChristian König 
5801357a5aSChristian König 	cursor->chain = dma_fence_chain_walk(cursor->chain);
5901357a5aSChristian König 	return __dma_fence_unwrap_array(cursor);
6001357a5aSChristian König }
6101357a5aSChristian König EXPORT_SYMBOL_GPL(dma_fence_unwrap_next);
62245a4a7bSChristian König 
63*5ea568e7STvrtko Ursulin 
fence_cmp(const void * _a,const void * _b)64*5ea568e7STvrtko Ursulin static int fence_cmp(const void *_a, const void *_b)
65*5ea568e7STvrtko Ursulin {
66*5ea568e7STvrtko Ursulin 	struct dma_fence *a = *(struct dma_fence **)_a;
67*5ea568e7STvrtko Ursulin 	struct dma_fence *b = *(struct dma_fence **)_b;
68*5ea568e7STvrtko Ursulin 
69*5ea568e7STvrtko Ursulin 	if (a->context < b->context)
70*5ea568e7STvrtko Ursulin 		return -1;
71*5ea568e7STvrtko Ursulin 	else if (a->context > b->context)
72*5ea568e7STvrtko Ursulin 		return 1;
73*5ea568e7STvrtko Ursulin 
74*5ea568e7STvrtko Ursulin 	if (dma_fence_is_later(b, a))
75*5ea568e7STvrtko Ursulin 		return 1;
76*5ea568e7STvrtko Ursulin 	else if (dma_fence_is_later(a, b))
77*5ea568e7STvrtko Ursulin 		return -1;
78*5ea568e7STvrtko Ursulin 
79*5ea568e7STvrtko Ursulin 	return 0;
80*5ea568e7STvrtko Ursulin }
81*5ea568e7STvrtko Ursulin 
82245a4a7bSChristian König /* Implementation for the dma_fence_merge() marco, don't use directly */
__dma_fence_unwrap_merge(unsigned int num_fences,struct dma_fence ** fences,struct dma_fence_unwrap * iter)83245a4a7bSChristian König struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
84245a4a7bSChristian König 					   struct dma_fence **fences,
85245a4a7bSChristian König 					   struct dma_fence_unwrap *iter)
86245a4a7bSChristian König {
87245a4a7bSChristian König 	struct dma_fence_array *result;
88245a4a7bSChristian König 	struct dma_fence *tmp, **array;
89f781f661SChristian König 	ktime_t timestamp;
90*5ea568e7STvrtko Ursulin 	int i, j, count;
91245a4a7bSChristian König 
92245a4a7bSChristian König 	count = 0;
93f781f661SChristian König 	timestamp = ns_to_ktime(0);
94245a4a7bSChristian König 	for (i = 0; i < num_fences; ++i) {
95f781f661SChristian König 		dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
96f781f661SChristian König 			if (!dma_fence_is_signaled(tmp)) {
97245a4a7bSChristian König 				++count;
98f781f661SChristian König 			} else {
99b83ce9cbSChristian König 				ktime_t t = dma_fence_timestamp(tmp);
100b83ce9cbSChristian König 
101b83ce9cbSChristian König 				if (ktime_after(t, timestamp))
102b83ce9cbSChristian König 					timestamp = t;
103f781f661SChristian König 			}
104f781f661SChristian König 		}
105245a4a7bSChristian König 	}
106245a4a7bSChristian König 
107f781f661SChristian König 	/*
108f781f661SChristian König 	 * If we couldn't find a pending fence just return a private signaled
109f781f661SChristian König 	 * fence with the timestamp of the last signaled one.
110f781f661SChristian König 	 */
111245a4a7bSChristian König 	if (count == 0)
112f781f661SChristian König 		return dma_fence_allocate_private_stub(timestamp);
113245a4a7bSChristian König 
114245a4a7bSChristian König 	array = kmalloc_array(count, sizeof(*array), GFP_KERNEL);
115245a4a7bSChristian König 	if (!array)
116245a4a7bSChristian König 		return NULL;
117245a4a7bSChristian König 
118245a4a7bSChristian König 	count = 0;
119245a4a7bSChristian König 	for (i = 0; i < num_fences; ++i) {
120*5ea568e7STvrtko Ursulin 		dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
121*5ea568e7STvrtko Ursulin 			if (!dma_fence_is_signaled(tmp)) {
122*5ea568e7STvrtko Ursulin 				array[count++] = dma_fence_get(tmp);
123*5ea568e7STvrtko Ursulin 			} else {
124*5ea568e7STvrtko Ursulin 				ktime_t t = dma_fence_timestamp(tmp);
125245a4a7bSChristian König 
126*5ea568e7STvrtko Ursulin 				if (ktime_after(t, timestamp))
127*5ea568e7STvrtko Ursulin 					timestamp = t;
128*5ea568e7STvrtko Ursulin 			}
129*5ea568e7STvrtko Ursulin 		}
130*5ea568e7STvrtko Ursulin 	}
131245a4a7bSChristian König 
132*5ea568e7STvrtko Ursulin 	if (count == 0 || count == 1)
133*5ea568e7STvrtko Ursulin 		goto return_fastpath;
134*5ea568e7STvrtko Ursulin 
135*5ea568e7STvrtko Ursulin 	sort(array, count, sizeof(*array), fence_cmp, NULL);
136245a4a7bSChristian König 
137245a4a7bSChristian König 	/*
138*5ea568e7STvrtko Ursulin 	 * Only keep the most recent fence for each context.
139245a4a7bSChristian König 	 */
140*5ea568e7STvrtko Ursulin 	j = 0;
141*5ea568e7STvrtko Ursulin 	for (i = 1; i < count; i++) {
142*5ea568e7STvrtko Ursulin 		if (array[i]->context == array[j]->context)
143*5ea568e7STvrtko Ursulin 			dma_fence_put(array[i]);
144*5ea568e7STvrtko Ursulin 		else
145*5ea568e7STvrtko Ursulin 			array[++j] = array[i];
146245a4a7bSChristian König 	}
147*5ea568e7STvrtko Ursulin 	count = ++j;
148245a4a7bSChristian König 
149*5ea568e7STvrtko Ursulin 	if (count > 1) {
150245a4a7bSChristian König 		result = dma_fence_array_create(count, array,
151245a4a7bSChristian König 						dma_fence_context_alloc(1),
152245a4a7bSChristian König 						1, false);
153245a4a7bSChristian König 		if (!result) {
154ce97e789STvrtko Ursulin 			for (i = 0; i < count; i++)
155ce97e789STvrtko Ursulin 				dma_fence_put(array[i]);
156245a4a7bSChristian König 			tmp = NULL;
157245a4a7bSChristian König 			goto return_tmp;
158245a4a7bSChristian König 		}
159245a4a7bSChristian König 		return &result->base;
160*5ea568e7STvrtko Ursulin 	}
161*5ea568e7STvrtko Ursulin 
162*5ea568e7STvrtko Ursulin return_fastpath:
163*5ea568e7STvrtko Ursulin 	if (count == 0)
164*5ea568e7STvrtko Ursulin 		tmp = dma_fence_allocate_private_stub(timestamp);
165*5ea568e7STvrtko Ursulin 	else
166*5ea568e7STvrtko Ursulin 		tmp = array[0];
167245a4a7bSChristian König 
168245a4a7bSChristian König return_tmp:
169245a4a7bSChristian König 	kfree(array);
170245a4a7bSChristian König 	return tmp;
171245a4a7bSChristian König }
172245a4a7bSChristian König EXPORT_SYMBOL_GPL(__dma_fence_unwrap_merge);
173