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