xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/obj_mgr/src/wlan_objmgr_debug.c (revision 503663c6daafffe652fa360bde17243568cd6d2a)
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