]>
Commit | Line | Data |
---|---|---|
a8c21a54 T |
1 | /* |
2 | * Copyright (C) 2015 Etnaviv Project | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License version 2 as published by | |
6 | * the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License along with | |
14 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | */ | |
16 | ||
9ad59fea | 17 | #include <linux/dma-fence-array.h> |
a8c21a54 | 18 | #include <linux/reservation.h> |
9ad59fea | 19 | #include <linux/sync_file.h> |
ea1f5729 | 20 | #include "etnaviv_cmdbuf.h" |
a8c21a54 T |
21 | #include "etnaviv_drv.h" |
22 | #include "etnaviv_gpu.h" | |
23 | #include "etnaviv_gem.h" | |
c8e4a7fd | 24 | #include "etnaviv_perfmon.h" |
a8c21a54 T |
25 | |
26 | /* | |
27 | * Cmdstream submission: | |
28 | */ | |
29 | ||
30 | #define BO_INVALID_FLAGS ~(ETNA_SUBMIT_BO_READ | ETNA_SUBMIT_BO_WRITE) | |
31 | /* make sure these don't conflict w/ ETNAVIV_SUBMIT_BO_x */ | |
32 | #define BO_LOCKED 0x4000 | |
33 | #define BO_PINNED 0x2000 | |
34 | ||
a8c21a54 T |
35 | static struct etnaviv_gem_submit *submit_create(struct drm_device *dev, |
36 | struct etnaviv_gpu *gpu, size_t nr) | |
37 | { | |
38 | struct etnaviv_gem_submit *submit; | |
39 | size_t sz = size_vstruct(nr, sizeof(submit->bos[0]), sizeof(*submit)); | |
40 | ||
c5283723 LS |
41 | submit = kzalloc(sz, GFP_KERNEL); |
42 | if (!submit) | |
43 | return NULL; | |
a8c21a54 | 44 | |
c5283723 | 45 | submit->gpu = gpu; |
a8c21a54 | 46 | |
c5283723 | 47 | ww_acquire_init(&submit->ticket, &reservation_ww_class); |
a8c21a54 T |
48 | |
49 | return submit; | |
50 | } | |
51 | ||
52 | static int submit_lookup_objects(struct etnaviv_gem_submit *submit, | |
53 | struct drm_file *file, struct drm_etnaviv_gem_submit_bo *submit_bos, | |
54 | unsigned nr_bos) | |
55 | { | |
56 | struct drm_etnaviv_gem_submit_bo *bo; | |
57 | unsigned i; | |
58 | int ret = 0; | |
59 | ||
60 | spin_lock(&file->table_lock); | |
61 | ||
62 | for (i = 0, bo = submit_bos; i < nr_bos; i++, bo++) { | |
63 | struct drm_gem_object *obj; | |
64 | ||
65 | if (bo->flags & BO_INVALID_FLAGS) { | |
66 | DRM_ERROR("invalid flags: %x\n", bo->flags); | |
67 | ret = -EINVAL; | |
68 | goto out_unlock; | |
69 | } | |
70 | ||
71 | submit->bos[i].flags = bo->flags; | |
72 | ||
73 | /* normally use drm_gem_object_lookup(), but for bulk lookup | |
74 | * all under single table_lock just hit object_idr directly: | |
75 | */ | |
76 | obj = idr_find(&file->object_idr, bo->handle); | |
77 | if (!obj) { | |
78 | DRM_ERROR("invalid handle %u at index %u\n", | |
79 | bo->handle, i); | |
80 | ret = -EINVAL; | |
81 | goto out_unlock; | |
82 | } | |
83 | ||
84 | /* | |
85 | * Take a refcount on the object. The file table lock | |
86 | * prevents the object_idr's refcount on this being dropped. | |
87 | */ | |
23d1dd03 | 88 | drm_gem_object_get(obj); |
a8c21a54 T |
89 | |
90 | submit->bos[i].obj = to_etnaviv_bo(obj); | |
91 | } | |
92 | ||
93 | out_unlock: | |
94 | submit->nr_bos = i; | |
95 | spin_unlock(&file->table_lock); | |
96 | ||
97 | return ret; | |
98 | } | |
99 | ||
100 | static void submit_unlock_object(struct etnaviv_gem_submit *submit, int i) | |
101 | { | |
102 | if (submit->bos[i].flags & BO_LOCKED) { | |
103 | struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; | |
104 | ||
105 | ww_mutex_unlock(&etnaviv_obj->resv->lock); | |
106 | submit->bos[i].flags &= ~BO_LOCKED; | |
107 | } | |
108 | } | |
109 | ||
110 | static int submit_lock_objects(struct etnaviv_gem_submit *submit) | |
111 | { | |
112 | int contended, slow_locked = -1, i, ret = 0; | |
113 | ||
114 | retry: | |
115 | for (i = 0; i < submit->nr_bos; i++) { | |
116 | struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; | |
117 | ||
118 | if (slow_locked == i) | |
119 | slow_locked = -1; | |
120 | ||
121 | contended = i; | |
122 | ||
123 | if (!(submit->bos[i].flags & BO_LOCKED)) { | |
124 | ret = ww_mutex_lock_interruptible(&etnaviv_obj->resv->lock, | |
125 | &submit->ticket); | |
126 | if (ret == -EALREADY) | |
127 | DRM_ERROR("BO at index %u already on submit list\n", | |
128 | i); | |
129 | if (ret) | |
130 | goto fail; | |
131 | submit->bos[i].flags |= BO_LOCKED; | |
132 | } | |
133 | } | |
134 | ||
135 | ww_acquire_done(&submit->ticket); | |
136 | ||
137 | return 0; | |
138 | ||
139 | fail: | |
140 | for (; i >= 0; i--) | |
141 | submit_unlock_object(submit, i); | |
142 | ||
143 | if (slow_locked > 0) | |
144 | submit_unlock_object(submit, slow_locked); | |
145 | ||
146 | if (ret == -EDEADLK) { | |
147 | struct etnaviv_gem_object *etnaviv_obj; | |
148 | ||
149 | etnaviv_obj = submit->bos[contended].obj; | |
150 | ||
151 | /* we lost out in a seqno race, lock and retry.. */ | |
152 | ret = ww_mutex_lock_slow_interruptible(&etnaviv_obj->resv->lock, | |
153 | &submit->ticket); | |
154 | if (!ret) { | |
155 | submit->bos[contended].flags |= BO_LOCKED; | |
156 | slow_locked = contended; | |
157 | goto retry; | |
158 | } | |
159 | } | |
160 | ||
161 | return ret; | |
162 | } | |
163 | ||
164 | static int submit_fence_sync(const struct etnaviv_gem_submit *submit) | |
165 | { | |
166 | unsigned int context = submit->gpu->fence_context; | |
167 | int i, ret = 0; | |
168 | ||
169 | for (i = 0; i < submit->nr_bos; i++) { | |
170 | struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; | |
171 | bool write = submit->bos[i].flags & ETNA_SUBMIT_BO_WRITE; | |
426ef1bb | 172 | bool explicit = !!(submit->flags & ETNA_SUBMIT_NO_IMPLICIT); |
a8c21a54 | 173 | |
9ad59fea PZ |
174 | ret = etnaviv_gpu_fence_sync_obj(etnaviv_obj, context, write, |
175 | explicit); | |
a8c21a54 T |
176 | if (ret) |
177 | break; | |
178 | } | |
179 | ||
9efabd73 LS |
180 | if (submit->flags & ETNA_SUBMIT_FENCE_FD_IN) { |
181 | /* | |
182 | * Wait if the fence is from a foreign context, or if the fence | |
183 | * array contains any fence from a foreign context. | |
184 | */ | |
185 | if (!dma_fence_match_context(submit->in_fence, context)) | |
186 | ret = dma_fence_wait(submit->in_fence, true); | |
187 | } | |
188 | ||
a8c21a54 T |
189 | return ret; |
190 | } | |
191 | ||
0236efe9 LS |
192 | static void submit_attach_object_fences(struct etnaviv_gem_submit *submit) |
193 | { | |
194 | int i; | |
195 | ||
196 | for (i = 0; i < submit->nr_bos; i++) { | |
197 | struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; | |
198 | ||
199 | if (submit->bos[i].flags & ETNA_SUBMIT_BO_WRITE) | |
200 | reservation_object_add_excl_fence(etnaviv_obj->resv, | |
10009ea2 | 201 | submit->out_fence); |
0236efe9 LS |
202 | else |
203 | reservation_object_add_shared_fence(etnaviv_obj->resv, | |
10009ea2 | 204 | submit->out_fence); |
0236efe9 LS |
205 | |
206 | submit_unlock_object(submit, i); | |
207 | } | |
208 | } | |
209 | ||
a8c21a54 T |
210 | static int submit_pin_objects(struct etnaviv_gem_submit *submit) |
211 | { | |
212 | int i, ret = 0; | |
213 | ||
214 | for (i = 0; i < submit->nr_bos; i++) { | |
215 | struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; | |
b6325f40 | 216 | struct etnaviv_vram_mapping *mapping; |
a8c21a54 | 217 | |
b6325f40 RK |
218 | mapping = etnaviv_gem_mapping_get(&etnaviv_obj->base, |
219 | submit->gpu); | |
220 | if (IS_ERR(mapping)) { | |
221 | ret = PTR_ERR(mapping); | |
a8c21a54 | 222 | break; |
b6325f40 | 223 | } |
a8c21a54 T |
224 | |
225 | submit->bos[i].flags |= BO_PINNED; | |
b6325f40 | 226 | submit->bos[i].mapping = mapping; |
a8c21a54 T |
227 | } |
228 | ||
229 | return ret; | |
230 | } | |
231 | ||
232 | static int submit_bo(struct etnaviv_gem_submit *submit, u32 idx, | |
8779aa8f | 233 | struct etnaviv_gem_submit_bo **bo) |
a8c21a54 T |
234 | { |
235 | if (idx >= submit->nr_bos) { | |
236 | DRM_ERROR("invalid buffer index: %u (out of %u)\n", | |
237 | idx, submit->nr_bos); | |
238 | return -EINVAL; | |
239 | } | |
240 | ||
8779aa8f | 241 | *bo = &submit->bos[idx]; |
a8c21a54 T |
242 | |
243 | return 0; | |
244 | } | |
245 | ||
246 | /* process the reloc's and patch up the cmdstream as needed: */ | |
247 | static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream, | |
248 | u32 size, const struct drm_etnaviv_gem_submit_reloc *relocs, | |
249 | u32 nr_relocs) | |
250 | { | |
251 | u32 i, last_offset = 0; | |
252 | u32 *ptr = stream; | |
253 | int ret; | |
254 | ||
255 | for (i = 0; i < nr_relocs; i++) { | |
256 | const struct drm_etnaviv_gem_submit_reloc *r = relocs + i; | |
8779aa8f RK |
257 | struct etnaviv_gem_submit_bo *bo; |
258 | u32 off; | |
a8c21a54 T |
259 | |
260 | if (unlikely(r->flags)) { | |
261 | DRM_ERROR("invalid reloc flags\n"); | |
262 | return -EINVAL; | |
263 | } | |
264 | ||
265 | if (r->submit_offset % 4) { | |
266 | DRM_ERROR("non-aligned reloc offset: %u\n", | |
267 | r->submit_offset); | |
268 | return -EINVAL; | |
269 | } | |
270 | ||
271 | /* offset in dwords: */ | |
272 | off = r->submit_offset / 4; | |
273 | ||
274 | if ((off >= size ) || | |
275 | (off < last_offset)) { | |
276 | DRM_ERROR("invalid offset %u at reloc %u\n", off, i); | |
277 | return -EINVAL; | |
278 | } | |
279 | ||
8779aa8f | 280 | ret = submit_bo(submit, r->reloc_idx, &bo); |
a8c21a54 T |
281 | if (ret) |
282 | return ret; | |
283 | ||
d6f756e0 WL |
284 | if (r->reloc_offset > bo->obj->base.size - sizeof(*ptr)) { |
285 | DRM_ERROR("relocation %u outside object\n", i); | |
a8c21a54 T |
286 | return -EINVAL; |
287 | } | |
288 | ||
8779aa8f | 289 | ptr[off] = bo->mapping->iova + r->reloc_offset; |
a8c21a54 T |
290 | |
291 | last_offset = off; | |
292 | } | |
293 | ||
294 | return 0; | |
295 | } | |
296 | ||
c8e4a7fd CG |
297 | static int submit_perfmon_validate(struct etnaviv_gem_submit *submit, |
298 | struct etnaviv_cmdbuf *cmdbuf, | |
299 | const struct drm_etnaviv_gem_submit_pmr *pmrs, | |
300 | u32 nr_pms) | |
301 | { | |
302 | u32 i; | |
303 | ||
304 | for (i = 0; i < nr_pms; i++) { | |
305 | const struct drm_etnaviv_gem_submit_pmr *r = pmrs + i; | |
306 | struct etnaviv_gem_submit_bo *bo; | |
307 | int ret; | |
308 | ||
309 | ret = submit_bo(submit, r->read_idx, &bo); | |
310 | if (ret) | |
311 | return ret; | |
312 | ||
313 | /* at offset 0 a sequence number gets stored used for userspace sync */ | |
314 | if (r->read_offset == 0) { | |
315 | DRM_ERROR("perfmon request: offset is 0"); | |
316 | return -EINVAL; | |
317 | } | |
318 | ||
319 | if (r->read_offset >= bo->obj->base.size - sizeof(u32)) { | |
320 | DRM_ERROR("perfmon request: offset %u outside object", i); | |
321 | return -EINVAL; | |
322 | } | |
323 | ||
324 | if (r->flags & ~(ETNA_PM_PROCESS_PRE | ETNA_PM_PROCESS_POST)) { | |
325 | DRM_ERROR("perfmon request: flags are not valid"); | |
326 | return -EINVAL; | |
327 | } | |
328 | ||
329 | if (etnaviv_pm_req_validate(r, cmdbuf->exec_state)) { | |
330 | DRM_ERROR("perfmon request: domain or signal not valid"); | |
331 | return -EINVAL; | |
332 | } | |
333 | ||
334 | cmdbuf->pmrs[i].flags = r->flags; | |
335 | cmdbuf->pmrs[i].domain = r->domain; | |
336 | cmdbuf->pmrs[i].signal = r->signal; | |
337 | cmdbuf->pmrs[i].sequence = r->sequence; | |
338 | cmdbuf->pmrs[i].offset = r->read_offset; | |
339 | cmdbuf->pmrs[i].bo_vma = etnaviv_gem_vmap(&bo->obj->base); | |
340 | } | |
341 | ||
342 | return 0; | |
343 | } | |
344 | ||
a8c21a54 T |
345 | static void submit_cleanup(struct etnaviv_gem_submit *submit) |
346 | { | |
347 | unsigned i; | |
348 | ||
349 | for (i = 0; i < submit->nr_bos; i++) { | |
350 | struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; | |
351 | ||
33a63e68 LS |
352 | /* unpin all objects */ |
353 | if (submit->bos[i].flags & BO_PINNED) { | |
354 | etnaviv_gem_mapping_unreference(submit->bos[i].mapping); | |
355 | submit->bos[i].mapping = NULL; | |
356 | submit->bos[i].flags &= ~BO_PINNED; | |
357 | } | |
358 | ||
0236efe9 | 359 | /* if the GPU submit failed, objects might still be locked */ |
a8c21a54 | 360 | submit_unlock_object(submit, i); |
23d1dd03 | 361 | drm_gem_object_put_unlocked(&etnaviv_obj->base); |
a8c21a54 T |
362 | } |
363 | ||
364 | ww_acquire_fini(&submit->ticket); | |
9efabd73 LS |
365 | if (submit->in_fence) |
366 | dma_fence_put(submit->in_fence); | |
10009ea2 LS |
367 | if (submit->out_fence) |
368 | dma_fence_put(submit->out_fence); | |
a8c21a54 T |
369 | kfree(submit); |
370 | } | |
371 | ||
372 | int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, | |
373 | struct drm_file *file) | |
374 | { | |
375 | struct etnaviv_drm_private *priv = dev->dev_private; | |
376 | struct drm_etnaviv_gem_submit *args = data; | |
377 | struct drm_etnaviv_gem_submit_reloc *relocs; | |
c8e4a7fd | 378 | struct drm_etnaviv_gem_submit_pmr *pmrs; |
a8c21a54 T |
379 | struct drm_etnaviv_gem_submit_bo *bos; |
380 | struct etnaviv_gem_submit *submit; | |
381 | struct etnaviv_cmdbuf *cmdbuf; | |
382 | struct etnaviv_gpu *gpu; | |
78ec187f PZ |
383 | struct sync_file *sync_file = NULL; |
384 | int out_fence_fd = -1; | |
a8c21a54 T |
385 | void *stream; |
386 | int ret; | |
387 | ||
388 | if (args->pipe >= ETNA_MAX_PIPES) | |
389 | return -EINVAL; | |
390 | ||
391 | gpu = priv->gpu[args->pipe]; | |
392 | if (!gpu) | |
393 | return -ENXIO; | |
394 | ||
395 | if (args->stream_size % 4) { | |
396 | DRM_ERROR("non-aligned cmdstream buffer size: %u\n", | |
397 | args->stream_size); | |
398 | return -EINVAL; | |
399 | } | |
400 | ||
401 | if (args->exec_state != ETNA_PIPE_3D && | |
402 | args->exec_state != ETNA_PIPE_2D && | |
403 | args->exec_state != ETNA_PIPE_VG) { | |
404 | DRM_ERROR("invalid exec_state: 0x%x\n", args->exec_state); | |
405 | return -EINVAL; | |
406 | } | |
407 | ||
9ad59fea PZ |
408 | if (args->flags & ~ETNA_SUBMIT_FLAGS) { |
409 | DRM_ERROR("invalid flags: 0x%x\n", args->flags); | |
410 | return -EINVAL; | |
411 | } | |
412 | ||
a8c21a54 T |
413 | /* |
414 | * Copy the command submission and bo array to kernel space in | |
415 | * one go, and do this outside of any locks. | |
416 | */ | |
2098105e MH |
417 | bos = kvmalloc_array(args->nr_bos, sizeof(*bos), GFP_KERNEL); |
418 | relocs = kvmalloc_array(args->nr_relocs, sizeof(*relocs), GFP_KERNEL); | |
c8e4a7fd | 419 | pmrs = kvmalloc_array(args->nr_pmrs, sizeof(*pmrs), GFP_KERNEL); |
2098105e | 420 | stream = kvmalloc_array(1, args->stream_size, GFP_KERNEL); |
e66774dd LS |
421 | cmdbuf = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc, |
422 | ALIGN(args->stream_size, 8) + 8, | |
c8e4a7fd CG |
423 | args->nr_bos, args->nr_pmrs); |
424 | if (!bos || !relocs || !pmrs || !stream || !cmdbuf) { | |
a8c21a54 T |
425 | ret = -ENOMEM; |
426 | goto err_submit_cmds; | |
427 | } | |
428 | ||
429 | cmdbuf->exec_state = args->exec_state; | |
430 | cmdbuf->ctx = file->driver_priv; | |
431 | ||
3ed605bc | 432 | ret = copy_from_user(bos, u64_to_user_ptr(args->bos), |
a8c21a54 T |
433 | args->nr_bos * sizeof(*bos)); |
434 | if (ret) { | |
435 | ret = -EFAULT; | |
436 | goto err_submit_cmds; | |
437 | } | |
438 | ||
3ed605bc | 439 | ret = copy_from_user(relocs, u64_to_user_ptr(args->relocs), |
a8c21a54 T |
440 | args->nr_relocs * sizeof(*relocs)); |
441 | if (ret) { | |
442 | ret = -EFAULT; | |
443 | goto err_submit_cmds; | |
444 | } | |
445 | ||
c8e4a7fd CG |
446 | ret = copy_from_user(pmrs, u64_to_user_ptr(args->pmrs), |
447 | args->nr_pmrs * sizeof(*pmrs)); | |
448 | if (ret) { | |
449 | ret = -EFAULT; | |
450 | goto err_submit_cmds; | |
451 | } | |
452 | cmdbuf->nr_pmrs = args->nr_pmrs; | |
453 | ||
3ed605bc | 454 | ret = copy_from_user(stream, u64_to_user_ptr(args->stream), |
a8c21a54 T |
455 | args->stream_size); |
456 | if (ret) { | |
457 | ret = -EFAULT; | |
458 | goto err_submit_cmds; | |
459 | } | |
460 | ||
78ec187f PZ |
461 | if (args->flags & ETNA_SUBMIT_FENCE_FD_OUT) { |
462 | out_fence_fd = get_unused_fd_flags(O_CLOEXEC); | |
463 | if (out_fence_fd < 0) { | |
464 | ret = out_fence_fd; | |
465 | goto err_submit_cmds; | |
466 | } | |
467 | } | |
468 | ||
a8c21a54 T |
469 | submit = submit_create(dev, gpu, args->nr_bos); |
470 | if (!submit) { | |
471 | ret = -ENOMEM; | |
472 | goto err_submit_cmds; | |
473 | } | |
474 | ||
9ad59fea PZ |
475 | submit->flags = args->flags; |
476 | ||
a8c21a54 T |
477 | ret = submit_lookup_objects(submit, file, bos, args->nr_bos); |
478 | if (ret) | |
479 | goto err_submit_objects; | |
480 | ||
481 | ret = submit_lock_objects(submit); | |
482 | if (ret) | |
483 | goto err_submit_objects; | |
484 | ||
485 | if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4, | |
486 | relocs, args->nr_relocs)) { | |
487 | ret = -EINVAL; | |
488 | goto err_submit_objects; | |
489 | } | |
490 | ||
9ad59fea | 491 | if (args->flags & ETNA_SUBMIT_FENCE_FD_IN) { |
9efabd73 LS |
492 | submit->in_fence = sync_file_get_fence(args->fence_fd); |
493 | if (!submit->in_fence) { | |
9ad59fea PZ |
494 | ret = -EINVAL; |
495 | goto err_submit_objects; | |
496 | } | |
9ad59fea PZ |
497 | } |
498 | ||
a8c21a54 T |
499 | ret = submit_fence_sync(submit); |
500 | if (ret) | |
501 | goto err_submit_objects; | |
502 | ||
503 | ret = submit_pin_objects(submit); | |
504 | if (ret) | |
33a63e68 | 505 | goto err_submit_objects; |
a8c21a54 T |
506 | |
507 | ret = submit_reloc(submit, stream, args->stream_size / 4, | |
508 | relocs, args->nr_relocs); | |
509 | if (ret) | |
33a63e68 | 510 | goto err_submit_objects; |
a8c21a54 | 511 | |
c8e4a7fd CG |
512 | ret = submit_perfmon_validate(submit, cmdbuf, pmrs, args->nr_pmrs); |
513 | if (ret) | |
33a63e68 | 514 | goto err_submit_objects; |
c8e4a7fd | 515 | |
a8c21a54 T |
516 | memcpy(cmdbuf->vaddr, stream, args->stream_size); |
517 | cmdbuf->user_size = ALIGN(args->stream_size, 8); | |
518 | ||
519 | ret = etnaviv_gpu_submit(gpu, submit, cmdbuf); | |
5a642e6b | 520 | if (ret) |
33a63e68 | 521 | goto err_submit_objects; |
5a642e6b | 522 | |
0236efe9 LS |
523 | submit_attach_object_fences(submit); |
524 | ||
5a642e6b | 525 | cmdbuf = NULL; |
a8c21a54 | 526 | |
78ec187f PZ |
527 | if (args->flags & ETNA_SUBMIT_FENCE_FD_OUT) { |
528 | /* | |
529 | * This can be improved: ideally we want to allocate the sync | |
530 | * file before kicking off the GPU job and just attach the | |
531 | * fence to the sync file here, eliminating the ENOMEM | |
532 | * possibility at this stage. | |
533 | */ | |
10009ea2 | 534 | sync_file = sync_file_create(submit->out_fence); |
78ec187f PZ |
535 | if (!sync_file) { |
536 | ret = -ENOMEM; | |
33a63e68 | 537 | goto err_submit_objects; |
78ec187f PZ |
538 | } |
539 | fd_install(out_fence_fd, sync_file->file); | |
540 | } | |
541 | ||
542 | args->fence_fd = out_fence_fd; | |
10009ea2 | 543 | args->fence = submit->out_fence->seqno; |
a8c21a54 | 544 | |
a8c21a54 T |
545 | err_submit_objects: |
546 | submit_cleanup(submit); | |
547 | ||
548 | err_submit_cmds: | |
78ec187f PZ |
549 | if (ret && (out_fence_fd >= 0)) |
550 | put_unused_fd(out_fence_fd); | |
a8c21a54 T |
551 | /* if we still own the cmdbuf */ |
552 | if (cmdbuf) | |
ea1f5729 | 553 | etnaviv_cmdbuf_free(cmdbuf); |
a8c21a54 | 554 | if (stream) |
2098105e | 555 | kvfree(stream); |
a8c21a54 | 556 | if (bos) |
2098105e | 557 | kvfree(bos); |
a8c21a54 | 558 | if (relocs) |
2098105e | 559 | kvfree(relocs); |
c8e4a7fd CG |
560 | if (pmrs) |
561 | kvfree(pmrs); | |
a8c21a54 T |
562 | |
563 | return ret; | |
564 | } |