xref: /wlan-dirver/qca-wifi-host-cmn/utils/logging/src/wlan_roam_debug.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2013-2018, 2020-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021 Qualcomm Innovation Center, Inc. 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 /*
21  * DOC: Roaming debug log operations routines and global data
22  */
23 
24 #include <qdf_types.h>
25 #include <qdf_atomic.h>
26 #include <qdf_mem.h>
27 #include <qdf_time.h>
28 #include <qdf_trace.h>
29 #include <qdf_module.h>
30 #include <wlan_cmn.h>
31 #include "wlan_roam_debug.h"
32 
33 #ifdef FEATURE_ROAM_DEBUG
34 static void wlan_roam_rec_print(struct wlan_roam_debug_rec *dbg_rec,
35 				uint32_t idx, uint32_t delta,
36 				bool to_kernel);
37 
38 static void wlan_conn_rec_print(struct wlan_roam_debug_rec *dbg_rec,
39 				uint32_t idx, uint32_t delta,
40 				bool to_kernel);
41 
42 #ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
43 static struct wlan_roam_debug_info *global_wlan_roam_debug_table;
44 
45 /**
46  * wlan_roam_debug_init() - Allocate log buffer dynamically
47  *
48  * Return: none
49  */
50 void wlan_roam_debug_init(void)
51 {
52 	uint8_t i;
53 	global_wlan_roam_debug_table = qdf_mem_valloc(
54 				sizeof(struct wlan_roam_debug_info) * REC_MAX);
55 
56 	QDF_BUG(global_wlan_roam_debug_table);
57 
58 	if (global_wlan_roam_debug_table) {
59 		for (i = 0; i < REC_MAX; i++) {
60 			qdf_atomic_init(&global_wlan_roam_debug_table[i].index);
61 			global_wlan_roam_debug_table[i].num_max_rec =
62 						WLAN_ROAM_DEBUG_MAX_REC;
63 			if (i == REC_ROAM)
64 				global_wlan_roam_debug_table[i].rec_print =
65 					wlan_roam_rec_print;
66 			else
67 				global_wlan_roam_debug_table[i].rec_print =
68 					wlan_conn_rec_print;
69 		}
70 	}
71 }
72 
73 qdf_export_symbol(wlan_roam_debug_init);
74 
75 static inline struct wlan_roam_debug_info *wlan_roam_debug_get_table(
76 	wlan_rec_type type)
77 {
78 	if (type >= REC_MAX)
79 		return NULL;
80 	return &global_wlan_roam_debug_table[type];
81 }
82 
83 /**
84  * wlan_roam_debug_deinit() - Free log buffer allocated dynamically
85  *
86  * Return: none
87  */
88 void wlan_roam_debug_deinit(void)
89 {
90 	qdf_mem_vfree(global_wlan_roam_debug_table);
91 	global_wlan_roam_debug_table = NULL;
92 }
93 
94 qdf_export_symbol(wlan_roam_debug_deinit);
95 #else /* WLAN_LOGGING_BUFFERS_DYNAMICALLY */
96 /*
97  * wlan roam debug log is stored in this global structure. It can be accessed
98  * without requiring any psoc or vdev context. It will be accessible in
99  * the crash dump without having to dereference complex stack traces.
100  */
101 static struct wlan_roam_debug_info global_wlan_roam_debug_table[REC_MAX] = {
102 	[REC_ROAM] = {{ 0 },
103 		      .num_max_rec = WLAN_ROAM_DEBUG_MAX_REC,
104 		      .rec_print = wlan_roam_rec_print},
105 	[REC_CONN] = {{ 0 },
106 		      .num_max_rec = WLAN_ROAM_DEBUG_MAX_REC,
107 		      .rec_print = wlan_conn_rec_print},
108 };
109 
110 static inline struct wlan_roam_debug_info *wlan_roam_debug_get_table(
111 	wlan_rec_type type)
112 {
113 	if (type >= REC_MAX)
114 		return NULL;
115 	return &global_wlan_roam_debug_table[type];
116 }
117 #endif /* WLAN_LOGGING_BUFFERS_DYNAMICALLY */
118 
119 /**
120  * wlan_roam_next_debug_log_index() - atomically increment and wrap around index
121  * @index: address of index to increment
122  * @size: wrap around this value
123  *
124  * Return: new value of index
125  */
126 static int wlan_roam_next_debug_log_index(qdf_atomic_t *index, int size)
127 {
128 	int i = qdf_atomic_inc_return(index);
129 
130 	if (i == WLAN_ROAM_DEBUG_MAX_REC)
131 		qdf_atomic_sub(WLAN_ROAM_DEBUG_MAX_REC, index);
132 	while (i >= size)
133 		i -= WLAN_ROAM_DEBUG_MAX_REC;
134 
135 	return i;
136 }
137 
138 /**
139  * wlan_roam_debug_log() - Add a debug log entry to wlan roam debug records
140  * @vdev_id: vdev identifier
141  * @op: operation identifier
142  * @peer_id: peer id
143  * @mac_addr: mac address of peer, can be NULL
144  * @peer_obj: peer object address, can be NULL
145  * @arg1: extra argument #1
146  * @arg2: extra argument #2
147  *
148  * Return: none
149  */
150 void wlan_roam_debug_log(uint8_t vdev_id, uint8_t op,
151 			uint16_t peer_id, void *mac_addr,
152 			void *peer_obj, uint32_t arg1, uint32_t arg2)
153 {
154 	wlan_rec_debug_log(REC_ROAM, vdev_id, op, peer_id, mac_addr,
155 			   peer_obj, arg1, arg2);
156 }
157 
158 qdf_export_symbol(wlan_roam_debug_log);
159 
160 void wlan_rec_debug_log(wlan_rec_type rec_type, uint8_t vdev_id, uint8_t op,
161 			uint16_t peer_id, const void *mac_addr,
162 			void *peer_obj, uint32_t arg1, uint32_t arg2)
163 {
164 	uint32_t i;
165 	struct wlan_roam_debug_info *dbg_tbl;
166 	struct wlan_roam_debug_rec *rec;
167 
168 	dbg_tbl = wlan_roam_debug_get_table(rec_type);
169 	if (!dbg_tbl)
170 		return;
171 
172 	i = wlan_roam_next_debug_log_index(
173 				    &dbg_tbl->index,
174 				    WLAN_ROAM_DEBUG_MAX_REC);
175 	rec = &dbg_tbl->rec[i];
176 	rec->time = qdf_get_log_timestamp();
177 	rec->operation = op;
178 	rec->vdev_id = vdev_id;
179 	rec->peer_id = peer_id;
180 	if (mac_addr)
181 		qdf_mem_copy(rec->mac_addr.bytes, mac_addr,
182 			     QDF_MAC_ADDR_SIZE);
183 	else
184 		qdf_mem_zero(rec->mac_addr.bytes,
185 			     QDF_MAC_ADDR_SIZE);
186 	rec->peer_obj = peer_obj;
187 	rec->arg1 = arg1;
188 	rec->arg2 = arg2;
189 }
190 
191 qdf_export_symbol(wlan_rec_debug_log);
192 
193 /**
194  * wlan_roam_debug_string() - convert operation value to printable string
195  * @op: operation identifier
196  *
197  * Return: printable string for the operation
198  */
199 static char *wlan_roam_debug_string(uint32_t op)
200 {
201 	switch (op) {
202 	case DEBUG_PEER_CREATE_SEND:
203 		return "peer create send";
204 	case DEBUG_PEER_CREATE_RESP:
205 		return "peer create resp_event";
206 	case DEBUG_PEER_DELETE_SEND:
207 		return "peer delete send";
208 	case DEBUG_PEER_DELETE_RESP:
209 		return "peer delete resp_event";
210 	case DEBUG_PEER_MAP_EVENT:
211 		return "peer map event";
212 	case DEBUG_PEER_UNMAP_EVENT:
213 		return "peer unmap event";
214 	case DEBUG_PEER_UNREF_DELETE:
215 		return "peer unref delete";
216 	case DEBUG_DELETING_PEER_OBJ:
217 		return "peer obj deleted";
218 	case DEBUG_ROAM_SYNCH_IND:
219 		return "roam synch ind event";
220 	case DEBUG_ROAM_SYNCH_CNF:
221 		return "roam sync conf sent";
222 	case DEBUG_ROAM_SYNCH_FAIL:
223 		return "roam sync fail event";
224 	case DEBUG_ROAM_EVENT:
225 		return "roam event";
226 	case DEBUG_WOW_ROAM_EVENT:
227 		return "wow wakeup roam event";
228 	case DEBUG_BUS_SUSPEND:
229 		return "host suspend";
230 	case DEBUG_BUS_RESUME:
231 		return "host wakeup";
232 	case DEBUG_WOW_REASON:
233 		return "wow wakeup reason";
234 	case DEBUG_CONN_CONNECTING:
235 		return "conn";
236 	case DEBUG_CONN_ASSOCIATION:
237 		return "assoc";
238 	case DEBUG_CONN_CONNECT_RESULT:
239 		return "cnrlt";
240 	case DEBUG_CONN_ROAMING:
241 		return "roaming";
242 	case DEBUG_CONN_ROAMED:
243 		return "roamed";
244 	case DEBUG_CONN_ROAMED_IND:
245 		return "rmind";
246 	case DEBUG_CONN_DISCONNECT:
247 		return "disc";
248 	case DEBUG_CONN_DISCONNECT_HANDLER:
249 		return "dishdr";
250 	case DEBUG_CONN_DISCONNECT_IND:
251 		return "disind";
252 	case DEBUG_CONN_RSO:
253 		return "rso";
254 	default:
255 		return "unknown";
256 	}
257 }
258 
259 void wlan_roam_rec_print(struct wlan_roam_debug_rec *dbg_rec,
260 			 uint32_t idx, uint32_t delta,
261 			 bool to_kernel)
262 {
263 	roam_debug("index = %5d timestamp = 0x%016llx delta ms = %-12u",
264 		   idx, dbg_rec->time, delta);
265 	roam_debug("info = %-24s vdev_id = %-3d mac addr = "QDF_MAC_ADDR_FMT,
266 		   wlan_roam_debug_string(dbg_rec->operation),
267 		   (int8_t)dbg_rec->vdev_id,
268 		   QDF_MAC_ADDR_REF(dbg_rec->mac_addr.bytes));
269 	roam_debug("peer obj = 0x%pK peer_id = %-4d", dbg_rec->peer_obj,
270 		   (int8_t)dbg_rec->peer_id);
271 	roam_debug("arg1 = 0x%-8x arg2 = 0x%-8x", dbg_rec->arg1,
272 		   dbg_rec->arg2);
273 }
274 
275 void wlan_conn_rec_print(struct wlan_roam_debug_rec *dbg_rec,
276 			 uint32_t idx, uint32_t delta,
277 			 bool to_kernel)
278 {
279 	if (to_kernel) {
280 		roam_info("i %d ti 0x%08llx ms %u vdv %d %s a1 0x%x a2 0x%x "QDF_MAC_ADDR_FMT,
281 			  idx, dbg_rec->time, delta, (int8_t)dbg_rec->vdev_id,
282 			  wlan_roam_debug_string(dbg_rec->operation),
283 			  dbg_rec->arg1, dbg_rec->arg2,
284 			  QDF_MAC_ADDR_REF(dbg_rec->mac_addr.bytes));
285 	} else {
286 		roam_debug("i %d ti 0x%08llx ms %u vdv %d %s a1 0x%x a2 0x%x "QDF_MAC_ADDR_FMT,
287 			   idx, dbg_rec->time, delta, (int8_t)dbg_rec->vdev_id,
288 			   wlan_roam_debug_string(dbg_rec->operation),
289 			   dbg_rec->arg1, dbg_rec->arg2,
290 			   QDF_MAC_ADDR_REF(dbg_rec->mac_addr.bytes));
291 	}
292 }
293 
294 /**
295  * wlan_rec_debug_dump_table() - Print the wlan roam debug log records
296  * print all the valid debug records in the order of timestamp
297  *
298  * Return: none
299  */
300 void wlan_rec_debug_dump_table(wlan_rec_type rec_type, uint32_t count,
301 			       bool to_kernel)
302 {
303 	uint32_t i;
304 	int32_t current_index;
305 	struct wlan_roam_debug_info *dbg_tbl;
306 	struct wlan_roam_debug_rec *dbg_rec;
307 	uint64_t startt = 0;
308 	uint32_t delta;
309 
310 #define DEBUG_CLOCK_TICKS_PER_MSEC 19200
311 	if (count > WLAN_ROAM_DEBUG_MAX_REC)
312 		count = WLAN_ROAM_DEBUG_MAX_REC;
313 	dbg_tbl = wlan_roam_debug_get_table(rec_type);
314 	if (!dbg_tbl)
315 		return;
316 
317 	current_index = qdf_atomic_read(&dbg_tbl->index);
318 	if (current_index < 0) {
319 		roam_debug("No records to dump");
320 		return;
321 	}
322 	roam_debug("dump %d rec type %d idx %d", count, rec_type,
323 		   current_index);
324 
325 	i = (current_index + WLAN_ROAM_DEBUG_MAX_REC - count) %
326 		WLAN_ROAM_DEBUG_MAX_REC;
327 	do {
328 		/* wrap around */
329 		i = (i + 1) % WLAN_ROAM_DEBUG_MAX_REC;
330 		dbg_rec = &dbg_tbl->rec[i];
331 		/* skip unused entry */
332 		if (dbg_rec->time == 0)
333 			continue;
334 		if (count == 0)
335 			break;
336 		count--;
337 
338 		if (startt == 0)
339 			startt = dbg_rec->time;
340 		/*
341 		 * Divide by 19200 == right shift 8 bits, then divide by 75
342 		 * 32 bit computation keeps both 32 and 64 bit compilers happy.
343 		 * The value will roll over after approx. 33554 seconds.
344 		 */
345 		delta = (uint32_t) (((dbg_rec->time - startt) >> 8) &
346 				    0xffffffff);
347 		delta = delta / (DEBUG_CLOCK_TICKS_PER_MSEC >> 8);
348 
349 		if (dbg_tbl->rec_print)
350 			dbg_tbl->rec_print(dbg_rec, i, delta, to_kernel);
351 	} while (i != current_index);
352 }
353 
354 qdf_export_symbol(wlan_rec_debug_dump_table);
355 
356 /**
357  * wlan_roam_debug_dump_table() - Print the wlan roam debug log records
358  * print all the valid debug records in the order of timestamp
359  *
360  * Return: none
361  */
362 void wlan_roam_debug_dump_table(void)
363 {
364 	wlan_rec_debug_dump_table(REC_ROAM, WLAN_ROAM_DEBUG_MAX_REC, false);
365 }
366 qdf_export_symbol(wlan_roam_debug_dump_table);
367 
368 #endif /* FEATURE_ROAM_DEBUG */
369