1 /* 2 * Copyright (c) 2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 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: qdf_nbuf_frag.c 22 * QCA driver framework(QDF) network nbuf frag management APIs 23 */ 24 25 #include <qdf_atomic.h> 26 #include <qdf_list.h> 27 #include <qdf_debugfs.h> 28 #include <qdf_module.h> 29 #include <qdf_nbuf_frag.h> 30 #include <qdf_trace.h> 31 #include "qdf_str.h" 32 33 #ifdef QDF_NBUF_FRAG_GLOBAL_COUNT 34 #define FRAG_DEBUGFS_NAME "frag_counters" 35 static qdf_atomic_t frag_count; 36 #endif 37 38 #if defined(NBUF_FRAG_MEMORY_DEBUG) || defined(QDF_NBUF_FRAG_GLOBAL_COUNT) 39 static bool is_initial_mem_debug_disabled; 40 #endif 41 42 #ifdef QDF_NBUF_FRAG_GLOBAL_COUNT 43 44 uint32_t __qdf_frag_count_get(void) 45 { 46 return qdf_atomic_read(&frag_count); 47 } 48 49 qdf_export_symbol(__qdf_frag_count_get); 50 51 void __qdf_frag_count_inc(uint32_t value) 52 { 53 if (qdf_likely(is_initial_mem_debug_disabled)) 54 return; 55 56 qdf_atomic_add(value, &frag_count); 57 } 58 59 qdf_export_symbol(__qdf_frag_count_inc); 60 61 void __qdf_frag_count_dec(uint32_t value) 62 { 63 if (qdf_likely(is_initial_mem_debug_disabled)) 64 return; 65 66 qdf_atomic_sub(value, &frag_count); 67 } 68 69 qdf_export_symbol(__qdf_frag_count_dec); 70 71 void __qdf_frag_mod_init(void) 72 { 73 is_initial_mem_debug_disabled = qdf_mem_debug_config_get(); 74 qdf_atomic_init(&frag_count); 75 qdf_debugfs_create_atomic(FRAG_DEBUGFS_NAME, S_IRUSR, NULL, 76 &frag_count); 77 } 78 79 void __qdf_frag_mod_exit(void) 80 { 81 } 82 #endif /* QDF_NBUF_FRAG_GLOBAL_COUNT */ 83 84 #ifdef NBUF_FRAG_MEMORY_DEBUG 85 86 #define QDF_FRAG_TRACK_MAX_SIZE 1024 87 88 /** 89 * struct qdf_frag_track_node_t - Network frag tracking node structure 90 * @hnode: list_head for next and prev pointers 91 * @p_frag: Pointer to frag 92 * @alloc_func_name: Function where frag is allocated 93 * @alloc_func_line: Allocation function line no. 94 * @refcount: No. of references to the frag 95 * @last_func_name: Function where frag recently accessed 96 * @last_func_line_num: Line number of last function 97 * 98 **/ 99 struct qdf_frag_track_node_t { 100 qdf_list_node_t hnode; 101 qdf_frag_t p_frag; 102 char alloc_func_name[QDF_MEM_FUNC_NAME_SIZE]; 103 uint32_t alloc_func_line; 104 uint8_t refcount; 105 char last_func_name[QDF_MEM_FUNC_NAME_SIZE]; 106 uint32_t last_func_line; 107 }; 108 109 /** 110 * struct qdf_frag_tracking_list_t - Frag node tracking list 111 * @track_list: qdf_list_t for maintaining the list 112 * @list_lock: Lock over the list 113 * 114 */ 115 typedef struct qdf_frag_tracking_list_t { 116 qdf_list_t track_list; 117 qdf_spinlock_t list_lock; 118 } qdf_frag_tracking_list; 119 120 typedef struct qdf_frag_track_node_t QDF_FRAG_TRACK; 121 122 /** 123 * Array of tracking list for maintaining 124 * allocated debug frag nodes as per the calculated 125 * hash value. 126 */ 127 static qdf_frag_tracking_list gp_qdf_frag_track_tbl[QDF_FRAG_TRACK_MAX_SIZE]; 128 129 static struct kmem_cache *frag_tracking_cache; 130 131 /* Tracking list for maintaining the free debug frag nodes */ 132 static qdf_frag_tracking_list qdf_frag_track_free_list; 133 134 /** 135 * Parameters for statistics 136 * qdf_frag_track_free_list_count: No. of free nodes 137 * qdf_frag_track_used_list_count : No. of nodes used 138 * qdf_frag_track_max_used : Max no. of nodes used during execution 139 * qdf_frag_track_max_free : Max free nodes observed during execution 140 * qdf_frag_track_max_allocated: Max no. of allocated nodes 141 */ 142 static uint32_t qdf_frag_track_free_list_count; 143 static uint32_t qdf_frag_track_used_list_count; 144 static uint32_t qdf_frag_track_max_used; 145 static uint32_t qdf_frag_track_max_free; 146 static uint32_t qdf_frag_track_max_allocated; 147 148 /** 149 * qdf_frag_update_max_used() - Update qdf_frag_track_max_used tracking variable 150 * 151 * Tracks the max number of frags that the wlan driver was tracking at any one 152 * time 153 * 154 * Return: none 155 **/ 156 static inline void qdf_frag_update_max_used(void) 157 { 158 int sum; 159 160 /* Update max_used if it is less than used list count */ 161 if (qdf_frag_track_max_used < qdf_frag_track_used_list_count) 162 qdf_frag_track_max_used = qdf_frag_track_used_list_count; 163 164 /* Calculate no. of allocated nodes */ 165 sum = qdf_frag_track_used_list_count + qdf_frag_track_free_list_count; 166 167 /* Update max allocated if less then no. of allocated nodes */ 168 if (qdf_frag_track_max_allocated < sum) 169 qdf_frag_track_max_allocated = sum; 170 } 171 172 /** 173 * qdf_frag_update_max_free() - Update qdf_frag_track_max_free 174 * 175 * Tracks the max number tracking buffers kept in the freelist. 176 * 177 * Return: none 178 */ 179 static inline void qdf_frag_update_max_free(void) 180 { 181 if (qdf_frag_track_max_free < qdf_frag_track_free_list_count) 182 qdf_frag_track_max_free = qdf_frag_track_free_list_count; 183 } 184 185 /** 186 * qdf_frag_track_alloc() - Allocate a cookie to track frags allocated by wlan 187 * 188 * This function pulls from freelist if possible,otherwise uses kmem_cache_alloc 189 * This function also adds fexibility to adjust the allocation and freelist 190 * schemes. 191 * 192 * Return: Pointer to an unused QDF_FRAG_TRACK structure which may not be zeroed 193 */ 194 static QDF_FRAG_TRACK *qdf_frag_track_alloc(void) 195 { 196 int flags = GFP_KERNEL; 197 QDF_FRAG_TRACK *frag_track_node = NULL; 198 qdf_list_node_t *temp_list_node; 199 200 qdf_spin_lock_irqsave(&qdf_frag_track_free_list.list_lock); 201 qdf_frag_track_used_list_count++; 202 203 if (!qdf_list_empty(&qdf_frag_track_free_list.track_list)) { 204 qdf_list_remove_front(&qdf_frag_track_free_list.track_list, 205 &temp_list_node); 206 frag_track_node = qdf_container_of(temp_list_node, 207 struct qdf_frag_track_node_t, 208 hnode); 209 qdf_frag_track_free_list_count--; 210 } 211 212 qdf_frag_update_max_used(); 213 qdf_spin_unlock_irqrestore(&qdf_frag_track_free_list.list_lock); 214 215 if (frag_track_node) 216 return frag_track_node; 217 218 if (in_interrupt() || irqs_disabled() || in_atomic()) 219 flags = GFP_ATOMIC; 220 221 frag_track_node = kmem_cache_alloc(frag_tracking_cache, flags); 222 if (frag_track_node) 223 qdf_init_list_head(&frag_track_node->hnode); 224 225 return frag_track_node; 226 } 227 228 /* FREEQ_POOLSIZE initial and minimum desired freelist poolsize */ 229 #define FREEQ_POOLSIZE 2048 230 231 /** 232 * qdf_frag_track_free() - Free the frag tracking cookie. 233 * @frag_track_node : Debug frag node address 234 * 235 * Matches calls to qdf_frag_track_alloc. 236 * Either frees the tracking cookie to kernel or an internal 237 * freelist based on the size of the freelist. 238 * 239 * Return: none 240 */ 241 static void qdf_frag_track_free(QDF_FRAG_TRACK *frag_track_node) 242 { 243 if (!frag_track_node) 244 return; 245 246 /* 247 * Try to shrink the freelist if free_list_count > than FREEQ_POOLSIZE 248 * only shrink the freelist if it is bigger than twice the number of 249 * frags in use. Otherwise add the frag debug track node to the front 250 * of qdf_frag_track_free_list. 251 */ 252 253 qdf_spin_lock_irqsave(&qdf_frag_track_free_list.list_lock); 254 255 qdf_frag_track_used_list_count--; 256 if (qdf_frag_track_free_list_count > FREEQ_POOLSIZE && 257 (qdf_frag_track_free_list_count > 258 qdf_frag_track_used_list_count << 1)) { 259 kmem_cache_free(frag_tracking_cache, frag_track_node); 260 } else { 261 qdf_list_insert_front(&qdf_frag_track_free_list.track_list, 262 &frag_track_node->hnode); 263 qdf_frag_track_free_list_count++; 264 } 265 qdf_frag_update_max_free(); 266 qdf_spin_unlock_irqrestore(&qdf_frag_track_free_list.list_lock); 267 } 268 269 /** 270 * qdf_frag_track_prefill() - Prefill the frag tracking cookie freelist 271 * 272 * Return: none 273 */ 274 static void qdf_frag_track_prefill(void) 275 { 276 int index; 277 QDF_FRAG_TRACK *curr_node, *next_node; 278 qdf_list_t temp_list; 279 280 qdf_list_create(&temp_list, 0); 281 282 /* Prepopulate the freelist */ 283 for (index = 0; index < FREEQ_POOLSIZE; index++) { 284 curr_node = qdf_frag_track_alloc(); 285 if (!curr_node) 286 continue; 287 qdf_list_insert_front(&temp_list, &curr_node->hnode); 288 } 289 290 curr_node = NULL; 291 next_node = NULL; 292 293 qdf_list_for_each_del(&temp_list, curr_node, next_node, hnode) { 294 qdf_list_remove_node(&temp_list, &curr_node->hnode); 295 qdf_frag_track_free(curr_node); 296 } 297 298 /* prefilled buffers should not count as used */ 299 qdf_frag_track_max_used = 0; 300 301 qdf_list_destroy(&temp_list); 302 } 303 304 /** 305 * qdf_frag_track_memory_manager_create() - Manager for frag tracking cookies 306 * 307 * This initializes the memory manager for the frag tracking cookies. Because 308 * these cookies are all the same size and only used in this feature, we can 309 * use a kmem_cache to provide tracking as well as to speed up allocations. 310 * To avoid the overhead of allocating and freeing the buffers (including SLUB 311 * features) a freelist is prepopulated here. 312 * 313 * Return: none 314 */ 315 static void qdf_frag_track_memory_manager_create(void) 316 { 317 qdf_spinlock_create(&qdf_frag_track_free_list.list_lock); 318 qdf_list_create(&qdf_frag_track_free_list.track_list, 0); 319 frag_tracking_cache = kmem_cache_create("qdf_frag_tracking_cache", 320 sizeof(QDF_FRAG_TRACK), 321 0, 0, NULL); 322 323 qdf_frag_track_prefill(); 324 } 325 326 /** 327 * qdf_frag_track_memory_manager_destroy() - Manager for frag tracking cookies 328 * 329 * Empty the freelist and print out usage statistics when it is no longer 330 * needed. Also the kmem_cache should be destroyed here so that it can warn if 331 * any frag tracking cookies were leaked. 332 * 333 * Return: none 334 */ 335 static void qdf_frag_track_memory_manager_destroy(void) 336 { 337 QDF_FRAG_TRACK *curr_node, *next_node; 338 339 curr_node = next_node = NULL; 340 341 qdf_spin_lock_irqsave(&qdf_frag_track_free_list.list_lock); 342 343 if (qdf_frag_track_max_used > FREEQ_POOLSIZE * 4) 344 qdf_info("Unexpectedly large max_used count %d", 345 qdf_frag_track_max_used); 346 347 if (qdf_frag_track_max_used < qdf_frag_track_max_allocated) 348 qdf_info("%d Unused trackers were allocated", 349 qdf_frag_track_max_allocated - 350 qdf_frag_track_max_used); 351 352 if (qdf_frag_track_free_list_count > FREEQ_POOLSIZE && 353 qdf_frag_track_free_list_count > 3 * qdf_frag_track_max_used / 4) 354 qdf_info("Check freelist shrinking functionality"); 355 356 qdf_info("%d Residual freelist size", qdf_frag_track_free_list_count); 357 358 qdf_info("%d Max freelist size observed", qdf_frag_track_max_free); 359 360 qdf_info("%d Max buffers used observed", qdf_frag_track_max_used); 361 362 qdf_info("%d Max buffers allocated observed", 363 qdf_frag_track_max_allocated); 364 365 qdf_list_for_each_del(&qdf_frag_track_free_list.track_list, 366 curr_node, next_node, hnode) { 367 qdf_list_remove_node(&qdf_frag_track_free_list.track_list, 368 &curr_node->hnode); 369 kmem_cache_free(frag_tracking_cache, curr_node); 370 qdf_frag_track_free_list_count--; 371 } 372 373 if (qdf_frag_track_free_list_count != 0) 374 qdf_info("%d Unfreed tracking memory lost in freelist", 375 qdf_frag_track_free_list_count); 376 377 if (qdf_frag_track_used_list_count != 0) 378 qdf_info("%d Unfreed tracking memory still in use", 379 qdf_frag_track_used_list_count); 380 381 qdf_spin_unlock_irqrestore(&qdf_frag_track_free_list.list_lock); 382 kmem_cache_destroy(frag_tracking_cache); 383 384 qdf_list_destroy(&qdf_frag_track_free_list.track_list); 385 qdf_spinlock_destroy(&qdf_frag_track_free_list.list_lock); 386 } 387 388 /** 389 * qdf_frag_debug_init() - Initialize network frag debug functionality 390 * 391 * QDF frag buffer debug feature tracks all frags allocated by WLAN driver 392 * in a hash table and when driver is unloaded it reports about leaked frags. 393 * 394 * Return: none 395 */ 396 void qdf_frag_debug_init(void) 397 { 398 uint32_t index; 399 400 is_initial_mem_debug_disabled = qdf_mem_debug_config_get(); 401 402 if (is_initial_mem_debug_disabled) 403 return; 404 405 qdf_frag_track_memory_manager_create(); 406 407 for (index = 0; index < QDF_FRAG_TRACK_MAX_SIZE; index++) { 408 qdf_list_create(&gp_qdf_frag_track_tbl[index].track_list, 0); 409 qdf_spinlock_create(&gp_qdf_frag_track_tbl[index].list_lock); 410 } 411 } 412 413 qdf_export_symbol(qdf_frag_debug_init); 414 415 /** 416 * qdf_frag_buf_debug_exit() - Exit network frag debug functionality 417 * 418 * Exit network frag tracking debug functionality and log frag memory leaks 419 * 420 * Return: none 421 */ 422 void qdf_frag_debug_exit(void) 423 { 424 uint32_t index; 425 QDF_FRAG_TRACK *p_node; 426 QDF_FRAG_TRACK *p_prev; 427 428 if (is_initial_mem_debug_disabled) 429 return; 430 431 for (index = 0; index < QDF_FRAG_TRACK_MAX_SIZE; index++) { 432 qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock); 433 qdf_list_for_each_del(&gp_qdf_frag_track_tbl[index].track_list, 434 p_prev, p_node, hnode) { 435 qdf_list_remove_node( 436 &gp_qdf_frag_track_tbl[index].track_list, 437 &p_prev->hnode); 438 qdf_info("******Frag Memory Leak******"); 439 qdf_info("@Frag Address: %pK", p_prev->p_frag); 440 qdf_info("@Refcount: %u", p_prev->refcount); 441 qdf_info("@Alloc Func Name: %s, @Alloc Func Line: %d", 442 p_prev->alloc_func_name, 443 p_prev->alloc_func_line); 444 qdf_info("@Last Func Name: %s, @Last Func Line: %d", 445 p_prev->last_func_name, 446 p_prev->last_func_line); 447 qdf_info("****************************"); 448 449 qdf_frag_track_free(p_prev); 450 } 451 qdf_list_destroy(&gp_qdf_frag_track_tbl[index].track_list); 452 qdf_spin_unlock_irqrestore( 453 &gp_qdf_frag_track_tbl[index].list_lock); 454 qdf_spinlock_destroy(&gp_qdf_frag_track_tbl[index].list_lock); 455 } 456 457 qdf_frag_track_memory_manager_destroy(); 458 } 459 460 qdf_export_symbol(qdf_frag_debug_exit); 461 462 /** 463 * qdf_frag_debug_hash() - Hash network frag pointer 464 * @p_frag: Frag address 465 * 466 * Return: hash value 467 */ 468 static uint32_t qdf_frag_debug_hash(qdf_frag_t p_frag) 469 { 470 uint32_t index; 471 472 index = (uint32_t)(((uintptr_t)p_frag) >> 4); 473 index += (uint32_t)(((uintptr_t)p_frag) >> 14); 474 index &= (QDF_FRAG_TRACK_MAX_SIZE - 1); 475 476 return index; 477 } 478 479 /** 480 * qdf_frag_debug_look_up() - Look up network frag in debug hash table 481 * @p_frag: Frag address 482 * 483 * Return: If frag is found in hash table then return pointer to network frag 484 * else return NULL 485 */ 486 static QDF_FRAG_TRACK *qdf_frag_debug_look_up(qdf_frag_t p_frag) 487 { 488 uint32_t index; 489 QDF_FRAG_TRACK *p_node; 490 491 index = qdf_frag_debug_hash(p_frag); 492 493 qdf_list_for_each(&gp_qdf_frag_track_tbl[index].track_list, p_node, 494 hnode) { 495 if (p_node->p_frag == p_frag) 496 return p_node; 497 } 498 499 return NULL; 500 } 501 502 /** 503 * __qdf_frag_debug_add_node()- Add frag node to debug tracker 504 * @fragp: Frag Pointer 505 * @idx: Index 506 * @func_name: Caller function name 507 * @line_num: Caller function line no. 508 * 509 * Return: Allocated frag tracker node address 510 */ 511 static QDF_FRAG_TRACK *__qdf_frag_debug_add_node(qdf_frag_t fragp, 512 uint32_t idx, 513 const char *func_name, 514 uint32_t line_num) 515 { 516 QDF_FRAG_TRACK *p_node; 517 518 p_node = qdf_frag_track_alloc(); 519 520 if (p_node) { 521 p_node->p_frag = fragp; 522 qdf_str_lcopy(p_node->alloc_func_name, func_name, 523 QDF_MEM_FUNC_NAME_SIZE); 524 p_node->alloc_func_line = line_num; 525 p_node->refcount = QDF_NBUF_FRAG_DEBUG_COUNT_ZERO; 526 527 qdf_str_lcopy(p_node->last_func_name, func_name, 528 QDF_MEM_FUNC_NAME_SIZE); 529 p_node->last_func_line = line_num; 530 531 qdf_list_insert_front(&gp_qdf_frag_track_tbl[idx].track_list, 532 &p_node->hnode); 533 } 534 return p_node; 535 } 536 537 /** 538 * __qdf_frag_debug_delete_node()- Remove frag node from debug tracker 539 * @p_node: Frag node address in debug tracker 540 * @idx: Index 541 * 542 * Return: none 543 */ 544 static void __qdf_frag_debug_delete_node(QDF_FRAG_TRACK *p_node, uint32_t idx) 545 { 546 if (idx < QDF_FRAG_TRACK_MAX_SIZE) { 547 qdf_list_remove_node(&gp_qdf_frag_track_tbl[idx].track_list, 548 &p_node->hnode); 549 qdf_frag_track_free(p_node); 550 } else { 551 qdf_info("Index value exceeds %d for delete node operation", 552 QDF_FRAG_TRACK_MAX_SIZE); 553 } 554 } 555 556 void qdf_frag_debug_add_node(qdf_frag_t fragp, const char *func_name, 557 uint32_t line_num) 558 { 559 uint32_t index; 560 QDF_FRAG_TRACK *p_node; 561 562 if (is_initial_mem_debug_disabled) 563 return; 564 565 index = qdf_frag_debug_hash(fragp); 566 567 qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock); 568 569 p_node = qdf_frag_debug_look_up(fragp); 570 571 if (p_node) { 572 qdf_info("Double addition of frag %pK to debug tracker!!", 573 fragp); 574 qdf_info("Already added from %s %d Current addition from %s %d", 575 p_node->alloc_func_name, 576 p_node->alloc_func_line, func_name, line_num); 577 } else { 578 p_node = __qdf_frag_debug_add_node(fragp, index, func_name, 579 line_num); 580 if (!p_node) 581 qdf_info("Memory allocation failed !! " 582 "Add node oprt failed for frag %pK from %s %d", 583 fragp, func_name, line_num); 584 } 585 qdf_spin_unlock_irqrestore(&gp_qdf_frag_track_tbl[index].list_lock); 586 } 587 588 void qdf_frag_debug_refcount_inc(qdf_frag_t fragp, const char *func_name, 589 uint32_t line_num) 590 { 591 uint32_t index; 592 QDF_FRAG_TRACK *p_node; 593 594 if (is_initial_mem_debug_disabled) 595 return; 596 597 index = qdf_frag_debug_hash(fragp); 598 599 qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock); 600 601 p_node = qdf_frag_debug_look_up(fragp); 602 603 if (p_node) { 604 (p_node->refcount)++; 605 606 qdf_str_lcopy(p_node->last_func_name, func_name, 607 QDF_MEM_FUNC_NAME_SIZE); 608 p_node->last_func_line = line_num; 609 } else { 610 p_node = __qdf_frag_debug_add_node(fragp, index, func_name, 611 line_num); 612 if (p_node) 613 p_node->refcount = QDF_NBUF_FRAG_DEBUG_COUNT_ONE; 614 else 615 qdf_info("Memory allocation failed !! " 616 "Refcount inc failed for frag %pK from %s %d", 617 fragp, func_name, line_num); 618 } 619 qdf_spin_unlock_irqrestore(&gp_qdf_frag_track_tbl[index].list_lock); 620 } 621 622 void qdf_frag_debug_refcount_dec(qdf_frag_t fragp, const char *func_name, 623 uint32_t line_num) 624 { 625 uint32_t index; 626 QDF_FRAG_TRACK *p_node; 627 628 if (is_initial_mem_debug_disabled) 629 return; 630 631 index = qdf_frag_debug_hash(fragp); 632 633 qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock); 634 635 p_node = qdf_frag_debug_look_up(fragp); 636 637 if (p_node) { 638 if (!(p_node->refcount)) { 639 qdf_info("Refcount dec oprt for frag %pK not permitted " 640 "as refcount=0", fragp); 641 goto done; 642 } 643 (p_node->refcount)--; 644 645 if (!(p_node->refcount)) { 646 /* Remove frag debug node when refcount reaches 0 */ 647 __qdf_frag_debug_delete_node(p_node, index); 648 } else { 649 qdf_str_lcopy(p_node->last_func_name, func_name, 650 QDF_MEM_FUNC_NAME_SIZE); 651 p_node->last_func_line = line_num; 652 } 653 } else { 654 qdf_info("Unallocated frag !! Could not track frag %pK", fragp); 655 qdf_info("Refcount dec oprt failed for frag %pK from %s %d", 656 fragp, func_name, line_num); 657 } 658 done: 659 qdf_spin_unlock_irqrestore(&gp_qdf_frag_track_tbl[index].list_lock); 660 } 661 662 void qdf_frag_debug_delete_node(qdf_frag_t fragp, const char *func_name, 663 uint32_t line_num) 664 { 665 uint32_t index; 666 QDF_FRAG_TRACK *p_node; 667 668 if (is_initial_mem_debug_disabled) 669 return; 670 671 index = qdf_frag_debug_hash(fragp); 672 673 qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock); 674 675 p_node = qdf_frag_debug_look_up(fragp); 676 677 if (p_node) { 678 if (p_node->refcount) { 679 qdf_info("Frag %pK has refcount %d", fragp, 680 p_node->refcount); 681 qdf_info("Delete oprt failed for frag %pK from %s %d", 682 fragp, func_name, line_num); 683 } else { 684 /* Remove node from tracker as refcount=0 */ 685 __qdf_frag_debug_delete_node(p_node, index); 686 } 687 } else { 688 qdf_info("Unallocated frag !! Double free of frag %pK", fragp); 689 qdf_info("Could not track frag %pK for delete oprt from %s %d", 690 fragp, func_name, line_num); 691 } 692 693 qdf_spin_unlock_irqrestore(&gp_qdf_frag_track_tbl[index].list_lock); 694 } 695 696 void qdf_frag_debug_update_addr(qdf_frag_t p_fragp, qdf_frag_t n_fragp, 697 const char *func_name, uint32_t line_num) 698 { 699 uint32_t prev_index, new_index; 700 QDF_FRAG_TRACK *p_node; 701 702 if (is_initial_mem_debug_disabled) 703 return; 704 705 prev_index = qdf_frag_debug_hash(p_fragp); 706 707 new_index = qdf_frag_debug_hash(n_fragp); 708 709 qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[prev_index].list_lock); 710 711 p_node = qdf_frag_debug_look_up(p_fragp); 712 713 if (!p_node) { 714 qdf_info("Unallocated frag !! Could not track frag %pK", 715 p_fragp); 716 qdf_info("Update address oprt failed for frag %pK from %s %d", 717 p_fragp, func_name, line_num); 718 qdf_spin_unlock_irqrestore( 719 &gp_qdf_frag_track_tbl[prev_index].list_lock); 720 } else { 721 /* Update frag address */ 722 p_node->p_frag = n_fragp; 723 724 qdf_str_lcopy(p_node->last_func_name, func_name, 725 QDF_MEM_FUNC_NAME_SIZE); 726 p_node->last_func_line = line_num; 727 728 if (prev_index != new_index) { 729 qdf_list_remove_node( 730 &gp_qdf_frag_track_tbl[prev_index].track_list, 731 &p_node->hnode); 732 733 qdf_spin_unlock_irqrestore( 734 &gp_qdf_frag_track_tbl[prev_index].list_lock); 735 736 qdf_spin_lock_irqsave( 737 &gp_qdf_frag_track_tbl[new_index].list_lock); 738 739 qdf_list_insert_front( 740 &gp_qdf_frag_track_tbl[new_index].track_list, 741 &p_node->hnode); 742 743 qdf_spin_unlock_irqrestore( 744 &gp_qdf_frag_track_tbl[new_index].list_lock); 745 } else { 746 qdf_spin_unlock_irqrestore( 747 &gp_qdf_frag_track_tbl[prev_index].list_lock); 748 } 749 } 750 } 751 752 qdf_frag_t qdf_frag_alloc_debug(qdf_frag_cache_t *pf_cache, 753 unsigned int frag_size, 754 const char *func_name, 755 uint32_t line_num) 756 { 757 qdf_frag_t p_frag; 758 759 if (is_initial_mem_debug_disabled) 760 return __qdf_frag_alloc(pf_cache, frag_size); 761 762 p_frag = __qdf_frag_alloc(pf_cache, frag_size); 763 764 /* Store frag in QDF Frag Tracking Table */ 765 if (qdf_likely(p_frag)) 766 qdf_frag_debug_add_node(p_frag, func_name, line_num); 767 768 return p_frag; 769 } 770 771 qdf_export_symbol(qdf_frag_alloc_debug); 772 773 void qdf_frag_free_debug(qdf_frag_t vaddr, const char *func_name, 774 uint32_t line_num) 775 { 776 if (qdf_unlikely(!vaddr)) 777 return; 778 779 if (is_initial_mem_debug_disabled) 780 goto free_frag; 781 782 qdf_frag_debug_delete_node(vaddr, func_name, line_num); 783 free_frag: 784 __qdf_frag_free(vaddr); 785 } 786 787 qdf_export_symbol(qdf_frag_free_debug); 788 789 #endif /* NBUF_FRAG_MEMORY_DEBUG */ 790 791 #if defined(HIF_PCI) 792 QDF_STATUS __qdf_mem_map_page(qdf_device_t osdev, __qdf_frag_t buf, 793 qdf_dma_dir_t dir, size_t nbytes, 794 qdf_dma_addr_t *phy_addr) 795 { 796 struct page *page; 797 unsigned long offset; 798 799 page = virt_to_head_page(buf); 800 offset = buf - page_address(page); 801 *phy_addr = dma_map_page(osdev->dev, page, offset, nbytes, 802 __qdf_dma_dir_to_os(dir)); 803 804 return dma_mapping_error(osdev->dev, *phy_addr) ? 805 QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; 806 } 807 #else 808 QDF_STATUS __qdf_mem_map_page(qdf_device_t osdev, __qdf_frag_t buf, 809 qdf_dma_dir_t dir, size_t nbytes, 810 qdf_dma_addr_t *phy_addr) 811 { 812 return QDF_STATUS_SUCCESS; 813 } 814 #endif 815 816 qdf_export_symbol(__qdf_mem_map_page); 817 818 #if defined(HIF_PCI) 819 void __qdf_mem_unmap_page(qdf_device_t osdev, qdf_dma_addr_t paddr, 820 size_t nbytes, qdf_dma_dir_t dir) 821 { 822 dma_unmap_page(osdev->dev, paddr, nbytes, 823 __qdf_dma_dir_to_os(dir)); 824 } 825 #else 826 void __qdf_mem_unmap_page(qdf_device_t osdev, qdf_dma_addr_t paddr, 827 size_t nbytes, qdf_dma_dir_t dir) 828 { 829 } 830 #endif 831 832 qdf_export_symbol(__qdf_mem_unmap_page); 833 834 #if defined(QDF_FRAG_CACHE_SUPPORT) 835 void __qdf_frag_cache_drain(qdf_frag_cache_t *pf_cache) 836 { 837 struct page *page; 838 839 page = virt_to_page(pf_cache->va); 840 __page_frag_cache_drain(page, pf_cache->pagecnt_bias); 841 memset(pf_cache, 0, sizeof(*pf_cache)); 842 } 843 #else 844 void __qdf_frag_cache_drain(qdf_frag_cache_t *pf_cache) 845 { 846 } 847 #endif 848 849 qdf_export_symbol(__qdf_frag_cache_drain); 850