1 /* 2 * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: Implements general SM debug framework 20 */ 21 #include <wlan_sm_engine.h> 22 #include <wlan_sm_engine_dbg.h> 23 24 void wlan_sm_save_history(struct wlan_sm *sm, 25 enum wlan_sm_trace_type trace_type, 26 uint8_t initial_state, uint8_t final_state, 27 uint16_t event_type) 28 { 29 struct wlan_sm_history *p_sm_history = &sm->history; 30 struct wlan_sm_history_info *p_memento; 31 32 /* 33 * History saved in circular buffer. 34 * Save a pointer to next write location and increment pointer. 35 */ 36 qdf_spin_lock_bh(&p_sm_history->sm_history_lock); 37 p_memento = &p_sm_history->data[p_sm_history->index]; 38 p_sm_history->index++; 39 40 p_sm_history->index %= WLAN_SM_ENGINE_HISTORY_SIZE; 41 42 qdf_spin_unlock_bh(&p_sm_history->sm_history_lock); 43 44 qdf_mem_zero(p_memento, sizeof(*p_memento)); 45 p_memento->trace_type = trace_type; 46 p_memento->initial_state = initial_state; 47 p_memento->final_state = final_state; 48 p_memento->event_type = event_type; 49 p_memento->time = qdf_get_log_timestamp(); 50 } 51 52 void wlan_sm_history_init(struct wlan_sm *sm) 53 { 54 qdf_mem_zero(&sm->history, sizeof(struct wlan_sm_history)); 55 qdf_spinlock_create(&sm->history.sm_history_lock); 56 } 57 58 void wlan_sm_history_delete(struct wlan_sm *sm) 59 { 60 qdf_spinlock_destroy(&sm->history.sm_history_lock); 61 } 62 63 static void wlan_sm_print_history_entry(struct wlan_sm *sm, 64 struct wlan_sm_history_info *ent, 65 uint16_t i) 66 { 67 const char *event_name = NULL; 68 69 if (sm->event_names) { 70 if (ent->event_type < sm->num_event_names) 71 event_name = sm->event_names[ent->event_type]; 72 73 if (!ent->trace_type) 74 return; 75 76 sm_engine_nofl_err( 77 "| 0x%016llx |%6d |%11d |%23s[%3d] |%19s[%2d] |%19s[%2d] |", 78 ent->time, i, ent->trace_type, 79 event_name ? event_name : "UNKNOWN_EVENT", 80 ent->event_type, 81 sm->state_info[ent->initial_state].name, 82 ent->initial_state, 83 sm->state_info[ent->final_state].name, 84 ent->final_state); 85 } else { 86 sm_engine_nofl_err( 87 "| 0x%016llx |%6d |%11d |%28d |%19s[%2d] |%19s[%2d] |", 88 ent->time, i, ent->trace_type, 89 ent->event_type, 90 sm->state_info[ent->initial_state].name, 91 ent->initial_state, 92 sm->state_info[ent->final_state].name, 93 ent->final_state); 94 } 95 } 96 97 void wlan_sm_print_history(struct wlan_sm *sm) 98 { 99 struct wlan_sm_history *p_sm_history = &sm->history; 100 uint8_t i; 101 uint8_t idx; 102 103 /* 104 * History saved in circular buffer. 105 * Save a pointer to next write location and increment pointer. 106 */ 107 qdf_spin_lock_bh(&p_sm_history->sm_history_lock); 108 109 sm_engine_nofl_err("|%19s |%6s |%11s |%28s |%23s |%23s |", "Time", 110 "Index", "Trace Type", "Event", 111 "Initial State", "Final State"); 112 113 for (i = 0; i < WLAN_SM_ENGINE_HISTORY_SIZE; i++) { 114 idx = (p_sm_history->index + i) % WLAN_SM_ENGINE_HISTORY_SIZE; 115 wlan_sm_print_history_entry( 116 sm, &p_sm_history->data[idx], idx); 117 } 118 119 qdf_spin_unlock_bh(&p_sm_history->sm_history_lock); 120 } 121 122 #if SM_HIST_DEBUGFS_SUPPORT 123 static void wlan_sm_print_fs_history_entry(struct wlan_sm *sm, 124 struct wlan_sm_history_info *ent, 125 uint16_t i, qdf_debugfs_file_t m) 126 { 127 const char *event_name = NULL; 128 129 if (sm->event_names) { 130 if (ent->event_type < sm->num_event_names) 131 event_name = sm->event_names[ent->event_type]; 132 133 if (!ent->trace_type) 134 return; 135 136 qdf_debugfs_printf( 137 m, "| 0x%016llx |%6d |%11d |%23s[%3d] |%19s[%2d] |%19s[%2d] |\n", 138 ent->time, i, ent->trace_type, 139 event_name ? event_name : "UNKNOWN_EVENT", 140 ent->event_type, 141 sm->state_info[ent->initial_state].name, 142 ent->initial_state, 143 sm->state_info[ent->final_state].name, 144 ent->final_state); 145 } else { 146 qdf_debugfs_printf( 147 m, "| 0x%016llx |%6d |%11d |%28d |%19s[%2d] |%19s[%2d] |\n", 148 ent->time, i, ent->trace_type, 149 ent->event_type, 150 sm->state_info[ent->initial_state].name, 151 ent->initial_state, 152 sm->state_info[ent->final_state].name, 153 ent->final_state); 154 } 155 } 156 157 void wlan_sm_print_fs_history(struct wlan_sm *sm, qdf_debugfs_file_t m) 158 { 159 struct wlan_sm_history *p_sm_history = &sm->history; 160 uint8_t i; 161 uint8_t idx; 162 163 /* 164 * History saved in circular buffer. 165 * Save a pointer to next write location and increment pointer. 166 */ 167 qdf_spin_lock_bh(&p_sm_history->sm_history_lock); 168 qdf_debugfs_printf(m, "|%19s |%6s |%11s |%28s |%23s |%23s |\n", "Time", 169 "Index", "Trace Type", "Event", 170 "Initial State", "Final State"); 171 172 for (i = 0; i < WLAN_SM_ENGINE_HISTORY_SIZE; i++) { 173 idx = (p_sm_history->index + i) % WLAN_SM_ENGINE_HISTORY_SIZE; 174 wlan_sm_print_fs_history_entry(sm, &p_sm_history->data[idx], 175 idx, m); 176 } 177 178 qdf_spin_unlock_bh(&p_sm_history->sm_history_lock); 179 } 180 #endif 181