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
wlan_sm_save_history(struct wlan_sm * sm,enum wlan_sm_trace_type trace_type,uint8_t initial_state,uint8_t final_state,uint16_t event_type)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
wlan_sm_history_init(struct wlan_sm * sm)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
wlan_sm_history_delete(struct wlan_sm * sm)61 void wlan_sm_history_delete(struct wlan_sm *sm)
62 {
63 qdf_spinlock_destroy(&sm->history.sm_history_lock);
64 }
65
wlan_sm_print_history_entry(struct wlan_sm * sm,struct wlan_sm_history_info * ent,uint16_t i)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
wlan_sm_print_history(struct wlan_sm * sm)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
wlan_sm_print_fs_history_entry(struct wlan_sm * sm,struct wlan_sm_history_info * ent,uint16_t i,qdf_debugfs_file_t m)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
wlan_sm_print_fs_history(struct wlan_sm * sm,qdf_debugfs_file_t m)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