1 /* 2 * 3 * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. 4 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for 7 * any purpose with or without fee is hereby granted, provided that the 8 * above copyright notice and this permission notice appear in all 9 * copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 12 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 13 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 14 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 15 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 16 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 17 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 18 * PERFORMANCE OF THIS SOFTWARE. 19 */ 20 /* 21 * DOC: Public APIs to perform debug operations on object manager 22 */ 23 24 #include <wlan_objmgr_psoc_obj.h> 25 #include <wlan_objmgr_pdev_obj.h> 26 #include <wlan_objmgr_vdev_obj.h> 27 #include <wlan_objmgr_peer_obj.h> 28 #include <wlan_objmgr_debug.h> 29 #include "wlan_objmgr_global_obj_i.h" 30 #include <qdf_mem.h> 31 #include <qdf_platform.h> 32 #include <qdf_str.h> 33 34 /* 35 * Default TTL (of FW) for mgmt frames is 5 sec, by considering all the other 36 * delays, arrived with this value 37 */ 38 #ifndef LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC 39 #define LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC 8000 40 #endif 41 #ifndef LOG_DEL_OBJ_DESTROY_DURATION_SEC 42 #define LOG_DEL_OBJ_DESTROY_DURATION_SEC 8 43 #endif 44 45 /* 46 * The max duration for which a obj can be allowed to remain in L-state 47 * The duration should be higher than the psoc idle timeout. 48 */ 49 #define LOG_DEL_OBJ_DESTROY_ASSERT_DURATION_SEC 32 50 #define LOG_DEL_OBJ_LIST_MAX_COUNT (3 + 5 + 48 + 4096) 51 52 union wlan_objmgr_del_obj { 53 struct wlan_objmgr_psoc *obj_psoc; 54 struct wlan_objmgr_pdev *obj_pdev; 55 struct wlan_objmgr_vdev *obj_vdev; 56 struct wlan_objmgr_peer *obj_peer; 57 }; 58 59 /** 60 * struct log_del_obj - Logically deleted Object 61 * @obj: Represents peer/vdev/pdev/psoc 62 * @node: List node from Logically deleted list 63 * @obj_type: Object type for peer/vdev/pdev/psoc 64 * @tstamp: Timestamp when node entered logically 65 * deleted state 66 */ 67 struct log_del_obj { 68 union wlan_objmgr_del_obj obj; 69 qdf_list_node_t node; 70 enum wlan_objmgr_obj_type obj_type; 71 qdf_time_t tstamp; 72 }; 73 74 /** 75 * struct wlan_objmgr_debug_info - Objmgr debug info 76 * for Logically deleted object 77 * @obj_timer: Timer object 78 * @obj_list: list object having linking logically 79 * deleted nodes 80 * @list_lock: lock to protect list 81 */ 82 struct wlan_objmgr_debug_info { 83 qdf_timer_t obj_timer; 84 qdf_list_t obj_list; 85 qdf_spinlock_t list_lock; 86 }; 87 88 static const char * 89 wlan_obj_type_get_obj_name(enum wlan_objmgr_obj_type obj_type) 90 { 91 static const struct wlan_obj_type_to_name { 92 enum wlan_objmgr_obj_type obj_type; 93 const char *name; 94 } obj_type_name[WLAN_OBJ_TYPE_MAX] = { 95 {WLAN_PSOC_OP, "psoc"}, 96 {WLAN_PDEV_OP, "pdev"}, 97 {WLAN_VDEV_OP, "vdev"}, 98 {WLAN_PEER_OP, "peer"} 99 }; 100 uint8_t idx; 101 102 for (idx = 0; idx < WLAN_OBJ_TYPE_MAX; idx++) { 103 if (obj_type == obj_type_name[idx].obj_type) 104 return obj_type_name[idx].name; 105 } 106 107 return NULL; 108 } 109 110 static uint8_t* 111 wlan_objmgr_debug_get_macaddr(union wlan_objmgr_del_obj *obj, 112 enum wlan_objmgr_obj_type obj_type) 113 { 114 switch (obj_type) { 115 case WLAN_PSOC_OP: 116 return wlan_psoc_get_hw_macaddr(obj->obj_psoc); 117 case WLAN_PDEV_OP: 118 return wlan_pdev_get_hw_macaddr(obj->obj_pdev); 119 case WLAN_VDEV_OP: 120 return wlan_vdev_mlme_get_macaddr(obj->obj_vdev); 121 case WLAN_PEER_OP: 122 return wlan_peer_get_macaddr(obj->obj_peer); 123 default: 124 obj_mgr_err("invalid obj_type"); 125 return NULL; 126 } 127 } 128 129 static void 130 wlan_objmgr_insert_ld_obj_to_list(struct wlan_objmgr_debug_info *debug_info, 131 qdf_list_node_t *node) 132 { 133 /* Insert object to list with lock being held*/ 134 qdf_spin_lock_bh(&debug_info->list_lock); 135 136 /* Start timer only when list is empty */ 137 if (qdf_list_empty(&debug_info->obj_list)) 138 qdf_timer_start(&debug_info->obj_timer, 139 LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC); 140 141 qdf_list_insert_back(&debug_info->obj_list, node); 142 qdf_spin_unlock_bh(&debug_info->list_lock); 143 } 144 145 static void wlan_obj_type_get_obj(union wlan_objmgr_del_obj *obj, 146 union wlan_objmgr_del_obj *del_obj, 147 enum wlan_objmgr_obj_type obj_type) 148 { 149 switch (obj_type) { 150 case WLAN_PSOC_OP: 151 del_obj->obj_psoc = obj->obj_psoc; 152 return; 153 case WLAN_PDEV_OP: 154 del_obj->obj_pdev = obj->obj_pdev; 155 return; 156 case WLAN_VDEV_OP: 157 del_obj->obj_vdev = obj->obj_vdev; 158 return; 159 case WLAN_PEER_OP: 160 del_obj->obj_peer = obj->obj_peer; 161 return; 162 default: 163 obj_mgr_err("invalid obj_type"); 164 return; 165 } 166 } 167 168 void wlan_objmgr_notify_log_delete(void *obj, 169 enum wlan_objmgr_obj_type obj_type) 170 { 171 struct wlan_objmgr_debug_info *debug_info; 172 const char *obj_name; 173 uint8_t *macaddr; 174 qdf_time_t tstamp; 175 struct log_del_obj *node; 176 union wlan_objmgr_del_obj *del_obj = (union wlan_objmgr_del_obj *)&obj; 177 178 if (!obj) { 179 obj_mgr_err("object is null"); 180 return; 181 } 182 183 debug_info = g_umac_glb_obj->debug_info; 184 185 if (!debug_info) { 186 obj_mgr_err("debug_info is null"); 187 return; 188 } 189 190 macaddr = wlan_objmgr_debug_get_macaddr(del_obj, obj_type); 191 if (!macaddr) { 192 obj_mgr_err("macaddr is null"); 193 return; 194 } 195 196 obj_name = wlan_obj_type_get_obj_name(obj_type); 197 if (!obj_name) { 198 obj_mgr_err("obj_name is null"); 199 return; 200 } 201 202 tstamp = qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000; 203 node = qdf_mem_malloc(sizeof(*node)); 204 if (!node) 205 return; 206 207 wlan_obj_type_get_obj(del_obj, &node->obj, obj_type); 208 node->obj_type = obj_type; 209 node->tstamp = tstamp; 210 obj_mgr_debug("#%s : mac_addr: "QDF_MAC_ADDR_FMT" entered L-state", 211 obj_name, QDF_MAC_ADDR_REF(macaddr)); 212 wlan_objmgr_insert_ld_obj_to_list(debug_info, &node->node); 213 } 214 215 static bool wlan_objmgr_del_obj_match(union wlan_objmgr_del_obj *obj, 216 union wlan_objmgr_del_obj *del_obj, 217 enum wlan_objmgr_obj_type obj_type) 218 { 219 switch (obj_type) { 220 case WLAN_PSOC_OP: 221 return (del_obj->obj_psoc == obj->obj_psoc); 222 case WLAN_PDEV_OP: 223 return (del_obj->obj_pdev == obj->obj_pdev); 224 case WLAN_VDEV_OP: 225 return (del_obj->obj_vdev == obj->obj_vdev); 226 case WLAN_PEER_OP: 227 return (del_obj->obj_peer == obj->obj_peer); 228 default: 229 return false; 230 } 231 } 232 233 static void 234 wlan_objmgr_rem_ld_obj_from_list(union wlan_objmgr_del_obj *obj, 235 struct wlan_objmgr_debug_info *debug_info, 236 enum wlan_objmgr_obj_type obj_type) 237 { 238 qdf_list_node_t *node = NULL; 239 struct log_del_obj *obj_to_remove = NULL; 240 qdf_list_t *list; 241 QDF_STATUS status; 242 243 list = &debug_info->obj_list; 244 qdf_spin_lock_bh(&debug_info->list_lock); 245 status = qdf_list_peek_front(list, &node); 246 247 while (QDF_IS_STATUS_SUCCESS(status)) { 248 obj_to_remove = qdf_container_of(node, 249 struct log_del_obj, node); 250 if (wlan_objmgr_del_obj_match(obj, &obj_to_remove->obj, 251 obj_type) && 252 obj_to_remove->obj_type == obj_type) { 253 status = qdf_list_remove_node(list, 254 &obj_to_remove->node); 255 /* Stop timer if list is empty */ 256 if (QDF_IS_STATUS_SUCCESS(status)) { 257 if (qdf_list_empty(&debug_info->obj_list)) 258 qdf_timer_stop(&debug_info->obj_timer); 259 qdf_mem_free(obj_to_remove); 260 } 261 break; 262 } 263 status = qdf_list_peek_next(list, node, &node); 264 }; 265 qdf_spin_unlock_bh(&debug_info->list_lock); 266 } 267 268 void wlan_objmgr_notify_destroy(void *obj, 269 enum wlan_objmgr_obj_type obj_type) 270 { 271 struct wlan_objmgr_debug_info *debug_info; 272 uint8_t *macaddr; 273 const char *obj_name; 274 union wlan_objmgr_del_obj *del_obj = (union wlan_objmgr_del_obj *)&obj; 275 276 debug_info = g_umac_glb_obj->debug_info; 277 278 if (!debug_info) { 279 obj_mgr_err("debug_info is null"); 280 return; 281 } 282 macaddr = wlan_objmgr_debug_get_macaddr(del_obj, obj_type); 283 if (!macaddr) { 284 obj_mgr_err("macaddr is null"); 285 return; 286 } 287 obj_name = wlan_obj_type_get_obj_name(obj_type); 288 if (!obj_name) { 289 obj_mgr_err("obj_name is null"); 290 return; 291 } 292 obj_mgr_debug("#%s : macaddr: "QDF_MAC_ADDR_FMT" exited L-state", 293 obj_name, QDF_MAC_ADDR_REF(macaddr)); 294 295 wlan_objmgr_rem_ld_obj_from_list(del_obj, 296 debug_info, obj_type); 297 } 298 299 /** 300 * wlan_objmgr_debug_obj_destroyed_panic() - Panic in case obj is in L-state 301 * for long 302 * @obj_name: The name of the module ID 303 * 304 * This will invoke panic in the case that the obj is in logically destroyed 305 * state for a long time. The panic is invoked only in case feature flag 306 * WLAN_OBJMGR_PANIC_ON_BUG is enabled 307 * 308 * Return: None 309 */ 310 #ifdef CONFIG_LEAK_DETECTION 311 static inline void wlan_objmgr_debug_obj_destroyed_panic(const char *obj_name) 312 { 313 obj_mgr_alert("#%s in L-state for too long!", obj_name); 314 QDF_BUG(0); 315 } 316 #else 317 static inline void wlan_objmgr_debug_obj_destroyed_panic(const char *obj_name) 318 { 319 } 320 #endif 321 322 /* 323 * wlan_objmgr_print_pending_refs() - Print pending refs according to the obj 324 * @obj: Represents peer/vdev/pdev/psoc 325 * @obj_type: Object type for peer/vdev/pdev/psoc 326 * 327 * Return: None 328 */ 329 static void wlan_objmgr_print_pending_refs(union wlan_objmgr_del_obj *obj, 330 enum wlan_objmgr_obj_type obj_type) 331 { 332 switch (obj_type) { 333 case WLAN_PSOC_OP: 334 wlan_objmgr_print_ref_ids(obj->obj_psoc->soc_objmgr.ref_id_dbg, 335 QDF_TRACE_LEVEL_DEBUG); 336 break; 337 case WLAN_PDEV_OP: 338 wlan_objmgr_print_ref_ids(obj->obj_pdev->pdev_objmgr.ref_id_dbg, 339 QDF_TRACE_LEVEL_DEBUG); 340 break; 341 case WLAN_VDEV_OP: 342 wlan_objmgr_print_ref_ids(obj->obj_vdev->vdev_objmgr.ref_id_dbg, 343 QDF_TRACE_LEVEL_DEBUG); 344 break; 345 case WLAN_PEER_OP: 346 wlan_objmgr_print_ref_ids(obj->obj_peer->peer_objmgr.ref_id_dbg, 347 QDF_TRACE_LEVEL_DEBUG); 348 break; 349 default: 350 obj_mgr_debug("invalid obj_type"); 351 } 352 } 353 354 #ifdef WLAN_OBJMGR_REF_ID_TRACE 355 static void 356 wlan_objmgr_print_ref_func_line(struct wlan_objmgr_trace_func *func_head, 357 uint32_t id) 358 { 359 uint32_t ref_cnt; 360 struct wlan_objmgr_line_ref_node *tmp_ln_node; 361 362 obj_mgr_debug("ID: %s(%d)", string_from_dbgid(id), id); 363 while (func_head) { 364 obj_mgr_debug("Func: %s", func_head->func); 365 tmp_ln_node = func_head->line_head; 366 while (tmp_ln_node) { 367 ref_cnt = qdf_atomic_read(&tmp_ln_node->line_ref.cnt); 368 obj_mgr_debug("line: %d cnt: %d", 369 tmp_ln_node->line_ref.line, 370 ref_cnt); 371 tmp_ln_node = tmp_ln_node->next; 372 } 373 func_head = func_head->next; 374 } 375 } 376 377 static void 378 wlan_objmgr_trace_print_ref(union wlan_objmgr_del_obj *obj, 379 enum wlan_objmgr_obj_type obj_type) 380 { 381 uint32_t id; 382 struct wlan_objmgr_trace_func *func_head; 383 struct wlan_objmgr_trace *trace; 384 struct wlan_objmgr_vdev_objmgr *vdev_obj; 385 struct wlan_objmgr_peer_objmgr *peer_obj; 386 387 switch (obj_type) { 388 case WLAN_VDEV_OP: 389 vdev_obj = &obj->obj_vdev->vdev_objmgr; 390 trace = &vdev_obj->trace; 391 for (id = 0; id < WLAN_REF_ID_MAX; id++) { 392 if (qdf_atomic_read(&vdev_obj->ref_id_dbg[id])) { 393 obj_mgr_debug("Reference:"); 394 395 func_head = trace->references[id].head; 396 wlan_objmgr_print_ref_func_line(func_head, id); 397 398 obj_mgr_debug("Dereference:"); 399 func_head = trace->dereferences[id].head; 400 wlan_objmgr_print_ref_func_line(func_head, id); 401 } 402 } 403 break; 404 case WLAN_PEER_OP: 405 peer_obj = &obj->obj_peer->peer_objmgr; 406 trace = &peer_obj->trace; 407 for (id = 0; id < WLAN_REF_ID_MAX; id++) { 408 if (qdf_atomic_read(&peer_obj->ref_id_dbg[id])) { 409 obj_mgr_debug("Reference:"); 410 411 func_head = trace->references[id].head; 412 wlan_objmgr_print_ref_func_line(func_head, id); 413 414 obj_mgr_debug("Dereference:"); 415 func_head = trace->dereferences[id].head; 416 wlan_objmgr_print_ref_func_line(func_head, id); 417 } 418 } 419 break; 420 default: 421 break; 422 } 423 } 424 #else 425 static void 426 wlan_objmgr_trace_print_ref(union wlan_objmgr_del_obj *obj, 427 enum wlan_objmgr_obj_type obj_type) 428 { 429 } 430 #endif 431 432 /* timeout handler for iterating logically deleted object */ 433 434 static void wlan_objmgr_iterate_log_del_obj_handler(void *timer_arg) 435 { 436 enum wlan_objmgr_obj_type obj_type; 437 uint8_t *macaddr; 438 const char *obj_name; 439 struct wlan_objmgr_debug_info *debug_info; 440 qdf_list_node_t *node; 441 qdf_list_t *log_del_obj_list = NULL; 442 struct log_del_obj *del_obj = NULL; 443 qdf_time_t cur_tstamp; 444 QDF_STATUS status; 445 446 debug_info = g_umac_glb_obj->debug_info; 447 448 if (!debug_info) { 449 obj_mgr_err("debug_info is not initialized"); 450 return; 451 } 452 453 log_del_obj_list = &debug_info->obj_list; 454 qdf_spin_lock_bh(&debug_info->list_lock); 455 456 status = qdf_list_peek_front(log_del_obj_list, &node); 457 if (QDF_IS_STATUS_ERROR(status)) { 458 qdf_spin_unlock_bh(&debug_info->list_lock); 459 return; 460 } 461 462 /* compute the current timestamp in seconds 463 * need to compare with destroy duration of object 464 */ 465 cur_tstamp = (qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000); 466 467 do { 468 del_obj = qdf_container_of(node, struct log_del_obj, node); 469 obj_type = del_obj->obj_type; 470 macaddr = wlan_objmgr_debug_get_macaddr(&del_obj->obj, 471 obj_type); 472 obj_name = wlan_obj_type_get_obj_name(obj_type); 473 474 /* If object is in logically deleted state for time more than 475 * destroy duration, print the object type and MAC 476 */ 477 if (cur_tstamp < (del_obj->tstamp + 478 LOG_DEL_OBJ_DESTROY_DURATION_SEC)) { 479 break; 480 } 481 if (!macaddr) { 482 obj_mgr_err("macaddr is null"); 483 QDF_BUG(0); 484 break; 485 } 486 if (!obj_name) { 487 obj_mgr_err("obj_name is null"); 488 QDF_BUG(0); 489 break; 490 } 491 492 obj_mgr_alert("#%s in L-state,MAC: " QDF_MAC_ADDR_FMT, 493 obj_name, QDF_MAC_ADDR_REF(macaddr)); 494 wlan_objmgr_print_pending_refs(&del_obj->obj, obj_type); 495 496 wlan_objmgr_trace_print_ref(&del_obj->obj, obj_type); 497 if (cur_tstamp > del_obj->tstamp + 498 LOG_DEL_OBJ_DESTROY_ASSERT_DURATION_SEC) { 499 if (!qdf_is_recovering() && !qdf_is_fw_down()) 500 wlan_objmgr_debug_obj_destroyed_panic(obj_name); 501 } 502 503 status = qdf_list_peek_next(log_del_obj_list, node, &node); 504 505 } while (QDF_IS_STATUS_SUCCESS(status)); 506 507 qdf_timer_mod(&debug_info->obj_timer, LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC); 508 qdf_spin_unlock_bh(&debug_info->list_lock); 509 } 510 511 void wlan_objmgr_debug_info_deinit(void) 512 { 513 struct log_del_obj *obj_to_remove; 514 struct wlan_objmgr_debug_info *debug_info; 515 qdf_list_node_t *node = NULL; 516 qdf_list_t *list; 517 bool is_child_alive = false; 518 519 debug_info = g_umac_glb_obj->debug_info; 520 521 if (!debug_info) { 522 obj_mgr_err("debug_info is not initialized"); 523 return; 524 } 525 list = &debug_info->obj_list; 526 527 qdf_spin_lock_bh(&debug_info->list_lock); 528 529 /* Check if any child of global object is in L-state and remove it, 530 * ideally it shouldn't be 531 */ 532 while (qdf_list_remove_front(list, &node) == QDF_STATUS_SUCCESS) { 533 is_child_alive = true; 534 obj_to_remove = qdf_container_of(node, 535 struct log_del_obj, node); 536 if (qdf_list_empty(&debug_info->obj_list)) 537 qdf_timer_stop(&debug_info->obj_timer); 538 /* free the object */ 539 qdf_mem_free(obj_to_remove); 540 } 541 qdf_spin_unlock_bh(&debug_info->list_lock); 542 543 if (is_child_alive) { 544 obj_mgr_alert("This shouldn't happen!!, No child of global" 545 "object should be in L-state, as global obj" 546 "is going to destroy"); 547 QDF_BUG(0); 548 } 549 550 /* free timer, destroy spinlock, list and debug_info object as 551 * global object is going to free 552 */ 553 qdf_list_destroy(list); 554 qdf_timer_free(&debug_info->obj_timer); 555 qdf_spinlock_destroy(&debug_info->list_lock); 556 qdf_mem_free(debug_info); 557 558 qdf_spin_lock_bh(&g_umac_glb_obj->global_lock); 559 g_umac_glb_obj->debug_info = NULL; 560 qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock); 561 } 562 563 void wlan_objmgr_debug_info_init(void) 564 { 565 struct wlan_objmgr_debug_info *debug_info; 566 567 debug_info = qdf_mem_malloc(sizeof(*debug_info)); 568 if (!debug_info) { 569 g_umac_glb_obj->debug_info = NULL; 570 return; 571 } 572 573 /* Initialize timer with timeout handler */ 574 qdf_timer_init(NULL, &debug_info->obj_timer, 575 wlan_objmgr_iterate_log_del_obj_handler, 576 NULL, QDF_TIMER_TYPE_WAKE_APPS); 577 578 /* Initialize the node_count to 0 and create list*/ 579 qdf_list_create(&debug_info->obj_list, 580 LOG_DEL_OBJ_LIST_MAX_COUNT); 581 582 /* Initialize the spin_lock to protect list */ 583 qdf_spinlock_create(&debug_info->list_lock); 584 585 /* attach debug_info object to global object */ 586 g_umac_glb_obj->debug_info = debug_info; 587 } 588 589 #ifdef WLAN_OBJMGR_REF_ID_TRACE 590 void 591 wlan_objmgr_trace_init_lock(struct wlan_objmgr_trace *trace) 592 { 593 qdf_spinlock_create(&trace->trace_lock); 594 } 595 596 void 597 wlan_objmgr_trace_deinit_lock(struct wlan_objmgr_trace *trace) 598 { 599 qdf_spinlock_destroy(&trace->trace_lock); 600 } 601 #endif 602 603 #ifdef WLAN_OBJMGR_REF_ID_TRACE 604 static inline struct wlan_objmgr_line_ref_node* 605 wlan_objmgr_trace_line_node_alloc(int line) 606 { 607 struct wlan_objmgr_line_ref_node *line_node; 608 609 line_node = qdf_mem_malloc_atomic(sizeof(*line_node)); 610 if (!line_node) 611 return NULL; 612 613 line_node->line_ref.line = line; 614 qdf_atomic_set(&line_node->line_ref.cnt, 1); 615 line_node->next = NULL; 616 617 return line_node; 618 } 619 620 static inline struct wlan_objmgr_trace_func* 621 wlan_objmgr_trace_ref_node_alloc(const char *func, int line) 622 { 623 struct wlan_objmgr_trace_func *func_node; 624 struct wlan_objmgr_line_ref_node *line_node; 625 626 func_node = qdf_mem_malloc_atomic(sizeof(*func_node)); 627 if (!func_node) 628 return NULL; 629 630 line_node = wlan_objmgr_trace_line_node_alloc(line); 631 if (!line_node) { 632 qdf_mem_free(func_node); 633 return NULL; 634 } 635 636 func_node->line_head = line_node; 637 qdf_str_lcopy(func_node->func, func, WLAN_OBJMGR_TRACE_FUNC_SIZE); 638 func_node->next = NULL; 639 640 return func_node; 641 } 642 643 static inline void 644 wlan_objmgr_trace_check_line(struct wlan_objmgr_trace_func *tmp_func_node, 645 struct wlan_objmgr_trace *trace, int line) 646 { 647 struct wlan_objmgr_line_ref_node *tmp_ln_node; 648 649 tmp_ln_node = tmp_func_node->line_head; 650 while (tmp_ln_node) { 651 if (tmp_ln_node->line_ref.line == line) { 652 qdf_atomic_inc(&tmp_ln_node->line_ref.cnt); 653 break; 654 } 655 tmp_ln_node = tmp_ln_node->next; 656 } 657 if (!tmp_ln_node) { 658 tmp_ln_node = wlan_objmgr_trace_line_node_alloc(line); 659 if (tmp_ln_node) { 660 tmp_ln_node->next = tmp_func_node->line_head; 661 tmp_func_node->line_head = tmp_ln_node; 662 } 663 } 664 } 665 666 void 667 wlan_objmgr_trace_ref(struct wlan_objmgr_trace_func **func_head, 668 struct wlan_objmgr_trace *trace, 669 const char *func, int line) 670 { 671 struct wlan_objmgr_trace_func *tmp_func_node; 672 struct wlan_objmgr_trace_func *func_node; 673 674 qdf_spin_lock_bh(&trace->trace_lock); 675 if (!*func_head) { 676 tmp_func_node = wlan_objmgr_trace_ref_node_alloc(func, line); 677 if (tmp_func_node) 678 *func_head = tmp_func_node; 679 } else { 680 tmp_func_node = *func_head; 681 while (tmp_func_node) { 682 func_node = tmp_func_node; 683 if (!qdf_str_ncmp(tmp_func_node->func, func, 684 WLAN_OBJMGR_TRACE_FUNC_SIZE - 1)) { 685 wlan_objmgr_trace_check_line(tmp_func_node, 686 trace, line); 687 break; 688 } 689 tmp_func_node = tmp_func_node->next; 690 } 691 692 if (!tmp_func_node) { 693 tmp_func_node = wlan_objmgr_trace_ref_node_alloc(func, 694 line); 695 if (tmp_func_node) 696 func_node->next = tmp_func_node; 697 } 698 } 699 qdf_spin_unlock_bh(&trace->trace_lock); 700 } 701 702 static void 703 wlan_objmgr_trace_del_line(struct wlan_objmgr_line_ref_node **line_head) 704 { 705 struct wlan_objmgr_line_ref_node *del_tmp_node; 706 struct wlan_objmgr_line_ref_node *line_node; 707 708 line_node = *line_head; 709 while (line_node) { 710 del_tmp_node = line_node; 711 line_node = line_node->next; 712 qdf_mem_free(del_tmp_node); 713 } 714 *line_head = NULL; 715 } 716 717 void 718 wlan_objmgr_trace_del_ref_list(struct wlan_objmgr_trace *trace) 719 { 720 struct wlan_objmgr_trace_func *func_node; 721 struct wlan_objmgr_trace_func *del_tmp_node; 722 uint32_t id; 723 724 qdf_spin_lock_bh(&trace->trace_lock); 725 for (id = 0; id < WLAN_REF_ID_MAX; id++) { 726 func_node = trace->references[id].head; 727 while (func_node) { 728 del_tmp_node = func_node; 729 wlan_objmgr_trace_del_line(&del_tmp_node->line_head); 730 func_node = func_node->next; 731 qdf_mem_free(del_tmp_node); 732 } 733 trace->references[id].head = NULL; 734 } 735 for (id = 0; id < WLAN_REF_ID_MAX; id++) { 736 func_node = trace->dereferences[id].head; 737 while (func_node) { 738 del_tmp_node = func_node; 739 wlan_objmgr_trace_del_line(&del_tmp_node->line_head); 740 func_node = func_node->next; 741 qdf_mem_free(del_tmp_node); 742 } 743 trace->dereferences[id].head = NULL; 744 } 745 qdf_spin_unlock_bh(&trace->trace_lock); 746 } 747 #endif 748