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