xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/obj_mgr/src/wlan_objmgr_debug.c (revision 302a1d9701784af5f4797b1a9fe07ae820b51907)
1 /*
2  *
3  * Copyright (c) 2018 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 		obj_mgr_err("Object node creation failed");
159 		return;
160 	}
161 	node->obj = obj;
162 	node->obj_type = obj_type;
163 	node->tstamp = tstamp;
164 	obj_mgr_debug("#%s : mac_addr :" QDF_MAC_ADDR_STR" entered L-state",
165 		      obj_name, QDF_MAC_ADDR_ARRAY(macaddr));
166 	wlan_objmgr_insert_ld_obj_to_list(debug_info, &node->node);
167 }
168 
169 static void
170 wlan_objmgr_rem_ld_obj_from_list(void *obj,
171 				 struct wlan_objmgr_debug_info *debug_info,
172 				 enum wlan_objmgr_obj_type obj_type)
173 {
174 	qdf_list_node_t *node = NULL;
175 	struct log_del_obj *obj_to_remove = NULL;
176 	qdf_list_t *list;
177 	QDF_STATUS status;
178 
179 	list = &debug_info->obj_list;
180 	qdf_spin_lock_bh(&debug_info->list_lock);
181 	status = qdf_list_peek_front(list, &node);
182 
183 	while (QDF_IS_STATUS_SUCCESS(status)) {
184 		obj_to_remove = qdf_container_of(node,
185 						 struct log_del_obj, node);
186 		if (obj_to_remove->obj == obj &&
187 		    obj_to_remove->obj_type == obj_type) {
188 			status = qdf_list_remove_node(list,
189 						      &obj_to_remove->node);
190 			/* Stop timer if list is empty */
191 			if (QDF_IS_STATUS_SUCCESS(status)) {
192 				if (qdf_list_empty(&debug_info->obj_list))
193 					qdf_timer_stop(&debug_info->obj_timer);
194 				qdf_mem_free(obj_to_remove);
195 			}
196 			break;
197 		}
198 		status = qdf_list_peek_next(list, node, &node);
199 	};
200 	qdf_spin_unlock_bh(&debug_info->list_lock);
201 }
202 
203 void wlan_objmgr_notify_destroy(void *obj,
204 				enum wlan_objmgr_obj_type obj_type)
205 {
206 	struct wlan_objmgr_debug_info *debug_info;
207 	uint8_t *macaddr;
208 	const char *obj_name;
209 
210 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
211 	debug_info = g_umac_glb_obj->debug_info;
212 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
213 
214 	if (!debug_info) {
215 		obj_mgr_err("debug_info is null");
216 		return;
217 	}
218 	macaddr = wlan_objmgr_debug_get_macaddr(obj, obj_type);
219 	if (!macaddr) {
220 		obj_mgr_err("macaddr is null");
221 		return;
222 	}
223 	obj_name = wlan_obj_type_get_obj_name(obj_type);
224 	if (!obj_name) {
225 		obj_mgr_err("obj_name is null");
226 		return;
227 	}
228 	obj_mgr_debug("#%s, macaddr: " QDF_MAC_ADDR_STR" exited L-state",
229 		      obj_name, QDF_MAC_ADDR_ARRAY(macaddr));
230 
231 	wlan_objmgr_rem_ld_obj_from_list(obj, debug_info, obj_type);
232 }
233 
234 /* timeout handler for iterating logically deleted object */
235 
236 static void wlan_objmgr_iterate_log_del_obj_handler(void *timer_arg)
237 {
238 	enum wlan_objmgr_obj_type obj_type;
239 	uint8_t *macaddr;
240 	const char *obj_name;
241 	struct wlan_objmgr_debug_info *debug_info;
242 	qdf_list_node_t *node;
243 	qdf_list_t *log_del_obj_list = NULL;
244 	struct log_del_obj *del_obj = NULL;
245 	qdf_time_t cur_tstamp;
246 	QDF_STATUS status;
247 
248 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
249 	debug_info = g_umac_glb_obj->debug_info;
250 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
251 
252 	if (!debug_info) {
253 		obj_mgr_err("debug_info is not initialized");
254 		return;
255 	}
256 
257 	log_del_obj_list = &debug_info->obj_list;
258 	qdf_spin_lock_bh(&debug_info->list_lock);
259 
260 	status = qdf_list_peek_front(log_del_obj_list, &node);
261 	if (QDF_IS_STATUS_ERROR(status)) {
262 		qdf_spin_unlock_bh(&debug_info->list_lock);
263 		return;
264 	}
265 
266 	/* compute the current timestamp in seconds
267 	 * need to compare with destroy duration of object
268 	 */
269 	cur_tstamp = (qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000);
270 
271 	do {
272 		del_obj = qdf_container_of(node, struct log_del_obj, node);
273 		obj_type = del_obj->obj_type;
274 		macaddr = wlan_objmgr_debug_get_macaddr(del_obj->obj, obj_type);
275 		obj_name = wlan_obj_type_get_obj_name(obj_type);
276 
277 		/* If object is in logically deleted state for time more than
278 		 * destroy duration, print the object type and MAC
279 		 */
280 		if (cur_tstamp  < (del_obj->tstamp +
281 					LOG_DEL_OBJ_DESTROY_DURATION_SEC)) {
282 			break;
283 		}
284 		if (!macaddr) {
285 			obj_mgr_err("macaddr is null");
286 			QDF_BUG(0);
287 			break;
288 		}
289 		if (!obj_name) {
290 			obj_mgr_err("obj_name is null");
291 			QDF_BUG(0);
292 			break;
293 		}
294 
295 		obj_mgr_alert("#%s in L-state,MAC: " QDF_MAC_ADDR_STR,
296 			      obj_name, QDF_MAC_ADDR_ARRAY(macaddr));
297 
298 		status = qdf_list_peek_next(log_del_obj_list, node, &node);
299 
300 	} while (QDF_IS_STATUS_SUCCESS(status));
301 
302 	qdf_timer_mod(&debug_info->obj_timer, LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC);
303 	qdf_spin_unlock_bh(&debug_info->list_lock);
304 }
305 
306 void wlan_objmgr_debug_info_deinit(void)
307 {
308 	struct log_del_obj *obj_to_remove;
309 	struct wlan_objmgr_debug_info *debug_info;
310 	qdf_list_node_t *node = NULL;
311 	qdf_list_t *list;
312 	bool is_child_alive = false;
313 
314 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
315 	debug_info = g_umac_glb_obj->debug_info;
316 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
317 
318 	if (!debug_info) {
319 		obj_mgr_err("debug_info is not initialized");
320 		return;
321 	}
322 	list = &debug_info->obj_list;
323 
324 	qdf_spin_lock_bh(&debug_info->list_lock);
325 
326 	/* Check if any child of global object is in L-state and remove it,
327 	 * ideally it shouldn't be
328 	 */
329 	while (qdf_list_remove_front(list, &node) == QDF_STATUS_SUCCESS) {
330 		is_child_alive = true;
331 		obj_to_remove = qdf_container_of(node,
332 						 struct log_del_obj, node);
333 		if (qdf_list_empty(&debug_info->obj_list))
334 			qdf_timer_stop(&debug_info->obj_timer);
335 		/* free the object */
336 		qdf_mem_free(obj_to_remove);
337 	}
338 	qdf_spin_unlock_bh(&debug_info->list_lock);
339 
340 	if (is_child_alive) {
341 		obj_mgr_alert("This shouldn't happen!!, No child of global"
342 			       "object should be in L-state, as global obj"
343 				"is going to destroy");
344 		QDF_BUG(0);
345 	}
346 
347 	/* free timer, destroy spinlock, list and debug_info object as
348 	 * global object is going to free
349 	 */
350 	qdf_list_destroy(list);
351 	qdf_timer_free(&debug_info->obj_timer);
352 	qdf_spinlock_destroy(&debug_info->list_lock);
353 	qdf_mem_free(debug_info);
354 
355 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
356 	g_umac_glb_obj->debug_info = NULL;
357 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
358 }
359 
360 void wlan_objmgr_debug_info_init(void)
361 {
362 	struct wlan_objmgr_debug_info *debug_info;
363 
364 	debug_info = qdf_mem_malloc(sizeof(*debug_info));
365 	if (!debug_info) {
366 		obj_mgr_err("debug_info allocation failed");
367 		g_umac_glb_obj->debug_info = NULL;
368 		return;
369 	}
370 
371 	/* Initialize timer with timeout handler */
372 	qdf_timer_init(NULL, &debug_info->obj_timer,
373 		       wlan_objmgr_iterate_log_del_obj_handler,
374 		       NULL, QDF_TIMER_TYPE_WAKE_APPS);
375 
376 	/* Initialze the node_count to 0 and create list*/
377 	qdf_list_create(&debug_info->obj_list,
378 			LOG_DEL_OBJ_LIST_MAX_COUNT);
379 
380 	/* Initialize the spin_lock to protect list */
381 	qdf_spinlock_create(&debug_info->list_lock);
382 
383 	/* attach debug_info object to global object */
384 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
385 	g_umac_glb_obj->debug_info = debug_info;
386 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
387 }
388