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