xref: /openbmc/linux/drivers/tee/tee_shm_pool.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2967c9ccaSJens Wiklander /*
3d88e0493SJens Wiklander  * Copyright (c) 2015, 2017, 2022 Linaro Limited
4967c9ccaSJens Wiklander  */
5967c9ccaSJens Wiklander #include <linux/device.h>
6967c9ccaSJens Wiklander #include <linux/dma-buf.h>
7967c9ccaSJens Wiklander #include <linux/genalloc.h>
8967c9ccaSJens Wiklander #include <linux/slab.h>
9967c9ccaSJens Wiklander #include <linux/tee_drv.h>
10967c9ccaSJens Wiklander #include "tee_private.h"
11967c9ccaSJens Wiklander 
pool_op_gen_alloc(struct tee_shm_pool * pool,struct tee_shm * shm,size_t size,size_t align)12d88e0493SJens Wiklander static int pool_op_gen_alloc(struct tee_shm_pool *pool, struct tee_shm *shm,
13d88e0493SJens Wiklander 			     size_t size, size_t align)
14967c9ccaSJens Wiklander {
15967c9ccaSJens Wiklander 	unsigned long va;
16d88e0493SJens Wiklander 	struct gen_pool *genpool = pool->private_data;
17d88e0493SJens Wiklander 	size_t a = max_t(size_t, align, BIT(genpool->min_alloc_order));
18d88e0493SJens Wiklander 	struct genpool_data_align data = { .align = a };
19d88e0493SJens Wiklander 	size_t s = roundup(size, a);
20967c9ccaSJens Wiklander 
21d88e0493SJens Wiklander 	va = gen_pool_alloc_algo(genpool, s, gen_pool_first_fit_align, &data);
22967c9ccaSJens Wiklander 	if (!va)
23967c9ccaSJens Wiklander 		return -ENOMEM;
24967c9ccaSJens Wiklander 
25967c9ccaSJens Wiklander 	memset((void *)va, 0, s);
26967c9ccaSJens Wiklander 	shm->kaddr = (void *)va;
27967c9ccaSJens Wiklander 	shm->paddr = gen_pool_virt_to_phys(genpool, va);
28967c9ccaSJens Wiklander 	shm->size = s;
29d88e0493SJens Wiklander 	/*
30d88e0493SJens Wiklander 	 * This is from a static shared memory pool so no need to register
31d88e0493SJens Wiklander 	 * each chunk, and no need to unregister later either.
32d88e0493SJens Wiklander 	 */
33*a45ea4efSJens Wiklander 	shm->flags &= ~TEE_SHM_DYNAMIC;
34967c9ccaSJens Wiklander 	return 0;
35967c9ccaSJens Wiklander }
36967c9ccaSJens Wiklander 
pool_op_gen_free(struct tee_shm_pool * pool,struct tee_shm * shm)37d88e0493SJens Wiklander static void pool_op_gen_free(struct tee_shm_pool *pool, struct tee_shm *shm)
38967c9ccaSJens Wiklander {
39d88e0493SJens Wiklander 	gen_pool_free(pool->private_data, (unsigned long)shm->kaddr,
40967c9ccaSJens Wiklander 		      shm->size);
41967c9ccaSJens Wiklander 	shm->kaddr = NULL;
42967c9ccaSJens Wiklander }
43967c9ccaSJens Wiklander 
pool_op_gen_destroy_pool(struct tee_shm_pool * pool)44d88e0493SJens Wiklander static void pool_op_gen_destroy_pool(struct tee_shm_pool *pool)
45e2aca5d8SJens Wiklander {
46d88e0493SJens Wiklander 	gen_pool_destroy(pool->private_data);
47d88e0493SJens Wiklander 	kfree(pool);
48e2aca5d8SJens Wiklander }
49e2aca5d8SJens Wiklander 
50d88e0493SJens Wiklander static const struct tee_shm_pool_ops pool_ops_generic = {
51967c9ccaSJens Wiklander 	.alloc = pool_op_gen_alloc,
52967c9ccaSJens Wiklander 	.free = pool_op_gen_free,
53d88e0493SJens Wiklander 	.destroy_pool = pool_op_gen_destroy_pool,
54967c9ccaSJens Wiklander };
55967c9ccaSJens Wiklander 
tee_shm_pool_alloc_res_mem(unsigned long vaddr,phys_addr_t paddr,size_t size,int min_alloc_order)56d88e0493SJens Wiklander struct tee_shm_pool *tee_shm_pool_alloc_res_mem(unsigned long vaddr,
57d88e0493SJens Wiklander 						phys_addr_t paddr, size_t size,
58e2aca5d8SJens Wiklander 						int min_alloc_order)
59e2aca5d8SJens Wiklander {
60e2aca5d8SJens Wiklander 	const size_t page_mask = PAGE_SIZE - 1;
61d88e0493SJens Wiklander 	struct tee_shm_pool *pool;
62e2aca5d8SJens Wiklander 	int rc;
63e2aca5d8SJens Wiklander 
64e2aca5d8SJens Wiklander 	/* Start and end must be page aligned */
65e2aca5d8SJens Wiklander 	if (vaddr & page_mask || paddr & page_mask || size & page_mask)
66e2aca5d8SJens Wiklander 		return ERR_PTR(-EINVAL);
67e2aca5d8SJens Wiklander 
68e2aca5d8SJens Wiklander 	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
69e2aca5d8SJens Wiklander 	if (!pool)
70e2aca5d8SJens Wiklander 		return ERR_PTR(-ENOMEM);
71e2aca5d8SJens Wiklander 
72d88e0493SJens Wiklander 	pool->private_data = gen_pool_create(min_alloc_order, -1);
73d88e0493SJens Wiklander 	if (!pool->private_data) {
74d88e0493SJens Wiklander 		rc = -ENOMEM;
75d88e0493SJens Wiklander 		goto err;
76d88e0493SJens Wiklander 	}
77d88e0493SJens Wiklander 
78d88e0493SJens Wiklander 	rc = gen_pool_add_virt(pool->private_data, vaddr, paddr, size, -1);
79d88e0493SJens Wiklander 	if (rc) {
80d88e0493SJens Wiklander 		gen_pool_destroy(pool->private_data);
81d88e0493SJens Wiklander 		goto err;
82d88e0493SJens Wiklander 	}
83d88e0493SJens Wiklander 
84d88e0493SJens Wiklander 	pool->ops = &pool_ops_generic;
85e2aca5d8SJens Wiklander 
86e2aca5d8SJens Wiklander 	return pool;
87d88e0493SJens Wiklander err:
88967c9ccaSJens Wiklander 	kfree(pool);
89d88e0493SJens Wiklander 
90d88e0493SJens Wiklander 	return ERR_PTR(rc);
91967c9ccaSJens Wiklander }
92d88e0493SJens Wiklander EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem);
93