1419b0af8Sopenharmony_ci/*
2419b0af8Sopenharmony_ci * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3419b0af8Sopenharmony_ci * Decription: memory operation for gp sharedmem.
4419b0af8Sopenharmony_ci *
5419b0af8Sopenharmony_ci * This software is licensed under the terms of the GNU General Public
6419b0af8Sopenharmony_ci * License version 2, as published by the Free Software Foundation, and
7419b0af8Sopenharmony_ci * may be copied, distributed, and modified under those terms.
8419b0af8Sopenharmony_ci *
9419b0af8Sopenharmony_ci * This program is distributed in the hope that it will be useful,
10419b0af8Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
11419b0af8Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12419b0af8Sopenharmony_ci * GNU General Public License for more details.
13419b0af8Sopenharmony_ci */
14419b0af8Sopenharmony_ci#include "mem.h"
15419b0af8Sopenharmony_ci#include <linux/slab.h>
16419b0af8Sopenharmony_ci#include <linux/uaccess.h>
17419b0af8Sopenharmony_ci#include <linux/sched.h>
18419b0af8Sopenharmony_ci#include <linux/list.h>
19419b0af8Sopenharmony_ci#include <linux/mutex.h>
20419b0af8Sopenharmony_ci#include <linux/freezer.h>
21419b0af8Sopenharmony_ci#include <linux/module.h>
22419b0af8Sopenharmony_ci#include <linux/mempool.h>
23419b0af8Sopenharmony_ci#include <linux/vmalloc.h>
24419b0af8Sopenharmony_ci#include <linux/of_reserved_mem.h>
25419b0af8Sopenharmony_ci#include <securec.h>
26419b0af8Sopenharmony_ci#include "smc_smp.h"
27419b0af8Sopenharmony_ci#include "tc_ns_client.h"
28419b0af8Sopenharmony_ci#include "teek_ns_client.h"
29419b0af8Sopenharmony_ci#include "agent.h"
30419b0af8Sopenharmony_ci#include "tc_ns_log.h"
31419b0af8Sopenharmony_ci#include "mailbox_mempool.h"
32419b0af8Sopenharmony_ci#include "internal_functions.h"
33419b0af8Sopenharmony_ci#include "reserved_mempool.h"
34419b0af8Sopenharmony_ci
35419b0af8Sopenharmony_civoid tc_mem_free(struct tc_ns_shared_mem *shared_mem)
36419b0af8Sopenharmony_ci{
37419b0af8Sopenharmony_ci	if (!shared_mem)
38419b0af8Sopenharmony_ci		return;
39419b0af8Sopenharmony_ci	if (shared_mem->mem_type == RESERVED_TYPE) {
40419b0af8Sopenharmony_ci		reserved_mem_free(shared_mem->kernel_addr);
41419b0af8Sopenharmony_ci		kfree(shared_mem);
42419b0af8Sopenharmony_ci		return;
43419b0af8Sopenharmony_ci	}
44419b0af8Sopenharmony_ci
45419b0af8Sopenharmony_ci	if (shared_mem->kernel_addr) {
46419b0af8Sopenharmony_ci#ifndef CONFIG_LIBLINUX
47419b0af8Sopenharmony_ci		vfree(shared_mem->kernel_addr);
48419b0af8Sopenharmony_ci#else
49419b0af8Sopenharmony_ci		kfree(shared_mem->kernel_addr);
50419b0af8Sopenharmony_ci#endif
51419b0af8Sopenharmony_ci		shared_mem->kernel_addr = NULL;
52419b0af8Sopenharmony_ci	}
53419b0af8Sopenharmony_ci	kfree(shared_mem);
54419b0af8Sopenharmony_ci}
55419b0af8Sopenharmony_ci
56419b0af8Sopenharmony_cistatic void init_shared_mem(struct tc_ns_shared_mem *sh, void *addr, size_t len)
57419b0af8Sopenharmony_ci{
58419b0af8Sopenharmony_ci	sh->kernel_addr = addr;
59419b0af8Sopenharmony_ci	sh->len = (uint32_t)len;
60419b0af8Sopenharmony_ci	sh->user_addr = INVALID_MAP_ADDR;
61419b0af8Sopenharmony_ci	sh->user_addr_ca = INVALID_MAP_ADDR;
62419b0af8Sopenharmony_ci	atomic_set(&sh->usage, 0);
63419b0af8Sopenharmony_ci}
64419b0af8Sopenharmony_cistruct tc_ns_shared_mem *tc_mem_allocate(size_t len)
65419b0af8Sopenharmony_ci{
66419b0af8Sopenharmony_ci	struct tc_ns_shared_mem *shared_mem = NULL;
67419b0af8Sopenharmony_ci	void *addr = NULL;
68419b0af8Sopenharmony_ci
69419b0af8Sopenharmony_ci	shared_mem = kmalloc(sizeof(*shared_mem), GFP_KERNEL | __GFP_ZERO);
70419b0af8Sopenharmony_ci	if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)shared_mem)) {
71419b0af8Sopenharmony_ci		tloge("shared_mem kmalloc failed\n");
72419b0af8Sopenharmony_ci		return ERR_PTR(-ENOMEM);
73419b0af8Sopenharmony_ci	}
74419b0af8Sopenharmony_ci	shared_mem->mem_type = VMALLOC_TYPE;
75419b0af8Sopenharmony_ci	len = ALIGN(len, SZ_4K);
76419b0af8Sopenharmony_ci	if (exist_res_mem()) {
77419b0af8Sopenharmony_ci		if (len > get_res_mem_slice_size()) {
78419b0af8Sopenharmony_ci			tloge("allocate reserved mem size too large\n");
79419b0af8Sopenharmony_ci			kfree(shared_mem);
80419b0af8Sopenharmony_ci			return ERR_PTR(-EINVAL);
81419b0af8Sopenharmony_ci		}
82419b0af8Sopenharmony_ci		addr = reserved_mem_alloc(len);
83419b0af8Sopenharmony_ci		if (addr) {
84419b0af8Sopenharmony_ci			shared_mem->mem_type = RESERVED_TYPE;
85419b0af8Sopenharmony_ci			init_shared_mem(shared_mem, addr, len);
86419b0af8Sopenharmony_ci			return shared_mem;
87419b0af8Sopenharmony_ci		} else {
88419b0af8Sopenharmony_ci			tlogw("no more reserved memory to alloc so we use system vmalloc.\n");
89419b0af8Sopenharmony_ci		}
90419b0af8Sopenharmony_ci	}
91419b0af8Sopenharmony_ci	if (len > MAILBOX_POOL_SIZE) {
92419b0af8Sopenharmony_ci		tloge("alloc sharemem size %zu is too large\n", len);
93419b0af8Sopenharmony_ci		kfree(shared_mem);
94419b0af8Sopenharmony_ci		return ERR_PTR(-EINVAL);
95419b0af8Sopenharmony_ci	}
96419b0af8Sopenharmony_ci#ifndef CONFIG_LIBLINUX
97419b0af8Sopenharmony_ci	addr = vmalloc_user(len);
98419b0af8Sopenharmony_ci#else
99419b0af8Sopenharmony_ci	addr = kzalloc(len, GFP_KERNEL);
100419b0af8Sopenharmony_ci#endif
101419b0af8Sopenharmony_ci	if (!addr) {
102419b0af8Sopenharmony_ci		tloge("alloc mailbox failed\n");
103419b0af8Sopenharmony_ci		kfree(shared_mem);
104419b0af8Sopenharmony_ci		return ERR_PTR(-ENOMEM);
105419b0af8Sopenharmony_ci	}
106419b0af8Sopenharmony_ci
107419b0af8Sopenharmony_ci	init_shared_mem(shared_mem, addr, len);
108419b0af8Sopenharmony_ci	return shared_mem;
109419b0af8Sopenharmony_ci}
110