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