1 /* 2 * Copyright (c) 2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-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: 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: 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 void qdf_frag_debug_exit(void) 416 { 417 uint32_t index; 418 QDF_FRAG_TRACK *p_node; 419 QDF_FRAG_TRACK *p_prev; 420 421 if (is_initial_mem_debug_disabled) 422 return; 423 424 for (index = 0; index < QDF_FRAG_TRACK_MAX_SIZE; index++) { 425 qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock); 426 qdf_list_for_each_del(&gp_qdf_frag_track_tbl[index].track_list, 427 p_prev, p_node, hnode) { 428 qdf_list_remove_node( 429 &gp_qdf_frag_track_tbl[index].track_list, 430 &p_prev->hnode); 431 qdf_info("******Frag Memory Leak******"); 432 qdf_info("@Frag Address: %pK", p_prev->p_frag); 433 qdf_info("@Refcount: %u", p_prev->refcount); 434 qdf_info("@Alloc Func Name: %s, @Alloc Func Line: %d", 435 p_prev->alloc_func_name, 436 p_prev->alloc_func_line); 437 qdf_info("@Last Func Name: %s, @Last Func Line: %d", 438 p_prev->last_func_name, 439 p_prev->last_func_line); 440 qdf_info("****************************"); 441 442 qdf_frag_track_free(p_prev); 443 } 444 qdf_list_destroy(&gp_qdf_frag_track_tbl[index].track_list); 445 qdf_spin_unlock_irqrestore( 446 &gp_qdf_frag_track_tbl[index].list_lock); 447 qdf_spinlock_destroy(&gp_qdf_frag_track_tbl[index].list_lock); 448 } 449 450 qdf_frag_track_memory_manager_destroy(); 451 } 452 453 qdf_export_symbol(qdf_frag_debug_exit); 454 455 /** 456 * qdf_frag_debug_hash() - Hash network frag pointer 457 * @p_frag: Frag address 458 * 459 * Return: hash value 460 */ 461 static uint32_t qdf_frag_debug_hash(qdf_frag_t p_frag) 462 { 463 uint32_t index; 464 465 index = (uint32_t)(((uintptr_t)p_frag) >> 4); 466 index += (uint32_t)(((uintptr_t)p_frag) >> 14); 467 index &= (QDF_FRAG_TRACK_MAX_SIZE - 1); 468 469 return index; 470 } 471 472 /** 473 * qdf_frag_debug_look_up() - Look up network frag in debug hash table 474 * @p_frag: Frag address 475 * 476 * Return: If frag is found in hash table then return pointer to network frag 477 * else return NULL 478 */ 479 static QDF_FRAG_TRACK *qdf_frag_debug_look_up(qdf_frag_t p_frag) 480 { 481 uint32_t index; 482 QDF_FRAG_TRACK *p_node; 483 484 index = qdf_frag_debug_hash(p_frag); 485 486 qdf_list_for_each(&gp_qdf_frag_track_tbl[index].track_list, p_node, 487 hnode) { 488 if (p_node->p_frag == p_frag) 489 return p_node; 490 } 491 492 return NULL; 493 } 494 495 /** 496 * __qdf_frag_debug_add_node()- Add frag node to debug tracker 497 * @fragp: Frag Pointer 498 * @idx: Index 499 * @func_name: Caller function name 500 * @line_num: Caller function line no. 501 * 502 * Return: Allocated frag tracker node address 503 */ 504 static QDF_FRAG_TRACK *__qdf_frag_debug_add_node(qdf_frag_t fragp, 505 uint32_t idx, 506 const char *func_name, 507 uint32_t line_num) 508 { 509 QDF_FRAG_TRACK *p_node; 510 511 p_node = qdf_frag_track_alloc(); 512 513 if (p_node) { 514 p_node->p_frag = fragp; 515 qdf_str_lcopy(p_node->alloc_func_name, func_name, 516 QDF_MEM_FUNC_NAME_SIZE); 517 p_node->alloc_func_line = line_num; 518 p_node->refcount = QDF_NBUF_FRAG_DEBUG_COUNT_ZERO; 519 520 qdf_str_lcopy(p_node->last_func_name, func_name, 521 QDF_MEM_FUNC_NAME_SIZE); 522 p_node->last_func_line = line_num; 523 524 qdf_list_insert_front(&gp_qdf_frag_track_tbl[idx].track_list, 525 &p_node->hnode); 526 } 527 return p_node; 528 } 529 530 /** 531 * __qdf_frag_debug_delete_node()- Remove frag node from debug tracker 532 * @p_node: Frag node address in debug tracker 533 * @idx: Index 534 * 535 * Return: none 536 */ 537 static void __qdf_frag_debug_delete_node(QDF_FRAG_TRACK *p_node, uint32_t idx) 538 { 539 if (idx < QDF_FRAG_TRACK_MAX_SIZE) { 540 qdf_list_remove_node(&gp_qdf_frag_track_tbl[idx].track_list, 541 &p_node->hnode); 542 qdf_frag_track_free(p_node); 543 } else { 544 qdf_info("Index value exceeds %d for delete node operation", 545 QDF_FRAG_TRACK_MAX_SIZE); 546 } 547 } 548 549 void qdf_frag_debug_add_node(qdf_frag_t fragp, const char *func_name, 550 uint32_t line_num) 551 { 552 uint32_t index; 553 QDF_FRAG_TRACK *p_node; 554 555 if (is_initial_mem_debug_disabled) 556 return; 557 558 index = qdf_frag_debug_hash(fragp); 559 560 qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock); 561 562 p_node = qdf_frag_debug_look_up(fragp); 563 564 if (p_node) { 565 qdf_info("Double addition of frag %pK to debug tracker!!", 566 fragp); 567 qdf_info("Already added from %s %d Current addition from %s %d", 568 p_node->alloc_func_name, 569 p_node->alloc_func_line, func_name, line_num); 570 } else { 571 p_node = __qdf_frag_debug_add_node(fragp, index, func_name, 572 line_num); 573 if (!p_node) 574 qdf_info("Memory allocation failed !! " 575 "Add node oprt failed for frag %pK from %s %d", 576 fragp, func_name, line_num); 577 } 578 qdf_spin_unlock_irqrestore(&gp_qdf_frag_track_tbl[index].list_lock); 579 } 580 581 void qdf_frag_debug_refcount_inc(qdf_frag_t fragp, const char *func_name, 582 uint32_t line_num) 583 { 584 uint32_t index; 585 QDF_FRAG_TRACK *p_node; 586 587 if (is_initial_mem_debug_disabled) 588 return; 589 590 index = qdf_frag_debug_hash(fragp); 591 592 qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock); 593 594 p_node = qdf_frag_debug_look_up(fragp); 595 596 if (p_node) { 597 (p_node->refcount)++; 598 599 qdf_str_lcopy(p_node->last_func_name, func_name, 600 QDF_MEM_FUNC_NAME_SIZE); 601 p_node->last_func_line = line_num; 602 } else { 603 p_node = __qdf_frag_debug_add_node(fragp, index, func_name, 604 line_num); 605 if (p_node) 606 p_node->refcount = QDF_NBUF_FRAG_DEBUG_COUNT_ONE; 607 else 608 qdf_info("Memory allocation failed !! " 609 "Refcount inc failed for frag %pK from %s %d", 610 fragp, func_name, line_num); 611 } 612 qdf_spin_unlock_irqrestore(&gp_qdf_frag_track_tbl[index].list_lock); 613 } 614 615 void qdf_frag_debug_refcount_dec(qdf_frag_t fragp, const char *func_name, 616 uint32_t line_num) 617 { 618 uint32_t index; 619 QDF_FRAG_TRACK *p_node; 620 621 if (is_initial_mem_debug_disabled) 622 return; 623 624 index = qdf_frag_debug_hash(fragp); 625 626 qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock); 627 628 p_node = qdf_frag_debug_look_up(fragp); 629 630 if (p_node) { 631 if (!(p_node->refcount)) { 632 qdf_info("Refcount dec oprt for frag %pK not permitted " 633 "as refcount=0", fragp); 634 goto done; 635 } 636 (p_node->refcount)--; 637 638 if (!(p_node->refcount)) { 639 /* Remove frag debug node when refcount reaches 0 */ 640 __qdf_frag_debug_delete_node(p_node, index); 641 } else { 642 qdf_str_lcopy(p_node->last_func_name, func_name, 643 QDF_MEM_FUNC_NAME_SIZE); 644 p_node->last_func_line = line_num; 645 } 646 } else { 647 qdf_info("Unallocated frag !! Could not track frag %pK", fragp); 648 qdf_info("Refcount dec oprt failed for frag %pK from %s %d", 649 fragp, func_name, line_num); 650 } 651 done: 652 qdf_spin_unlock_irqrestore(&gp_qdf_frag_track_tbl[index].list_lock); 653 } 654 655 void qdf_frag_debug_delete_node(qdf_frag_t fragp, const char *func_name, 656 uint32_t line_num) 657 { 658 uint32_t index; 659 QDF_FRAG_TRACK *p_node; 660 661 if (is_initial_mem_debug_disabled) 662 return; 663 664 index = qdf_frag_debug_hash(fragp); 665 666 qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock); 667 668 p_node = qdf_frag_debug_look_up(fragp); 669 670 if (p_node) { 671 if (p_node->refcount) { 672 qdf_info("Frag %pK has refcount %d", fragp, 673 p_node->refcount); 674 qdf_info("Delete oprt failed for frag %pK from %s %d", 675 fragp, func_name, line_num); 676 } else { 677 /* Remove node from tracker as refcount=0 */ 678 __qdf_frag_debug_delete_node(p_node, index); 679 } 680 } else { 681 qdf_info("Unallocated frag !! Double free of frag %pK", fragp); 682 qdf_info("Could not track frag %pK for delete oprt from %s %d", 683 fragp, func_name, line_num); 684 } 685 686 qdf_spin_unlock_irqrestore(&gp_qdf_frag_track_tbl[index].list_lock); 687 } 688 689 void qdf_frag_debug_update_addr(qdf_frag_t p_fragp, qdf_frag_t n_fragp, 690 const char *func_name, uint32_t line_num) 691 { 692 uint32_t prev_index, new_index; 693 QDF_FRAG_TRACK *p_node; 694 695 if (is_initial_mem_debug_disabled) 696 return; 697 698 prev_index = qdf_frag_debug_hash(p_fragp); 699 700 new_index = qdf_frag_debug_hash(n_fragp); 701 702 qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[prev_index].list_lock); 703 704 p_node = qdf_frag_debug_look_up(p_fragp); 705 706 if (!p_node) { 707 qdf_info("Unallocated frag !! Could not track frag %pK", 708 p_fragp); 709 qdf_info("Update address oprt failed for frag %pK from %s %d", 710 p_fragp, func_name, line_num); 711 qdf_spin_unlock_irqrestore( 712 &gp_qdf_frag_track_tbl[prev_index].list_lock); 713 } else { 714 /* Update frag address */ 715 p_node->p_frag = n_fragp; 716 717 qdf_str_lcopy(p_node->last_func_name, func_name, 718 QDF_MEM_FUNC_NAME_SIZE); 719 p_node->last_func_line = line_num; 720 721 if (prev_index != new_index) { 722 qdf_list_remove_node( 723 &gp_qdf_frag_track_tbl[prev_index].track_list, 724 &p_node->hnode); 725 726 qdf_spin_unlock_irqrestore( 727 &gp_qdf_frag_track_tbl[prev_index].list_lock); 728 729 qdf_spin_lock_irqsave( 730 &gp_qdf_frag_track_tbl[new_index].list_lock); 731 732 qdf_list_insert_front( 733 &gp_qdf_frag_track_tbl[new_index].track_list, 734 &p_node->hnode); 735 736 qdf_spin_unlock_irqrestore( 737 &gp_qdf_frag_track_tbl[new_index].list_lock); 738 } else { 739 qdf_spin_unlock_irqrestore( 740 &gp_qdf_frag_track_tbl[prev_index].list_lock); 741 } 742 } 743 } 744 745 qdf_frag_t qdf_frag_alloc_debug(qdf_frag_cache_t *pf_cache, 746 unsigned int frag_size, 747 const char *func_name, 748 uint32_t line_num) 749 { 750 qdf_frag_t p_frag; 751 752 if (is_initial_mem_debug_disabled) 753 return __qdf_frag_alloc(pf_cache, frag_size); 754 755 p_frag = __qdf_frag_alloc(pf_cache, frag_size); 756 757 /* Store frag in QDF Frag Tracking Table */ 758 if (qdf_likely(p_frag)) 759 qdf_frag_debug_add_node(p_frag, func_name, line_num); 760 761 return p_frag; 762 } 763 764 qdf_export_symbol(qdf_frag_alloc_debug); 765 766 void qdf_frag_free_debug(qdf_frag_t vaddr, const char *func_name, 767 uint32_t line_num) 768 { 769 if (qdf_unlikely(!vaddr)) 770 return; 771 772 if (is_initial_mem_debug_disabled) 773 goto free_frag; 774 775 qdf_frag_debug_delete_node(vaddr, func_name, line_num); 776 free_frag: 777 __qdf_frag_free(vaddr); 778 } 779 780 qdf_export_symbol(qdf_frag_free_debug); 781 782 #endif /* NBUF_FRAG_MEMORY_DEBUG */ 783 784 #if defined(HIF_PCI) 785 QDF_STATUS __qdf_mem_map_page(qdf_device_t osdev, __qdf_frag_t buf, 786 qdf_dma_dir_t dir, size_t nbytes, 787 qdf_dma_addr_t *phy_addr) 788 { 789 struct page *page; 790 unsigned long offset; 791 792 page = virt_to_head_page(buf); 793 offset = buf - page_address(page); 794 *phy_addr = dma_map_page(osdev->dev, page, offset, nbytes, 795 __qdf_dma_dir_to_os(dir)); 796 797 return dma_mapping_error(osdev->dev, *phy_addr) ? 798 QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; 799 } 800 #else 801 QDF_STATUS __qdf_mem_map_page(qdf_device_t osdev, __qdf_frag_t buf, 802 qdf_dma_dir_t dir, size_t nbytes, 803 qdf_dma_addr_t *phy_addr) 804 { 805 return QDF_STATUS_SUCCESS; 806 } 807 #endif 808 809 qdf_export_symbol(__qdf_mem_map_page); 810 811 #if defined(HIF_PCI) 812 void __qdf_mem_unmap_page(qdf_device_t osdev, qdf_dma_addr_t paddr, 813 size_t nbytes, qdf_dma_dir_t dir) 814 { 815 dma_unmap_page(osdev->dev, paddr, nbytes, 816 __qdf_dma_dir_to_os(dir)); 817 } 818 #else 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 } 823 #endif 824 825 qdf_export_symbol(__qdf_mem_unmap_page); 826 827 #if defined(QDF_FRAG_CACHE_SUPPORT) 828 void __qdf_frag_cache_drain(qdf_frag_cache_t *pf_cache) 829 { 830 struct page *page; 831 832 page = virt_to_page(pf_cache->va); 833 __page_frag_cache_drain(page, pf_cache->pagecnt_bias); 834 memset(pf_cache, 0, sizeof(*pf_cache)); 835 } 836 #else 837 void __qdf_frag_cache_drain(qdf_frag_cache_t *pf_cache) 838 { 839 } 840 #endif 841 842 qdf_export_symbol(__qdf_frag_cache_drain); 843