1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2015, 2017, 2022 Linaro Limited |
4 | */ |
5 | #include <linux/device.h> |
6 | #include <linux/dma-buf.h> |
7 | #include <linux/genalloc.h> |
8 | #include <linux/slab.h> |
9 | #include <linux/tee_drv.h> |
10 | #include "tee_private.h" |
11 | |
12 | static int pool_op_gen_alloc(struct tee_shm_pool *pool, struct tee_shm *shm, |
13 | size_t size, size_t align) |
14 | { |
15 | unsigned long va; |
16 | struct gen_pool *genpool = pool->private_data; |
17 | size_t a = max_t(size_t, align, BIT(genpool->min_alloc_order)); |
18 | struct genpool_data_align data = { .align = a }; |
19 | size_t s = roundup(size, a); |
20 | |
21 | va = gen_pool_alloc_algo(pool: genpool, size: s, algo: gen_pool_first_fit_align, data: &data); |
22 | if (!va) |
23 | return -ENOMEM; |
24 | |
25 | memset((void *)va, 0, s); |
26 | shm->kaddr = (void *)va; |
27 | shm->paddr = gen_pool_virt_to_phys(pool: genpool, va); |
28 | shm->size = s; |
29 | /* |
30 | * This is from a static shared memory pool so no need to register |
31 | * each chunk, and no need to unregister later either. |
32 | */ |
33 | shm->flags &= ~TEE_SHM_DYNAMIC; |
34 | return 0; |
35 | } |
36 | |
37 | static void pool_op_gen_free(struct tee_shm_pool *pool, struct tee_shm *shm) |
38 | { |
39 | gen_pool_free(pool: pool->private_data, addr: (unsigned long)shm->kaddr, |
40 | size: shm->size); |
41 | shm->kaddr = NULL; |
42 | } |
43 | |
44 | static void pool_op_gen_destroy_pool(struct tee_shm_pool *pool) |
45 | { |
46 | gen_pool_destroy(pool->private_data); |
47 | kfree(objp: pool); |
48 | } |
49 | |
50 | static const struct tee_shm_pool_ops pool_ops_generic = { |
51 | .alloc = pool_op_gen_alloc, |
52 | .free = pool_op_gen_free, |
53 | .destroy_pool = pool_op_gen_destroy_pool, |
54 | }; |
55 | |
56 | struct tee_shm_pool *tee_shm_pool_alloc_res_mem(unsigned long vaddr, |
57 | phys_addr_t paddr, size_t size, |
58 | int min_alloc_order) |
59 | { |
60 | const size_t page_mask = PAGE_SIZE - 1; |
61 | struct tee_shm_pool *pool; |
62 | int rc; |
63 | |
64 | /* Start and end must be page aligned */ |
65 | if (vaddr & page_mask || paddr & page_mask || size & page_mask) |
66 | return ERR_PTR(error: -EINVAL); |
67 | |
68 | pool = kzalloc(size: sizeof(*pool), GFP_KERNEL); |
69 | if (!pool) |
70 | return ERR_PTR(error: -ENOMEM); |
71 | |
72 | pool->private_data = gen_pool_create(min_alloc_order, -1); |
73 | if (!pool->private_data) { |
74 | rc = -ENOMEM; |
75 | goto err; |
76 | } |
77 | |
78 | rc = gen_pool_add_virt(pool: pool->private_data, addr: vaddr, phys: paddr, size, nid: -1); |
79 | if (rc) { |
80 | gen_pool_destroy(pool->private_data); |
81 | goto err; |
82 | } |
83 | |
84 | pool->ops = &pool_ops_generic; |
85 | |
86 | return pool; |
87 | err: |
88 | kfree(objp: pool); |
89 | |
90 | return ERR_PTR(error: rc); |
91 | } |
92 | EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem); |
93 | |