dma-heaps: Define qcom tui carveout heap

Move behavior specific to the tui carveout heap usecase out of
the mem-buf driver, and existing dma-heap carveout driver into a
new file. This is done to reduce code complexity in the dma-heap
carveout driver, as well as to prepare for adding new mem-buf
clients.

Change-Id: I1241e009e63b8e21c55920d3561c5a1777cbf83c
Signed-off-by: Patrick Daly <quic_pdaly@quicinc.com>
This commit is contained in:
Patrick Daly 2022-05-19 18:39:40 -07:00 committed by Chris Goldsworthy
parent 9cac3c58a2
commit aa9a1b50ef
13 changed files with 433 additions and 420 deletions

View File

@ -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.

View File

@ -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

View File

@ -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 <linux/dma-mapping.h>
@ -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);

View File

@ -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 <linux/module.h>
@ -9,6 +10,7 @@
#include <linux/err.h>
#include <linux/qcom_dma_heap.h>
#include <linux/qcom_tui_heap.h>
#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;

View File

@ -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 <linux/of.h>
@ -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);

View File

@ -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;

View File

@ -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 <linux/genalloc.h>
#include <linux/dma-heap.h>
#include <linux/slab.h>
#include <linux/mem-buf.h>
#include <linux/anon_inodes.h>
#include <linux/kref.h>
#include <linux/qcom_tui_heap.h>
#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;
}

View File

@ -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)
{

View File

@ -10,6 +10,7 @@
#include <linux/memory_hotplug.h>
#include <linux/module.h>
#include <linux/qcom_dma_heap.h>
#include <linux/qcom_tui_heap.h>
#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;
}

View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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 <linux/mem-buf.h>
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 */