xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/obj_mgr/src/wlan_objmgr_debug.c (revision d97a5912d37f3ed3ec22e5ea3d41a9537ae60ae6)
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 
30 #define LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC   5000
31 #define LOG_DEL_OBJ_DESTROY_DURATION_SEC 5
32 #define LOG_DEL_OBJ_LIST_MAX_COUNT       (3 + 5 + 48 + 4096)
33 
34 /**
35  * struct log_del_obj    - Logically deleted Object
36  * @obj:            Represents peer/vdev/pdev/psoc
37  * @node:           List node from Logically deleted list
38  * @obj_type:       Object type for peer/vdev/pdev/psoc
39  * @tstamp:         Timestamp when node entered logically
40  *                  deleted state
41  */
42 struct log_del_obj {
43 	void *obj;
44 	qdf_list_node_t node;
45 	enum wlan_objmgr_obj_type obj_type;
46 	qdf_time_t tstamp;
47 };
48 
49 /**
50  * struct wlan_objmgr_debug_info     - Objmgr debug info
51  * for Logically deleted object
52  * @obj_timer:          Timer object
53  * @obj_list:           list object having linking logically
54  *                       deleted nodes
55  * @list_lock:          lock to protect list
56  */
57 struct wlan_objmgr_debug_info {
58 	qdf_timer_t obj_timer;
59 	qdf_list_t obj_list;
60 	qdf_spinlock_t list_lock;
61 };
62 
63 static const char *
64 wlan_obj_type_get_obj_name(enum wlan_objmgr_obj_type obj_type)
65 {
66 	static const struct wlan_obj_type_to_name {
67 		enum wlan_objmgr_obj_type obj_type;
68 		const char *name;
69 	} obj_type_name[WLAN_OBJ_TYPE_MAX] = {
70 		{WLAN_PSOC_OP, "psoc"},
71 		{WLAN_PDEV_OP, "pdev"},
72 		{WLAN_VDEV_OP, "vdev"},
73 		{WLAN_PEER_OP, "peer"}
74 	};
75 	uint8_t idx;
76 
77 	for (idx = 0; idx < WLAN_OBJ_TYPE_MAX; idx++) {
78 		if (obj_type == obj_type_name[idx].obj_type)
79 			return obj_type_name[idx].name;
80 	}
81 
82 	return NULL;
83 }
84 
85 static uint8_t*
86 wlan_objmgr_debug_get_macaddr(void *obj,
87 			      enum wlan_objmgr_obj_type obj_type)
88 {
89 	switch (obj_type) {
90 	case WLAN_PSOC_OP:
91 		return wlan_psoc_get_hw_macaddr(obj);
92 	case WLAN_PDEV_OP:
93 		return wlan_pdev_get_hw_macaddr(obj);
94 	case WLAN_VDEV_OP:
95 		return wlan_vdev_mlme_get_macaddr(obj);
96 	case WLAN_PEER_OP:
97 		return wlan_peer_get_macaddr(obj);
98 	default:
99 		obj_mgr_err("invalid obj_type");
100 		return NULL;
101 	}
102 }
103 
104 static void
105 wlan_objmgr_insert_ld_obj_to_list(struct wlan_objmgr_debug_info *debug_info,
106 				  qdf_list_node_t *node)
107 {
108 	/* Insert object to list with lock being held*/
109 	qdf_spin_lock_bh(&debug_info->list_lock);
110 
111 	/* Start timer only when list is empty */
112 	if (qdf_list_empty(&debug_info->obj_list))
113 		qdf_timer_start(&debug_info->obj_timer,
114 				LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC);
115 
116 	qdf_list_insert_back(&debug_info->obj_list, node);
117 	qdf_spin_unlock_bh(&debug_info->list_lock);
118 }
119 
120 void wlan_objmgr_notify_log_delete(void *obj,
121 				   enum wlan_objmgr_obj_type obj_type)
122 {
123 	struct wlan_objmgr_debug_info *debug_info;
124 	const char *obj_name;
125 	uint8_t *macaddr;
126 	qdf_time_t tstamp;
127 	struct log_del_obj *node;
128 
129 	if (!obj) {
130 		obj_mgr_err("object is null");
131 		return;
132 	}
133 
134 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
135 	debug_info = g_umac_glb_obj->debug_info;
136 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
137 
138 	if (!debug_info) {
139 		obj_mgr_err("debug_info is null");
140 		return;
141 	}
142 
143 	macaddr = wlan_objmgr_debug_get_macaddr(obj, obj_type);
144 	if (!macaddr) {
145 		obj_mgr_err("macaddr is null");
146 		return;
147 	}
148 
149 	obj_name = wlan_obj_type_get_obj_name(obj_type);
150 	if (!obj_name) {
151 		obj_mgr_err("obj_name is null");
152 		return;
153 	}
154 
155 	tstamp = qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000;
156 	node = qdf_mem_malloc(sizeof(*node));
157 	if (!node)
158 		return;
159 
160 	node->obj = obj;
161 	node->obj_type = obj_type;
162 	node->tstamp = tstamp;
163 	obj_mgr_debug("#%s : mac_addr :" QDF_MAC_ADDR_STR" entered L-state",
164 		      obj_name, QDF_MAC_ADDR_ARRAY(macaddr));
165 	wlan_objmgr_insert_ld_obj_to_list(debug_info, &node->node);
166 }
167 
168 static void
169 wlan_objmgr_rem_ld_obj_from_list(void *obj,
170 				 struct wlan_objmgr_debug_info *debug_info,
171 				 enum wlan_objmgr_obj_type obj_type)
172 {
173 	qdf_list_node_t *node = NULL;
174 	struct log_del_obj *obj_to_remove = NULL;
175 	qdf_list_t *list;
176 	QDF_STATUS status;
177 
178 	list = &debug_info->obj_list;
179 	qdf_spin_lock_bh(&debug_info->list_lock);
180 	status = qdf_list_peek_front(list, &node);
181 
182 	while (QDF_IS_STATUS_SUCCESS(status)) {
183 		obj_to_remove = qdf_container_of(node,
184 						 struct log_del_obj, node);
185 		if (obj_to_remove->obj == obj &&
186 		    obj_to_remove->obj_type == obj_type) {
187 			status = qdf_list_remove_node(list,
188 						      &obj_to_remove->node);
189 			/* Stop timer if list is empty */
190 			if (QDF_IS_STATUS_SUCCESS(status)) {
191 				if (qdf_list_empty(&debug_info->obj_list))
192 					qdf_timer_stop(&debug_info->obj_timer);
193 				qdf_mem_free(obj_to_remove);
194 			}
195 			break;
196 		}
197 		status = qdf_list_peek_next(list, node, &node);
198 	};
199 	qdf_spin_unlock_bh(&debug_info->list_lock);
200 }
201 
202 void wlan_objmgr_notify_destroy(void *obj,
203 				enum wlan_objmgr_obj_type obj_type)
204 {
205 	struct wlan_objmgr_debug_info *debug_info;
206 	uint8_t *macaddr;
207 	const char *obj_name;
208 
209 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
210 	debug_info = g_umac_glb_obj->debug_info;
211 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
212 
213 	if (!debug_info) {
214 		obj_mgr_err("debug_info is null");
215 		return;
216 	}
217 	macaddr = wlan_objmgr_debug_get_macaddr(obj, obj_type);
218 	if (!macaddr) {
219 		obj_mgr_err("macaddr is null");
220 		return;
221 	}
222 	obj_name = wlan_obj_type_get_obj_name(obj_type);
223 	if (!obj_name) {
224 		obj_mgr_err("obj_name is null");
225 		return;
226 	}
227 	obj_mgr_debug("#%s, macaddr: " QDF_MAC_ADDR_STR" exited L-state",
228 		      obj_name, QDF_MAC_ADDR_ARRAY(macaddr));
229 
230 	wlan_objmgr_rem_ld_obj_from_list(obj, debug_info, obj_type);
231 }
232 
233 /* timeout handler for iterating logically deleted object */
234 
235 static void wlan_objmgr_iterate_log_del_obj_handler(void *timer_arg)
236 {
237 	enum wlan_objmgr_obj_type obj_type;
238 	uint8_t *macaddr;
239 	const char *obj_name;
240 	struct wlan_objmgr_debug_info *debug_info;
241 	qdf_list_node_t *node;
242 	qdf_list_t *log_del_obj_list = NULL;
243 	struct log_del_obj *del_obj = NULL;
244 	qdf_time_t cur_tstamp;
245 	QDF_STATUS status;
246 
247 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
248 	debug_info = g_umac_glb_obj->debug_info;
249 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
250 
251 	if (!debug_info) {
252 		obj_mgr_err("debug_info is not initialized");
253 		return;
254 	}
255 
256 	log_del_obj_list = &debug_info->obj_list;
257 	qdf_spin_lock_bh(&debug_info->list_lock);
258 
259 	status = qdf_list_peek_front(log_del_obj_list, &node);
260 	if (QDF_IS_STATUS_ERROR(status)) {
261 		qdf_spin_unlock_bh(&debug_info->list_lock);
262 		return;
263 	}
264 
265 	/* compute the current timestamp in seconds
266 	 * need to compare with destroy duration of object
267 	 */
268 	cur_tstamp = (qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000);
269 
270 	do {
271 		del_obj = qdf_container_of(node, struct log_del_obj, node);
272 		obj_type = del_obj->obj_type;
273 		macaddr = wlan_objmgr_debug_get_macaddr(del_obj->obj, obj_type);
274 		obj_name = wlan_obj_type_get_obj_name(obj_type);
275 
276 		/* If object is in logically deleted state for time more than
277 		 * destroy duration, print the object type and MAC
278 		 */
279 		if (cur_tstamp  < (del_obj->tstamp +
280 					LOG_DEL_OBJ_DESTROY_DURATION_SEC)) {
281 			break;
282 		}
283 		if (!macaddr) {
284 			obj_mgr_err("macaddr is null");
285 			QDF_BUG(0);
286 			break;
287 		}
288 		if (!obj_name) {
289 			obj_mgr_err("obj_name is null");
290 			QDF_BUG(0);
291 			break;
292 		}
293 
294 		obj_mgr_alert("#%s in L-state,MAC: " QDF_MAC_ADDR_STR,
295 			      obj_name, QDF_MAC_ADDR_ARRAY(macaddr));
296 
297 		status = qdf_list_peek_next(log_del_obj_list, node, &node);
298 
299 	} while (QDF_IS_STATUS_SUCCESS(status));
300 
301 	qdf_timer_mod(&debug_info->obj_timer, LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC);
302 	qdf_spin_unlock_bh(&debug_info->list_lock);
303 }
304 
305 void wlan_objmgr_debug_info_deinit(void)
306 {
307 	struct log_del_obj *obj_to_remove;
308 	struct wlan_objmgr_debug_info *debug_info;
309 	qdf_list_node_t *node = NULL;
310 	qdf_list_t *list;
311 	bool is_child_alive = false;
312 
313 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
314 	debug_info = g_umac_glb_obj->debug_info;
315 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
316 
317 	if (!debug_info) {
318 		obj_mgr_err("debug_info is not initialized");
319 		return;
320 	}
321 	list = &debug_info->obj_list;
322 
323 	qdf_spin_lock_bh(&debug_info->list_lock);
324 
325 	/* Check if any child of global object is in L-state and remove it,
326 	 * ideally it shouldn't be
327 	 */
328 	while (qdf_list_remove_front(list, &node) == QDF_STATUS_SUCCESS) {
329 		is_child_alive = true;
330 		obj_to_remove = qdf_container_of(node,
331 						 struct log_del_obj, node);
332 		if (qdf_list_empty(&debug_info->obj_list))
333 			qdf_timer_stop(&debug_info->obj_timer);
334 		/* free the object */
335 		qdf_mem_free(obj_to_remove);
336 	}
337 	qdf_spin_unlock_bh(&debug_info->list_lock);
338 
339 	if (is_child_alive) {
340 		obj_mgr_alert("This shouldn't happen!!, No child of global"
341 			       "object should be in L-state, as global obj"
342 				"is going to destroy");
343 		QDF_BUG(0);
344 	}
345 
346 	/* free timer, destroy spinlock, list and debug_info object as
347 	 * global object is going to free
348 	 */
349 	qdf_list_destroy(list);
350 	qdf_timer_free(&debug_info->obj_timer);
351 	qdf_spinlock_destroy(&debug_info->list_lock);
352 	qdf_mem_free(debug_info);
353 
354 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
355 	g_umac_glb_obj->debug_info = NULL;
356 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
357 }
358 
359 void wlan_objmgr_debug_info_init(void)
360 {
361 	struct wlan_objmgr_debug_info *debug_info;
362 
363 	debug_info = qdf_mem_malloc(sizeof(*debug_info));
364 	if (!debug_info) {
365 		g_umac_glb_obj->debug_info = NULL;
366 		return;
367 	}
368 
369 	/* Initialize timer with timeout handler */
370 	qdf_timer_init(NULL, &debug_info->obj_timer,
371 		       wlan_objmgr_iterate_log_del_obj_handler,
372 		       NULL, QDF_TIMER_TYPE_WAKE_APPS);
373 
374 	/* Initialze the node_count to 0 and create list*/
375 	qdf_list_create(&debug_info->obj_list,
376 			LOG_DEL_OBJ_LIST_MAX_COUNT);
377 
378 	/* Initialize the spin_lock to protect list */
379 	qdf_spinlock_create(&debug_info->list_lock);
380 
381 	/* attach debug_info object to global object */
382 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
383 	g_umac_glb_obj->debug_info = debug_info;
384 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
385 }
386