From 632167a62c02657e1f3861dc3d1a27ace14f9a5b Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Mon, 4 Nov 2019 11:37:37 -0800 Subject: [PATCH] shmbridge: get bridge mem pool's DMA address with dma_map_single set up IOMMU mapping for default bridge memory pool and get its DMA address, thus to address the cache maintenance requirement when clients suballocate buffer from the pool and pass this buffer to TZ. Add two APIs to do sync buffer allocated from bridge. Change-Id: Icd6c70a1185ac96642d9efba74d2b55739eb78ba Signed-off-by: Zhen Kong --- drivers/firmware/qtee_shmbridge.c | 42 ++++++++++++++++++++++++++++--- include/linux/qtee_shmbridge.h | 22 ++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/qtee_shmbridge.c b/drivers/firmware/qtee_shmbridge.c index a8c4fbf506f9..7b7737be677c 100644 --- a/drivers/firmware/qtee_shmbridge.c +++ b/drivers/firmware/qtee_shmbridge.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,7 @@ struct bridge_info { uint64_t handle; int min_alloc_order; struct gen_pool *genpool; + struct device *dev; }; struct bridge_list { @@ -301,11 +303,29 @@ void qtee_shmbridge_free_shm(struct qtee_shm *shm) } EXPORT_SYMBOL(qtee_shmbridge_free_shm); +/* cache clean operation for buffer sub-allocated from default bridge */ +void qtee_shmbridge_flush_shm_buf(struct qtee_shm *shm) +{ + if (shm) + return dma_sync_single_for_device(default_bridge.dev, + shm->paddr, shm->size, DMA_TO_DEVICE); +} +EXPORT_SYMBOL(qtee_shmbridge_flush_shm_buf); + +/* cache invalidation operation for buffer sub-allocated from default bridge */ +void qtee_shmbridge_inv_shm_buf(struct qtee_shm *shm) +{ + if (shm) + return dma_sync_single_for_cpu(default_bridge.dev, + shm->paddr, shm->size, DMA_FROM_DEVICE); +} +EXPORT_SYMBOL(qtee_shmbridge_inv_shm_buf); + /* * shared memory bridge initialization * */ -static int qtee_shmbridge_init(void) +static int qtee_shmbridge_init(struct platform_device *pdev) { int ret = 0; uint32_t ns_vm_ids[] = {VMID_HLOS}; @@ -322,7 +342,15 @@ static int qtee_shmbridge_init(void) get_order(default_bridge.size)); if (!default_bridge.vaddr) return -ENOMEM; - default_bridge.paddr = virt_to_phys(default_bridge.vaddr); + default_bridge.paddr = dma_map_single(&pdev->dev, + default_bridge.vaddr, default_bridge.size, + DMA_TO_DEVICE); + if (dma_mapping_error(&pdev->dev, default_bridge.paddr)) { + pr_err("dma_map_single() failed\n"); + ret = -ENOMEM; + goto exit_freebuf; + } + default_bridge.dev = &pdev->dev; /* create a general mem pool */ default_bridge.min_alloc_order = PAGE_SHIFT; /* 4K page size aligned */ @@ -331,7 +359,7 @@ static int qtee_shmbridge_init(void) if (!default_bridge.genpool) { pr_err("gen_pool_add_virt() failed\n"); ret = -ENOMEM; - goto exit_freebuf; + goto exit_unmap; } gen_pool_set_algo(default_bridge.genpool, gen_pool_best_fit, NULL); @@ -372,6 +400,9 @@ static int qtee_shmbridge_init(void) exit_destroy_pool: gen_pool_destroy(default_bridge.genpool); +exit_unmap: + dma_unmap_single(&pdev->dev, default_bridge.paddr, default_bridge.size, + DMA_TO_DEVICE); exit_freebuf: free_pages((long)default_bridge.vaddr, get_order(default_bridge.size)); exit: @@ -380,7 +411,10 @@ exit: static int qtee_shmbridge_probe(struct platform_device *pdev) { - return qtee_shmbridge_init(); +#ifdef CONFIG_ARM64 + dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); +#endif + return qtee_shmbridge_init(pdev); } static const struct of_device_id qtee_shmbridge_of_match[] = { diff --git a/include/linux/qtee_shmbridge.h b/include/linux/qtee_shmbridge.h index ee12264ad5eb..e6039b41a852 100644 --- a/include/linux/qtee_shmbridge.h +++ b/include/linux/qtee_shmbridge.h @@ -76,6 +76,12 @@ int32_t qtee_shmbridge_deregister(uint64_t handle); * size; returns ERR_PTR or NULL otherwise * * return success or error + * + * Note: This will allocate a cached buffer, so after a client allocates + * a bridge buffer, it need to first flush cache with + * "qtee_shmbridge_flush_shm_buf" before invoke scm_call to TZ, + * and then invalidate cache with "qtee_shmbridge_inv_shm_buf" + * after scm_call return. */ int32_t qtee_shmbridge_allocate_shm(size_t size, struct qtee_shm *shm); @@ -87,4 +93,20 @@ int32_t qtee_shmbridge_allocate_shm(size_t size, struct qtee_shm *shm); */ void qtee_shmbridge_free_shm(struct qtee_shm *shm); +/* + * cache clean operation for buffer sub-allocated from default bridge + * + * @ [IN] shm: qtee_shm, its cache to be cleaned + * + */ +void qtee_shmbridge_flush_shm_buf(struct qtee_shm *shm); + +/* + * cache invalidation operation for buffer sub-allocated from default bridge + * + * @ [IN] shm: qtee_shm, its cache to be invalidated + * + */ +void qtee_shmbridge_inv_shm_buf(struct qtee_shm *shm); + #endif /*__QTEE_SHMBRIDGE_H__*/