diff options
author | Haixia Shi <hshi@chromium.org> | 2018-01-30 15:28:32 -0500 |
---|---|---|
committer | Heiko Stuebner <heiko@sntech.de> | 2018-02-18 05:16:40 -0500 |
commit | 6fd0bfe2f7ea1a5828c44b8d8811820bf7be13a9 (patch) | |
tree | 0d17ae539f8a935d07ac4224c3be947817d8e788 | |
parent | b4a92d0eef5ab1f81282c9ebca1822d99a35547a (diff) |
drm/rockchip: support prime import sg table
The prime fd to handle ioctl was not used with rockchip before. Support
was added in order to pass graphics_Gbm and to support potential uses
within Chrome OS (e.g. zero-copy video decode, camera).
Signed-off-by: Haixia Shi <hshi@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20180130202913.28724-3-thierry.escande@collabora.com
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 118 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_gem.h | 5 |
3 files changed, 115 insertions, 9 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index d85431400a0d..88084ca15115 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c | |||
@@ -230,6 +230,7 @@ static struct drm_driver rockchip_drm_driver = { | |||
230 | .gem_prime_import = drm_gem_prime_import, | 230 | .gem_prime_import = drm_gem_prime_import, |
231 | .gem_prime_export = drm_gem_prime_export, | 231 | .gem_prime_export = drm_gem_prime_export, |
232 | .gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table, | 232 | .gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table, |
233 | .gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table, | ||
233 | .gem_prime_vmap = rockchip_gem_prime_vmap, | 234 | .gem_prime_vmap = rockchip_gem_prime_vmap, |
234 | .gem_prime_vunmap = rockchip_gem_prime_vunmap, | 235 | .gem_prime_vunmap = rockchip_gem_prime_vunmap, |
235 | .gem_prime_mmap = rockchip_gem_mmap_buf, | 236 | .gem_prime_mmap = rockchip_gem_mmap_buf, |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 1d9655576b6e..5d52020deca1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <drm/drmP.h> | 16 | #include <drm/drmP.h> |
17 | #include <drm/drm_gem.h> | 17 | #include <drm/drm_gem.h> |
18 | #include <drm/drm_vma_manager.h> | 18 | #include <drm/drm_vma_manager.h> |
19 | |||
20 | #include <linux/dma-buf.h> | ||
19 | #include <linux/iommu.h> | 21 | #include <linux/iommu.h> |
20 | 22 | ||
21 | #include "rockchip_drm_drv.h" | 23 | #include "rockchip_drm_drv.h" |
@@ -309,12 +311,10 @@ static void rockchip_gem_release_object(struct rockchip_gem_object *rk_obj) | |||
309 | } | 311 | } |
310 | 312 | ||
311 | struct rockchip_gem_object * | 313 | struct rockchip_gem_object * |
312 | rockchip_gem_create_object(struct drm_device *drm, unsigned int size, | 314 | rockchip_gem_alloc_object(struct drm_device *drm, unsigned int size) |
313 | bool alloc_kmap) | ||
314 | { | 315 | { |
315 | struct rockchip_gem_object *rk_obj; | 316 | struct rockchip_gem_object *rk_obj; |
316 | struct drm_gem_object *obj; | 317 | struct drm_gem_object *obj; |
317 | int ret; | ||
318 | 318 | ||
319 | size = round_up(size, PAGE_SIZE); | 319 | size = round_up(size, PAGE_SIZE); |
320 | 320 | ||
@@ -326,6 +326,20 @@ struct rockchip_gem_object * | |||
326 | 326 | ||
327 | drm_gem_object_init(drm, obj, size); | 327 | drm_gem_object_init(drm, obj, size); |
328 | 328 | ||
329 | return rk_obj; | ||
330 | } | ||
331 | |||
332 | struct rockchip_gem_object * | ||
333 | rockchip_gem_create_object(struct drm_device *drm, unsigned int size, | ||
334 | bool alloc_kmap) | ||
335 | { | ||
336 | struct rockchip_gem_object *rk_obj; | ||
337 | int ret; | ||
338 | |||
339 | rk_obj = rockchip_gem_alloc_object(drm, size); | ||
340 | if (IS_ERR(rk_obj)) | ||
341 | return rk_obj; | ||
342 | |||
329 | ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap); | 343 | ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap); |
330 | if (ret) | 344 | if (ret) |
331 | goto err_free_rk_obj; | 345 | goto err_free_rk_obj; |
@@ -343,11 +357,21 @@ err_free_rk_obj: | |||
343 | */ | 357 | */ |
344 | void rockchip_gem_free_object(struct drm_gem_object *obj) | 358 | void rockchip_gem_free_object(struct drm_gem_object *obj) |
345 | { | 359 | { |
346 | struct rockchip_gem_object *rk_obj; | 360 | struct drm_device *drm = obj->dev; |
347 | 361 | struct rockchip_drm_private *private = drm->dev_private; | |
348 | rk_obj = to_rockchip_obj(obj); | 362 | struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); |
349 | 363 | ||
350 | rockchip_gem_free_buf(rk_obj); | 364 | if (obj->import_attach) { |
365 | if (private->domain) { | ||
366 | rockchip_gem_iommu_unmap(rk_obj); | ||
367 | } else { | ||
368 | dma_unmap_sg(drm->dev, rk_obj->sgt->sgl, | ||
369 | rk_obj->sgt->nents, DMA_BIDIRECTIONAL); | ||
370 | } | ||
371 | drm_prime_gem_destroy(obj, rk_obj->sgt); | ||
372 | } else { | ||
373 | rockchip_gem_free_buf(rk_obj); | ||
374 | } | ||
351 | 375 | ||
352 | rockchip_gem_release_object(rk_obj); | 376 | rockchip_gem_release_object(rk_obj); |
353 | } | 377 | } |
@@ -451,6 +475,86 @@ struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj) | |||
451 | return sgt; | 475 | return sgt; |
452 | } | 476 | } |
453 | 477 | ||
478 | static unsigned long rockchip_sg_get_contiguous_size(struct sg_table *sgt, | ||
479 | int count) | ||
480 | { | ||
481 | struct scatterlist *s; | ||
482 | dma_addr_t expected = sg_dma_address(sgt->sgl); | ||
483 | unsigned int i; | ||
484 | unsigned long size = 0; | ||
485 | |||
486 | for_each_sg(sgt->sgl, s, count, i) { | ||
487 | if (sg_dma_address(s) != expected) | ||
488 | break; | ||
489 | expected = sg_dma_address(s) + sg_dma_len(s); | ||
490 | size += sg_dma_len(s); | ||
491 | } | ||
492 | return size; | ||
493 | } | ||
494 | |||
495 | static int | ||
496 | rockchip_gem_iommu_map_sg(struct drm_device *drm, | ||
497 | struct dma_buf_attachment *attach, | ||
498 | struct sg_table *sg, | ||
499 | struct rockchip_gem_object *rk_obj) | ||
500 | { | ||
501 | rk_obj->sgt = sg; | ||
502 | return rockchip_gem_iommu_map(rk_obj); | ||
503 | } | ||
504 | |||
505 | static int | ||
506 | rockchip_gem_dma_map_sg(struct drm_device *drm, | ||
507 | struct dma_buf_attachment *attach, | ||
508 | struct sg_table *sg, | ||
509 | struct rockchip_gem_object *rk_obj) | ||
510 | { | ||
511 | int count = dma_map_sg(drm->dev, sg->sgl, sg->nents, | ||
512 | DMA_BIDIRECTIONAL); | ||
513 | if (!count) | ||
514 | return -EINVAL; | ||
515 | |||
516 | if (rockchip_sg_get_contiguous_size(sg, count) < attach->dmabuf->size) { | ||
517 | DRM_ERROR("failed to map sg_table to contiguous linear address.\n"); | ||
518 | dma_unmap_sg(drm->dev, sg->sgl, sg->nents, | ||
519 | DMA_BIDIRECTIONAL); | ||
520 | return -EINVAL; | ||
521 | } | ||
522 | |||
523 | rk_obj->dma_addr = sg_dma_address(sg->sgl); | ||
524 | rk_obj->sgt = sg; | ||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | struct drm_gem_object * | ||
529 | rockchip_gem_prime_import_sg_table(struct drm_device *drm, | ||
530 | struct dma_buf_attachment *attach, | ||
531 | struct sg_table *sg) | ||
532 | { | ||
533 | struct rockchip_drm_private *private = drm->dev_private; | ||
534 | struct rockchip_gem_object *rk_obj; | ||
535 | int ret; | ||
536 | |||
537 | rk_obj = rockchip_gem_alloc_object(drm, attach->dmabuf->size); | ||
538 | if (IS_ERR(rk_obj)) | ||
539 | return ERR_CAST(rk_obj); | ||
540 | |||
541 | if (private->domain) | ||
542 | ret = rockchip_gem_iommu_map_sg(drm, attach, sg, rk_obj); | ||
543 | else | ||
544 | ret = rockchip_gem_dma_map_sg(drm, attach, sg, rk_obj); | ||
545 | |||
546 | if (ret < 0) { | ||
547 | DRM_ERROR("failed to import sg table: %d\n", ret); | ||
548 | goto err_free_rk_obj; | ||
549 | } | ||
550 | |||
551 | return &rk_obj->base; | ||
552 | |||
553 | err_free_rk_obj: | ||
554 | rockchip_gem_release_object(rk_obj); | ||
555 | return ERR_PTR(ret); | ||
556 | } | ||
557 | |||
454 | void *rockchip_gem_prime_vmap(struct drm_gem_object *obj) | 558 | void *rockchip_gem_prime_vmap(struct drm_gem_object *obj) |
455 | { | 559 | { |
456 | struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); | 560 | struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h index f237375582fb..d41fa65219d2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h | |||
@@ -36,8 +36,9 @@ struct rockchip_gem_object { | |||
36 | 36 | ||
37 | struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj); | 37 | struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj); |
38 | struct drm_gem_object * | 38 | struct drm_gem_object * |
39 | rockchip_gem_prime_import_sg_table(struct drm_device *dev, size_t size, | 39 | rockchip_gem_prime_import_sg_table(struct drm_device *dev, |
40 | struct sg_table *sgt); | 40 | struct dma_buf_attachment *attach, |
41 | struct sg_table *sg); | ||
41 | void *rockchip_gem_prime_vmap(struct drm_gem_object *obj); | 42 | void *rockchip_gem_prime_vmap(struct drm_gem_object *obj); |
42 | void rockchip_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); | 43 | void rockchip_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); |
43 | 44 | ||