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