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 <qdf_threads.h> 22 #include <wlan_sm_engine.h> 23 #include <wlan_sm_engine_dbg.h> 24 25 void wlan_sm_save_history(struct wlan_sm *sm, 26 enum wlan_sm_trace_type trace_type, 27 uint8_t initial_state, uint8_t final_state, 28 uint16_t event_type) 29 { 30 struct wlan_sm_history *p_sm_history = &sm->history; 31 struct wlan_sm_history_info *p_memento; 32 33 /* 34 * History saved in circular buffer. 35 * Save a pointer to next write location and increment pointer. 36 */ 37 qdf_spin_lock_bh(&p_sm_history->sm_history_lock); 38 p_memento = &p_sm_history->data[p_sm_history->index]; 39 p_sm_history->index++; 40 41 p_sm_history->index %= WLAN_SM_ENGINE_HISTORY_SIZE; 42 43 qdf_spin_unlock_bh(&p_sm_history->sm_history_lock); 44 45 qdf_mem_zero(p_memento, sizeof(*p_memento)); 46 p_memento->trace_type = trace_type; 47 p_memento->initial_state = initial_state; 48 p_memento->final_state = final_state; 49 p_memento->event_type = event_type; 50 p_memento->time = qdf_get_log_timestamp(); 51 qdf_scnprintf(p_memento->pid_name, WLAN_SM_PID_MAX_LEN, "%.6s", 52 qdf_get_current_comm()); 53 } 54 55 void wlan_sm_history_init(struct wlan_sm *sm) 56 { 57 qdf_mem_zero(&sm->history, sizeof(struct wlan_sm_history)); 58 qdf_spinlock_create(&sm->history.sm_history_lock); 59 } 60 61 void wlan_sm_history_delete(struct wlan_sm *sm) 62 { 63 qdf_spinlock_destroy(&sm->history.sm_history_lock); 64 } 65 66 static void wlan_sm_print_history_entry(struct wlan_sm *sm, 67 struct wlan_sm_history_info *ent, 68 uint16_t i) 69 { 70 const char *event_name = NULL; 71 72 if (sm->event_names) { 73 if (ent->event_type < sm->num_event_names) 74 event_name = sm->event_names[ent->event_type]; 75 76 if (!ent->trace_type) 77 return; 78 79 sm_engine_nofl_err( 80 "| 0x%016llx |%6d |%6s |%11d |%23s[%3d] |%19s[%2d] |%19s[%2d] |", 81 ent->time, i, ent->pid_name, ent->trace_type, 82 event_name ? event_name : "UNKNOWN_EVENT", 83 ent->event_type, 84 sm->state_info[ent->initial_state].name, 85 ent->initial_state, 86 sm->state_info[ent->final_state].name, 87 ent->final_state); 88 } else { 89 sm_engine_nofl_err( 90 "| 0x%016llx |%6d |%6s |%11d |%28d |%19s[%2d] |%19s[%2d] |", 91 ent->time, i, ent->pid_name, ent->trace_type, 92 ent->event_type, 93 sm->state_info[ent->initial_state].name, 94 ent->initial_state, 95 sm->state_info[ent->final_state].name, 96 ent->final_state); 97 } 98 } 99 100 void wlan_sm_print_history(struct wlan_sm *sm) 101 { 102 struct wlan_sm_history *p_sm_history = &sm->history; 103 uint8_t i; 104 uint8_t idx; 105 106 /* 107 * History saved in circular buffer. 108 * Save a pointer to next write location and increment pointer. 109 */ 110 qdf_spin_lock_bh(&p_sm_history->sm_history_lock); 111 112 sm_engine_nofl_err("|%19s |%6s |%6s |%11s |%28s |%23s |%23s |", "Time", 113 "Index", "PID", "Trace Type", "Event", 114 "Initial State", "Final State"); 115 116 for (i = 0; i < WLAN_SM_ENGINE_HISTORY_SIZE; i++) { 117 idx = (p_sm_history->index + i) % WLAN_SM_ENGINE_HISTORY_SIZE; 118 wlan_sm_print_history_entry( 119 sm, &p_sm_history->data[idx], idx); 120 } 121 122 qdf_spin_unlock_bh(&p_sm_history->sm_history_lock); 123 } 124 125 #if SM_HIST_DEBUGFS_SUPPORT 126 static void wlan_sm_print_fs_history_entry(struct wlan_sm *sm, 127 struct wlan_sm_history_info *ent, 128 uint16_t i, qdf_debugfs_file_t m) 129 { 130 const char *event_name = NULL; 131 132 if (sm->event_names) { 133 if (ent->event_type < sm->num_event_names) 134 event_name = sm->event_names[ent->event_type]; 135 136 if (!ent->trace_type) 137 return; 138 139 qdf_debugfs_printf( 140 m, "| 0x%016llx |%6d |%6s |%11d |%23s[%3d] |%19s[%2d] |%19s[%2d] |\n", 141 ent->time, i, ent->pid_name, ent->trace_type, 142 event_name ? event_name : "UNKNOWN_EVENT", 143 ent->event_type, 144 sm->state_info[ent->initial_state].name, 145 ent->initial_state, 146 sm->state_info[ent->final_state].name, 147 ent->final_state); 148 } else { 149 qdf_debugfs_printf( 150 m, "| 0x%016llx |%6d |%6s |%11d |%28d |%19s[%2d] |%19s[%2d] |\n", 151 ent->time, i, ent->pid_name, ent->trace_type, 152 ent->event_type, 153 sm->state_info[ent->initial_state].name, 154 ent->initial_state, 155 sm->state_info[ent->final_state].name, 156 ent->final_state); 157 } 158 } 159 160 void wlan_sm_print_fs_history(struct wlan_sm *sm, qdf_debugfs_file_t m) 161 { 162 struct wlan_sm_history *p_sm_history = &sm->history; 163 uint8_t i; 164 uint8_t idx; 165 166 /* 167 * History saved in circular buffer. 168 * Save a pointer to next write location and increment pointer. 169 */ 170 qdf_spin_lock_bh(&p_sm_history->sm_history_lock); 171 qdf_debugfs_printf(m, "|%19s |%6s |%6s |%11s |%28s |%23s |%23s |\n", "Time", 172 "Index", "PID", "Trace Type", "Event", 173 "Initial State", "Final State"); 174 175 for (i = 0; i < WLAN_SM_ENGINE_HISTORY_SIZE; i++) { 176 idx = (p_sm_history->index + i) % WLAN_SM_ENGINE_HISTORY_SIZE; 177 wlan_sm_print_fs_history_entry(sm, &p_sm_history->data[idx], 178 idx, m); 179 } 180 181 qdf_spin_unlock_bh(&p_sm_history->sm_history_lock); 182 } 183 #endif 184