xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/obj_mgr/src/wlan_objmgr_debug.c (revision a175314c51a4ce5cec2835cc8a8c7dc0c1810915)
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 			qdf_spin_unlock_bh(&debug_info->list_lock);
286 			obj_mgr_err("macaddr is null");
287 			QDF_BUG(0);
288 			goto modify_timer;
289 		}
290 		if (!obj_name) {
291 			qdf_spin_unlock_bh(&debug_info->list_lock);
292 			obj_mgr_err("obj_name is null");
293 			QDF_BUG(0);
294 			goto modify_timer;
295 		}
296 
297 		obj_mgr_alert("#%s in L-state,MAC: " QDF_MAC_ADDR_STR,
298 			      obj_name, QDF_MAC_ADDR_ARRAY(macaddr));
299 
300 		status = qdf_list_peek_next(log_del_obj_list, node, &node);
301 
302 	} while (QDF_IS_STATUS_SUCCESS(status));
303 
304 	qdf_spin_unlock_bh(&debug_info->list_lock);
305 
306 modify_timer:
307 	/* modify timer timeout value */
308 	qdf_timer_mod(&debug_info->obj_timer, LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC);
309 }
310 
311 void wlan_objmgr_debug_info_deinit(void)
312 {
313 	struct log_del_obj *obj_to_remove;
314 	struct wlan_objmgr_debug_info *debug_info;
315 	qdf_list_node_t *node = NULL;
316 	qdf_list_t *list;
317 	bool is_child_alive = false;
318 
319 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
320 	debug_info = g_umac_glb_obj->debug_info;
321 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
322 
323 	if (!debug_info) {
324 		obj_mgr_err("debug_info is not initialized");
325 		return;
326 	}
327 	list = &debug_info->obj_list;
328 
329 	qdf_spin_lock_bh(&debug_info->list_lock);
330 
331 	/* Check if any child of global object is in L-state and remove it,
332 	 * ideally it shouldn't be
333 	 */
334 	while (qdf_list_remove_front(list, &node) == QDF_STATUS_SUCCESS) {
335 		is_child_alive = true;
336 		obj_to_remove = qdf_container_of(node,
337 						 struct log_del_obj, node);
338 		if (qdf_list_empty(&debug_info->obj_list))
339 			qdf_timer_stop(&debug_info->obj_timer);
340 		/* free the object */
341 		qdf_mem_free(obj_to_remove);
342 	}
343 	qdf_spin_unlock_bh(&debug_info->list_lock);
344 
345 	if (is_child_alive) {
346 		obj_mgr_alert("This shouldn't happen!!, No child of global"
347 			       "object should be in L-state, as global obj"
348 				"is going to destroy");
349 		QDF_BUG(0);
350 	}
351 
352 	/* free timer, destroy spinlock, list and debug_info object as
353 	 * global object is going to free
354 	 */
355 	qdf_list_destroy(list);
356 	qdf_timer_free(&debug_info->obj_timer);
357 	qdf_spinlock_destroy(&debug_info->list_lock);
358 	qdf_mem_free(debug_info);
359 
360 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
361 	g_umac_glb_obj->debug_info = NULL;
362 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
363 }
364 
365 void wlan_objmgr_debug_info_init(void)
366 {
367 	struct wlan_objmgr_debug_info *debug_info;
368 
369 	debug_info = qdf_mem_malloc(sizeof(*debug_info));
370 	if (!debug_info) {
371 		obj_mgr_err("debug_info allocation failed");
372 		g_umac_glb_obj->debug_info = NULL;
373 		return;
374 	}
375 
376 	/* Initialize timer with timeout handler */
377 	qdf_timer_init(NULL, &debug_info->obj_timer,
378 		       wlan_objmgr_iterate_log_del_obj_handler,
379 		       NULL, QDF_TIMER_TYPE_WAKE_APPS);
380 
381 	/* Initialze the node_count to 0 and create list*/
382 	qdf_list_create(&debug_info->obj_list,
383 			LOG_DEL_OBJ_LIST_MAX_COUNT);
384 
385 	/* Initialize the spin_lock to protect list */
386 	qdf_spinlock_create(&debug_info->list_lock);
387 
388 	/* attach debug_info object to global object */
389 	qdf_spin_lock_bh(&g_umac_glb_obj->global_lock);
390 	g_umac_glb_obj->debug_info = debug_info;
391 	qdf_spin_unlock_bh(&g_umac_glb_obj->global_lock);
392 }
393