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 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 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 */ 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 */ 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 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 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 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 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 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 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 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 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 * 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 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 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 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