* Moves shared memory pool handing into tee_shm_pool.c and contains it in a 'struct tee_shm_pool' which the specific driver creates before the driver is registered in the subsystem. * Adds support for allocating shared memory from either CMA or previously reserved memory. * Removes support for allocating shared memory using __get_free_pages(). * Removes teedev pointer from 'struct tee_shm', the pointer can be acquired through the teefilp pointer instead. For private shared memory object the teefilp pointer points to teefilp_private inside the 'struct tee_device' which holds a pointer to teedev.
Note that there's an incompatible API change in tee_drv.h which causes a compile error in OP-TEE. This is fixed in next OP-TEE patch.
Signed-off-by: Jens Wiklander jens.wiklander@linaro.org --- drivers/sec-hw/Makefile | 1 + drivers/sec-hw/tee.c | 13 ++- drivers/sec-hw/tee_private.h | 47 +++++++-- drivers/sec-hw/tee_shm.c | 148 ++++++++++---------------- drivers/sec-hw/tee_shm_pool.c | 232 +++++++++++++++++++++++++++++++++++++++++ include/linux/sec-hw/tee_drv.h | 54 +++++++++- 6 files changed, 383 insertions(+), 112 deletions(-) create mode 100644 drivers/sec-hw/tee_shm_pool.c
diff --git a/drivers/sec-hw/Makefile b/drivers/sec-hw/Makefile index 1c3d990..77a3e9c 100644 --- a/drivers/sec-hw/Makefile +++ b/drivers/sec-hw/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_TEE_GENERIC) += tee.o obj-$(CONFIG_TEE_GENERIC) += tee_shm.o +obj-$(CONFIG_TEE_GENERIC) += tee_shm_pool.o obj-$(CONFIG_TEE_OPTEE) += optee/ diff --git a/drivers/sec-hw/tee.c b/drivers/sec-hw/tee.c index 28d8bc6..afd2925 100644 --- a/drivers/sec-hw/tee.c +++ b/drivers/sec-hw/tee.c @@ -15,10 +15,7 @@ #include <linux/fs.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/fdtable.h> -#include <linux/thread_info.h> #include <linux/uaccess.h> -#include <linux/sched.h> #include <linux/sec-hw/tee_drv.h> #include "tee_private.h"
@@ -125,7 +122,7 @@ static long tee_ioctl_shm_alloc(struct tee_filp *teefilp, return 0; err: if (data.fd >= 0) - __close_fd(current->files, data.fd); + tee_shm_put_fd(data.fd); tee_shm_free(shm); return ret; } @@ -174,14 +171,15 @@ static const struct file_operations tee_fops = { };
struct tee_device *tee_register(const struct tee_desc *teedesc, - struct device *dev, void *driver_data) + struct device *dev, struct tee_shm_pool *pool, + void *driver_data) { static atomic_t device_no = ATOMIC_INIT(-1); static atomic_t priv_device_no = ATOMIC_INIT(-1); struct tee_device *teedev; int ret;
- if (!teedesc || !teedesc->name || !dev) + if (!teedesc || !teedesc->name || !dev || !pool) return NULL;
teedev = kzalloc(sizeof(*teedev), GFP_KERNEL); @@ -190,6 +188,7 @@ struct tee_device *tee_register(const struct tee_desc *teedesc,
teedev->dev = dev; teedev->desc = teedesc; + teedev->pool = pool; teedev->driver_data = driver_data;
if (teedesc->flags & TEE_DESC_PRIVILEGED) @@ -212,7 +211,7 @@ struct tee_device *tee_register(const struct tee_desc *teedesc, }
INIT_LIST_HEAD(&teedev->list_shm); - mutex_init(&teedev->mutex); + teedev->teefilp_private.teedev = teedev;
dev_set_drvdata(teedev->miscdev.this_device, teedev);
diff --git a/drivers/sec-hw/tee_private.h b/drivers/sec-hw/tee_private.h index 0bf4f52..06a59ab 100644 --- a/drivers/sec-hw/tee_private.h +++ b/drivers/sec-hw/tee_private.h @@ -13,28 +13,53 @@ #ifndef TEE_PRIVATE_H #define TEE_PRIVATE_H
-#define TEE_MAX_DEV_NAME_LEN 32 -struct tee_device { - char name[TEE_MAX_DEV_NAME_LEN]; - const struct tee_desc *desc; - struct device *dev; - struct miscdevice miscdev; - struct list_head list_shm; - struct mutex mutex; - void *driver_data; -}; +struct tee_device;
struct tee_shm { struct list_head list_node; - struct tee_device *teedev; struct tee_filp *teefilp; phys_addr_t paddr; void *kaddr; size_t size; struct dma_buf *dmabuf; + struct page *pages; u32 flags; };
+struct tee_shm_pool_mgr; +struct tee_shm_pool_mgr_ops { + int (*alloc)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm, + size_t size); + void (*free)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm); +}; + +struct tee_shm_pool_mgr { + const struct tee_shm_pool_mgr_ops *ops; + void *private_data; +}; + +struct tee_shm_pool { + struct tee_shm_pool_mgr private_mgr; + struct tee_shm_pool_mgr dma_buf_mgr; + void *private_data; +}; + +#define TEE_MAX_DEV_NAME_LEN 32 +struct tee_device { + char name[TEE_MAX_DEV_NAME_LEN]; + const struct tee_desc *desc; + struct device *dev; + struct miscdevice miscdev; + + void *driver_data; + + struct list_head list_shm; + struct tee_filp teefilp_private; + struct tee_shm_pool *pool; +}; + void tee_shm_free_by_teefilp(struct tee_filp *teefilp);
+int tee_shm_init(void); + #endif /*TEE_PRIVATE_H*/ diff --git a/drivers/sec-hw/tee_shm.c b/drivers/sec-hw/tee_shm.c index d70b5ad..7e8a082 100644 --- a/drivers/sec-hw/tee_shm.c +++ b/drivers/sec-hw/tee_shm.c @@ -12,13 +12,16 @@ * */ #include <linux/device.h> +#include <linux/fdtable.h> +#include <linux/sched.h> #include <linux/dma-buf.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/sec-hw/tee_drv.h> #include "tee_private.h"
-static DEFINE_MUTEX(teeshm_list_mutex); -static LIST_HEAD(teeshm_list); +/* Mutex for all shm objects and lists */ +static DEFINE_MUTEX(teeshm_mutex); static LIST_HEAD(teeshm_pending_free_list);
static void tee_shm_release(struct tee_shm *shm); @@ -74,10 +77,10 @@ static struct dma_buf_ops tee_shm_dma_buf_ops = { struct tee_shm *tee_shm_alloc(struct tee_device *teedev, struct tee_filp *teefilp, size_t size, u32 flags) { + struct tee_shm_pool_mgr *poolm = NULL; struct tee_shm *shm; void *ret; - struct mutex *mutex; - struct list_head *list_shm; + int rc;
if (!(flags & TEE_SHM_MAPPED)) { dev_err(teedev->dev, "only mapped allocations supported\n"); @@ -96,27 +99,30 @@ struct tee_shm *tee_shm_alloc(struct tee_device *teedev, shm->flags = flags;
if (flags & TEE_SHM_DMA_BUF) { - int order = get_order(size); - - /* Global shm's must have a teefilp attached */ + /* dma_buf shm:s must have a teefilp attached */ if (!teefilp) { ret = ERR_PTR(-EINVAL); goto err; } - shm->teefilp = teefilp; - shm->size = (1 << order) << PAGE_SHIFT; - /* Request zeroed pages to not leak information */ - shm->kaddr = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, - order); - if (!shm->kaddr) { - dev_err(teedev->dev, - "failed to get order %d pages for shared memory\n", - order); - ret = ERR_PTR(-ENOMEM); + poolm = &teedev->pool->dma_buf_mgr; + } else { + /* Driver private shm:s must not have a teefilp attached */ + if (teefilp) { + ret = ERR_PTR(-EINVAL); goto err; } + shm->teefilp = &teedev->teefilp_private; + poolm = &teedev->pool->private_mgr; + } + + rc = poolm->ops->alloc(poolm, shm, size); + if (rc) { + ret = ERR_PTR(rc); + goto err; + }
+ if (flags & TEE_SHM_DMA_BUF) { shm->dmabuf = dma_buf_export(shm, &tee_shm_dma_buf_ops, shm->size, O_RDWR, NULL); if (IS_ERR(shm->dmabuf)) { @@ -125,56 +131,25 @@ struct tee_shm *tee_shm_alloc(struct tee_device *teedev, } get_dma_buf(shm->dmabuf);
- mutex = &teeshm_list_mutex; - list_shm = &teeshm_list; - } else { - /* Driver private shm's must not have a teefilp attached */ - if (teefilp) { - ret = ERR_PTR(-EINVAL); - goto err; - } - shm->size = size; - shm->kaddr = kzalloc(size, GFP_KERNEL); - if (!shm->kaddr) { - dev_err(teedev->dev, - "failed to allocate %zu bytes of shared memory\n", - size); - ret = ERR_PTR(-ENOMEM); - goto err; - } - - mutex = &teedev->mutex; - list_shm = &teedev->list_shm; - } - - shm->teedev = teedev; - shm->paddr = virt_to_phys(shm->kaddr); - - if (flags & TEE_SHM_DMA_BUF) { /* * Only call share on global shm:s, as the driver private * shm:s always originates from the driver itself. */ - int rc = teedev->desc->ops->shm_share(shm); - + rc = teedev->desc->ops->shm_share(shm); if (rc) { ret = ERR_PTR(rc); goto err; } }
- mutex_lock(mutex); - list_add_tail(&shm->list_node, list_shm); - mutex_unlock(mutex); + mutex_lock(&teeshm_mutex); + list_add_tail(&shm->list_node, &teedev->list_shm); + mutex_unlock(&teeshm_mutex);
return shm; err: - if (shm->kaddr) { - if (shm->flags & TEE_SHM_DMA_BUF) - free_pages((unsigned long)shm->kaddr, get_order(size)); - else - kfree(shm->kaddr); - } + if (poolm && shm->kaddr) + poolm->ops->free(poolm, shm); kfree(shm); return ret; } @@ -193,30 +168,34 @@ int tee_shm_fd(struct tee_shm *shm) } EXPORT_SYMBOL_GPL(tee_shm_fd);
+int tee_shm_put_fd(int fd) +{ + return __close_fd(current->files, fd); +} +EXPORT_SYMBOL_GPL(tee_shm_put_fd); + + static void tee_shm_release(struct tee_shm *shm) { - struct tee_device *teedev = shm->teedev; + struct tee_device *teedev = shm->teefilp->teedev; + struct tee_shm_pool_mgr *poolm;
- if (shm->flags & TEE_SHM_DMA_BUF) { - /* Only unshare global shm:s */ - shm->teedev->desc->ops->shm_unshare(shm); + mutex_lock(&teeshm_mutex); + list_del(&shm->list_node); + mutex_unlock(&teeshm_mutex);
- free_pages((unsigned long)shm->kaddr, get_order(shm->size)); - mutex_lock(&teeshm_list_mutex); - list_del(&shm->list_node); - mutex_unlock(&teeshm_list_mutex); - } else { - kfree(shm->kaddr); - mutex_lock(&teedev->mutex); - list_del(&shm->list_node); - mutex_unlock(&teedev->mutex); - } + if (shm->flags & TEE_SHM_DMA_BUF) + poolm = &teedev->pool->dma_buf_mgr; + else + poolm = &teedev->pool->private_mgr;
+ poolm->ops->free(poolm, shm); kfree(shm); }
void tee_shm_free_by_teefilp(struct tee_filp *teefilp) { + struct tee_device *teedev = teefilp->teedev; struct tee_shm *shm; struct tee_shm *tmp; LIST_HEAD(tmp_list); @@ -224,36 +203,30 @@ void tee_shm_free_by_teefilp(struct tee_filp *teefilp) /* * Move all matching shm:s to a temporary list */ - mutex_lock(&teeshm_list_mutex); - list_for_each_entry_safe(shm, tmp, &teeshm_list, list_node) { + mutex_lock(&teeshm_mutex); + list_for_each_entry_safe(shm, tmp, &teedev->list_shm, list_node) { if (shm->teefilp == teefilp) { list_del(&shm->list_node); list_add_tail(&shm->list_node, &tmp_list); } } - mutex_unlock(&teeshm_list_mutex); + mutex_unlock(&teeshm_mutex);
/* * For each shm in the temporary list move it to the pending free * list and call tee_shm_free(). Once the ref_count is 0 the shm * will be removed from this list. - * - * Since the 'struct tee_filp' is about to be freed (the reason - * this function was called) set the teefilp to NULL. The only - * purpose of the teefilp in 'struct tee_shm' is to be able to find - * all shm:s related to a teefilp. */ while (true) { - mutex_lock(&teeshm_list_mutex); + mutex_lock(&teeshm_mutex); shm = list_first_entry_or_null(&tmp_list, struct tee_shm, list_node); if (shm) { list_del(&shm->list_node); list_add_tail(&shm->list_node, &teeshm_pending_free_list); - shm->teefilp = NULL; } - mutex_unlock(&teeshm_list_mutex); + mutex_unlock(&teeshm_mutex); if (!shm) break; tee_shm_free(shm); @@ -263,6 +236,7 @@ void tee_shm_free_by_teefilp(struct tee_filp *teefilp)
void tee_shm_free(struct tee_shm *shm) { + /* * dma_buf_put() decreases the dmabuf reference counter and will * call tee_shm_release() when the last reference is gone. @@ -295,25 +269,15 @@ static struct tee_shm *tee_shm_find_by_key(struct tee_device *teedev, u32 flags, { struct tee_shm *ret = NULL; struct tee_shm *shm; - struct mutex *mutex; - struct list_head *list_shm; - - if (flags & TEE_SHM_DMA_BUF) { - mutex = &teeshm_list_mutex; - list_shm = &teeshm_list; - } else { - mutex = &teedev->mutex; - list_shm = &teedev->list_shm; - }
- mutex_lock(mutex); - list_for_each_entry(shm, list_shm, list_node) { + mutex_lock(&teeshm_mutex); + list_for_each_entry(shm, &teedev->list_shm, list_node) { if (cmp(shm, key)) { ret = shm; break; } } - mutex_unlock(mutex); + mutex_unlock(&teeshm_mutex);
return ret; } diff --git a/drivers/sec-hw/tee_shm_pool.c b/drivers/sec-hw/tee_shm_pool.c new file mode 100644 index 0000000..b1abad7 --- /dev/null +++ b/drivers/sec-hw/tee_shm_pool.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <linux/device.h> +#include <linux/dma-buf.h> +#include <linux/slab.h> +#include <linux/genalloc.h> +#ifdef CONFIG_CMA +#include <linux/cma.h> +#include <linux/dma-contiguous.h> +#endif +#include <linux/sec-hw/tee_drv.h> +#include "tee_private.h" + +#define SHM_POOL_NUM_PRIV_PAGES 1 + +static int pool_op_gen_alloc(struct tee_shm_pool_mgr *poolm, + struct tee_shm *shm, size_t size) +{ + unsigned long va; + struct gen_pool *genpool = poolm->private_data; + size_t s = roundup(size, 1 << genpool->min_alloc_order); + + va = gen_pool_alloc(genpool, s); + if (!va) + return -ENOMEM; + shm->kaddr = (void *)va; + shm->paddr = gen_pool_virt_to_phys(genpool, va); + shm->size = s; + return 0; +} + +static void pool_op_gen_free(struct tee_shm_pool_mgr *poolm, + struct tee_shm *shm) +{ + gen_pool_free(poolm->private_data, (unsigned long)shm->kaddr, + shm->size); + shm->kaddr = NULL; +} + +static const struct tee_shm_pool_mgr_ops pool_ops_generic = { + .alloc = pool_op_gen_alloc, + .free = pool_op_gen_free, +}; + +#ifdef CONFIG_CMA +static int pool_op_cma_alloc(struct tee_shm_pool_mgr *poolm, + struct tee_shm *shm, size_t size) +{ + unsigned long order = get_order(PAGE_SIZE); + size_t count; + struct page *pages; + + /* + * It's not valid to call this function with size = 0, but if size + * is 0 we'll get a very large number and the allocation will fail. + */ + count = ((size - 1) >> PAGE_SHIFT) + 1; + pages = cma_alloc(poolm->private_data, count, order); + if (!pages) + return -ENOMEM; + shm->kaddr = page_address(pages); + shm->pages = pages; + shm->paddr = virt_to_phys(shm->kaddr); + shm->size = count << PAGE_SHIFT; + return 0; +} + +static void pool_op_cma_free(struct tee_shm_pool_mgr *poolm, + struct tee_shm *shm) +{ + size_t count; + + count = shm->size >> PAGE_SHIFT; + cma_release(poolm->private_data, shm->pages, count); + shm->kaddr = NULL; +} + +static const struct tee_shm_pool_mgr_ops pool_ops_cma = { + .alloc = pool_op_cma_alloc, + .free = pool_op_cma_free, +}; + +struct tee_shm_pool *tee_shm_pool_alloc_cma(struct device *dev, u_long *vaddr, + phys_addr_t *paddr, size_t *size) +{ + struct cma *cma = dev_get_cma_area(dev); + struct tee_shm_pool *pool; + struct page *page; + size_t order = get_order(PAGE_SIZE); + struct gen_pool *genpool = NULL; + void *va; + int ret; + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + return ERR_PTR(-ENOMEM); + + page = cma_alloc(cma, SHM_POOL_NUM_PRIV_PAGES, order); + if (!page) { + ret = -ENOMEM; + goto err; + } + genpool = gen_pool_create(get_order(8), -1); + if (!genpool) { + ret = -ENOMEM; + goto err; + } + gen_pool_set_algo(genpool, gen_pool_best_fit, NULL); + + va = page_address(page); + ret = gen_pool_add_virt(genpool, (u_long)va, virt_to_phys(va), + SHM_POOL_NUM_PRIV_PAGES * PAGE_SIZE, -1); + if (ret) + goto err; + + pool->private_data = page; + pool->private_mgr.private_data = genpool; + pool->private_mgr.ops = &pool_ops_generic; + pool->dma_buf_mgr.private_data = cma; + pool->dma_buf_mgr.ops = &pool_ops_cma; + + *paddr = cma_get_base(cma); + *vaddr = (u_long)phys_to_virt(*paddr); + *size = cma_get_size(cma); + return pool; +err: + if (genpool) + gen_pool_destroy(genpool); + if (page) + cma_release(cma, page, SHM_POOL_NUM_PRIV_PAGES); + kfree(pool); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_cma); +#endif + +struct tee_shm_pool *tee_shm_pool_alloc_res_mem(u_long vaddr, + phys_addr_t paddr, size_t size) +{ + size_t page_mask = PAGE_SIZE - 1; + size_t priv_size = PAGE_SIZE * SHM_POOL_NUM_PRIV_PAGES; + struct tee_shm_pool *pool; + struct gen_pool *genpool = NULL; + int ret; + + /* + * Start and end must be page aligned + */ + if ((vaddr & page_mask) || (paddr & page_mask) || (size & page_mask)) + return ERR_PTR(-EINVAL); + + /* + * Wouldn't make sense to have less than twice the number of + * private pages, in practice the size has to be much larger, but + * this is the absolute minimum. + */ + if (size < priv_size * 2) + return ERR_PTR(-EINVAL); + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + return ERR_PTR(-ENOMEM); + + /* + * Create the pool for driver private shared memory + */ + genpool = gen_pool_create(3 /* 8 byte aligned */, -1); + if (!genpool) { + ret = -ENOMEM; + goto err; + } + gen_pool_set_algo(genpool, gen_pool_best_fit, NULL); + ret = gen_pool_add_virt(genpool, vaddr, paddr, priv_size, -1); + if (ret) + goto err; + pool->private_mgr.private_data = genpool; + pool->private_mgr.ops = &pool_ops_generic; + + /* + * Create the pool for dma_buf shared memory + */ + genpool = gen_pool_create(PAGE_SHIFT, -1); + gen_pool_set_algo(genpool, gen_pool_best_fit, NULL); + if (!genpool) { + ret = -ENOMEM; + goto err; + } + ret = gen_pool_add_virt(genpool, vaddr + priv_size, paddr + priv_size, + size - priv_size, -1); + if (ret) + goto err; + pool->dma_buf_mgr.private_data = genpool; + pool->dma_buf_mgr.ops = &pool_ops_generic; + return pool; +err: + if (pool->private_mgr.private_data) + gen_pool_destroy(pool->private_mgr.private_data); + if (genpool) + gen_pool_destroy(genpool); + kfree(pool); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem); + +void tee_shm_pool_free(struct tee_shm_pool *pool) +{ +#ifdef CONFIG_CMA + if (pool->dma_buf_mgr.ops == &pool_ops_cma) { + gen_pool_destroy(pool->private_mgr.private_data); + cma_release(pool->dma_buf_mgr.private_data, pool->private_data, + SHM_POOL_NUM_PRIV_PAGES); + } else +#endif + if (pool->dma_buf_mgr.ops == &pool_ops_generic) { + gen_pool_destroy(pool->private_mgr.private_data); + gen_pool_destroy(pool->dma_buf_mgr.private_data); + } + + kfree(pool); +} +EXPORT_SYMBOL_GPL(tee_shm_pool_free); diff --git a/include/linux/sec-hw/tee_drv.h b/include/linux/sec-hw/tee_drv.h index 0ea8c10..f9dd9d6 100644 --- a/include/linux/sec-hw/tee_drv.h +++ b/include/linux/sec-hw/tee_drv.h @@ -32,7 +32,7 @@
struct tee_device; struct tee_shm; - +struct tee_shm_pool;
/** * struct tee_filp - driver specific file pointer data @@ -90,7 +90,8 @@ struct tee_desc { * @returns a pointer to struct tee_device */ struct tee_device *tee_register(const struct tee_desc *teedesc, - struct device *dev, void *driver_data); + struct device *dev, struct tee_shm_pool *pool, + void *driver_data);
/** * tee_unregister() - Unregister a specific TEE driver @@ -99,6 +100,48 @@ struct tee_device *tee_register(const struct tee_desc *teedesc, void tee_unregister(struct tee_device *teedev);
/** + * tee_shm_pool_alloc_cma() - Create a shared memory pool based on device default CMA area + * @dev: Device to get default CMA area from + * @vaddr: Returned virtual address of start of CMA area + * @paddr: Returned physical address of start of CMA area + * @size: Returned size of CMA area + * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure. + */ +#ifdef CONFIG_CMA +struct tee_shm_pool *tee_shm_pool_alloc_cma(struct device *dev, u_long *vaddr, + phys_addr_t *paddr, size_t *size); +#else +struct tee_shm_pool *tee_shm_pool_alloc_cma(struct device *dev, u_long *vaddr, + phys_addr_t *paddr, size_t *size) +{ + return ERR_PTR(-ENOENT); +} +#endif + +/** + * tee_shm_pool_alloc_res_mem() - Create a shared memory pool a reserved memory range + * @vaddr: Virtual address of start of pool + * @paddr: Physical address of start of pool + * @size: Size in bytes of the pool + * + * Start of pool will be rounded up to the nearest page, end of pool will + * be rounded down to the nearest page. + * + * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure. + */ +struct tee_shm_pool *tee_shm_pool_alloc_res_mem(u_long vaddr, + phys_addr_t paddr, size_t size); + +/** + * tee_shm_pool_free() - Free a shared memory pool + * @pool: The shared memory pool to free + * + * The must be no remaining shared memory allocated from this pool when + * this function is called. + */ +void tee_shm_pool_free(struct tee_shm_pool *pool); + +/** * tee_get_drvdata() - Return driver_data pointer * @returns the driver_data pointer supplied to tee_register(). */ @@ -218,4 +261,11 @@ void tee_shm_put(struct tee_shm *shm); */ int tee_shm_fd(struct tee_shm *shm);
+/** + * tee_shm_put_fd() - Decrease reference count and close file descriptor + * @fd: File descriptor to close + * @returns < 0 on failure + */ +int tee_shm_put_fd(int fd); + #endif /*__TEE_DRV_H*/