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
35void 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
56static 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}
64struct 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