mirror of
https://github.com/torvalds/linux.git
synced 2026-06-07 14:04:54 +02:00
drm/rockchip: gem: support secure memory
Change-Id: I91dfbbfbf5d13983edfb79585e9beb980566f784 Signed-off-by: Mark Yao <mark.yao@rock-chips.com> Signed-off-by: jay.xu <xjq@rock-chips.com> Signed-off-by: Sandy Huang <hjc@rock-chips.com>
This commit is contained in:
parent
f89f356895
commit
d0ca05b8a4
|
|
@ -22,6 +22,7 @@
|
|||
#include <drm/drm_of.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dma-iommu.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -864,6 +865,46 @@ static void rockchip_iommu_cleanup(struct drm_device *drm_dev)
|
|||
iommu_domain_free(private->domain);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -919,6 +960,7 @@ static int rockchip_drm_bind(struct device *dev)
|
|||
/* init kms poll for handling hpd */
|
||||
drm_kms_helper_poll_init(drm_dev);
|
||||
|
||||
rockchip_gem_pool_init(drm_dev);
|
||||
#ifndef MODULE
|
||||
show_loader_logo(drm_dev);
|
||||
#endif
|
||||
|
|
@ -929,6 +971,7 @@ static int rockchip_drm_bind(struct device *dev)
|
|||
|
||||
return 0;
|
||||
err_kms_helper_poll_fini:
|
||||
rockchip_gem_pool_destroy(drm_dev);
|
||||
drm_kms_helper_poll_fini(drm_dev);
|
||||
rockchip_drm_fbdev_fini(drm_dev);
|
||||
err_unbind_all:
|
||||
|
|
@ -950,6 +993,7 @@ static void rockchip_drm_unbind(struct device *dev)
|
|||
drm_dev_unregister(drm_dev);
|
||||
|
||||
rockchip_drm_fbdev_fini(drm_dev);
|
||||
rockchip_gem_pool_destroy(drm_dev);
|
||||
drm_kms_helper_poll_fini(drm_dev);
|
||||
|
||||
drm_atomic_helper_shutdown(drm_dev);
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ struct rockchip_drm_private {
|
|||
struct drm_gem_object *fbdev_bo;
|
||||
struct drm_atomic_state *state;
|
||||
struct iommu_domain *domain;
|
||||
struct gen_pool *secure_buffer_pool;
|
||||
struct mutex mm_lock;
|
||||
struct drm_mm mm;
|
||||
struct list_head psr_list;
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@
|
|||
#include <drm/drm_vma_manager.h>
|
||||
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_gem.h"
|
||||
|
|
@ -293,6 +295,91 @@ static int rockchip_gem_alloc_dma(struct rockchip_gem_object *rk_obj,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void *drm_calloc_large(size_t nmemb, size_t size)
|
||||
{
|
||||
if (size != 0 && nmemb > SIZE_MAX / size)
|
||||
return NULL;
|
||||
|
||||
if (size * nmemb <= PAGE_SIZE)
|
||||
return kcalloc(nmemb, size, GFP_KERNEL);
|
||||
|
||||
return __vmalloc(size * nmemb,
|
||||
GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL);
|
||||
}
|
||||
|
||||
static inline void drm_free_large(void *ptr)
|
||||
{
|
||||
kvfree(ptr);
|
||||
}
|
||||
|
||||
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 = 0, 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");
|
||||
ret = -ENOMEM;
|
||||
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)
|
||||
{
|
||||
|
|
@ -303,10 +390,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;
|
||||
}
|
||||
return rockchip_gem_alloc_secure(rk_obj);
|
||||
} else if (rk_obj->flags & ROCKCHIP_BO_CONTIG) {
|
||||
rk_obj->buf_type = ROCKCHIP_GEM_BUF_TYPE_CMA;
|
||||
return rockchip_gem_alloc_dma(rk_obj, alloc_kmap);
|
||||
|
||||
} else {
|
||||
rk_obj->buf_type = ROCKCHIP_GEM_BUF_TYPE_SHMEM;
|
||||
return rockchip_gem_alloc_iommu(rk_obj, alloc_kmap);
|
||||
|
|
@ -331,7 +425,9 @@ static void rockchip_gem_free_dma(struct rockchip_gem_object *rk_obj)
|
|||
|
||||
static void rockchip_gem_free_buf(struct rockchip_gem_object *rk_obj)
|
||||
{
|
||||
if (rk_obj->pages)
|
||||
if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_SECURE)
|
||||
rockchip_gem_free_secure(rk_obj);
|
||||
else if (rk_obj->pages)
|
||||
rockchip_gem_free_iommu(rk_obj);
|
||||
else
|
||||
rockchip_gem_free_dma(rk_obj);
|
||||
|
|
@ -408,10 +504,14 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
|
|||
*/
|
||||
vma->vm_flags &= ~VM_PFNMAP;
|
||||
|
||||
if (rk_obj->pages)
|
||||
if (rk_obj->buf_type == ROCKCHIP_GEM_BUF_TYPE_SECURE) {
|
||||
DRM_ERROR("Disallow mmap for secure buffer\n");
|
||||
ret = -EINVAL;
|
||||
} else if (rk_obj->pages) {
|
||||
ret = rockchip_drm_gem_object_mmap_iommu(obj, vma);
|
||||
else
|
||||
} else {
|
||||
ret = rockchip_drm_gem_object_mmap_dma(obj, vma);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
drm_gem_vm_close(vma);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user