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