From 0fc8ce4b39f8fa641b663e065801103c42c551f2 Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Tue, 25 Jul 2017 17:27:03 +0800 Subject: [PATCH] drm/rockchip: gem: support secure memory Change-Id: I91dfbbfbf5d13983edfb79585e9beb980566f784 Signed-off-by: Mark Yao --- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 44 ++++++++ drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 + drivers/gpu/drm/rockchip/rockchip_drm_gem.c | 106 ++++++++++++++++++-- drivers/gpu/drm/rockchip/rockchip_drm_gem.h | 1 + include/uapi/drm/rockchip_drm.h | 1 + 5 files changed, 144 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 67c12afef2bc..50dfdb304616 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -1081,6 +1082,46 @@ static int rockchip_drm_create_properties(struct drm_device *dev) return 0; } +static int rockchip_gem_pool_init(struct drm_device *drm) +{ + struct rockchip_drm_private *private = drm->dev_private; + struct device_node *np = drm->dev->of_node; + struct device_node *node; + phys_addr_t start, size; + struct resource res; + int ret; + + node = of_parse_phandle(np, "secure-memory-region", 0); + if (!node) + return -ENXIO; + + ret = of_address_to_resource(node, 0, &res); + if (ret) + return ret; + start = res.start; + size = resource_size(&res); + if (!size) + return -ENOMEM; + + private->secure_buffer_pool = gen_pool_create(PAGE_SHIFT, -1); + if (!private->secure_buffer_pool) + return -ENOMEM; + + gen_pool_add(private->secure_buffer_pool, start, size, -1); + + return 0; +} + +static void rockchip_gem_pool_destroy(struct drm_device *drm) +{ + struct rockchip_drm_private *private = drm->dev_private; + + if (!private->secure_buffer_pool) + return; + + gen_pool_destroy(private->secure_buffer_pool); +} + static int rockchip_drm_bind(struct device *dev) { struct drm_device *drm_dev; @@ -1173,6 +1214,7 @@ static int rockchip_drm_bind(struct device *dev) drm_mode_config_reset(drm_dev); + rockchip_gem_pool_init(drm_dev); #ifndef MODULE show_loader_logo(drm_dev); #endif @@ -1191,6 +1233,7 @@ static int rockchip_drm_bind(struct device *dev) err_fbdev_fini: rockchip_drm_fbdev_fini(drm_dev); err_vblank_cleanup: + rockchip_gem_pool_destroy(drm_dev); drm_vblank_cleanup(drm_dev); err_kms_helper_poll_fini: drm_kms_helper_poll_fini(drm_dev); @@ -1210,6 +1253,7 @@ static void rockchip_drm_unbind(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev); rockchip_drm_fbdev_fini(drm_dev); + rockchip_gem_pool_destroy(drm_dev); drm_vblank_cleanup(drm_dev); drm_kms_helper_poll_fini(drm_dev); component_unbind_all(dev, drm_dev); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 8b23b3047239..b40c8f6d5a39 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -146,6 +146,7 @@ struct rockchip_drm_private { struct rockchip_atomic_commit commit; struct iommu_domain *domain; + struct gen_pool *secure_buffer_pool; #ifdef CONFIG_DRM_DMA_SYNC unsigned int cpu_fence_context; atomic_t cpu_fence_seqno; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 0913f74b65c9..034cde799a84 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -319,6 +320,72 @@ static void rockchip_gem_free_cma(struct rockchip_gem_object *rk_obj) rk_obj->dma_addr, &rk_obj->dma_attrs); } +static int rockchip_gem_alloc_secure(struct rockchip_gem_object *rk_obj) +{ + struct drm_gem_object *obj = &rk_obj->base; + struct drm_device *drm = obj->dev; + struct rockchip_drm_private *private = drm->dev_private; + unsigned long paddr; + struct sg_table *sgt; + int ret, i; + + if (!private->secure_buffer_pool) { + DRM_ERROR("No secure buffer pool found\n"); + return -ENOMEM; + } + + paddr = gen_pool_alloc(private->secure_buffer_pool, rk_obj->base.size); + if (!paddr) { + DRM_ERROR("failed to allocate secure buffer\n"); + return -ENOMEM; + } + + rk_obj->dma_handle = paddr; + rk_obj->num_pages = rk_obj->base.size >> PAGE_SHIFT; + + rk_obj->pages = drm_calloc_large(rk_obj->num_pages, + sizeof(*rk_obj->pages)); + if (!rk_obj->pages) { + DRM_ERROR("failed to allocate pages.\n"); + goto err_buf_free; + } + + i = 0; + while (i < rk_obj->num_pages) { + rk_obj->pages[i] = phys_to_page(paddr); + paddr += PAGE_SIZE; + i++; + } + sgt = drm_prime_pages_to_sg(rk_obj->pages, rk_obj->num_pages); + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + goto err_free_pages; + } + + rk_obj->sgt = sgt; + + return 0; + +err_free_pages: + drm_free_large(rk_obj->pages); +err_buf_free: + gen_pool_free(private->secure_buffer_pool, paddr, rk_obj->base.size); + + return ret; +} + +static void rockchip_gem_free_secure(struct rockchip_gem_object *rk_obj) +{ + struct drm_gem_object *obj = &rk_obj->base; + struct drm_device *drm = obj->dev; + struct rockchip_drm_private *private = drm->dev_private; + + drm_free_large(rk_obj->pages); + sg_free_table(rk_obj->sgt); + kfree(rk_obj->sgt); + gen_pool_free(private->secure_buffer_pool, rk_obj->dma_handle, + rk_obj->base.size); +} static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj, bool alloc_kmap) { @@ -330,7 +397,17 @@ static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj, if (!private->domain) rk_obj->flags |= ROCKCHIP_BO_CONTIG; - if (rk_obj->flags & ROCKCHIP_BO_CONTIG) { + if (rk_obj->flags & ROCKCHIP_BO_SECURE) { + rk_obj->buf_type = ROCKCHIP_GEM_BUF_TYPE_SECURE; + rk_obj->flags |= ROCKCHIP_BO_CONTIG; + if (alloc_kmap) { + DRM_ERROR("Not allow alloc secure buffer with kmap\n"); + return -EINVAL; + } + ret = rockchip_gem_alloc_secure(rk_obj); + if (ret < 0) + return ret; + } else if (rk_obj->flags & ROCKCHIP_BO_CONTIG) { rk_obj->buf_type = ROCKCHIP_GEM_BUF_TYPE_CMA; ret = rockchip_gem_alloc_cma(rk_obj); if (ret < 0) @@ -367,7 +444,9 @@ err_iommu_free: if (private->domain) rockchip_gem_iommu_unmap(rk_obj); err_free: - if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_CMA) + if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_SECURE) + rockchip_gem_free_secure(rk_obj); + else if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_CMA) rockchip_gem_free_cma(rk_obj); else rockchip_gem_put_pages(rk_obj); @@ -384,11 +463,12 @@ static void rockchip_gem_free_buf(struct rockchip_gem_object *rk_obj) vunmap(rk_obj->kvaddr); - if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_SHMEM) { + if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_SHMEM) rockchip_gem_put_pages(rk_obj); - } else { + else if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_SECURE) + rockchip_gem_free_secure(rk_obj); + else rockchip_gem_free_cma(rk_obj); - } } static int rockchip_drm_gem_object_mmap_shm(struct drm_gem_object *obj, @@ -443,10 +523,14 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj, */ vma->vm_flags &= ~VM_PFNMAP; - if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_SHMEM) + if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_SECURE) { + DRM_ERROR("Disallow mmap for secure buffer\n"); + ret = -EINVAL; + } else if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_SHMEM) { ret = rockchip_drm_gem_object_mmap_shm(obj, vma); - else + } else { ret = rockchip_drm_gem_object_mmap_cma(obj, vma); + } if (ret) drm_gem_vm_close(vma); @@ -678,6 +762,7 @@ int rockchip_gem_get_phys_ioctl(struct drm_device *dev, void *data, struct drm_rockchip_gem_phys *args = data; struct rockchip_gem_object *rk_obj; struct drm_gem_object *obj; + int ret = 0; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (!obj) { @@ -688,12 +773,15 @@ int rockchip_gem_get_phys_ioctl(struct drm_device *dev, void *data, if (!(rk_obj->flags & ROCKCHIP_BO_CONTIG)) { DRM_ERROR("Can't get phys address from non-continus buf.\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } args->phy_addr = page_to_phys(rk_obj->pages[0]); - return 0; +out: + drm_gem_object_unreference_unlocked(obj); + return ret; } int rockchip_gem_create_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h index aadf0d3e66ac..74544f8cc615 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h @@ -20,6 +20,7 @@ enum rockchip_gem_buf_type { ROCKCHIP_GEM_BUF_TYPE_CMA, ROCKCHIP_GEM_BUF_TYPE_SHMEM, + ROCKCHIP_GEM_BUF_TYPE_SECURE, }; struct rockchip_gem_object { diff --git a/include/uapi/drm/rockchip_drm.h b/include/uapi/drm/rockchip_drm.h index 58e557548b3a..6d8f11c93ba4 100644 --- a/include/uapi/drm/rockchip_drm.h +++ b/include/uapi/drm/rockchip_drm.h @@ -25,6 +25,7 @@ enum drm_rockchip_gem_mem_type { ROCKCHIP_BO_CACHABLE = 1 << 1, /* write-combine mapping. */ ROCKCHIP_BO_WC = 1 << 2, + ROCKCHIP_BO_SECURE = 1 << 3, ROCKCHIP_BO_MASK = ROCKCHIP_BO_CONTIG | ROCKCHIP_BO_CACHABLE | ROCKCHIP_BO_WC }; -- 2.34.1