1 /*
2  * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3  * Decription: memory operation for gp sharedmem.
4  *
5  * This software is licensed under the terms of the GNU General Public
6  * License version 2, as published by the Free Software Foundation, and
7  * may be copied, distributed, and modified under those terms.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  */
14 #include "mem.h"
15 #include <linux/slab.h>
16 #include <linux/uaccess.h>
17 #include <linux/sched.h>
18 #include <linux/list.h>
19 #include <linux/mutex.h>
20 #include <linux/freezer.h>
21 #include <linux/module.h>
22 #include <linux/mempool.h>
23 #include <linux/vmalloc.h>
24 #include <linux/of_reserved_mem.h>
25 #include <securec.h>
26 #include "smc_smp.h"
27 #include "tc_ns_client.h"
28 #include "teek_ns_client.h"
29 #include "agent.h"
30 #include "tc_ns_log.h"
31 #include "mailbox_mempool.h"
32 #include "internal_functions.h"
33 #include "reserved_mempool.h"
34 
tc_mem_free(struct tc_ns_shared_mem *shared_mem)35 void tc_mem_free(struct tc_ns_shared_mem *shared_mem)
36 {
37 	if (!shared_mem)
38 		return;
39 	if (shared_mem->mem_type == RESERVED_TYPE) {
40 		reserved_mem_free(shared_mem->kernel_addr);
41 		kfree(shared_mem);
42 		return;
43 	}
44 
45 	if (shared_mem->kernel_addr) {
46 #ifndef CONFIG_LIBLINUX
47 		vfree(shared_mem->kernel_addr);
48 #else
49 		kfree(shared_mem->kernel_addr);
50 #endif
51 		shared_mem->kernel_addr = NULL;
52 	}
53 	kfree(shared_mem);
54 }
55 
init_shared_mem(struct tc_ns_shared_mem *sh, void *addr, size_t len)56 static void init_shared_mem(struct tc_ns_shared_mem *sh, void *addr, size_t len)
57 {
58 	sh->kernel_addr = addr;
59 	sh->len = (uint32_t)len;
60 	sh->user_addr = INVALID_MAP_ADDR;
61 	sh->user_addr_ca = INVALID_MAP_ADDR;
62 	atomic_set(&sh->usage, 0);
63 }
tc_mem_allocate(size_t len)64 struct tc_ns_shared_mem *tc_mem_allocate(size_t len)
65 {
66 	struct tc_ns_shared_mem *shared_mem = NULL;
67 	void *addr = NULL;
68 
69 	shared_mem = kmalloc(sizeof(*shared_mem), GFP_KERNEL | __GFP_ZERO);
70 	if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)shared_mem)) {
71 		tloge("shared_mem kmalloc failed\n");
72 		return ERR_PTR(-ENOMEM);
73 	}
74 	shared_mem->mem_type = VMALLOC_TYPE;
75 	len = ALIGN(len, SZ_4K);
76 	if (exist_res_mem()) {
77 		if (len > get_res_mem_slice_size()) {
78 			tloge("allocate reserved mem size too large\n");
79 			kfree(shared_mem);
80 			return ERR_PTR(-EINVAL);
81 		}
82 		addr = reserved_mem_alloc(len);
83 		if (addr) {
84 			shared_mem->mem_type = RESERVED_TYPE;
85 			init_shared_mem(shared_mem, addr, len);
86 			return shared_mem;
87 		} else {
88 			tlogw("no more reserved memory to alloc so we use system vmalloc.\n");
89 		}
90 	}
91 	if (len > MAILBOX_POOL_SIZE) {
92 		tloge("alloc sharemem size %zu is too large\n", len);
93 		kfree(shared_mem);
94 		return ERR_PTR(-EINVAL);
95 	}
96 #ifndef CONFIG_LIBLINUX
97 	addr = vmalloc_user(len);
98 #else
99 	addr = kzalloc(len, GFP_KERNEL);
100 #endif
101 	if (!addr) {
102 		tloge("alloc mailbox failed\n");
103 		kfree(shared_mem);
104 		return ERR_PTR(-ENOMEM);
105 	}
106 
107 	init_shared_mem(shared_mem, addr, len);
108 	return shared_mem;
109 }
110