Commit | Line | Data |
---|---|---|
9c92ab61 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
967c9cca | 2 | /* |
d88e0493 | 3 | * Copyright (c) 2015, 2017, 2022 Linaro Limited |
967c9cca JW |
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 | ||
d88e0493 JW |
12 | static int pool_op_gen_alloc(struct tee_shm_pool *pool, struct tee_shm *shm, |
13 | size_t size, size_t align) | |
967c9cca JW |
14 | { |
15 | unsigned long va; | |
d88e0493 JW |
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); | |
967c9cca | 20 | |
d88e0493 | 21 | va = gen_pool_alloc_algo(genpool, s, gen_pool_first_fit_align, &data); |
967c9cca JW |
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(genpool, va); | |
28 | shm->size = s; | |
d88e0493 JW |
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 | */ | |
a45ea4ef | 33 | shm->flags &= ~TEE_SHM_DYNAMIC; |
967c9cca JW |
34 | return 0; |
35 | } | |
36 | ||
d88e0493 | 37 | static void pool_op_gen_free(struct tee_shm_pool *pool, struct tee_shm *shm) |
967c9cca | 38 | { |
d88e0493 | 39 | gen_pool_free(pool->private_data, (unsigned long)shm->kaddr, |
967c9cca JW |
40 | shm->size); |
41 | shm->kaddr = NULL; | |
42 | } | |
43 | ||
d88e0493 | 44 | static void pool_op_gen_destroy_pool(struct tee_shm_pool *pool) |
e2aca5d8 | 45 | { |
d88e0493 JW |
46 | gen_pool_destroy(pool->private_data); |
47 | kfree(pool); | |
e2aca5d8 JW |
48 | } |
49 | ||
d88e0493 | 50 | static const struct tee_shm_pool_ops pool_ops_generic = { |
967c9cca JW |
51 | .alloc = pool_op_gen_alloc, |
52 | .free = pool_op_gen_free, | |
d88e0493 | 53 | .destroy_pool = pool_op_gen_destroy_pool, |
967c9cca JW |
54 | }; |
55 | ||
d88e0493 JW |
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) | |
e2aca5d8 JW |
59 | { |
60 | const size_t page_mask = PAGE_SIZE - 1; | |
d88e0493 | 61 | struct tee_shm_pool *pool; |
e2aca5d8 JW |
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(-EINVAL); | |
67 | ||
d88e0493 JW |
68 | pool = kzalloc(sizeof(*pool), GFP_KERNEL); |
69 | if (!pool) | |
e2aca5d8 JW |
70 | return ERR_PTR(-ENOMEM); |
71 | ||
d88e0493 JW |
72 | pool->private_data = gen_pool_create(min_alloc_order, -1); |
73 | if (!pool->private_data) { | |
e2aca5d8 | 74 | rc = -ENOMEM; |
967c9cca | 75 | goto err; |
e2aca5d8 | 76 | } |
967c9cca | 77 | |
d88e0493 | 78 | rc = gen_pool_add_virt(pool->private_data, vaddr, paddr, size, -1); |
e2aca5d8 | 79 | if (rc) { |
d88e0493 | 80 | gen_pool_destroy(pool->private_data); |
e2aca5d8 JW |
81 | goto err; |
82 | } | |
83 | ||
d88e0493 | 84 | pool->ops = &pool_ops_generic; |
e2aca5d8 | 85 | |
d88e0493 | 86 | return pool; |
967c9cca | 87 | err: |
d88e0493 | 88 | kfree(pool); |
e2aca5d8 JW |
89 | |
90 | return ERR_PTR(rc); | |
967c9cca | 91 | } |
d88e0493 | 92 | EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem); |