blob: f87aac685d52f9a8466f28929521cefee4101c86 [file] [log] [blame]
Googlerb48fa912023-03-17 12:40:29 +05301/* Copyright (c) 2008-2014, 2016-2017, 2019, 2021 The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/mempool.h>
17#include <linux/slab.h>
18#include <linux/of.h>
19#include <linux/kmemleak.h>
20#include <linux/ratelimit.h>
21#include <linux/atomic.h>
22#include <linux/slab.h>
23#include <linux/of.h>
24#include <linux/kmemleak.h>
25
26#include "diagchar.h"
27#include "diagmem.h"
28
29struct diag_mempool_t diag_mempools[NUM_MEMORY_POOLS] = {
30 {
31 .id = POOL_TYPE_COPY,
32 .name = "POOL_COPY",
33 .pool = NULL,
34 .itemsize = 0,
35 .poolsize = 0,
36 .count = 0
37 },
38 {
39 .id = POOL_TYPE_HDLC,
40 .name = "POOL_HDLC",
41 .pool = NULL,
42 .itemsize = 0,
43 .poolsize = 0,
44 .count = 0
45 },
46 {
47 .id = POOL_TYPE_USER,
48 .name = "POOL_USER",
49 .pool = NULL,
50 .itemsize = 0,
51 .poolsize = 0,
52 .count = 0
53 },
54 {
55 .id = POOL_TYPE_MUX_APPS,
56 .name = "POOL_MUX_APPS",
57 .pool = NULL,
58 .itemsize = 0,
59 .poolsize = 0,
60 .count = 0
61 },
62 {
63 .id = POOL_TYPE_DCI,
64 .name = "POOL_DCI",
65 .pool = NULL,
66 .itemsize = 0,
67 .poolsize = 0,
68 .count = 0
69 },
70#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
71 {
72 .id = POOL_TYPE_MDM,
73 .name = "POOL_MDM",
74 .pool = NULL,
75 .itemsize = 0,
76 .poolsize = 0,
77 .count = 0
78 },
79 {
80 .id = POOL_TYPE_MDM2,
81 .name = "POOL_MDM2",
82 .pool = NULL,
83 .itemsize = 0,
84 .poolsize = 0,
85 .count = 0
86 },
87 {
88 .id = POOL_TYPE_MDM_DCI,
89 .name = "POOL_MDM_DCI",
90 .pool = NULL,
91 .itemsize = 0,
92 .poolsize = 0,
93 .count = 0
94 },
95 {
96 .id = POOL_TYPE_MDM2_DCI,
97 .name = "POOL_MDM2_DCI",
98 .pool = NULL,
99 .itemsize = 0,
100 .poolsize = 0,
101 .count = 0
102 },
103 {
104 .id = POOL_TYPE_MDM_MUX,
105 .name = "POOL_MDM_MUX",
106 .pool = NULL,
107 .itemsize = 0,
108 .poolsize = 0,
109 .count = 0
110 },
111 {
112 .id = POOL_TYPE_MDM2_MUX,
113 .name = "POOL_MDM2_MUX",
114 .pool = NULL,
115 .itemsize = 0,
116 .poolsize = 0,
117 .count = 0
118 },
119 {
120 .id = POOL_TYPE_MDM_DCI_WRITE,
121 .name = "POOL_MDM_DCI_WRITE",
122 .pool = NULL,
123 .itemsize = 0,
124 .poolsize = 0,
125 .count = 0
126 },
127 {
128 .id = POOL_TYPE_MDM2_DCI_WRITE,
129 .name = "POOL_MDM2_DCI_WRITE",
130 .pool = NULL,
131 .itemsize = 0,
132 .poolsize = 0,
133 .count = 0
134 },
135 {
136 .id = POOL_TYPE_QSC_MUX,
137 .name = "POOL_QSC_MUX",
138 .pool = NULL,
139 .itemsize = 0,
140 .poolsize = 0,
141 .count = 0
142 }
143#endif
144};
145
146void diagmem_setsize(int pool_idx, int itemsize, int poolsize)
147{
148 if (pool_idx < 0 || pool_idx >= NUM_MEMORY_POOLS) {
149 pr_err("diag: Invalid pool index %d in %s\n", pool_idx,
150 __func__);
151 return;
152 }
153
154 diag_mempools[pool_idx].itemsize = itemsize;
155 if (diag_mempools[pool_idx].pool)
156 diag_mempools[pool_idx].pool->pool_data =
157 (void *)(uintptr_t)itemsize;
158 diag_mempools[pool_idx].poolsize = poolsize;
159 pr_debug("diag: Mempool %s sizes: itemsize %d poolsize %d\n",
160 diag_mempools[pool_idx].name, diag_mempools[pool_idx].itemsize,
161 diag_mempools[pool_idx].poolsize);
162}
163
164void *diagmem_alloc(struct diagchar_dev *driver, int size, int pool_type)
165{
166 void *buf = NULL;
167 int i = 0;
168 unsigned long flags;
169 struct diag_mempool_t *mempool = NULL;
170
171 if (!driver)
172 return NULL;
173
174 for (i = 0; i < NUM_MEMORY_POOLS; i++) {
175 mempool = &diag_mempools[i];
176 if (pool_type != mempool->id)
177 continue;
178 if (!mempool->pool) {
179 pr_err_ratelimited("diag: %s mempool is not initialized yet\n",
180 mempool->name);
181 break;
182 }
183 if (size == 0 || size > mempool->itemsize ||
184 size > (uintptr_t) mempool->pool->pool_data
185 ) {
186 pr_err_ratelimited("diag: cannot alloc from mempool %s, invalid size: %d\n",
187 mempool->name, size);
188 break;
189 }
190 spin_lock_irqsave(&mempool->lock, flags);
191 if (mempool->count < mempool->poolsize) {
192 atomic_add(1, (atomic_t *)&mempool->count);
193 buf = mempool_alloc(mempool->pool, GFP_ATOMIC);
194 kmemleak_not_leak(buf);
195 }
196 spin_unlock_irqrestore(&mempool->lock, flags);
197 if (!buf) {
198 pr_debug_ratelimited("diag: Unable to allocate buffer from memory pool %s, size: %d/%d count: %d/%d\n",
199 mempool->name,
200 size, mempool->itemsize,
201 mempool->count,
202 mempool->poolsize);
203 }
204 break;
205 }
206
207 return buf;
208}
209
210void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type)
211{
212 int i = 0;
213 unsigned long flags;
214 struct diag_mempool_t *mempool = NULL;
215
216 if (!driver || !buf)
217 return;
218
219 for (i = 0; i < NUM_MEMORY_POOLS; i++) {
220 mempool = &diag_mempools[i];
221 if (pool_type != mempool->id)
222 continue;
223 if (!mempool->pool) {
224 pr_err_ratelimited("diag: %s mempool is not initialized yet\n",
225 mempool->name);
226 break;
227 }
228 spin_lock_irqsave(&mempool->lock, flags);
229 if (mempool->count > 0 && buf) {
230 mempool_free(buf, mempool->pool);
231 atomic_add(-1, (atomic_t *)&mempool->count);
232 } else {
233 pr_err_ratelimited("diag: Attempting to free items from %s mempool which is already empty\n",
234 mempool->name);
235 }
236 spin_unlock_irqrestore(&mempool->lock, flags);
237 break;
238 }
239}
240
241void diagmem_init(struct diagchar_dev *driver, int index)
242{
243 struct diag_mempool_t *mempool = NULL;
244
245 if (!driver)
246 return;
247
248 if (index < 0 || index >= NUM_MEMORY_POOLS) {
249 pr_err("diag: In %s, Invalid index %d\n", __func__, index);
250 return;
251 }
252
253 mempool = &diag_mempools[index];
254 if (mempool->pool) {
255 pr_debug("diag: mempool %s is already initialized\n",
256 mempool->name);
257 return;
258 }
259 if (mempool->itemsize <= 0 || mempool->poolsize <= 0) {
260 pr_err("diag: Unable to initialize %s mempool, itemsize: %d poolsize: %d\n",
261 mempool->name, mempool->itemsize,
262 mempool->poolsize);
263 return;
264 }
265
266 mempool->pool = mempool_create_kmalloc_pool(mempool->poolsize,
267 mempool->itemsize);
268 if (!mempool->pool)
269 pr_err("diag: cannot allocate %s mempool\n", mempool->name);
270 else
271 kmemleak_not_leak(mempool->pool);
272
273 spin_lock_init(&mempool->lock);
274}
275
276void diagmem_exit(struct diagchar_dev *driver, int index)
277{
278 unsigned long flags;
279 struct diag_mempool_t *mempool = NULL;
280
281 if (!driver)
282 return;
283
284 if (index < 0 || index >= NUM_MEMORY_POOLS) {
285 pr_err("diag: In %s, Invalid index %d\n", __func__, index);
286 return;
287 }
288
289 mempool = &diag_mempools[index];
290 spin_lock_irqsave(&mempool->lock, flags);
291 if (mempool->count == 0 && mempool->pool != NULL) {
292 mempool_destroy(mempool->pool);
293 mempool->pool = NULL;
294 } else {
295 pr_err("diag: Unable to destroy %s pool, count: %d\n",
296 mempool->name, mempool->count);
297 }
298 spin_unlock_irqrestore(&mempool->lock, flags);
299}
300