12
12
#include <linux/dma-fence-chain.h>
13
13
#include <linux/dma-fence-unwrap.h>
14
14
#include <linux/slab.h>
15
+ #include <linux/sort.h>
15
16
16
17
/* Internal helper to start new array iteration, don't use directly */
17
18
static struct dma_fence *
@@ -59,6 +60,25 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
59
60
}
60
61
EXPORT_SYMBOL_GPL (dma_fence_unwrap_next );
61
62
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
+
62
82
/* Implementation for the dma_fence_merge() marco, don't use directly */
63
83
struct dma_fence * __dma_fence_unwrap_merge (unsigned int num_fences ,
64
84
struct dma_fence * * fences ,
@@ -67,8 +87,7 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
67
87
struct dma_fence_array * result ;
68
88
struct dma_fence * tmp , * * array ;
69
89
ktime_t timestamp ;
70
- unsigned int i ;
71
- size_t count ;
90
+ int i , j , count ;
72
91
73
92
count = 0 ;
74
93
timestamp = ns_to_ktime (0 );
@@ -96,78 +115,55 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
96
115
if (!array )
97
116
return NULL ;
98
117
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
-
108
118
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 );
141
123
} 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 ;
144
128
}
145
129
}
130
+ }
146
131
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 ;
152
134
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 );
157
136
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 ];
161
146
}
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 ;
169
160
}
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 ];
171
167
172
168
return_tmp :
173
169
kfree (array );
0 commit comments