diff --git a/drivers/dma-buf/heaps/Kconfig b/drivers/dma-buf/heaps/Kconfig index e28ff68b4337..e2c7899b3bdc 100644 --- a/drivers/dma-buf/heaps/Kconfig +++ b/drivers/dma-buf/heaps/Kconfig @@ -84,3 +84,12 @@ config QCOM_DMABUF_HEAPS_UBWCP The heap itself is backed by system heap memory and works in tandem with the UBWC-P driver. If in doubt, say Y here. + +config QCOM_DMABUF_HEAPS_TUI_CARVEOUT + bool "QCOM DMA-BUF TUI Carveout Heap" + depends on QCOM_DMABUF_HEAPS + help + Choose this option to build the QCOM Trusted UI carvout heap. + This heap is controlled from an ioctl, and memory is transferred + to it from the Primary VM. Not GKI-Compatible as it cannot + be built as a module. diff --git a/drivers/dma-buf/heaps/Makefile b/drivers/dma-buf/heaps/Makefile index 4d6a0e8cee22..afc620792e84 100644 --- a/drivers/dma-buf/heaps/Makefile +++ b/drivers/dma-buf/heaps/Makefile @@ -13,3 +13,4 @@ qcom_dma_heaps-$(CONFIG_QCOM_DMABUF_HEAPS_CARVEOUT) += qcom_carveout_heap.o \ qcom_dma_heap_secure_utils.o qcom_dma_heaps-$(CONFIG_QCOM_DMABUF_HEAPS_BITSTREAM_CONTIG) += qcom_bitstream_contig_heap.o qcom_dma_heaps-$(CONFIG_QCOM_DMABUF_HEAPS_UBWCP) += qcom_ubwcp_heap.o +qcom_dma_heaps-$(CONFIG_QCOM_DMABUF_HEAPS_TUI_CARVEOUT) += qcom_tui_carveout_heap.o diff --git a/drivers/dma-buf/heaps/qcom_carveout_heap.c b/drivers/dma-buf/heaps/qcom_carveout_heap.c index 511ae29557b2..65097cb79b23 100644 --- a/drivers/dma-buf/heaps/qcom_carveout_heap.c +++ b/drivers/dma-buf/heaps/qcom_carveout_heap.c @@ -7,6 +7,7 @@ * * Copyright (C) 2011 Google, Inc. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -50,10 +51,6 @@ struct carveout_heap { bool is_secure; bool is_nomap; phys_addr_t base; - - void *pool_refcount_priv; - int (*pool_refcount_get)(void *priv); - void (*pool_refcount_put)(void *priv); }; struct secure_carveout_heap { @@ -79,22 +76,6 @@ void pages_sync_for_device(struct device *dev, struct page *page, dma_sync_sg_for_device(dev, &sg, 1, dir); } -static int carveout_pool_refcount_get(struct carveout_heap *carveout_heap) -{ - if (!carveout_heap->pool_refcount_get) - return 0; - - return carveout_heap->pool_refcount_get(carveout_heap->pool_refcount_priv); -} - -static void carveout_pool_refcount_put(struct carveout_heap *carveout_heap) -{ - if (!carveout_heap->pool_refcount_put) - return; - - carveout_heap->pool_refcount_put(carveout_heap->pool_refcount_priv); -} - static phys_addr_t carveout_allocate(struct carveout_heap *carveout_heap, unsigned long size) { @@ -102,13 +83,9 @@ static phys_addr_t carveout_allocate(struct carveout_heap *carveout_heap, down_read(&carveout_heap->mem_sem); if (carveout_heap->pool) { - if (carveout_pool_refcount_get(carveout_heap)) - goto unlock; - offset = gen_pool_alloc(carveout_heap->pool, size); if (!offset) { offset = CARVEOUT_ALLOCATE_FAIL; - carveout_pool_refcount_put(carveout_heap); goto unlock; } } @@ -127,7 +104,6 @@ static void carveout_free(struct carveout_heap *carveout_heap, down_read(&carveout_heap->mem_sem); if (carveout_heap->pool) gen_pool_free(carveout_heap->pool, addr, size); - carveout_pool_refcount_put(carveout_heap); up_read(&carveout_heap->mem_sem); } @@ -344,111 +320,17 @@ static int carveout_init_heap_memory(struct carveout_heap *co_heap, return 0; } -int carveout_heap_add_memory(char *heap_name, struct sg_table *sgt, void *cookie, - int (*get)(void *), void (*put)(void *)) -{ - struct dma_heap *heap; - struct carveout_heap *carveout_heap; - int ret; - - if (!sgt || sgt->nents != 1) - return -EINVAL; - - heap = dma_heap_find(heap_name); - if (!heap) { - pr_err_ratelimited("%s: No heap named %s\n", __func__, heap_name); - return -EINVAL; - } - - if (!get || !put || !cookie) { - pr_err_ratelimited("%s: Missing refcount callbacks\n", __func__); - return -EINVAL; - } - - carveout_heap = dma_heap_get_drvdata(heap); - - down_write(&carveout_heap->mem_sem); - if (carveout_heap->pool) { - ret = -EBUSY; - goto unlock; - } - - ret = carveout_init_heap_memory(carveout_heap, - page_to_phys(sg_page(sgt->sgl)), - sgt->sgl->length, true); - if (ret) - goto unlock; - - carveout_heap->pool_refcount_priv = cookie; - carveout_heap->pool_refcount_get = get; - carveout_heap->pool_refcount_put = put; - -unlock: - up_write(&carveout_heap->mem_sem); - return ret; -} -EXPORT_SYMBOL(carveout_heap_add_memory); - -int carveout_heap_remove_memory(char *heap_name, - struct sg_table *sgt) -{ - struct dma_heap *heap; - struct carveout_heap *carveout_heap; - phys_addr_t base; - int ret = 0; - - if (!sgt || sgt->nents != 1) - return -EINVAL; - - heap = dma_heap_find(heap_name); - if (!heap) - return -EINVAL; - - carveout_heap = dma_heap_get_drvdata(heap); - - down_write(&carveout_heap->mem_sem); - if (!carveout_heap->pool) { - ret = -EINVAL; - goto unlock; - } - - base = page_to_phys(sg_page(sgt->sgl)); - if (carveout_heap->base != base) { - ret = 0; - goto unlock; - } - - if (gen_pool_size(carveout_heap->pool) != - gen_pool_avail(carveout_heap->pool)) { - ret = -EBUSY; - goto unlock; - } - - gen_pool_destroy(carveout_heap->pool); - carveout_heap->pool = NULL; - carveout_heap->base = 0; - carveout_heap->pool_refcount_priv = NULL; - carveout_heap->pool_refcount_get = NULL; - carveout_heap->pool_refcount_put = NULL; -unlock: - up_write(&carveout_heap->mem_sem); - return ret; -} -EXPORT_SYMBOL(carveout_heap_remove_memory); - static int __carveout_heap_init(struct platform_heap *heap_data, struct carveout_heap *carveout_heap, bool sync) { struct device *dev = heap_data->dev; - bool dynamic_heap = heap_data->is_dynamic; int ret = 0; carveout_heap->dev = dev; - if (!dynamic_heap) - ret = carveout_init_heap_memory(carveout_heap, - heap_data->base, - heap_data->size, sync); + ret = carveout_init_heap_memory(carveout_heap, + heap_data->base, + heap_data->size, sync); init_rwsem(&carveout_heap->mem_sem); diff --git a/drivers/dma-buf/heaps/qcom_dma_heap.c b/drivers/dma-buf/heaps/qcom_dma_heap.c index d5e34a41efcd..bf77237e84d5 100644 --- a/drivers/dma-buf/heaps/qcom_dma_heap.c +++ b/drivers/dma-buf/heaps/qcom_dma_heap.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -9,6 +10,7 @@ #include #include +#include #include "qcom_cma_heap.h" #include "qcom_dt_parser.h" #include "qcom_system_heap.h" @@ -65,6 +67,16 @@ static int qcom_dma_heap_probe(struct platform_device *pdev) pr_info("%s: DMA-BUF Heap: Created %s\n", __func__, heap_data->name); break; + case HEAP_TYPE_TUI_CARVEOUT: + ret = qcom_tui_carveout_heap_create(heap_data); + if (ret) + pr_err("%s: DMA-BUF Heap: Failed to create %s, error is %d\n", + __func__, heap_data->name, ret); + else + pr_info("%s: DMA-BUF Heap: Created %s\n", __func__, + heap_data->name); + break; + default: pr_err("%s: Unknown heap type %u\n", __func__, heap_data->type); break; diff --git a/drivers/dma-buf/heaps/qcom_dt_parser.c b/drivers/dma-buf/heaps/qcom_dt_parser.c index 26e8bb84a113..521981c4398b 100644 --- a/drivers/dma-buf/heaps/qcom_dt_parser.c +++ b/drivers/dma-buf/heaps/qcom_dt_parser.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -37,8 +38,6 @@ static int populate_heap(struct device_node *node, } /* Optional properties */ - heap->is_dynamic = of_property_read_bool(node, "qcom,dynamic-heap"); - heap->is_uncached = of_property_read_bool(node, "qcom,uncached-heap"); ret = of_property_read_u32(node, "qcom,token", &heap->token); diff --git a/drivers/dma-buf/heaps/qcom_dt_parser.h b/drivers/dma-buf/heaps/qcom_dt_parser.h index f1cf66a63f4b..c94df10f11ee 100644 --- a/drivers/dma-buf/heaps/qcom_dt_parser.h +++ b/drivers/dma-buf/heaps/qcom_dt_parser.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _QCOM_DT_PARSER_H @@ -33,7 +34,6 @@ struct platform_heap { size_t size; struct device *dev; bool is_uncached; - bool is_dynamic; bool is_nomap; u32 token; u32 max_align; diff --git a/drivers/dma-buf/heaps/qcom_tui_carveout_heap.c b/drivers/dma-buf/heaps/qcom_tui_carveout_heap.c new file mode 100644 index 000000000000..110949a734cc --- /dev/null +++ b/drivers/dma-buf/heaps/qcom_tui_carveout_heap.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#define pr_fmt(fmt) "tui_heap: %s" fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include "qcom_dt_parser.h" +#include "qcom_sg_ops.h" + +struct tui_heap; +struct tui_pool { + struct tui_heap *heap; + void *membuf; + struct kref kref; + struct gen_pool *pool; + struct file *filp; +}; + +struct tui_heap_obj { + struct qcom_sg_buffer buffer; + struct tui_pool *pool; +}; + +struct tui_heap { + struct dma_heap *heap; + /* Protects the pool pointer, not the pool itself */ + struct rw_semaphore pool_sem; + struct tui_pool *pool; +}; +#define CARVEOUT_ALLOCATE_FAIL -1 + +static struct tui_pool *tui_pool_create(struct mem_buf_allocation_data *alloc_data) +{ + struct tui_pool *pool; + struct gh_sgl_desc *sgl_desc; + phys_addr_t base; + size_t size; + int ret; + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + return ERR_PTR(-ENOMEM); + + pool->membuf = mem_buf_alloc(alloc_data); + if (IS_ERR(pool->membuf)) { + ret = PTR_ERR(pool->membuf); + goto err_mem_buf_alloc; + } + sgl_desc = mem_buf_get_sgl(pool->membuf); + + ret = mem_buf_map_mem_s1(sgl_desc); + if (ret) + goto err_mem_buf_map_mem_s1; + + kref_init(&pool->kref); + pool->pool = gen_pool_create(PAGE_SHIFT, -1); + if (!pool->pool) { + ret = -ENOMEM; + goto err_gen_pool_create; + } + + base = sgl_desc->sgl_entries[0].ipa_base; + size = sgl_desc->sgl_entries[0].size; + ret = gen_pool_add(pool->pool, base, size, -1); + if (ret) + goto err_gen_pool_add; + + return pool; + +err_gen_pool_add: + gen_pool_destroy(pool->pool); +err_gen_pool_create: + if (WARN_ON(mem_buf_unmap_mem_s1(sgl_desc))) + return ERR_PTR(ret); +err_mem_buf_map_mem_s1: + mem_buf_free(pool->membuf); +err_mem_buf_alloc: + kfree(pool); + return ERR_PTR(ret); +} + +static void tui_pool_release(struct kref *kref) +{ + struct tui_pool *pool; + struct gh_sgl_desc *sgl_desc; + + pool = container_of(kref, struct tui_pool, kref); + + gen_pool_destroy(pool->pool); + sgl_desc = mem_buf_get_sgl(pool->membuf); + if (WARN_ON(mem_buf_unmap_mem_s1(sgl_desc))) + return; + mem_buf_free(pool->membuf); + kfree(pool); +} + +/* Prevent new allocations from this pool, and drop our refcount */ +static void qcom_tui_heap_remove_pool(void *handle) +{ + struct tui_pool *pool = handle; + struct tui_heap *heap = pool->heap; + + down_write(&heap->pool_sem); + heap->pool = NULL; + pool->heap = NULL; + kref_put(&pool->kref, tui_pool_release); + up_write(&heap->pool_sem); +} + +static void *qcom_tui_heap_add_pool(struct mem_buf_allocation_data *alloc_data) +{ + struct dma_heap *dma_heap; + struct tui_heap *heap; + struct tui_pool *pool; + char *heap_name; + + if (alloc_data->dst_mem_type != MEM_BUF_DMAHEAP_MEM_TYPE) + return ERR_PTR(-EINVAL); + + heap_name = alloc_data->dst_data; + dma_heap = dma_heap_find(heap_name); + if (!dma_heap) { + pr_err_ratelimited("No heap named %s\n", heap_name); + return ERR_PTR(-EINVAL); + } + heap = dma_heap_get_drvdata(dma_heap); + + /* + * Subsection alignment is a requirement of SPARSEMEM_VMEMMAP. + * refer to check_pfn_span(). This is the minimum granularity + * pfn_valid() and pfn_to_online_page() operate at. + */ + alloc_data->size = ALIGN(alloc_data->size, 1UL << SUBSECTION_SHIFT); + alloc_data->trans_type = GH_RM_TRANS_TYPE_DONATE; + alloc_data->sgl_desc = NULL; + pool = tui_pool_create(alloc_data); + if (IS_ERR(pool)) + return ERR_CAST(pool); + + down_write(&heap->pool_sem); + if (heap->pool) { + pr_err_ratelimited("%s already has a pool\n", heap_name); + kref_put(&pool->kref, tui_pool_release); + pool = ERR_PTR(-EBUSY); + } else { + pool->heap = heap; + heap->pool = pool; + } + up_write(&heap->pool_sem); + + return pool; +} + +static int tui_heap_file_release(struct inode *inode, struct file *filp) +{ + qcom_tui_heap_remove_pool(filp->private_data); + return 0; +} + +static const struct file_operations tui_heap_fops = { + .release = tui_heap_file_release, +}; + +int qcom_tui_heap_add_pool_fd(struct mem_buf_allocation_data *alloc_data) +{ + struct tui_pool *pool; + int fd; + + /* + * Tui heap specific ioctl parsing should move here eventually. + */ + + pool = qcom_tui_heap_add_pool(alloc_data); + if (IS_ERR(pool)) + return PTR_ERR(pool); + + pool->filp = anon_inode_getfile("tui_heap", &tui_heap_fops, pool, O_RDWR); + if (IS_ERR(pool->filp)) { + int ret = PTR_ERR(pool->filp); + + qcom_tui_heap_remove_pool(pool); + return ret; + } + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) { + fput(pool->filp); + return fd; + } + + fd_install(fd, pool->filp); + return fd; +} + +static void tui_heap_obj_release(struct qcom_sg_buffer *buffer) +{ + struct tui_heap_obj *obj = container_of(buffer, struct tui_heap_obj, buffer); + struct sg_table *table = &buffer->sg_table; + + /* Prevent data from previous user from leaking to next user */ + memset(sg_virt(table->sgl), 0, buffer->len); + gen_pool_free(obj->pool->pool, sg_phys(table->sgl), buffer->len); + kref_put(&obj->pool->kref, tui_pool_release); + sg_free_table(table); + kfree(obj); +} + +static struct dma_buf *tui_heap_allocate(struct dma_heap *dma_heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + struct tui_heap *heap = dma_heap_get_drvdata(dma_heap); + struct tui_pool *pool; + struct sg_table *table; + struct tui_heap_obj *obj; + struct qcom_sg_buffer *buffer; + u64 paddr; + int ret; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + struct dma_buf *dmabuf; + + len = PAGE_ALIGN(len); + + obj = kzalloc(sizeof(*obj), GFP_KERNEL); + if (!obj) + return ERR_PTR(-ENOMEM); + buffer = &obj->buffer; + + down_read(&heap->pool_sem); + pool = heap->pool; + if (!pool) { + pr_err_ratelimited("%s does not have a pool\n", + dma_heap_get_name(heap->heap)); + ret = -ENODEV; + goto err_no_pool; + } + + obj->pool = pool; + kref_get(&pool->kref); + + /* Returns 0 on failure */ + paddr = gen_pool_alloc(pool->pool, len); + if (!paddr) { + ret = -ENOMEM; + goto err_tui_pool_alloc; + } + + /* Initialize the buffer */ + INIT_LIST_HEAD(&buffer->attachments); + mutex_init(&buffer->lock); + buffer->heap = heap->heap; + buffer->len = len; + buffer->free = tui_heap_obj_release; + buffer->uncached = false; + + table = &buffer->sg_table; + ret = sg_alloc_table(table, 1, GFP_KERNEL); + if (ret) + goto err_sg_alloc_table; + sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(paddr)), len, 0); + + buffer->vmperm = mem_buf_vmperm_alloc(table); + if (IS_ERR(buffer->vmperm)) { + ret = PTR_ERR(buffer->vmperm); + goto err_vmperm_alloc; + } + + /* Instantiate our dma_buf */ + exp_info.exp_name = dma_heap_get_name(heap->heap); + exp_info.size = buffer->len; + exp_info.flags = fd_flags; + exp_info.priv = buffer; + dmabuf = mem_buf_dma_buf_export(&exp_info, &qcom_sg_buf_ops); + if (IS_ERR(dmabuf)) { + ret = PTR_ERR(dmabuf); + goto err_export; + } + + up_read(&heap->pool_sem); + return dmabuf; + +err_export: + mem_buf_vmperm_release(buffer->vmperm); +err_vmperm_alloc: + sg_free_table(table); +err_sg_alloc_table: + gen_pool_free(pool->pool, paddr, len); +err_tui_pool_alloc: + kref_put(&pool->kref, tui_pool_release); +err_no_pool: + up_read(&heap->pool_sem); + kfree(obj); + return ERR_PTR(ret); +} + +static const struct dma_heap_ops tui_heap_ops = { + .allocate = tui_heap_allocate, +}; + +int qcom_tui_carveout_heap_create(struct platform_heap *heap_data) +{ + struct dma_heap_export_info exp_info; + struct tui_heap *heap; + int ret; + + heap = kzalloc(sizeof(*heap), GFP_KERNEL); + if (!heap) + return -ENOMEM; + + exp_info.name = heap_data->name; + exp_info.ops = &tui_heap_ops; + exp_info.priv = heap; + + heap->heap = dma_heap_add(&exp_info); + if (IS_ERR(heap->heap)) { + ret = PTR_ERR(heap->heap); + goto err_dma_heap_add; + } + + return 0; + +err_dma_heap_add: + kfree(heap); + return ret; +} diff --git a/drivers/soc/qcom/mem_buf/mem-buf-dev.h b/drivers/soc/qcom/mem_buf/mem-buf-dev.h index be8c358e6ed5..f7b32a262b36 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-dev.h +++ b/drivers/soc/qcom/mem_buf/mem-buf-dev.h @@ -31,10 +31,6 @@ int mem_buf_hyp_assign_table(struct sg_table *sgt, u32 *src_vmid, int source_nel int *dest_vmids, int *dest_perms, int dest_nelems); #ifdef CONFIG_QCOM_MEM_BUF_DEV_GH - -int mem_buf_map_mem_s1(struct gh_sgl_desc *sgl_desc); -int mem_buf_unmap_mem_s1(struct gh_sgl_desc *sgl_desc); - struct gh_acl_desc *mem_buf_vmid_perm_list_to_gh_acl(int *vmids, int *perms, unsigned int nr_acl_entries); struct gh_sgl_desc *mem_buf_sgt_to_gh_sgl_desc(struct sg_table *sgt); @@ -51,16 +47,6 @@ int mem_buf_assign_mem_gunyah(u32 op, struct sg_table *sgt, struct mem_buf_lend_kernel_arg *arg); int mem_buf_unassign_mem_gunyah(gh_memparcel_handle_t memparcel_hdl); #else -static inline int mem_buf_map_mem_s1(struct gh_sgl_desc *sgl_desc) -{ - return -EINVAL; -} - -static inline int mem_buf_unmap_mem_s1(struct gh_sgl_desc *sgl_desc) -{ - return -EINVAL; -} - static inline struct gh_acl_desc *mem_buf_vmid_perm_list_to_gh_acl(int *vmids, int *perms, unsigned int nr_acl_entries) { diff --git a/drivers/soc/qcom/mem_buf/mem-buf-gh.c b/drivers/soc/qcom/mem_buf/mem-buf-gh.c index a5b56f4b41dd..119a54ffcd96 100644 --- a/drivers/soc/qcom/mem_buf/mem-buf-gh.c +++ b/drivers/soc/qcom/mem_buf/mem-buf-gh.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "../../../../drivers/dma-buf/heaps/qcom_sg_ops.h" #include "mem-buf-gh.h" @@ -750,103 +751,6 @@ static void mem_buf_relinquish_memparcel_hdl(void *hdlr_data, u32 obj_id, gh_mem __mem_buf_relinquish_mem(obj_id, hdl); } -static int get_mem_buf(void *membuf_desc); -static int mem_buf_add_dmaheap_mem(struct mem_buf_desc *membuf, struct sg_table *sgt, - void *dst_data) -{ - char *heap_name = dst_data; - - return carveout_heap_add_memory(heap_name, sgt, (void *)membuf, - get_mem_buf, mem_buf_put); -} - -static int mem_buf_add_mem_type(struct mem_buf_desc *membuf, enum mem_buf_mem_type type, - void *dst_data, struct sg_table *sgt) -{ - if (type == MEM_BUF_DMAHEAP_MEM_TYPE) - return mem_buf_add_dmaheap_mem(membuf, sgt, dst_data); - - return -EINVAL; -} - -static int mem_buf_add_mem(struct mem_buf_desc *membuf) -{ - int i, ret, nr_sgl_entries; - struct sg_table sgt; - struct scatterlist *sgl; - u64 base, size; - - pr_debug("%s: adding memory to destination\n", __func__); - nr_sgl_entries = membuf->sgl_desc->n_sgl_entries; - ret = sg_alloc_table(&sgt, nr_sgl_entries, GFP_KERNEL); - if (ret) - return ret; - - for_each_sg(sgt.sgl, sgl, nr_sgl_entries, i) { - base = membuf->sgl_desc->sgl_entries[i].ipa_base; - size = membuf->sgl_desc->sgl_entries[i].size; - sg_set_page(sgl, phys_to_page(base), size, 0); - } - - ret = mem_buf_add_mem_type(membuf, membuf->dst_mem_type, membuf->dst_data, - &sgt); - if (ret) - pr_err("%s failed to add memory to destination rc: %d\n", - __func__, ret); - else - pr_debug("%s: memory added to destination\n", __func__); - - sg_free_table(&sgt); - return ret; -} - -static int mem_buf_remove_dmaheap_mem(struct sg_table *sgt, void *dst_data) -{ - char *heap_name = dst_data; - - return carveout_heap_remove_memory(heap_name, sgt); -} - -static int mem_buf_remove_mem_type(enum mem_buf_mem_type type, void *dst_data, - struct sg_table *sgt) -{ - if (type == MEM_BUF_DMAHEAP_MEM_TYPE) - return mem_buf_remove_dmaheap_mem(sgt, dst_data); - - return -EINVAL; -} - -static int mem_buf_remove_mem(struct mem_buf_desc *membuf) -{ - int i, ret, nr_sgl_entries; - struct sg_table sgt; - struct scatterlist *sgl; - u64 base, size; - - pr_debug("%s: removing memory from destination\n", __func__); - nr_sgl_entries = membuf->sgl_desc->n_sgl_entries; - ret = sg_alloc_table(&sgt, nr_sgl_entries, GFP_KERNEL); - if (ret) - return ret; - - for_each_sg(sgt.sgl, sgl, nr_sgl_entries, i) { - base = membuf->sgl_desc->sgl_entries[i].ipa_base; - size = membuf->sgl_desc->sgl_entries[i].size; - sg_set_page(sgl, phys_to_page(base), size, 0); - } - - ret = mem_buf_remove_mem_type(membuf->dst_mem_type, membuf->dst_data, - &sgt); - if (ret) - pr_err("%s failed to remove memory from destination rc: %d\n", - __func__, ret); - else - pr_debug("%s: memory removed from destination\n", __func__); - - sg_free_table(&sgt); - return ret; -} - static void *mem_buf_retrieve_dmaheap_mem_type_data_user( struct mem_buf_dmaheap_data __user *udata) { @@ -912,48 +816,14 @@ static void mem_buf_free_mem_type_data(enum mem_buf_mem_type mem_type, mem_buf_free_dmaheap_mem_type_data(mem_type_data); } -static int mem_buf_buffer_release(struct inode *inode, struct file *filp) -{ - struct mem_buf_desc *membuf = filp->private_data; - int ret; - - mutex_lock(&mem_buf_list_lock); - list_del(&membuf->entry); - mutex_unlock(&mem_buf_list_lock); - - pr_debug("%s: Destroyng carveout memory\n", __func__); - ret = mem_buf_remove_mem(membuf); - if (ret < 0) - goto out_free_mem; - - ret = mem_buf_unmap_mem_s1(membuf->sgl_desc); - if (ret < 0) - goto out_free_mem; - - mem_buf_relinquish_mem(membuf); - -out_free_mem: - mem_buf_free_mem_type_data(membuf->dst_mem_type, membuf->dst_data); - mem_buf_free_mem_type_data(membuf->src_mem_type, membuf->src_data); - kvfree(membuf->sgl_desc); - kfree(membuf->acl_desc); - kfree(membuf); - return ret; -} - -static const struct file_operations mem_buf_fops = { - .release = mem_buf_buffer_release, -}; - static bool is_valid_mem_type(enum mem_buf_mem_type mem_type) { return mem_type == MEM_BUF_DMAHEAP_MEM_TYPE; } -static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) +void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) { int ret; - struct file *filp; struct mem_buf_desc *membuf; int perms = PERM_READ | PERM_WRITE | PERM_EXEC; @@ -971,7 +841,7 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) return ERR_PTR(-ENOMEM); pr_debug("%s: mem buf alloc begin\n", __func__); - membuf->size = ALIGN(alloc_data->size, MEM_BUF_MHP_ALIGNMENT); + membuf->size = alloc_data->size; /* Create copies of data structures from alloc_data as they may be on-stack */ membuf->acl_desc = mem_buf_vmid_perm_list_to_gh_acl( @@ -1021,37 +891,13 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) if (ret) goto err_map_mem_s2; - ret = mem_buf_map_mem_s1(membuf->sgl_desc); - if (ret) - goto err_map_mem_s1; - - filp = anon_inode_getfile("membuf", &mem_buf_fops, membuf, O_RDWR); - if (IS_ERR(filp)) { - ret = PTR_ERR(filp); - goto err_get_file; - } - membuf->filp = filp; - mutex_lock(&mem_buf_list_lock); list_add_tail(&membuf->entry, &mem_buf_list); mutex_unlock(&mem_buf_list_lock); - ret = mem_buf_add_mem(membuf); - if (ret) - goto err_add_mem; - pr_debug("%s: mem buf alloc success\n", __func__); return membuf; -err_add_mem: - fput(filp); - return ERR_PTR(ret); -err_get_file: - if (mem_buf_unmap_mem_s1(membuf->sgl_desc) < 0) { - kvfree(membuf->sgl_desc); - goto err_mem_req; - } -err_map_mem_s1: err_map_mem_s2: mem_buf_relinquish_mem(membuf); err_mem_req: @@ -1068,82 +914,22 @@ static void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) return ERR_PTR(ret); } -static int _mem_buf_get_fd(struct file *filp) +void mem_buf_free(void *__membuf) { - int fd; + struct mem_buf_desc *membuf = __membuf; - if (!filp) - return -EINVAL; + mutex_lock(&mem_buf_list_lock); + list_del(&membuf->entry); + mutex_unlock(&mem_buf_list_lock); - fd = get_unused_fd_flags(O_CLOEXEC); - if (fd < 0) - return fd; - - fd_install(fd, filp); - return fd; -} - -int mem_buf_get_fd(void *membuf_desc) -{ - struct mem_buf_desc *membuf = membuf_desc; - - if (!membuf_desc) - return -EINVAL; - - return _mem_buf_get_fd(membuf->filp); -} -EXPORT_SYMBOL(mem_buf_get_fd); - -static void _mem_buf_put(struct file *filp) -{ - fput(filp); -} - -void mem_buf_put(void *membuf_desc) -{ - struct mem_buf_desc *membuf = membuf_desc; - - if (membuf && membuf->filp) - _mem_buf_put(membuf->filp); -} -EXPORT_SYMBOL(mem_buf_put); - -static bool is_mem_buf_file(struct file *filp) -{ - return filp->f_op == &mem_buf_fops; -} - -void *mem_buf_get(int fd) -{ - struct file *filp; - - filp = fget(fd); - - if (!filp) - return ERR_PTR(-EBADF); - - if (!is_mem_buf_file(filp)) { - fput(filp); - return ERR_PTR(-EINVAL); - } - - return filp->private_data; -} -EXPORT_SYMBOL(mem_buf_get); - -static int get_mem_buf(void *membuf_desc) -{ - struct mem_buf_desc *membuf = membuf_desc; - - /* - * get_file_rcu used for atomic_long_inc_unless_zero. - * It returns 0 if file count is already zero. - */ - if (!get_file_rcu(membuf->filp)) - return -EINVAL; - - return 0; + mem_buf_relinquish_mem(membuf); + kvfree(membuf->sgl_desc); + mem_buf_free_mem_type_data(membuf->dst_mem_type, membuf->dst_data); + mem_buf_free_mem_type_data(membuf->src_mem_type, membuf->src_data); + kfree(membuf->acl_desc); + kfree(membuf); } +EXPORT_SYMBOL(mem_buf_free); struct gh_sgl_desc *mem_buf_get_sgl(void *__membuf) { @@ -1306,7 +1092,6 @@ static void mem_buf_free_alloc_data(struct mem_buf_allocation_data *alloc_data) int mem_buf_alloc_fd(struct mem_buf_alloc_ioctl_arg *allocation_args) { - struct mem_buf_desc *membuf; struct mem_buf_allocation_data alloc_data; int ret; @@ -1323,19 +1108,11 @@ int mem_buf_alloc_fd(struct mem_buf_alloc_ioctl_arg *allocation_args) if (ret < 0) return ret; - /* Only donate is supported currently */ - alloc_data.trans_type = GH_RM_TRANS_TYPE_DONATE; - membuf = mem_buf_alloc(&alloc_data); - if (IS_ERR(membuf)) { - ret = PTR_ERR(membuf); - goto out; - } + if (alloc_data.dst_mem_type == MEM_BUF_DMAHEAP_MEM_TYPE) + ret = qcom_tui_heap_add_pool_fd(&alloc_data); + else + ret = -EINVAL; - ret = mem_buf_get_fd(membuf); - if (ret < 0) - mem_buf_put(membuf); - -out: mem_buf_free_alloc_data(&alloc_data); return ret; } diff --git a/include/linux/mem-buf.h b/include/linux/mem-buf.h index 3f69e1d9755a..ba62641ad8a4 100644 --- a/include/linux/mem-buf.h +++ b/include/linux/mem-buf.h @@ -98,32 +98,37 @@ int mem_buf_reclaim(struct dma_buf *dmabuf); #if IS_ENABLED(CONFIG_QCOM_MEM_BUF) -int mem_buf_get_fd(void *membuf_desc); - -void mem_buf_put(void *membuf_desc); - -void *mem_buf_get(int fd); - +void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data); +void mem_buf_free(void *membuf); struct gh_sgl_desc *mem_buf_get_sgl(void *membuf); #else -static inline int mem_buf_get_fd(void *membuf_desc) -{ - return -ENODEV; -} - -static inline void mem_buf_put(void *membuf_desc) -{ -} - -static inline void *mem_buf_get(int fd) +static inline void *mem_buf_alloc(struct mem_buf_allocation_data *alloc_data) { return ERR_PTR(-ENODEV); } +static inline void mem_buf_free(void *membuf) {} + static inline struct gh_sgl_desc *mem_buf_get_sgl(void *membuf) { return ERR_PTR(-EINVAL); } #endif /* CONFIG_QCOM_MEM_BUF */ + + +#ifdef CONFIG_QCOM_MEM_BUF_DEV_GH +int mem_buf_map_mem_s1(struct gh_sgl_desc *sgl_desc); +int mem_buf_unmap_mem_s1(struct gh_sgl_desc *sgl_desc); +#else +static inline int mem_buf_map_mem_s1(struct gh_sgl_desc *sgl_desc) +{ + return -EINVAL; +} + +static inline int mem_buf_unmap_mem_s1(struct gh_sgl_desc *sgl_desc) +{ + return -EINVAL; +} +#endif /* CONFIG_QCOM_MEM_BUF_DEV_GH */ #endif /* _MEM_BUF_H */ diff --git a/include/linux/qcom_dma_heap.h b/include/linux/qcom_dma_heap.h index 177ed7ef9f75..ce34d5e95a3c 100644 --- a/include/linux/qcom_dma_heap.h +++ b/include/linux/qcom_dma_heap.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _QCOM_DMA_HEAP_H #define _QCOM_DMA_HEAP_H @@ -36,29 +37,6 @@ #define QCOM_DMA_HEAP_FLAG_SECURE BIT(31) -/** - * carveout_heap_add_memory - Dynamically add reserved heap memory - * @heap_name: The name of the DMA-BUF Heap we're giving memory to - * @sgt: An SGT corresponding to the memory adding to the heap - * @cookie: Cookie for managing refcount. - * @get: Function callback for increasing refcount. - * @put: Function callback for decreasing refcount. - * - * Return: 0 on success, a negative error value otherwise. - */ -int carveout_heap_add_memory(char *heap_name, struct sg_table *sgt, void *cookie, - int (*get)(void *), void (*put)(void *)); - - -/** - * carveout_heap_remove_memory - Dynamically remove reserved heap memory - * @heap_name: The name of the DMA-BUF Heap we're taking memory away from - * @sgt: An SGT corresponding to the memory we're removing from the heap - * - * Return: 0 on success, a negative error value otherwise. - */ -int carveout_heap_remove_memory(char *heap_name, struct sg_table *sgt); - struct dma_buf_heap_prefetch_region { u64 size; struct dma_heap *heap; diff --git a/include/linux/qcom_dma_heap_dt_constants.h b/include/linux/qcom_dma_heap_dt_constants.h index 7bfd56fa42e7..088d88a9e009 100644 --- a/include/linux/qcom_dma_heap_dt_constants.h +++ b/include/linux/qcom_dma_heap_dt_constants.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _QCOM_DMA_HEAP_DT_CONSTATS_H #define _QCOM_DMA_HEAP_DT_CONSTATS_H @@ -8,5 +9,6 @@ #define HEAP_TYPE_SECURE_CARVEOUT 0 #define HEAP_TYPE_CARVEOUT 1 #define HEAP_TYPE_CMA 2 +#define HEAP_TYPE_TUI_CARVEOUT 3 #endif /* _QCOM_DMA_HEAP_DT_CONSTATS_H */ diff --git a/include/linux/qcom_tui_heap.h b/include/linux/qcom_tui_heap.h new file mode 100644 index 000000000000..72101b353e66 --- /dev/null +++ b/include/linux/qcom_tui_heap.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _QCOM_TUI_HEAP_H +#define _QCOM_TUI_HEAP_H + +#include + +struct platform_heap; + +#ifdef CONFIG_QCOM_DMABUF_HEAPS_TUI_CARVEOUT +int qcom_tui_carveout_heap_create(struct platform_heap *heap_data); +int qcom_tui_heap_add_pool_fd(struct mem_buf_allocation_data *alloc_data); +#else +static inline int qcom_tui_carveout_heap_create(struct platform_heap *heap_data) +{ + return -EINVAL; +} +static inline int qcom_tui_heap_add_pool_fd(struct mem_buf_allocation_data *alloc_data) +{ + return -EINVAL; +} +#endif + + +#endif /* _QCOM_TUI_HEAP_H */