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