xref: /wlan-driver/qca-wifi-host-cmn/wbuff/src/wbuff.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: wbuff.c
22  * wbuff buffer management APIs
23  */
24 
25 #include <wbuff.h>
26 #include <linux/debugfs.h>
27 #include <linux/seq_file.h>
28 #include <qdf_debugfs.h>
29 #include "i_wbuff.h"
30 
31 /*
32  * Allocation holder array for all wbuff registered modules
33  */
34 struct wbuff_holder wbuff;
35 
36 /**
37  * wbuff_get_pool_slot_from_len() - get pool_id from length
38  * @mod: wbuff module reference
39  * @len: length of the buffer
40  *
41  * Return: pool_id
42  */
43 static uint8_t
wbuff_get_pool_slot_from_len(struct wbuff_module * mod,uint16_t len)44 wbuff_get_pool_slot_from_len(struct wbuff_module *mod, uint16_t len)
45 {
46 	struct wbuff_pool *pool;
47 	uint16_t prev_buf_size = 0;
48 	int i;
49 
50 	for (i = 0; i < WBUFF_MAX_POOLS; i++) {
51 		pool = &mod->wbuff_pool[i];
52 
53 		if (!pool->initialized)
54 			continue;
55 
56 		if ((len > prev_buf_size) && (len <= pool->buffer_size))
57 			break;
58 
59 		prev_buf_size = mod->wbuff_pool[i].buffer_size;
60 	}
61 
62 	return i;
63 }
64 
65 /**
66  * wbuff_is_valid_alloc_req() - validate alloc  request
67  * @req: allocation request from registered module
68  * @num: number of pools required
69  *
70  * Return: true if valid wbuff_alloc_request
71  *         false if invalid wbuff_alloc_request
72  */
73 static bool
wbuff_is_valid_alloc_req(struct wbuff_alloc_request * req,uint8_t num)74 wbuff_is_valid_alloc_req(struct wbuff_alloc_request *req, uint8_t num)
75 {
76 	int i;
77 
78 	for (i = 0; i < num; i++) {
79 		if (req[i].pool_id >= WBUFF_MAX_POOLS)
80 			return false;
81 	}
82 
83 	return true;
84 }
85 
86 /**
87  * wbuff_prepare_nbuf() - allocate nbuf
88  * @module_id: module ID
89  * @pool_id: pool ID
90  * @len: length of the buffer
91  * @reserve: nbuf headroom to start with
92  * @align: alignment for the nbuf
93  *
94  * Return: nbuf if success
95  *         NULL if failure
96  */
wbuff_prepare_nbuf(uint8_t module_id,uint8_t pool_id,uint32_t len,int reserve,int align)97 static qdf_nbuf_t wbuff_prepare_nbuf(uint8_t module_id, uint8_t pool_id,
98 				     uint32_t len, int reserve, int align)
99 {
100 	qdf_nbuf_t buf;
101 	unsigned long dev_scratch = 0;
102 	struct wbuff_module *mod = &wbuff.mod[module_id];
103 	struct wbuff_pool *wbuff_pool = &mod->wbuff_pool[pool_id];
104 
105 	buf = qdf_nbuf_page_frag_alloc(NULL, len, reserve, align,
106 				       &wbuff.pf_cache);
107 	if (!buf)
108 		return NULL;
109 	dev_scratch = module_id;
110 	dev_scratch <<= WBUFF_MODULE_ID_SHIFT;
111 	dev_scratch |= ((pool_id << WBUFF_POOL_ID_SHIFT) | 1);
112 	qdf_nbuf_set_dev_scratch(buf, dev_scratch);
113 
114 	wbuff_pool->mem_alloc += qdf_nbuf_get_allocsize(buf);
115 
116 	return buf;
117 }
118 
119 /**
120  * wbuff_is_valid_handle() - validate wbuff handle
121  * @handle: wbuff handle passed by module
122  *
123  * Return: true - valid wbuff_handle
124  *         false - invalid wbuff_handle
125  */
wbuff_is_valid_handle(struct wbuff_handle * handle)126 static bool wbuff_is_valid_handle(struct wbuff_handle *handle)
127 {
128 	if ((handle) && (handle->id < WBUFF_MAX_MODULES) &&
129 	    (wbuff.mod[handle->id].registered))
130 		return true;
131 
132 	return false;
133 }
134 
wbuff_get_mod_name(enum wbuff_module_id module_id)135 static char *wbuff_get_mod_name(enum wbuff_module_id module_id)
136 {
137 	char *str;
138 
139 	switch (module_id) {
140 	case WBUFF_MODULE_WMI_TX:
141 		str = "WBUFF_MODULE_WMI_TX";
142 		break;
143 	case WBUFF_MODULE_CE_RX:
144 		str = "WBUFF_MODULE_CE_RX";
145 		break;
146 	default:
147 		str = "Invalid Module ID";
148 		break;
149 	}
150 
151 	return str;
152 }
153 
wbuff_debugfs_print(qdf_debugfs_file_t file,const char * fmt,...)154 static void wbuff_debugfs_print(qdf_debugfs_file_t file, const char *fmt, ...)
155 {
156 	va_list args;
157 
158 	va_start(args, fmt);
159 	seq_vprintf(file, fmt, args);
160 	va_end(args);
161 }
162 
wbuff_stats_debugfs_show(qdf_debugfs_file_t file,void * data)163 static int wbuff_stats_debugfs_show(qdf_debugfs_file_t file, void *data)
164 {
165 	struct wbuff_module *mod;
166 	struct wbuff_pool *wbuff_pool;
167 	int i, j;
168 
169 	wbuff_debugfs_print(file, "WBUFF POOL STATS:\n");
170 	wbuff_debugfs_print(file, "=================\n");
171 
172 	for (i = 0; i < WBUFF_MAX_MODULES; i++) {
173 		mod = &wbuff.mod[i];
174 
175 		if (!mod->registered)
176 			continue;
177 
178 		wbuff_debugfs_print(file, "Module (%d) : %s\n", i,
179 				    wbuff_get_mod_name(i));
180 
181 		wbuff_debugfs_print(file, "%s %25s %20s %20s\n", "Pool ID",
182 				    "Mem Allocated (In Bytes)",
183 				    "Wbuff Success Count",
184 				    "Wbuff Fail Count");
185 
186 		for (j = 0; j < WBUFF_MAX_POOLS; j++) {
187 			wbuff_pool = &mod->wbuff_pool[j];
188 
189 			if (!wbuff_pool->initialized)
190 				continue;
191 
192 			wbuff_debugfs_print(file, "%d %30llu %20llu %20llu\n",
193 					    j, wbuff_pool->mem_alloc,
194 					    wbuff_pool->alloc_success,
195 					    wbuff_pool->alloc_fail);
196 		}
197 		wbuff_debugfs_print(file, "\n");
198 	}
199 
200 	return 0;
201 }
202 
wbuff_stats_debugfs_open(struct inode * inode,struct file * file)203 static int wbuff_stats_debugfs_open(struct inode *inode, struct file *file)
204 {
205 	return single_open(file, wbuff_stats_debugfs_show,
206 			   inode->i_private);
207 }
208 
209 static const struct file_operations wbuff_stats_fops = {
210 	.owner          = THIS_MODULE,
211 	.open           = wbuff_stats_debugfs_open,
212 	.release        = single_release,
213 	.read           = seq_read,
214 	.llseek         = seq_lseek,
215 };
216 
wbuff_debugfs_init(void)217 static QDF_STATUS wbuff_debugfs_init(void)
218 {
219 	wbuff.wbuff_debugfs_dir =
220 		qdf_debugfs_create_dir("wbuff", NULL);
221 
222 	if (!wbuff.wbuff_debugfs_dir)
223 		return QDF_STATUS_E_FAILURE;
224 
225 	wbuff.wbuff_stats_dentry =
226 		qdf_debugfs_create_entry("wbuff_stats", QDF_FILE_USR_READ,
227 					 wbuff.wbuff_debugfs_dir, NULL,
228 					 &wbuff_stats_fops);
229 	if (!wbuff.wbuff_stats_dentry)
230 		return QDF_STATUS_E_FAILURE;
231 
232 	return QDF_STATUS_SUCCESS;
233 }
234 
wbuff_debugfs_exit(void)235 static void wbuff_debugfs_exit(void)
236 {
237 	if (!wbuff.wbuff_debugfs_dir)
238 		return;
239 
240 	debugfs_remove_recursive(wbuff.wbuff_debugfs_dir);
241 	wbuff.wbuff_debugfs_dir = NULL;
242 }
243 
wbuff_module_init(void)244 QDF_STATUS wbuff_module_init(void)
245 {
246 	struct wbuff_module *mod = NULL;
247 	uint8_t module_id = 0, pool_id = 0;
248 
249 	if (!qdf_nbuf_is_dev_scratch_supported()) {
250 		wbuff.initialized = false;
251 		return QDF_STATUS_E_NOSUPPORT;
252 	}
253 
254 	for (module_id = 0; module_id < WBUFF_MAX_MODULES; module_id++) {
255 		mod = &wbuff.mod[module_id];
256 		qdf_spinlock_create(&mod->lock);
257 		for (pool_id = 0; pool_id < WBUFF_MAX_POOLS; pool_id++)
258 			mod->wbuff_pool[pool_id].pool = NULL;
259 		mod->registered = false;
260 	}
261 
262 	wbuff_debugfs_init();
263 
264 	wbuff.initialized = true;
265 
266 	return QDF_STATUS_SUCCESS;
267 }
268 
wbuff_module_deinit(void)269 QDF_STATUS wbuff_module_deinit(void)
270 {
271 	struct wbuff_module *mod = NULL;
272 	uint8_t module_id = 0;
273 
274 	if (!wbuff.initialized)
275 		return QDF_STATUS_E_INVAL;
276 
277 	wbuff.initialized = false;
278 	wbuff_debugfs_exit();
279 
280 	for (module_id = 0; module_id < WBUFF_MAX_MODULES; module_id++) {
281 		mod = &wbuff.mod[module_id];
282 		if (mod->registered)
283 			wbuff_module_deregister((struct wbuff_mod_handle *)
284 						&mod->handle);
285 		qdf_spinlock_destroy(&mod->lock);
286 	}
287 
288 	return QDF_STATUS_SUCCESS;
289 }
290 
291 struct wbuff_mod_handle *
wbuff_module_register(struct wbuff_alloc_request * req,uint8_t num_pools,int reserve,int align,enum wbuff_module_id module_id)292 wbuff_module_register(struct wbuff_alloc_request *req, uint8_t num_pools,
293 		      int reserve, int align, enum wbuff_module_id module_id)
294 {
295 	struct wbuff_module *mod = NULL;
296 	struct wbuff_pool *wbuff_pool;
297 	qdf_nbuf_t buf = NULL;
298 	uint32_t len;
299 	uint16_t pool_size;
300 	uint8_t pool_id;
301 	int i;
302 	int j;
303 
304 	if (!wbuff.initialized)
305 		return NULL;
306 
307 	if ((num_pools == 0) || (num_pools > WBUFF_MAX_POOLS))
308 		return NULL;
309 
310 	if (module_id >= WBUFF_MAX_MODULES)
311 		return NULL;
312 
313 	if (!wbuff_is_valid_alloc_req(req, num_pools))
314 		return NULL;
315 
316 	mod = &wbuff.mod[module_id];
317 	if (mod->registered)
318 		return NULL;
319 
320 	mod->handle.id = module_id;
321 
322 	for (i = 0; i < num_pools; i++) {
323 		pool_id = req[i].pool_id;
324 		pool_size = req[i].pool_size;
325 		len = req[i].buffer_size;
326 		wbuff_pool = &mod->wbuff_pool[pool_id];
327 
328 		if (!pool_size)
329 			continue;
330 
331 		/**
332 		 * Allocate pool_size number of buffers for
333 		 * the pool given by pool_id
334 		 */
335 		for (j = 0; j < pool_size; j++) {
336 			buf = wbuff_prepare_nbuf(module_id, pool_id, len,
337 						 reserve, align);
338 			if (!buf)
339 				continue;
340 
341 			if (!wbuff_pool->pool)
342 				qdf_nbuf_set_next(buf, NULL);
343 			else
344 				qdf_nbuf_set_next(buf, wbuff_pool->pool);
345 
346 			wbuff_pool->pool = buf;
347 		}
348 
349 		wbuff_pool->pool_id = pool_id;
350 		wbuff_pool->buffer_size = len;
351 		wbuff_pool->initialized = true;
352 	}
353 
354 	mod->reserve = reserve;
355 	mod->align = align;
356 	mod->registered = true;
357 
358 
359 	return (struct wbuff_mod_handle *)&mod->handle;
360 }
361 
wbuff_module_deregister(struct wbuff_mod_handle * hdl)362 QDF_STATUS wbuff_module_deregister(struct wbuff_mod_handle *hdl)
363 {
364 	struct wbuff_handle *handle;
365 	struct wbuff_module *mod = NULL;
366 	uint8_t module_id = 0, pool_id = 0;
367 	qdf_nbuf_t first = NULL, buf = NULL;
368 	struct wbuff_pool *wbuff_pool;
369 
370 	handle = (struct wbuff_handle *)hdl;
371 
372 	if ((!wbuff.initialized) || (!wbuff_is_valid_handle(handle)))
373 		return QDF_STATUS_E_INVAL;
374 
375 	module_id = handle->id;
376 
377 	if (module_id >= WBUFF_MAX_MODULES)
378 		return QDF_STATUS_E_INVAL;
379 
380 	mod = &wbuff.mod[module_id];
381 
382 	qdf_spin_lock_bh(&mod->lock);
383 	for (pool_id = 0; pool_id < WBUFF_MAX_POOLS; pool_id++) {
384 		wbuff_pool = &mod->wbuff_pool[pool_id];
385 
386 		if (!wbuff_pool->initialized)
387 			continue;
388 
389 		first = wbuff_pool->pool;
390 		while (first) {
391 			buf = first;
392 			first = qdf_nbuf_next(buf);
393 			qdf_nbuf_free(buf);
394 		}
395 
396 		wbuff_pool->mem_alloc = 0;
397 		wbuff_pool->alloc_success = 0;
398 		wbuff_pool->alloc_fail = 0;
399 
400 	}
401 	mod->registered = false;
402 	qdf_spin_unlock_bh(&mod->lock);
403 
404 	return QDF_STATUS_SUCCESS;
405 }
406 
407 qdf_nbuf_t
wbuff_buff_get(struct wbuff_mod_handle * hdl,uint8_t pool_id,uint32_t len,const char * func_name,uint32_t line_num)408 wbuff_buff_get(struct wbuff_mod_handle *hdl, uint8_t pool_id, uint32_t len,
409 	       const char *func_name, uint32_t line_num)
410 {
411 	struct wbuff_handle *handle;
412 	struct wbuff_module *mod = NULL;
413 	struct wbuff_pool *wbuff_pool;
414 	uint8_t module_id = 0;
415 	qdf_nbuf_t buf = NULL;
416 
417 	handle = (struct wbuff_handle *)hdl;
418 
419 	if ((!wbuff.initialized) || (!wbuff_is_valid_handle(handle)) ||
420 	    ((pool_id >= WBUFF_MAX_POOL_ID && !len)))
421 		return NULL;
422 
423 	module_id = handle->id;
424 
425 	if (module_id >= WBUFF_MAX_MODULES)
426 		return NULL;
427 
428 	mod = &wbuff.mod[module_id];
429 
430 	if (pool_id == WBUFF_MAX_POOL_ID && len)
431 		pool_id = wbuff_get_pool_slot_from_len(mod, len);
432 
433 	if (pool_id >= WBUFF_MAX_POOLS)
434 		return NULL;
435 
436 	wbuff_pool = &mod->wbuff_pool[pool_id];
437 	if (!wbuff_pool->initialized)
438 		return NULL;
439 
440 	qdf_spin_lock_bh(&mod->lock);
441 	if (wbuff_pool->pool) {
442 		buf = wbuff_pool->pool;
443 		wbuff_pool->pool = qdf_nbuf_next(buf);
444 		mod->pending_returns++;
445 	}
446 	qdf_spin_unlock_bh(&mod->lock);
447 
448 	if (buf) {
449 		qdf_nbuf_set_next(buf, NULL);
450 		qdf_net_buf_debug_update_node(buf, func_name, line_num);
451 		wbuff_pool->alloc_success++;
452 	} else {
453 		wbuff_pool->alloc_fail++;
454 	}
455 
456 	return buf;
457 }
458 
wbuff_buff_put(qdf_nbuf_t buf)459 qdf_nbuf_t wbuff_buff_put(qdf_nbuf_t buf)
460 {
461 	qdf_nbuf_t buffer = buf;
462 	unsigned long pool_info = 0;
463 	uint8_t module_id = 0, pool_id = 0;
464 	struct wbuff_pool *wbuff_pool;
465 
466 	if (qdf_nbuf_get_users(buffer) > 1)
467 		return buffer;
468 
469 	if (!wbuff.initialized)
470 		return buffer;
471 
472 	pool_info = qdf_nbuf_get_dev_scratch(buf);
473 	if (!pool_info)
474 		return buffer;
475 
476 	module_id = (pool_info & WBUFF_MODULE_ID_BITMASK) >>
477 			WBUFF_MODULE_ID_SHIFT;
478 	pool_id = (pool_info & WBUFF_POOL_ID_BITMASK) >> WBUFF_POOL_ID_SHIFT;
479 
480 	if (module_id >= WBUFF_MAX_MODULES || pool_id >= WBUFF_MAX_POOLS)
481 		return buffer;
482 
483 	wbuff_pool = &wbuff.mod[module_id].wbuff_pool[pool_id];
484 	if (!wbuff_pool->initialized)
485 		return buffer;
486 
487 	qdf_nbuf_reset(buffer, wbuff.mod[module_id].reserve,
488 		       wbuff.mod[module_id].align);
489 
490 	qdf_spin_lock_bh(&wbuff.mod[module_id].lock);
491 	if (wbuff.mod[module_id].registered) {
492 		qdf_nbuf_set_next(buffer, wbuff_pool->pool);
493 		wbuff_pool->pool = buffer;
494 		wbuff.mod[module_id].pending_returns--;
495 		buffer = NULL;
496 	}
497 	qdf_spin_unlock_bh(&wbuff.mod[module_id].lock);
498 
499 	return buffer;
500 }
501