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 *
wlan_obj_type_get_obj_name(enum wlan_objmgr_obj_type obj_type)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*
wlan_objmgr_debug_get_macaddr(union wlan_objmgr_del_obj * obj,enum wlan_objmgr_obj_type obj_type)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
wlan_objmgr_insert_ld_obj_to_list(struct wlan_objmgr_debug_info * debug_info,qdf_list_node_t * node)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
wlan_obj_type_get_obj(union wlan_objmgr_del_obj * obj,union wlan_objmgr_del_obj * del_obj,enum wlan_objmgr_obj_type obj_type)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
wlan_objmgr_notify_log_delete(void * obj,enum wlan_objmgr_obj_type obj_type)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
wlan_objmgr_del_obj_match(union wlan_objmgr_del_obj * obj,union wlan_objmgr_del_obj * del_obj,enum wlan_objmgr_obj_type obj_type)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
wlan_objmgr_rem_ld_obj_from_list(union wlan_objmgr_del_obj * obj,struct wlan_objmgr_debug_info * debug_info,enum wlan_objmgr_obj_type obj_type)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
wlan_objmgr_notify_destroy(void * obj,enum wlan_objmgr_obj_type obj_type)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
wlan_objmgr_debug_obj_destroyed_panic(const char * obj_name)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
wlan_objmgr_debug_obj_destroyed_panic(const char * obj_name)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 */
wlan_objmgr_print_pending_refs(union wlan_objmgr_del_obj * obj,enum wlan_objmgr_obj_type obj_type)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
wlan_objmgr_print_ref_func_line(struct wlan_objmgr_trace_func * func_head,uint32_t id)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
wlan_objmgr_trace_print_ref(union wlan_objmgr_del_obj * obj,enum wlan_objmgr_obj_type obj_type)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
wlan_objmgr_trace_print_ref(union wlan_objmgr_del_obj * obj,enum wlan_objmgr_obj_type obj_type)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
wlan_objmgr_iterate_log_del_obj_handler(void * timer_arg)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
wlan_objmgr_debug_info_deinit(void)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
wlan_objmgr_debug_info_init(void)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
wlan_objmgr_trace_init_lock(struct wlan_objmgr_trace * trace)591 wlan_objmgr_trace_init_lock(struct wlan_objmgr_trace *trace)
592 {
593 qdf_spinlock_create(&trace->trace_lock);
594 }
595
596 void
wlan_objmgr_trace_deinit_lock(struct wlan_objmgr_trace * trace)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*
wlan_objmgr_trace_line_node_alloc(int line)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*
wlan_objmgr_trace_ref_node_alloc(const char * func,int line)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
wlan_objmgr_trace_check_line(struct wlan_objmgr_trace_func * tmp_func_node,struct wlan_objmgr_trace * trace,int line)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
wlan_objmgr_trace_ref(struct wlan_objmgr_trace_func ** func_head,struct wlan_objmgr_trace * trace,const char * func,int line)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
wlan_objmgr_trace_del_line(struct wlan_objmgr_line_ref_node ** line_head)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
wlan_objmgr_trace_del_ref_list(struct wlan_objmgr_trace * trace)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