1 /* 2 * Copyright (c) 2013-2018 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 <wlan_cmn.h> 29 #include "wlan_roam_debug.h" 30 31 /* 32 * wlan roam debug log is stored in this global structure. It can be accessed 33 * without requiring any psoc or vdev context. It will be accessible in 34 * the crash dump without having to dereference complex stack traces. 35 */ 36 static struct wlan_roam_debug_info global_wlan_roam_debug_table = { 37 { 0 }, 38 WLAN_ROAM_DEBUG_MAX_REC, 39 }; 40 41 /** 42 * wlan_roam_next_debug_log_index() - atomically increment and wrap around index 43 * @index: address of index to increment 44 * @size: wrap around this value 45 * 46 * Return: new value of index 47 */ 48 static int wlan_roam_next_debug_log_index(qdf_atomic_t *index, int size) 49 { 50 int i = qdf_atomic_inc_return(index); 51 52 if (i == WLAN_ROAM_DEBUG_MAX_REC) 53 qdf_atomic_sub(WLAN_ROAM_DEBUG_MAX_REC, index); 54 while (i >= size) 55 i -= WLAN_ROAM_DEBUG_MAX_REC; 56 57 return i; 58 } 59 60 /** 61 * wlan_roam_debug_log() - Add a debug log entry to wlan roam debug records 62 * @vdev_id: vdev identifier 63 * @op: operation identifier 64 * @peer_id: peer id 65 * @mac_addr: mac address of peer, can be NULL 66 * @peer_obj: peer object address, can be NULL 67 * @arg1: extra argument #1 68 * @arg2: extra argument #2 69 * 70 * Return: none 71 */ 72 void wlan_roam_debug_log(uint8_t vdev_id, uint8_t op, 73 uint16_t peer_id, void *mac_addr, 74 void *peer_obj, uint32_t arg1, uint32_t arg2) 75 { 76 uint32_t i; 77 struct wlan_roam_debug_rec *rec; 78 79 i = wlan_roam_next_debug_log_index( 80 &global_wlan_roam_debug_table.index, 81 WLAN_ROAM_DEBUG_MAX_REC); 82 rec = &global_wlan_roam_debug_table.rec[i]; 83 rec->time = qdf_get_log_timestamp(); 84 rec->operation = op; 85 rec->vdev_id = vdev_id; 86 rec->peer_id = peer_id; 87 if (mac_addr) 88 qdf_mem_copy(rec->mac_addr.bytes, mac_addr, 89 QDF_MAC_ADDR_SIZE); 90 else 91 qdf_mem_zero(rec->mac_addr.bytes, 92 QDF_MAC_ADDR_SIZE); 93 rec->peer_obj = peer_obj; 94 rec->arg1 = arg1; 95 rec->arg2 = arg2; 96 } 97 EXPORT_SYMBOL(wlan_roam_debug_log); 98 99 /** 100 * wlan_roam_debug_string() - convert operation value to printable string 101 * @op: operation identifier 102 * 103 * Return: printable string for the operation 104 */ 105 static char *wlan_roam_debug_string(uint32_t op) 106 { 107 switch (op) { 108 case DEBUG_PEER_CREATE_SEND: 109 return "peer create send"; 110 case DEBUG_PEER_CREATE_RESP: 111 return "peer create resp_event"; 112 case DEBUG_PEER_DELETE_SEND: 113 return "peer delete send"; 114 case DEBUG_PEER_DELETE_RESP: 115 return "peer delete resp_event"; 116 case DEBUG_PEER_MAP_EVENT: 117 return "peer map event"; 118 case DEBUG_PEER_UNMAP_EVENT: 119 return "peer unmap event"; 120 case DEBUG_PEER_UNREF_DELETE: 121 return "peer unref delete"; 122 case DEBUG_DELETING_PEER_OBJ: 123 return "peer obj deleted"; 124 case DEBUG_ROAM_SYNCH_IND: 125 return "roam synch ind event"; 126 case DEBUG_ROAM_SYNCH_CNF: 127 return "roam sync conf sent"; 128 case DEBUG_ROAM_SYNCH_FAIL: 129 return "roam sync fail event"; 130 case DEBUG_ROAM_EVENT: 131 return "roam event"; 132 case DEBUG_WOW_ROAM_EVENT: 133 return "wow wakeup roam event"; 134 case DEBUG_BUS_SUSPEND: 135 return "host suspend"; 136 case DEBUG_BUS_RESUME: 137 return "host wakeup"; 138 case DEBUG_WOW_REASON: 139 return "wow wakeup reason"; 140 default: 141 return "unknown"; 142 } 143 } 144 145 /** 146 * wlan_roam_debug_dump_table() - Print the wlan roam debug log records 147 * print all the valid debug records in the order of timestamp 148 * 149 * Return: none 150 */ 151 void wlan_roam_debug_dump_table(void) 152 { 153 uint32_t i; 154 int32_t current_index; 155 struct wlan_roam_debug_rec *dbg_rec; 156 uint64_t startt = 0; 157 uint32_t delta; 158 159 #define DEBUG_CLOCK_TICKS_PER_MSEC 19200 160 161 current_index = qdf_atomic_read(&global_wlan_roam_debug_table.index); 162 if (current_index < 0) { 163 QDF_TRACE(QDF_MODULE_ID_ROAM_DEBUG, QDF_TRACE_LEVEL_ERROR, 164 "%s: No records to dump", __func__); 165 return; 166 } 167 QDF_TRACE(QDF_MODULE_ID_ROAM_DEBUG, QDF_TRACE_LEVEL_ERROR, 168 "%s: Dumping all records. current index %d", 169 __func__, current_index); 170 171 i = current_index; 172 do { 173 /* wrap around */ 174 i = (i + 1) % WLAN_ROAM_DEBUG_MAX_REC; 175 dbg_rec = &global_wlan_roam_debug_table.rec[i]; 176 /* skip unused entry */ 177 if (dbg_rec->time == 0) 178 continue; 179 if (startt == 0) 180 startt = dbg_rec->time; 181 182 /* 183 * Divide by 19200 == right shift 8 bits, then divide by 75 184 * 32 bit computation keeps both 32 and 64 bit compilers happy. 185 * The value will roll over after approx. 33554 seconds. 186 */ 187 delta = (uint32_t) (((dbg_rec->time - startt) >> 8) & 188 0xffffffff); 189 delta = delta / (DEBUG_CLOCK_TICKS_PER_MSEC >> 8); 190 191 QDF_TRACE(QDF_MODULE_ID_ROAM_DEBUG, QDF_TRACE_LEVEL_ERROR, 192 "index = %5d timestamp = 0x%016llx delta ms = %-12u", 193 i, dbg_rec->time, delta); 194 QDF_TRACE(QDF_MODULE_ID_ROAM_DEBUG, QDF_TRACE_LEVEL_ERROR, 195 "info = %-24s vdev_id = %-3d mac addr = %pM", 196 wlan_roam_debug_string(dbg_rec->operation), 197 (int8_t) dbg_rec->vdev_id, dbg_rec->mac_addr.bytes); 198 QDF_TRACE(QDF_MODULE_ID_ROAM_DEBUG, QDF_TRACE_LEVEL_ERROR, 199 "peer obj = 0x%pK peer_id = %-4d", 200 dbg_rec->peer_obj, (int8_t) dbg_rec->peer_id); 201 QDF_TRACE(QDF_MODULE_ID_ROAM_DEBUG, QDF_TRACE_LEVEL_ERROR, 202 "arg1 = 0x%-8x arg2 = 0x%-8x", 203 dbg_rec->arg1, dbg_rec->arg2); 204 } while (i != current_index); 205 } 206 EXPORT_SYMBOL(global_wlan_roam_debug_table); 207 208 209 210