xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/obj_mgr/src/wlan_objmgr_debug.c (revision a86b23ee68a2491aede2e03991f3fb37046f4e41)
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_STR" entered L-state",
207 		      obj_name, QDF_MAC_ADDR_ARRAY(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 		if (del_obj->obj_psoc == obj->obj_psoc)
218 			return true;
219 	case WLAN_PDEV_OP:
220 		if (del_obj->obj_pdev == obj->obj_pdev)
221 			return true;
222 	case WLAN_VDEV_OP:
223 		if (del_obj->obj_vdev == obj->obj_vdev)
224 			return true;
225 	case WLAN_PEER_OP:
226 		if (del_obj->obj_peer == obj->obj_peer)
227 			return true;
228 	default:
229 		return false;
230 	}
231 }
232 
233 static void
234 wlan_objmgr_rem_ld_obj_from_list(union wlan_objmgr_del_obj *obj,
235 				 struct wlan_objmgr_debug_info *debug_info,
236 				 enum wlan_objmgr_obj_type obj_type)
237 {
238 	qdf_list_node_t *node = NULL;
239 	struct log_del_obj *obj_to_remove = NULL;
240 	qdf_list_t *list;
241 	QDF_STATUS status;
242 
243 	list = &debug_info->obj_list;
244 	qdf_spin_lock_bh(&debug_info->list_lock);
245 	status = qdf_list_peek_front(list, &node);
246 
247 	while (QDF_IS_STATUS_SUCCESS(status)) {
248 		obj_to_remove = qdf_container_of(node,
249 						 struct log_del_obj, node);
250 		if (wlan_objmgr_del_obj_match(obj, &obj_to_remove->obj,
251 					      obj_type) &&
252 		    obj_to_remove->obj_type == obj_type) {
253 			status = qdf_list_remove_node(list,
254 						      &obj_to_remove->node);
255 			/* Stop timer if list is empty */
256 			if (QDF_IS_STATUS_SUCCESS(status)) {
257 				if (qdf_list_empty(&debug_info->obj_list))
258 					qdf_timer_stop(&debug_info->obj_timer);
259 				qdf_mem_free(obj_to_remove);
260 			}
261 			break;
262 		}
263 		status = qdf_list_peek_next(list, node, &node);
264 	};
265 	qdf_spin_unlock_bh(&debug_info->list_lock);
266 }
267 
268 void wlan_objmgr_notify_destroy(void *obj,
269 				enum wlan_objmgr_obj_type obj_type)
270 {
271 	struct wlan_objmgr_debug_info *debug_info;
272 	uint8_t *macaddr;
273 	const char *obj_name;
274 	union wlan_objmgr_del_obj *del_obj = (union wlan_objmgr_del_obj *)&obj;
275 
276 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
277 	debug_info = g_umac_glb_obj->debug_info;
278 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
279 
280 	if (!debug_info) {
281 		obj_mgr_err("debug_info is null");
282 		return;
283 	}
284 	macaddr = wlan_objmgr_debug_get_macaddr(del_obj, obj_type);
285 	if (!macaddr) {
286 		obj_mgr_err("macaddr is null");
287 		return;
288 	}
289 	obj_name = wlan_obj_type_get_obj_name(obj_type);
290 	if (!obj_name) {
291 		obj_mgr_err("obj_name is null");
292 		return;
293 	}
294 	obj_mgr_debug("#%s, macaddr: " QDF_MAC_ADDR_STR" exited L-state",
295 		      obj_name, QDF_MAC_ADDR_ARRAY(macaddr));
296 
297 	wlan_objmgr_rem_ld_obj_from_list(del_obj,
298 					 debug_info, obj_type);
299 }
300 
301 /**
302  * wlan_objmgr_debug_obj_destroyed_panic() - Panic in case obj is in L-state
303  * for long
304  * @obj_name: The name of the module ID
305  *
306  * This will invoke panic in the case that the obj is in logically destroyed
307  * state for a long time. The panic is invoked only in case feature flag
308  * WLAN_OBJMGR_PANIC_ON_BUG is enabled
309  *
310  * Return: None
311  */
312 #ifdef CONFIG_LEAK_DETECTION
313 static inline void wlan_objmgr_debug_obj_destroyed_panic(const char *obj_name)
314 {
315 	obj_mgr_alert("#%s in L-state for too long!", obj_name);
316 	QDF_BUG(0);
317 }
318 #else
319 static inline void wlan_objmgr_debug_obj_destroyed_panic(const char *obj_name)
320 {
321 }
322 #endif
323 
324 /*
325  * wlan_objmgr_print_pending_refs() - Print pending refs according to the obj
326  * @obj:	Represents peer/vdev/pdev/psoc
327  * @obj_type:	Object type for peer/vdev/pdev/psoc
328  *
329  * Return: None
330  */
331 static void wlan_objmgr_print_pending_refs(union wlan_objmgr_del_obj *obj,
332 					   enum wlan_objmgr_obj_type obj_type)
333 {
334 	switch (obj_type) {
335 	case WLAN_PSOC_OP:
336 		wlan_objmgr_print_ref_ids(obj->obj_psoc->soc_objmgr.ref_id_dbg,
337 					  QDF_TRACE_LEVEL_DEBUG);
338 		break;
339 	case WLAN_PDEV_OP:
340 		wlan_objmgr_print_ref_ids(obj->obj_pdev->pdev_objmgr.ref_id_dbg,
341 					  QDF_TRACE_LEVEL_DEBUG);
342 		break;
343 	case WLAN_VDEV_OP:
344 		wlan_objmgr_print_ref_ids(obj->obj_vdev->vdev_objmgr.ref_id_dbg,
345 					  QDF_TRACE_LEVEL_DEBUG);
346 		break;
347 	case WLAN_PEER_OP:
348 		wlan_objmgr_print_ref_ids(obj->obj_peer->peer_objmgr.ref_id_dbg,
349 					  QDF_TRACE_LEVEL_DEBUG);
350 		break;
351 	default:
352 		obj_mgr_debug("invalid obj_type");
353 	}
354 }
355 
356 #ifdef WLAN_OBJMGR_REF_ID_TRACE
357 static void
358 wlan_objmgr_print_ref_func_line(struct wlan_objmgr_trace_func *func_head,
359 				uint32_t id)
360 {
361 	uint32_t ref_cnt;
362 	struct wlan_objmgr_line_ref_node *tmp_ln_node;
363 
364 	obj_mgr_debug("ID: %s", string_from_dbgid(id));
365 	while (func_head) {
366 		obj_mgr_debug("Func: %s", func_head->func);
367 		tmp_ln_node = func_head->line_head;
368 		while (tmp_ln_node) {
369 			ref_cnt = qdf_atomic_read(&tmp_ln_node->line_ref.cnt);
370 			obj_mgr_debug("line: %d cnt: %d",
371 				      tmp_ln_node->line_ref.line,
372 				      ref_cnt);
373 			tmp_ln_node = tmp_ln_node->next;
374 		}
375 		func_head = func_head->next;
376 	}
377 }
378 
379 static void
380 wlan_objmgr_trace_print_ref(union wlan_objmgr_del_obj *obj,
381 			    enum wlan_objmgr_obj_type obj_type)
382 {
383 	uint32_t id;
384 	struct wlan_objmgr_trace_func *func_head;
385 	struct wlan_objmgr_trace *trace;
386 	struct wlan_objmgr_vdev_objmgr *vdev_obj;
387 	struct wlan_objmgr_peer_objmgr *peer_obj;
388 
389 	switch (obj_type) {
390 	case WLAN_VDEV_OP:
391 		vdev_obj = &obj->obj_vdev->vdev_objmgr;
392 		trace = &vdev_obj->trace;
393 		for (id = 0; id < WLAN_REF_ID_MAX; id++) {
394 			if (qdf_atomic_read(&vdev_obj->ref_id_dbg[id])) {
395 				obj_mgr_debug("Reference:");
396 
397 				func_head = trace->references[id].head;
398 				wlan_objmgr_print_ref_func_line(func_head, id);
399 
400 				obj_mgr_debug("Dereference:");
401 				func_head = trace->dereferences[id].head;
402 				wlan_objmgr_print_ref_func_line(func_head, id);
403 			}
404 		}
405 		break;
406 	case WLAN_PEER_OP:
407 		peer_obj = &obj->obj_peer->peer_objmgr;
408 		trace = &peer_obj->trace;
409 		for (id = 0; id < WLAN_REF_ID_MAX; id++) {
410 			if (qdf_atomic_read(&vdev_obj->ref_id_dbg[id])) {
411 				obj_mgr_debug("Reference:");
412 
413 				func_head = trace->references[id].head;
414 				wlan_objmgr_print_ref_func_line(func_head, id);
415 
416 				obj_mgr_debug("Dereference:");
417 				func_head = trace->dereferences[id].head;
418 				wlan_objmgr_print_ref_func_line(func_head, id);
419 			}
420 		}
421 		break;
422 	default:
423 		break;
424 	}
425 }
426 #else
427 static void
428 wlan_objmgr_trace_print_ref(union wlan_objmgr_del_obj *obj,
429 			    enum wlan_objmgr_obj_type obj_type)
430 {
431 }
432 #endif
433 
434 /* timeout handler for iterating logically deleted object */
435 
436 static void wlan_objmgr_iterate_log_del_obj_handler(void *timer_arg)
437 {
438 	enum wlan_objmgr_obj_type obj_type;
439 	uint8_t *macaddr;
440 	const char *obj_name;
441 	struct wlan_objmgr_debug_info *debug_info;
442 	qdf_list_node_t *node;
443 	qdf_list_t *log_del_obj_list = NULL;
444 	struct log_del_obj *del_obj = NULL;
445 	qdf_time_t cur_tstamp;
446 	QDF_STATUS status;
447 
448 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
449 	debug_info = g_umac_glb_obj->debug_info;
450 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
451 
452 	if (!debug_info) {
453 		obj_mgr_err("debug_info is not initialized");
454 		return;
455 	}
456 
457 	log_del_obj_list = &debug_info->obj_list;
458 	qdf_spin_lock_bh(&debug_info->list_lock);
459 
460 	status = qdf_list_peek_front(log_del_obj_list, &node);
461 	if (QDF_IS_STATUS_ERROR(status)) {
462 		qdf_spin_unlock_bh(&debug_info->list_lock);
463 		return;
464 	}
465 
466 	/* compute the current timestamp in seconds
467 	 * need to compare with destroy duration of object
468 	 */
469 	cur_tstamp = (qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000);
470 
471 	do {
472 		del_obj = qdf_container_of(node, struct log_del_obj, node);
473 		obj_type = del_obj->obj_type;
474 		macaddr = wlan_objmgr_debug_get_macaddr(&del_obj->obj,
475 							obj_type);
476 		obj_name = wlan_obj_type_get_obj_name(obj_type);
477 
478 		/* If object is in logically deleted state for time more than
479 		 * destroy duration, print the object type and MAC
480 		 */
481 		if (cur_tstamp  < (del_obj->tstamp +
482 					LOG_DEL_OBJ_DESTROY_DURATION_SEC)) {
483 			break;
484 		}
485 		if (!macaddr) {
486 			obj_mgr_err("macaddr is null");
487 			QDF_BUG(0);
488 			break;
489 		}
490 		if (!obj_name) {
491 			obj_mgr_err("obj_name is null");
492 			QDF_BUG(0);
493 			break;
494 		}
495 
496 		obj_mgr_alert("#%s in L-state,MAC: " QDF_MAC_ADDR_STR,
497 			      obj_name, QDF_MAC_ADDR_ARRAY(macaddr));
498 		wlan_objmgr_print_pending_refs(&del_obj->obj, obj_type);
499 
500 		wlan_objmgr_trace_print_ref(&del_obj->obj, obj_type);
501 		if (cur_tstamp > del_obj->tstamp +
502 		    LOG_DEL_OBJ_DESTROY_ASSERT_DURATION_SEC) {
503 			if (!qdf_is_recovering() && !qdf_is_fw_down())
504 				wlan_objmgr_debug_obj_destroyed_panic(obj_name);
505 		}
506 
507 		status = qdf_list_peek_next(log_del_obj_list, node, &node);
508 
509 	} while (QDF_IS_STATUS_SUCCESS(status));
510 
511 	qdf_timer_mod(&debug_info->obj_timer, LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC);
512 	qdf_spin_unlock_bh(&debug_info->list_lock);
513 }
514 
515 void wlan_objmgr_debug_info_deinit(void)
516 {
517 	struct log_del_obj *obj_to_remove;
518 	struct wlan_objmgr_debug_info *debug_info;
519 	qdf_list_node_t *node = NULL;
520 	qdf_list_t *list;
521 	bool is_child_alive = false;
522 
523 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
524 	debug_info = g_umac_glb_obj->debug_info;
525 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
526 
527 	if (!debug_info) {
528 		obj_mgr_err("debug_info is not initialized");
529 		return;
530 	}
531 	list = &debug_info->obj_list;
532 
533 	qdf_spin_lock_bh(&debug_info->list_lock);
534 
535 	/* Check if any child of global object is in L-state and remove it,
536 	 * ideally it shouldn't be
537 	 */
538 	while (qdf_list_remove_front(list, &node) == QDF_STATUS_SUCCESS) {
539 		is_child_alive = true;
540 		obj_to_remove = qdf_container_of(node,
541 						 struct log_del_obj, node);
542 		if (qdf_list_empty(&debug_info->obj_list))
543 			qdf_timer_stop(&debug_info->obj_timer);
544 		/* free the object */
545 		qdf_mem_free(obj_to_remove);
546 	}
547 	qdf_spin_unlock_bh(&debug_info->list_lock);
548 
549 	if (is_child_alive) {
550 		obj_mgr_alert("This shouldn't happen!!, No child of global"
551 			       "object should be in L-state, as global obj"
552 				"is going to destroy");
553 		QDF_BUG(0);
554 	}
555 
556 	/* free timer, destroy spinlock, list and debug_info object as
557 	 * global object is going to free
558 	 */
559 	qdf_list_destroy(list);
560 	qdf_timer_free(&debug_info->obj_timer);
561 	qdf_spinlock_destroy(&debug_info->list_lock);
562 	qdf_mem_free(debug_info);
563 
564 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
565 	g_umac_glb_obj->debug_info = NULL;
566 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
567 }
568 
569 void wlan_objmgr_debug_info_init(void)
570 {
571 	struct wlan_objmgr_debug_info *debug_info;
572 
573 	debug_info = qdf_mem_malloc(sizeof(*debug_info));
574 	if (!debug_info) {
575 		g_umac_glb_obj->debug_info = NULL;
576 		return;
577 	}
578 
579 	/* Initialize timer with timeout handler */
580 	qdf_timer_init(NULL, &debug_info->obj_timer,
581 		       wlan_objmgr_iterate_log_del_obj_handler,
582 		       NULL, QDF_TIMER_TYPE_WAKE_APPS);
583 
584 	/* Initialze the node_count to 0 and create list*/
585 	qdf_list_create(&debug_info->obj_list,
586 			LOG_DEL_OBJ_LIST_MAX_COUNT);
587 
588 	/* Initialize the spin_lock to protect list */
589 	qdf_spinlock_create(&debug_info->list_lock);
590 
591 	/* attach debug_info object to global object */
592 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
593 	g_umac_glb_obj->debug_info = debug_info;
594 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
595 }
596 
597 #ifdef WLAN_OBJMGR_REF_ID_TRACE
598 void
599 wlan_objmgr_trace_init_lock(struct wlan_objmgr_trace *trace)
600 {
601 	qdf_spinlock_create(&trace->trace_lock);
602 }
603 
604 void
605 wlan_objmgr_trace_deinit_lock(struct wlan_objmgr_trace *trace)
606 {
607 	qdf_spinlock_destroy(&trace->trace_lock);
608 }
609 #endif
610 
611 #ifdef WLAN_OBJMGR_REF_ID_TRACE
612 static inline struct wlan_objmgr_line_ref_node*
613 wlan_objmgr_trace_line_node_alloc(int line)
614 {
615 	struct wlan_objmgr_line_ref_node *line_node;
616 
617 	line_node = qdf_mem_malloc_atomic(sizeof(*line_node));
618 	if (!line_node)
619 		return NULL;
620 
621 	line_node->line_ref.line = line;
622 	qdf_atomic_set(&line_node->line_ref.cnt, 1);
623 	line_node->next = NULL;
624 
625 	return line_node;
626 }
627 
628 static inline struct wlan_objmgr_trace_func*
629 wlan_objmgr_trace_ref_node_alloc(const char *func, int line)
630 {
631 	struct wlan_objmgr_trace_func *func_node;
632 	struct wlan_objmgr_line_ref_node *line_node;
633 
634 	func_node = qdf_mem_malloc_atomic(sizeof(*func_node));
635 	if (!func_node)
636 		return NULL;
637 
638 	line_node = wlan_objmgr_trace_line_node_alloc(line);
639 	if (!line_node) {
640 		qdf_mem_free(func_node);
641 		return NULL;
642 	}
643 
644 	func_node->line_head = line_node;
645 	qdf_str_lcopy(func_node->func, func, WLAN_OBJMGR_TRACE_FUNC_SIZE);
646 	func_node->next = NULL;
647 
648 	return func_node;
649 }
650 
651 static inline void
652 wlan_objmgr_trace_check_line(struct wlan_objmgr_trace_func *tmp_func_node,
653 			     struct wlan_objmgr_trace *trace, int line)
654 {
655 	struct wlan_objmgr_line_ref_node *line_node;
656 	struct wlan_objmgr_line_ref_node *tmp_ln_node;
657 
658 	tmp_ln_node = tmp_func_node->line_head;
659 	while (tmp_ln_node) {
660 		line_node = tmp_ln_node;
661 		if (tmp_ln_node->line_ref.line == line) {
662 			qdf_atomic_inc(&tmp_ln_node->line_ref.cnt);
663 			break;
664 		}
665 		tmp_ln_node = tmp_ln_node->next;
666 	}
667 	if (!tmp_ln_node) {
668 		tmp_ln_node = wlan_objmgr_trace_line_node_alloc(line);
669 		if (tmp_ln_node)
670 			line_node->next = tmp_ln_node;
671 	}
672 }
673 
674 void
675 wlan_objmgr_trace_ref(struct wlan_objmgr_trace_func **func_head,
676 		      struct wlan_objmgr_trace *trace,
677 		      const char *func, int line)
678 {
679 	struct wlan_objmgr_trace_func *tmp_func_node;
680 	struct wlan_objmgr_trace_func *func_node;
681 
682 	qdf_spin_lock_bh(&trace->trace_lock);
683 	if (!*func_head) {
684 		tmp_func_node = wlan_objmgr_trace_ref_node_alloc(func, line);
685 		if (tmp_func_node)
686 			*func_head = tmp_func_node;
687 	} else {
688 		tmp_func_node = *func_head;
689 		while (tmp_func_node) {
690 			func_node = tmp_func_node;
691 			if (!qdf_str_ncmp(tmp_func_node->func, func,
692 					  WLAN_OBJMGR_TRACE_FUNC_SIZE - 1)) {
693 				wlan_objmgr_trace_check_line(tmp_func_node,
694 							     trace, line);
695 				break;
696 			}
697 			tmp_func_node = tmp_func_node->next;
698 		}
699 
700 		if (!tmp_func_node) {
701 			tmp_func_node = wlan_objmgr_trace_ref_node_alloc(func,
702 									 line);
703 			if (tmp_func_node)
704 				func_node->next = tmp_func_node;
705 		}
706 	}
707 	qdf_spin_unlock_bh(&trace->trace_lock);
708 }
709 
710 void
711 wlan_objmgr_trace_del_line(struct wlan_objmgr_line_ref_node **line_head)
712 {
713 	struct wlan_objmgr_line_ref_node *del_tmp_node;
714 	struct wlan_objmgr_line_ref_node *line_node;
715 
716 	line_node = *line_head;
717 	while (line_node) {
718 		del_tmp_node = line_node;
719 		line_node = line_node->next;
720 		qdf_mem_free(del_tmp_node);
721 	}
722 	*line_head = NULL;
723 }
724 
725 void
726 wlan_objmgr_trace_del_ref_list(struct wlan_objmgr_trace *trace)
727 {
728 	struct wlan_objmgr_trace_func *func_node;
729 	struct wlan_objmgr_trace_func *del_tmp_node;
730 	uint32_t id;
731 
732 	qdf_spin_lock_bh(&trace->trace_lock);
733 	for (id = 0; id < WLAN_REF_ID_MAX; id++) {
734 		func_node = trace->references[id].head;
735 		while (func_node) {
736 			del_tmp_node = func_node;
737 			wlan_objmgr_trace_del_line(&del_tmp_node->line_head);
738 			func_node = func_node->next;
739 			qdf_mem_free(del_tmp_node);
740 		}
741 		trace->references[id].head = NULL;
742 	}
743 	for (id = 0; id < WLAN_REF_ID_MAX; id++) {
744 		func_node = trace->dereferences[id].head;
745 		while (func_node) {
746 			del_tmp_node = func_node;
747 			wlan_objmgr_trace_del_line(&del_tmp_node->line_head);
748 			func_node = func_node->next;
749 			qdf_mem_free(del_tmp_node);
750 		}
751 		trace->dereferences[id].head = NULL;
752 	}
753 	qdf_spin_unlock_bh(&trace->trace_lock);
754 }
755 #endif
756