xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/obj_mgr/src/wlan_objmgr_debug.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
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 *
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*
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
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 
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 
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 
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
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 	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
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
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  */
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
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
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
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 
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 
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 
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 	/* Initialze 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
591 wlan_objmgr_trace_init_lock(struct wlan_objmgr_trace *trace)
592 {
593 	qdf_spinlock_create(&trace->trace_lock);
594 }
595 
596 void
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*
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*
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
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
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
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
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