1212#include <linux/dma-fence-chain.h>
1313#include <linux/dma-fence-unwrap.h>
1414#include <linux/slab.h>
15+ #include <linux/sort.h>
1516
1617/* Internal helper to start new array iteration, don't use directly */
1718static struct dma_fence *
@@ -59,6 +60,25 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
5960}
6061EXPORT_SYMBOL_GPL (dma_fence_unwrap_next );
6162
63+
64+ static int fence_cmp (const void * _a , const void * _b )
65+ {
66+ struct dma_fence * a = * (struct dma_fence * * )_a ;
67+ struct dma_fence * b = * (struct dma_fence * * )_b ;
68+
69+ if (a -> context < b -> context )
70+ return -1 ;
71+ else if (a -> context > b -> context )
72+ return 1 ;
73+
74+ if (dma_fence_is_later (b , a ))
75+ return 1 ;
76+ else if (dma_fence_is_later (a , b ))
77+ return -1 ;
78+
79+ return 0 ;
80+ }
81+
6282/* Implementation for the dma_fence_merge() marco, don't use directly */
6383struct dma_fence * __dma_fence_unwrap_merge (unsigned int num_fences ,
6484 struct dma_fence * * fences ,
@@ -67,8 +87,7 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
6787 struct dma_fence_array * result ;
6888 struct dma_fence * tmp , * * array ;
6989 ktime_t timestamp ;
70- unsigned int i ;
71- size_t count ;
90+ int i , j , count ;
7291
7392 count = 0 ;
7493 timestamp = ns_to_ktime (0 );
@@ -96,78 +115,55 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
96115 if (!array )
97116 return NULL ;
98117
99- /*
100- * This trashes the input fence array and uses it as position for the
101- * following merge loop. This works because the dma_fence_merge()
102- * wrapper macro is creating this temporary array on the stack together
103- * with the iterators.
104- */
105- for (i = 0 ; i < num_fences ; ++ i )
106- fences [i ] = dma_fence_unwrap_first (fences [i ], & iter [i ]);
107-
108118 count = 0 ;
109- do {
110- unsigned int sel ;
111-
112- restart :
113- tmp = NULL ;
114- for (i = 0 ; i < num_fences ; ++ i ) {
115- struct dma_fence * next ;
116-
117- while (fences [i ] && dma_fence_is_signaled (fences [i ]))
118- fences [i ] = dma_fence_unwrap_next (& iter [i ]);
119-
120- next = fences [i ];
121- if (!next )
122- continue ;
123-
124- /*
125- * We can't guarantee that inpute fences are ordered by
126- * context, but it is still quite likely when this
127- * function is used multiple times. So attempt to order
128- * the fences by context as we pass over them and merge
129- * fences with the same context.
130- */
131- if (!tmp || tmp -> context > next -> context ) {
132- tmp = next ;
133- sel = i ;
134-
135- } else if (tmp -> context < next -> context ) {
136- continue ;
137-
138- } else if (dma_fence_is_later (tmp , next )) {
139- fences [i ] = dma_fence_unwrap_next (& iter [i ]);
140- goto restart ;
119+ for (i = 0 ; i < num_fences ; ++ i ) {
120+ dma_fence_unwrap_for_each (tmp , & iter [i ], fences [i ]) {
121+ if (!dma_fence_is_signaled (tmp )) {
122+ array [count ++ ] = dma_fence_get (tmp );
141123 } else {
142- fences [sel ] = dma_fence_unwrap_next (& iter [sel ]);
143- goto restart ;
124+ ktime_t t = dma_fence_timestamp (tmp );
125+
126+ if (ktime_after (t , timestamp ))
127+ timestamp = t ;
144128 }
145129 }
130+ }
146131
147- if (tmp ) {
148- array [count ++ ] = dma_fence_get (tmp );
149- fences [sel ] = dma_fence_unwrap_next (& iter [sel ]);
150- }
151- } while (tmp );
132+ if (count == 0 || count == 1 )
133+ goto return_fastpath ;
152134
153- if (count == 0 ) {
154- tmp = dma_fence_allocate_private_stub (ktime_get ());
155- goto return_tmp ;
156- }
135+ sort (array , count , sizeof (* array ), fence_cmp , NULL );
157136
158- if (count == 1 ) {
159- tmp = array [0 ];
160- goto return_tmp ;
137+ /*
138+ * Only keep the most recent fence for each context.
139+ */
140+ j = 0 ;
141+ for (i = 1 ; i < count ; i ++ ) {
142+ if (array [i ]-> context == array [j ]-> context )
143+ dma_fence_put (array [i ]);
144+ else
145+ array [++ j ] = array [i ];
161146 }
162-
163- result = dma_fence_array_create (count , array ,
164- dma_fence_context_alloc (1 ),
165- 1 , false);
166- if (!result ) {
167- tmp = NULL ;
168- goto return_tmp ;
147+ count = ++ j ;
148+
149+ if (count > 1 ) {
150+ result = dma_fence_array_create (count , array ,
151+ dma_fence_context_alloc (1 ),
152+ 1 , false);
153+ if (!result ) {
154+ for (i = 0 ; i < count ; i ++ )
155+ dma_fence_put (array [i ]);
156+ tmp = NULL ;
157+ goto return_tmp ;
158+ }
159+ return & result -> base ;
169160 }
170- return & result -> base ;
161+
162+ return_fastpath :
163+ if (count == 0 )
164+ tmp = dma_fence_allocate_private_stub (timestamp );
165+ else
166+ tmp = array [0 ];
171167
172168return_tmp :
173169 kfree (array );
0 commit comments