diff options
Diffstat (limited to 'drivers/gpu/drm/drm_prime.c')
-rw-r--r-- | drivers/gpu/drm/drm_prime.c | 99 |
1 files changed, 51 insertions, 48 deletions
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 366910ddcfcb..dcde35231e25 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c | |||
@@ -62,6 +62,7 @@ struct drm_prime_member { | |||
62 | struct dma_buf *dma_buf; | 62 | struct dma_buf *dma_buf; |
63 | uint32_t handle; | 63 | uint32_t handle; |
64 | }; | 64 | }; |
65 | static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle); | ||
65 | 66 | ||
66 | static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, | 67 | static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, |
67 | enum dma_data_direction dir) | 68 | enum dma_data_direction dir) |
@@ -200,7 +201,8 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, | |||
200 | { | 201 | { |
201 | struct drm_gem_object *obj; | 202 | struct drm_gem_object *obj; |
202 | void *buf; | 203 | void *buf; |
203 | int ret; | 204 | int ret = 0; |
205 | struct dma_buf *dmabuf; | ||
204 | 206 | ||
205 | obj = drm_gem_object_lookup(dev, file_priv, handle); | 207 | obj = drm_gem_object_lookup(dev, file_priv, handle); |
206 | if (!obj) | 208 | if (!obj) |
@@ -209,43 +211,44 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, | |||
209 | mutex_lock(&file_priv->prime.lock); | 211 | mutex_lock(&file_priv->prime.lock); |
210 | /* re-export the original imported object */ | 212 | /* re-export the original imported object */ |
211 | if (obj->import_attach) { | 213 | if (obj->import_attach) { |
212 | get_dma_buf(obj->import_attach->dmabuf); | 214 | dmabuf = obj->import_attach->dmabuf; |
213 | *prime_fd = dma_buf_fd(obj->import_attach->dmabuf, flags); | 215 | goto out_have_obj; |
214 | drm_gem_object_unreference_unlocked(obj); | ||
215 | mutex_unlock(&file_priv->prime.lock); | ||
216 | return 0; | ||
217 | } | 216 | } |
218 | 217 | ||
219 | if (obj->export_dma_buf) { | 218 | if (obj->export_dma_buf) { |
220 | get_dma_buf(obj->export_dma_buf); | 219 | dmabuf = obj->export_dma_buf; |
221 | *prime_fd = dma_buf_fd(obj->export_dma_buf, flags); | 220 | goto out_have_obj; |
222 | drm_gem_object_unreference_unlocked(obj); | 221 | } |
223 | } else { | 222 | |
224 | buf = dev->driver->gem_prime_export(dev, obj, flags); | 223 | buf = dev->driver->gem_prime_export(dev, obj, flags); |
225 | if (IS_ERR(buf)) { | 224 | if (IS_ERR(buf)) { |
226 | /* normally the created dma-buf takes ownership of the ref, | 225 | /* normally the created dma-buf takes ownership of the ref, |
227 | * but if that fails then drop the ref | 226 | * but if that fails then drop the ref |
228 | */ | 227 | */ |
229 | drm_gem_object_unreference_unlocked(obj); | 228 | ret = PTR_ERR(buf); |
230 | mutex_unlock(&file_priv->prime.lock); | 229 | goto out; |
231 | return PTR_ERR(buf); | ||
232 | } | ||
233 | obj->export_dma_buf = buf; | ||
234 | *prime_fd = dma_buf_fd(buf, flags); | ||
235 | } | 230 | } |
231 | obj->export_dma_buf = buf; | ||
232 | |||
236 | /* if we've exported this buffer the cheat and add it to the import list | 233 | /* if we've exported this buffer the cheat and add it to the import list |
237 | * so we get the correct handle back | 234 | * so we get the correct handle back |
238 | */ | 235 | */ |
239 | ret = drm_prime_add_imported_buf_handle(&file_priv->prime, | 236 | ret = drm_prime_add_buf_handle(&file_priv->prime, |
240 | obj->export_dma_buf, handle); | 237 | obj->export_dma_buf, handle); |
241 | if (ret) { | 238 | if (ret) |
242 | drm_gem_object_unreference_unlocked(obj); | 239 | goto out; |
243 | mutex_unlock(&file_priv->prime.lock); | ||
244 | return ret; | ||
245 | } | ||
246 | 240 | ||
241 | *prime_fd = dma_buf_fd(buf, flags); | ||
247 | mutex_unlock(&file_priv->prime.lock); | 242 | mutex_unlock(&file_priv->prime.lock); |
248 | return 0; | 243 | return 0; |
244 | |||
245 | out_have_obj: | ||
246 | get_dma_buf(dmabuf); | ||
247 | *prime_fd = dma_buf_fd(dmabuf, flags); | ||
248 | out: | ||
249 | drm_gem_object_unreference_unlocked(obj); | ||
250 | mutex_unlock(&file_priv->prime.lock); | ||
251 | return ret; | ||
249 | } | 252 | } |
250 | EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); | 253 | EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); |
251 | 254 | ||
@@ -268,7 +271,6 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, | |||
268 | * refcount on gem itself instead of f_count of dmabuf. | 271 | * refcount on gem itself instead of f_count of dmabuf. |
269 | */ | 272 | */ |
270 | drm_gem_object_reference(obj); | 273 | drm_gem_object_reference(obj); |
271 | dma_buf_put(dma_buf); | ||
272 | return obj; | 274 | return obj; |
273 | } | 275 | } |
274 | } | 276 | } |
@@ -277,6 +279,8 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, | |||
277 | if (IS_ERR(attach)) | 279 | if (IS_ERR(attach)) |
278 | return ERR_PTR(PTR_ERR(attach)); | 280 | return ERR_PTR(PTR_ERR(attach)); |
279 | 281 | ||
282 | get_dma_buf(dma_buf); | ||
283 | |||
280 | sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); | 284 | sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); |
281 | if (IS_ERR_OR_NULL(sgt)) { | 285 | if (IS_ERR_OR_NULL(sgt)) { |
282 | ret = PTR_ERR(sgt); | 286 | ret = PTR_ERR(sgt); |
@@ -297,6 +301,8 @@ fail_unmap: | |||
297 | dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); | 301 | dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); |
298 | fail_detach: | 302 | fail_detach: |
299 | dma_buf_detach(dma_buf, attach); | 303 | dma_buf_detach(dma_buf, attach); |
304 | dma_buf_put(dma_buf); | ||
305 | |||
300 | return ERR_PTR(ret); | 306 | return ERR_PTR(ret); |
301 | } | 307 | } |
302 | EXPORT_SYMBOL(drm_gem_prime_import); | 308 | EXPORT_SYMBOL(drm_gem_prime_import); |
@@ -314,7 +320,7 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, | |||
314 | 320 | ||
315 | mutex_lock(&file_priv->prime.lock); | 321 | mutex_lock(&file_priv->prime.lock); |
316 | 322 | ||
317 | ret = drm_prime_lookup_imported_buf_handle(&file_priv->prime, | 323 | ret = drm_prime_lookup_buf_handle(&file_priv->prime, |
318 | dma_buf, handle); | 324 | dma_buf, handle); |
319 | if (!ret) { | 325 | if (!ret) { |
320 | ret = 0; | 326 | ret = 0; |
@@ -333,12 +339,15 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, | |||
333 | if (ret) | 339 | if (ret) |
334 | goto out_put; | 340 | goto out_put; |
335 | 341 | ||
336 | ret = drm_prime_add_imported_buf_handle(&file_priv->prime, | 342 | ret = drm_prime_add_buf_handle(&file_priv->prime, |
337 | dma_buf, *handle); | 343 | dma_buf, *handle); |
338 | if (ret) | 344 | if (ret) |
339 | goto fail; | 345 | goto fail; |
340 | 346 | ||
341 | mutex_unlock(&file_priv->prime.lock); | 347 | mutex_unlock(&file_priv->prime.lock); |
348 | |||
349 | dma_buf_put(dma_buf); | ||
350 | |||
342 | return 0; | 351 | return 0; |
343 | 352 | ||
344 | fail: | 353 | fail: |
@@ -401,21 +410,17 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, | |||
401 | struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages) | 410 | struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages) |
402 | { | 411 | { |
403 | struct sg_table *sg = NULL; | 412 | struct sg_table *sg = NULL; |
404 | struct scatterlist *iter; | ||
405 | int i; | ||
406 | int ret; | 413 | int ret; |
407 | 414 | ||
408 | sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL); | 415 | sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL); |
409 | if (!sg) | 416 | if (!sg) |
410 | goto out; | 417 | goto out; |
411 | 418 | ||
412 | ret = sg_alloc_table(sg, nr_pages, GFP_KERNEL); | 419 | ret = sg_alloc_table_from_pages(sg, pages, nr_pages, 0, |
420 | nr_pages << PAGE_SHIFT, GFP_KERNEL); | ||
413 | if (ret) | 421 | if (ret) |
414 | goto out; | 422 | goto out; |
415 | 423 | ||
416 | for_each_sg(sg->sgl, iter, nr_pages, i) | ||
417 | sg_set_page(iter, pages[i], PAGE_SIZE, 0); | ||
418 | |||
419 | return sg; | 424 | return sg; |
420 | out: | 425 | out: |
421 | kfree(sg); | 426 | kfree(sg); |
@@ -483,15 +488,12 @@ EXPORT_SYMBOL(drm_prime_init_file_private); | |||
483 | 488 | ||
484 | void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv) | 489 | void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv) |
485 | { | 490 | { |
486 | struct drm_prime_member *member, *safe; | 491 | /* by now drm_gem_release should've made sure the list is empty */ |
487 | list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { | 492 | WARN_ON(!list_empty(&prime_fpriv->head)); |
488 | list_del(&member->entry); | ||
489 | kfree(member); | ||
490 | } | ||
491 | } | 493 | } |
492 | EXPORT_SYMBOL(drm_prime_destroy_file_private); | 494 | EXPORT_SYMBOL(drm_prime_destroy_file_private); |
493 | 495 | ||
494 | int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) | 496 | static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) |
495 | { | 497 | { |
496 | struct drm_prime_member *member; | 498 | struct drm_prime_member *member; |
497 | 499 | ||
@@ -499,14 +501,14 @@ int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv | |||
499 | if (!member) | 501 | if (!member) |
500 | return -ENOMEM; | 502 | return -ENOMEM; |
501 | 503 | ||
504 | get_dma_buf(dma_buf); | ||
502 | member->dma_buf = dma_buf; | 505 | member->dma_buf = dma_buf; |
503 | member->handle = handle; | 506 | member->handle = handle; |
504 | list_add(&member->entry, &prime_fpriv->head); | 507 | list_add(&member->entry, &prime_fpriv->head); |
505 | return 0; | 508 | return 0; |
506 | } | 509 | } |
507 | EXPORT_SYMBOL(drm_prime_add_imported_buf_handle); | ||
508 | 510 | ||
509 | int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle) | 511 | int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle) |
510 | { | 512 | { |
511 | struct drm_prime_member *member; | 513 | struct drm_prime_member *member; |
512 | 514 | ||
@@ -518,19 +520,20 @@ int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fp | |||
518 | } | 520 | } |
519 | return -ENOENT; | 521 | return -ENOENT; |
520 | } | 522 | } |
521 | EXPORT_SYMBOL(drm_prime_lookup_imported_buf_handle); | 523 | EXPORT_SYMBOL(drm_prime_lookup_buf_handle); |
522 | 524 | ||
523 | void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf) | 525 | void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf) |
524 | { | 526 | { |
525 | struct drm_prime_member *member, *safe; | 527 | struct drm_prime_member *member, *safe; |
526 | 528 | ||
527 | mutex_lock(&prime_fpriv->lock); | 529 | mutex_lock(&prime_fpriv->lock); |
528 | list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { | 530 | list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { |
529 | if (member->dma_buf == dma_buf) { | 531 | if (member->dma_buf == dma_buf) { |
532 | dma_buf_put(dma_buf); | ||
530 | list_del(&member->entry); | 533 | list_del(&member->entry); |
531 | kfree(member); | 534 | kfree(member); |
532 | } | 535 | } |
533 | } | 536 | } |
534 | mutex_unlock(&prime_fpriv->lock); | 537 | mutex_unlock(&prime_fpriv->lock); |
535 | } | 538 | } |
536 | EXPORT_SYMBOL(drm_prime_remove_imported_buf_handle); | 539 | EXPORT_SYMBOL(drm_prime_remove_buf_handle); |