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